utils.class.php 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824
  1. <?php
  2. if (!defined('IN_ONLINE')) {
  3. exit('Access Denied');
  4. }
  5. /**
  6. * Description of utilsclass
  7. *
  8. * @author Administrator
  9. */
  10. class utils {
  11. public static function checkPassword($password,$rule="",$user_login="") {
  12. $str ="";
  13. if (!empty($rule)) {
  14. //是否校验大小写
  15. if (!empty($rule["hasOneUpperChar"])&&$rule["hasOneUpperChar"]) {
  16. if (!preg_match('/[A-Z]/',$password)) {
  17. $str ="Password must contain uppercase letters";
  18. }
  19. }
  20. //是否校验小写
  21. if (!empty($rule["hasOneLowerChar"])&&$rule["hasOneLowerChar"]) {
  22. if (!preg_match('/[a-z]/',$password)) {
  23. $str ="Password must contain lowercase letters";
  24. }
  25. }
  26. //是否存在数字
  27. if (!empty($rule["hasOneNumberChar"])&&$rule["hasOneNumberChar"]) {
  28. if (!preg_match('/[0-9]/',$password)) {
  29. $str ="Password must contain numbers";
  30. }
  31. }
  32. $sql = "select user_type from ra_online_user_roles_rel where upper(user_login)=upper('".$user_login."') and exists(select count(0) from ra_online_user where upper(user_login)=upper('".$user_login."') and is_desktop=true) order by id desc limit 1;";
  33. $user_type = common::excuteOneSql($sql);
  34. if (!empty($user_type)&&$user_type=="Super User") {
  35. if (strlen($password)<$rule["SuperMinLen"]||strlen($password)>$rule["SuperMaxLen"]) {
  36. $str ="Super user password length between ".$rule["SuperMinLen"]." and ".$rule["SuperMaxLen"];
  37. }
  38. }else{
  39. //校验密码长度
  40. if (strlen($password)<$rule["MinLen"]||strlen($password)>$rule["MaxLen"]) {
  41. $str ="Password length between ".$rule["MinLen"]." and ".$rule["MaxLen"];
  42. }
  43. }
  44. return $str;
  45. }else{
  46. if (preg_match('/^\d*$/', $password) || preg_match('/^[a-zA-Z]+$/', $password)) {
  47. $str ="Must include letters and numbers";
  48. }
  49. $len = strlen($password);
  50. $t = substr($password, 0, 1);
  51. for ($i = 1; $i < $len; $i++) {
  52. $t1 = substr($password, $i, 1);
  53. if ($t != $t1) {
  54. return "";
  55. }
  56. }
  57. return "error";
  58. }
  59. }
  60. //隐藏邮箱地址
  61. public static function maskEmail($email) {
  62. $idex = strlen($email) - strrpos($email, ".");
  63. $mask = substr($email, 0, 1) . str_repeat('*', 6) . "@" . str_repeat('*', 3) . substr($email, -$idex);
  64. return $mask;
  65. }
  66. public static function getInSql($str, $not = false, $sep = ";") {
  67. $str = trim($str);
  68. $str = trim($str, $sep);
  69. $str = trim($str);
  70. if (empty($str) && $str !== "0" && $str !== 0)
  71. return "in ('') and 1<>1";
  72. $str = strtolower($str);
  73. if (utils::checkExist($str, $sep)) {
  74. $aa = explode($sep, $str);
  75. $msg = "";
  76. foreach ($aa as $value) {
  77. $value = trim($value);
  78. if (empty($value))
  79. continue;
  80. if (empty($msg))
  81. $msg = "'" . common::check_input($value) . "'";
  82. else
  83. $msg .= ",'" . common::check_input($value) . "'";
  84. }
  85. if ($not !== FALSE)
  86. return " not in (" . $msg . ")";
  87. else
  88. return " in (" . $msg . ")";
  89. } else {
  90. if ($not !== FALSE)
  91. return " != '" . common::check_input(trim($str)) . "'";
  92. else
  93. return " = '" . common::check_input(trim($str)) . "'";
  94. }
  95. }
  96. public static function checkExist($string, $search, $u = TRUE) {
  97. if ($u === TRUE) {
  98. if (stripos($string, $search) !== false)
  99. return TRUE;
  100. }else {
  101. if (strpos($string, $search) !== false)
  102. return TRUE;
  103. }
  104. return FALSE;
  105. }
  106. public static function endWith($string, $end, $u = TRUE) {
  107. if ($u === TRUE) {
  108. $string = strtolower($string);
  109. $end = strtolower($end);
  110. return strrchr($string, $end) == $end;
  111. }
  112. return strrchr($string, $end) == $end;
  113. }
  114. public static function _get($str) {
  115. $rs = isset($_POST[$str]) ? $_POST[$str] : null;
  116. if (empty($rs))
  117. $rs = isset($_GET[$str]) ? $_GET[$str] : null;
  118. return $rs;
  119. }
  120. public static function startWith($string, $start, $u = TRUE) {
  121. if ($u === TRUE)
  122. return stripos($string, $start) === 0;
  123. return strpos($string, $start) === 0;
  124. }
  125. public static function outDisplay($content, $is_time = 'f', $is_first = 'f', $is_boolean = 'f', $excel_export = FALSE) {
  126. if (empty($content) && $content !== 0 && $content !== "0")
  127. return "";
  128. if (strtolower($is_time) == 't')
  129. return utils::dealTimeDisplay($content);
  130. if (strtolower($is_first) == 't') {
  131. if ($excel_export !== FALSE)
  132. return utils::getCompanyName($content);
  133. else
  134. return '<span title="' . $content . '">' . utils::getCompanyName($content) . '</span>';
  135. }
  136. if (strtolower($is_boolean) == 't')
  137. return utils::outTrue($content);
  138. return nl2br($content);
  139. }
  140. public static function _output($value) {
  141. if (empty($value))
  142. return "&nbsp;";
  143. else
  144. return $value;
  145. }
  146. public static function dealTimeDisplay($date) {
  147. if (empty($date))
  148. return "";
  149. if (strlen($date) > 10)
  150. return date("m/d/Y H:i:s", strtotime($date));
  151. return date("m/d/Y", strtotime($date));
  152. }
  153. public static function outDisplayForMerge($frist,$last,$split = "/") {
  154. if($frist == $last){
  155. return $frist;
  156. }
  157. if (!empty($frist)){
  158. if(!empty($last)){
  159. return $frist.$split.$last;
  160. }else{
  161. return $frist;
  162. }
  163. }else{
  164. return $last;
  165. }
  166. }
  167. public static function outTrue($r) {
  168. if (empty($r))
  169. return "No";
  170. $r = strtolower($r);
  171. if ($r == "t")
  172. return "Yes";
  173. elseif ($r == "f")
  174. return "No";
  175. else
  176. return $r;
  177. }
  178. public static function getCompanyName($detail) {
  179. $detail = nl2br($detail);
  180. if (strpos($detail, '<br />') === FALSE)
  181. return $detail;
  182. return substr($detail, 0, strpos($detail, '<br />'));
  183. }
  184. public static function getEmail($serial_no) {
  185. $ocean = common::excuteObjectSql("select sales_rep, last_user, created_by, order_from, h_bol, consignee, dest_op, agent from public.kln_ocean where md5(serial_no)=md5('$serial_no') "
  186. . "order by schem_not_display nulls last limit 1");
  187. $schema = $ocean["order_from"] . ".";
  188. if(empty($ocean)){
  189. $ocean = common::excuteObjectSql("select sales_rep, last_user, created_by,'public' as order_from, h_bol, consignee, dest_op, destination_station as agent from public.ocean
  190. where md5(serial_no)=md5('$serial_no') order by schem_not_display nulls last limit 1");
  191. $schema = "public.";
  192. }
  193. //如果不是ocean air 直接返回,这里搬得ocean当前取值逻辑
  194. if(empty($ocean)){
  195. $email["email"] = "";
  196. $email["h_bol"] = "";
  197. $email["consignee"] = "";
  198. return $email;
  199. }
  200. $dest_op_from_agent = common::excuteOneSql("select dest_op_from_agent from " . $schema . "ocean where md5(serial_no)=md5('$serial_no')");
  201. if ($ocean["agent"] == "KYMTL" || $ocean["agent"] == "KYYYZ") {
  202. $email = array();
  203. $email["email"] = "";
  204. if (!empty($dest_op_from_agent)) {
  205. $so_email = common::excuteOneSql("select email from " . $schema . "employee where employee_id='" . $dest_op_from_agent . "' and active=true");
  206. }
  207. if (!empty($so_email)) {
  208. if (empty($email["email"])) {
  209. $email["email"] = $so_email;
  210. } else {
  211. $email["email"] .= ";" . $so_email;
  212. }
  213. }
  214. if (!empty($ocean["sales_rep"])) {
  215. $rep_email = common::excuteOneSql("select email from " . $schema . "employee where lower(salesopcode)='" . strtolower($ocean["sales_rep"]) . "' and active=true");
  216. if (!empty($rep_email)) {
  217. if (empty($email["email"])) {
  218. $email["email"] = $rep_email;
  219. } else {
  220. $email["email"] .= ";" . $rep_email;
  221. }
  222. }
  223. }
  224. } else {
  225. $email = common::excuteObjectSql("select string_agg(e.email, ';') as email, string_agg(e.first_name, ';') as name from " . $schema . "ra_online_user u, " . $schema . "employee e WHERE u.employee_id = e.employee_id and "
  226. . "lower(u.user_login) in ('" . strtolower($ocean["created_by"]) . "', '" . strtolower($ocean["last_user"]) . "')");
  227. if (empty($dest_op_from_agent)) {
  228. if (!empty($ocean["dest_op"])) {
  229. $so_email = common::excuteOneSql("select email from " . $schema . "employee where employee_id='" . $ocean["dest_op"] . "' and active=true");
  230. }
  231. } else {
  232. $so_email = common::excuteOneSql("select email from " . $schema . "employee where employee_id='" . $dest_op_from_agent . "' and active=true");
  233. }
  234. if (empty($so_email)) {
  235. if ($ocean["agent"] == "APEXSFO") {
  236. $so_email = "oid2@apexshipping.com";
  237. }
  238. if ($ocean["agent"] == "APEXLAX") {
  239. $so_email = "laxoid@apexshipping.com";
  240. }
  241. if ($ocean["agent"] == "APEXNYC") {
  242. $so_email = "NYCOID@APEXSHIPPING.COM";
  243. }
  244. if ($ocean["agent"] == "APEXPNW") {
  245. $so_email = "pnwoid@apexshipping.com";
  246. }
  247. if ($ocean["agent"] == "STLUTA") {
  248. $so_email = "starlinkOID@apexshipping.com ";
  249. }
  250. if ($ocean["agent"] == "APEXORD") {
  251. $so_email = "ordoid@apexshipping.com";
  252. }
  253. }
  254. if (!empty($so_email)) {
  255. if (empty($email["email"])) {
  256. $email["email"] = $so_email;
  257. } else {
  258. $email["email"] .= ";" . $so_email;
  259. }
  260. }
  261. if (!empty($ocean["sales_rep"])) {
  262. $rep_email = common::excuteOneSql("select email from " . $schema . "employee where lower(salesopcode)='" . strtolower($ocean["sales_rep"]) . "' and active=true");
  263. if (!empty($rep_email)) {
  264. if (empty($email["email"])) {
  265. $email["email"] = $rep_email;
  266. } else {
  267. $email["email"] .= ";" . $rep_email;
  268. }
  269. }
  270. }
  271. }
  272. //邮件处理,去重
  273. $array = array_filter(
  274. array_map('trim', explode(';', $email["email"])),
  275. 'strlen'
  276. );
  277. $array = array_unique($array);
  278. $email["email"] = utils::implode(';',$array);
  279. $email["h_bol"] = $ocean["h_bol"];
  280. $email["consignee"] = $ocean["consignee"];
  281. return $email;
  282. }
  283. /***
  284. * 过滤json中的某个数据
  285. * @param unknown $json
  286. * @param unknown $search
  287. * @param unknown $replace
  288. * @return mixed
  289. */
  290. public static function jsonFiltration($search,$replace,$json){
  291. //处理json中将斜杠转义问题
  292. $json = str_replace("\\/", "/", $json);
  293. return str_replace($search, $replace, $json);
  294. }
  295. /*
  296. * calculate eta destination by etd port
  297. */
  298. public static function calculate_ETA_Des($serial_no) {
  299. $sql = "SELECT m_eta as eat, mport_of_discharge as poul, place_of_delivery as pod,service from ocean where lower(serial_no) = '" . strtolower($serial_no) . "'";
  300. $rs = common::excuteObjectSql($sql);
  301. $date = "";
  302. if (!empty($rs['eat'])) {
  303. $date = utils::calculate_ETA_Dest($rs['eat'], $rs['poul'], $rs['pod'], $rs['service']);
  304. }
  305. return $date;
  306. }
  307. public static function calculate_ETA_Dest($eta, $poul, $pod, $service) {
  308. if (empty($poul) || empty($pod))
  309. return $eta;
  310. $sql = "SELECT door_days, cy_days
  311. FROM eta_dest
  312. WHERE eta_dest.state::text = ((( SELECT unlocode.state
  313. FROM ports, unlocode
  314. WHERE ports.uncode::text = unlocode.uncode::text AND ports.code::text = '" . common::check_input($pod) . "'
  315. LIMIT 1))::text) AND (','::text || eta_dest.pod::text) ~~* (('%,'::text || '" . common::check_input($poul) . "') || '%'::text)
  316. LIMIT 1";
  317. //$sql = "select door_days, cy_days from eta_dest where state = (select state from ports where code = '" . common::check_input($poul) . "' limit 1) and ','||pod ilike '%," . common::check_input($pod) . "%'";
  318. $rs = common::excuteObjectSql($sql);
  319. if (empty($rs))
  320. return $eta;
  321. if (utils::endWith($service, "cy"))
  322. return common::addDays($eta, $rs['cy_days']);
  323. else
  324. return common::addDays($eta, $rs['door_days']);
  325. }
  326. /*
  327. * password change, email alert
  328. */
  329. public static function sendEmailByPassword($username, $password, $email, $companyname='') {
  330. $sql = "select subject, ra_content as content from ra_online_email_tpl where lower(ra_type) = 'forgotpw'";
  331. $rs = common::excuteObjectSql($sql);
  332. if (!empty($rs)) {
  333. $subject = $rs['subject'];
  334. $content = $rs['content'];
  335. }
  336. if (!empty($subject) && !empty($content)) {
  337. $content = str_replace('<{username}>', $username, $content);
  338. $content = str_replace('<{password}>', $password, $content);
  339. $content = str_replace('<{companyname}>', $companyname, $content);
  340. global $db;
  341. common::excuteUpdateSql("INSERT INTO public.email_record_forgotpassword(type, title, from_email, to_email, content, insert_date,
  342. cc_email) VALUES ('forgot_password', '" . common::check_input($subject) . "', 'US.KApex.Online@kerryapex.com', '" .
  343. common::check_input($email) . "', '" . common::check_input($content) . "', now(), '');");
  344. return "success";
  345. //return Mail::sendMail($email, $subject, $content);
  346. } else
  347. return null;
  348. }
  349. /**
  350. * reset password link email sendEmailByResetPassword
  351. */
  352. public static function sendEmailByResetPassword($data, $email) {
  353. if(strtolower($data["user_type"]) == "employee"){
  354. $sql = "select subject, ra_content as content from ra_online_email_tpl where lower(ra_type) = 'ra_reset'";
  355. } else {
  356. $sql = "select subject, ra_content as content from ra_online_email_tpl where lower(ra_type) = 'kln_reset'";
  357. }
  358. $rs = common::excuteObjectSql($sql);
  359. if (!empty($rs)) {
  360. $subject = $rs['subject'];
  361. $content = $rs['content'];
  362. }
  363. if (!empty($subject) && !empty($content)) {
  364. $verifcation_code = utils::AES_128_CBC_Encrypt($data['user_login'],"USAIandy20244Q9X","0123456123456789");
  365. //http://localhost:8080/k_new_online/login?state=reset&verifcation_code=XXX
  366. $encoded = rawurlencode($verifcation_code);
  367. $link = SERVER_Vue_PAHT."login?state=reset&name=".$data['user_login']."&verifcation_code=".$encoded;
  368. $tplData = array("username"=>$data['user_login'],
  369. "creation_date"=>$data['current_time'],
  370. "link" =>$link);
  371. // 动态构建替换数组(格式:[key] => value)
  372. $replacements = [];
  373. foreach ($tplData as $key => $value) {
  374. $replacements["{{$key}}"] = $value;
  375. $replacements["{{{$key}}}"] = $value;
  376. }
  377. $content = strtr($content, $replacements);
  378. $content = common::check_input($content);
  379. common::excuteUpdateSql("INSERT INTO public.email_record_forgotpassword(type, title, from_email, to_email, content, insert_date,
  380. cc_email) VALUES ('forgot_password', '" . common::check_input($subject) . "', 'US.KApex.Online@kerryapex.com', '" .
  381. common::check_input($email) . "', '" . $content . "', now(), '');
  382. INSERT INTO public.customer_service_secret_key(secret_key, create_time) VALUES('".$verifcation_code."',now())");
  383. return "success";
  384. //return Mail::sendMail($email, $subject, $content);
  385. } else
  386. return null;
  387. }
  388. /**
  389. * reset password link email sendEmailByResetPassword
  390. */
  391. public static function sendEmailWithPasswordUpdate($user_login, $user_type) {
  392. if (strtolower($user_type) == "employee"){
  393. $sql = "select subject, ra_content as content from ra_online_email_tpl where lower(ra_type) = 'ra_passwordchange'";
  394. } else {
  395. $sql = "select subject, ra_content as content from ra_online_email_tpl where lower(ra_type) = 'kln_passwordchange'";
  396. }
  397. $rs = common::excuteObjectSql($sql);
  398. if (!empty($rs)) {
  399. $subject = $rs['subject'];
  400. $content = $rs['content'];
  401. }
  402. if (!empty($subject) && !empty($content)) {
  403. if(strtolower($user_type) == "employee"){
  404. $sql = "SELECT lower(ra_name) as ra_name, ra_value from ra_online_config where lower(ra_name) in ('employee_password_change_cycle')";
  405. } else {
  406. $sql = "SELECT lower(ra_name) as ra_name, ra_value from ra_online_config where lower(ra_name) in ('customer_password_change_cycle')";
  407. }
  408. $PASSWORD_CHANGE_CYCLE = 0;
  409. $rs1s = common::excuteListSql($sql);
  410. foreach ($rs1s as $rs1) {
  411. $PASSWORD_CHANGE_CYCLE = $rs1['ra_value'];
  412. }
  413. $dateInfo = common::excuteObjectSql("select
  414. to_char(now(), 'Mon-DD-YYYY') as current_date,
  415. to_char(now(), 'Mon-DD-YYYY HH24:MI:SS') as current_time,
  416. to_char((current_date + INTERVAL '".$PASSWORD_CHANGE_CYCLE." days'),'Mon-DD-YYYY') as expiry_date ;");
  417. $tplData = array("username"=>$user_login,
  418. "creation_date"=>$dateInfo['current_time'],
  419. "update_date"=>$dateInfo['current_date'],
  420. "expiry_date"=>$dateInfo['expiry_date']);
  421. // 动态构建替换数组(格式:[key] => value)
  422. $replacements = [];
  423. foreach ($tplData as $key => $value) {
  424. $replacements["{{$key}}"] = $value;
  425. $replacements["{{{$key}}}"] = $value;
  426. }
  427. $content = strtr($content, $replacements);
  428. $content = common::check_input($content);
  429. $email = _getLoginEamil();
  430. $sql = "INSERT INTO email_record(type, title, from_email, to_email, content, insert_date, cc_email, attachment_path)
  431. VALUES ('kln_passwordChange', '" . common::check_input($subject) . "', 'US.KApex.Online@kerryapex.com', '" .
  432. common::check_input($email) . "', '" . common::check_input($content) . "', now(), '', '');";
  433. common::excuteUpdateSql($sql);
  434. return "success";
  435. } else
  436. return null;
  437. }
  438. public static function operation_log_records(){
  439. //排除opreation_log操作
  440. if( empty($_REQUEST["operate"])
  441. || ($_REQUEST["action"] == "login" && $_REQUEST["operate"] == "verifcation_code")
  442. || ($_REQUEST["action"] == "login" && $_REQUEST["operate"] == "check_uname")
  443. || ($_REQUEST["action"] == "ocean_order" && $_REQUEST["operate"] == "setting_ocean_order_display")
  444. || ($_REQUEST["action"] == "ocean_booking" && $_REQUEST["operate"] == "setting_display")
  445. //opreation_log 过滤非下载的所有请求
  446. || ($_REQUEST["action"] == "opreation_log" && $_REQUEST["operate"] != "excel")
  447. //monitoring_setting 过滤非查询和保存的所有请求
  448. || ($_REQUEST["action"] == "monitoring_setting"
  449. && !($_REQUEST["operate"] == "monitoring_rules_init" || $_REQUEST["operate"] == "monitoring_rules_do"))
  450. //notifications_rules 过滤以下和登录自动轮播和五分钟有消息提醒
  451. || ($_REQUEST["action"] == "notifications_rules"
  452. && ($_REQUEST["operate"] == "check_notifications_message"
  453. || $_REQUEST["operate"] == "notifications_see_all"
  454. || ($_REQUEST["operate"] == "notifications_init" && $_REQUEST['info_type'] == 'true')
  455. || ($_REQUEST["operate"] == "notifications_init" && !empty($_REQUEST['current_time']))))
  456. ){
  457. return;
  458. }
  459. //排除robot的相关的记录
  460. if((stripos($_REQUEST["action"], "robot") === 0)){
  461. return;
  462. }
  463. if($_REQUEST["action"] == "login" && $_REQUEST["operate"] == "tracking_checked"){
  464. //public tracking_checked 的user name 记录对应IP 地址
  465. $user_type = "Customer";
  466. $user_name = common::ip();
  467. } elseif($_REQUEST["action"] == "login" && $_REQUEST["operate"] == "do_login"){
  468. //移除do_login 因为在登录的过程中,是没有用户信息的
  469. $user_name = $_REQUEST["uname"];
  470. } else{
  471. $user_name = _getLoginName();
  472. }
  473. $user_type = _isApexLogin() ? "Employee" : "Customer";
  474. //如果在没有登录前,没有登录信息,指定用户
  475. if(!isset($_SESSION['ONLINE_USER'])){
  476. $user_type = common::excuteOneSql("select user_type from public.ra_online_user u where lower(user_login) = '" . strtolower($user_name) . "'");
  477. }
  478. $operateInfo = utils::getPageByAction($_REQUEST["action"],$_REQUEST["operate"]);
  479. $page = common::check_input($operateInfo["page"]);
  480. $operation = common::check_input($operateInfo["operate"]);
  481. $operation_detail = common::check_input(utils::analyzeOperationDetail($_REQUEST["action"],$_REQUEST["operate"]));
  482. if(empty($operation_detail)){
  483. $operation_detail = common::check_input(utils::jsonFiltration("null", "\"\"", json_encode($_REQUEST)));
  484. }
  485. $user_name = common::check_input($user_name);
  486. //过滤一分钟以内,相同用户的重复请求
  487. $exist_sql = "select count(1) from public.customer_service_operation_log
  488. where user_name = '$user_name'
  489. and page = '$page' and operation = '$operation' and operation_detail = '$operation_detail'
  490. and operation_time > NOW() - INTERVAL '1 minute' limit 1;";
  491. $exist_obj = common::excuteOneSql($exist_sql);
  492. if(empty($exist_obj)){
  493. $sql = "INSERT INTO public.customer_service_operation_log(user_type, user_name, page, operation, operation_detail,
  494. operation_time)
  495. VALUES ('$user_type', '$user_name', '$page', '$operation', '$operation_detail', now())";
  496. common::excuteUpdateSql($sql);
  497. }
  498. }
  499. public static function getPageByAction($action,$operate){
  500. //取消
  501. $operationConvertName = array(
  502. "login=do_login" => array("page" =>"Login","operate"=>"Login"),
  503. "login=forgot_password" => array("page" =>"Login","operate"=>"Forgot_PPassword"),
  504. "login=logout" => array("page" =>"logout","operate"=>"logout"),
  505. "login=update_pwd_expires" => array("page" =>"Login","operate"=>"Reset password"),
  506. "ocean_booking=search" => array("page" =>"Booking","operate"=>"Search"),
  507. "Booking_Search=save_setting_display" => array("page" =>"Booking","operate"=>"Customize Coulumns"),
  508. "booking=autody" => array("page" =>"Booking","operate"=>"More Filter"),
  509. "booking=autoport" => array("page" =>"Booking","operate"=>"More Filter"),
  510. "ocean_booking=detail" => array("page" =>"Booking","operate"=>"Open Detailed Page"),
  511. "ocean_booking=excel" => array("page" =>"Booking","operate"=>"Download"),
  512. "ocean_booking=save_communication" => array("page" =>"Booking","operate"=>"Send Email"),
  513. "opreation_log=search" => array("page" =>"Opreation_log","operate"=>"Search"),
  514. "login=tracking_checked" => array("page" =>"Tracking","operate"=>"Public tracking"),
  515. "ocean_order=search" => array("page" =>"Tracking","operate"=>"Search"),
  516. "Ocean_Search=save_setting_display" => array("page" =>"Tracking","operate"=>"Customize Coulumns"),
  517. "tracking=autody" => array("page" =>"Tracking","operate"=>"More Filter"),
  518. "tracking=autoport" => array("page" =>"Tracking","operate"=>"More Filter"),
  519. "ocean_order=detail" => array("page" =>"Tracking","operate"=>"Open Detailed Page"),
  520. "ocean_order=excel" => array("page" =>"Tracking","operate"=>"Download"),
  521. "ocean_order=download" => array("page" =>"Tracking","operate"=>"Download"),
  522. "ocean_order=save_communication" => array("page" =>"Booking","operate"=>"Send Email"),
  523. "ocean_order=ams_isf_log" => array("page" =>"Tracking","operate"=>"AMS/ISF"),
  524. "ocean_order=ocean_vgm" => array("page" =>"Tracking","operate"=>"Enter VGM"),
  525. "ocean_order=save_ocean_vgm" => array("page" =>"Tracking","operate"=>"Save VGM"),
  526. "ocean_order=share_shipment" => array("page" =>"Tracking","operate"=>"Share shipment"),
  527. "ocean_order=document_upload" => array("page" =>"Tracking","operate"=>"document_upload"),
  528. "ocean_order=document_upload_do" => array("page" =>"Tracking","operate"=>"document_upload_do"),
  529. "opreation_log=excel" => array("page" =>"Opreation_Log","operate"=>"Download"),
  530. "ocean_order=default_vgm" => array("page" =>"Tracking","operate"=>"Enter Default VGM Settings"),
  531. "ocean_order=default_vgm_update" => array("page" =>"Tracking","operate"=>"Save Default VGM Settings"),
  532. "notifications_rules=notifications_init" => array("page" =>"Top Section","operate"=>"Save Notifiation bell"),
  533. "notifications_rules=notifications_read" => array("page" =>"Top Section","operate"=>"Read Message"),
  534. "notifications_rules=notifications_message_init" => array("page" =>"System_Message","operate"=>"Enter Page"),
  535. "system_setting=subscribe_shipment" => array("page" =>"Dashboard/Tracking","operate"=>"Subscribe Shipment"),
  536. "system_setting=personal_profile_save" => array("page" =>"System_Setting","operate"=>"Personal Profile"),
  537. "system_setting=subscribe_notification_init" => array("page" =>"System_Setting","operate"=>"Subscribe_Notification"),
  538. "system_setting=subscribe_notification_event_update" => array("page" =>"System_Setting","operate"=>"Subscribe_Notification"),
  539. "monitoring_setting=monitoring_rules_search" => array("page" =>"System_Setting","operate"=>"Monitoring_Setting"),
  540. "monitoring_setting=monitoring_rules_do" => array("page" =>"System_Setting","operate"=>"Monitoring_Setting"),
  541. "tools=mark_save" => array("page" =>"Tools","operate"=>"Mark_Save"),
  542. "password=" => array("page" =>"Profile","operate"=>"Change password"));
  543. if($action == "ajax" && $operate == "save_setting_display"){
  544. $model_name = $_REQUEST['model_name'];
  545. return $operationConvertName[$model_name."=".$operate];
  546. }
  547. if($action == "ajax" && ($operate == "autody" || $operate == "autoport")){
  548. $model_name = $_REQUEST['search_mode'];
  549. return $operationConvertName[$model_name."=".$operate];
  550. }
  551. return $operationConvertName[$action."=".$operate];
  552. }
  553. /**
  554. * 这里是配置需要自定义的 operation Details
  555. */
  556. public static function analyzeOperationDetail($action,$operate){
  557. $detail = "";
  558. if($action == "login" && $operate == "do_login"){
  559. $detail = 'System Account';
  560. if($_REQUEST['token']){
  561. $detail = 'From Apex Online';
  562. }
  563. }
  564. if($action == "login" && $operate == "logout"){
  565. $detail = 'User Logout';
  566. }
  567. if($action == "login" && $operate == "tracking_checked"){
  568. $detail = 'Join public tracking action,Public tracking number:'.$_POST['reference_number'];
  569. }
  570. if($action == "password"){
  571. $detail = 'User Change password';
  572. }
  573. if(($action == "ocean_booking" || $action == "ocean_order") && $operate == "search"){
  574. $detail = "";
  575. //还有一个同以分钟内,不记录相同的查询 这个需要建表查询
  576. //{"action":"ocean_booking","operate":"search","_ntype":"ocean_booking","cp":"1","ps":"100","rc":"-1","other_filed":"","uname":"ra.admin","psw":"abc123456789"}
  577. $filter_common_field = array("action","operate","_ntype","cp","ps","rc","other_filed","uname","psw");
  578. foreach($_REQUEST as $selected_key => $selected){
  579. if(!utils::in_array($selected_key, $filter_common_field)){
  580. if(is_array($selected)){
  581. $selected = utils::implode(",",$selected);
  582. }
  583. $detail .="$selected_key:".$selected."; ";
  584. }
  585. }
  586. if(empty($detail)){
  587. $detail .="No search condition";
  588. }
  589. }
  590. if($action == "ajax" && $operate == "save_setting_display"){
  591. $detail = "";
  592. $type = $_REQUEST['model_name'] == "Booking_Search" ? "Booking_Search" : "Ocean_Search";
  593. //记录最终save 和 default 字段相比的结果
  594. // $default_ids = common::excuteListSql("select id,display_name from public.ra_online_search_display_cso where model_name = '$type'
  595. // and display_name in('Booking No.','MBL No.','HBL No.','Mode','Status',
  596. // 'Shipper','Consignee','Origin Agent','Destination Agent','Creation Time','ETD','ETA',
  597. // 'Voyage','Vessel','Week','Created by') order by default_order");
  598. $default_ids = common::excuteListSql("select id,display_name from public.ra_online_search_display_cso where model_name = '$type'
  599. and default_display = true order by default_order");
  600. $ids = utils::implode(";", $_POST['ids']);
  601. $save_ids = common::excuteListSql("select id,display_name from public.ra_online_search_display_cso where model_name = '$type'
  602. and id::text = any(regexp_split_to_array('$ids', ';')) order by default_order");
  603. $detele_detail = "";
  604. foreach($default_ids as $did){
  605. if(!utils::exist_array($did['id'],$save_ids)){
  606. $detele_detail .=$did['display_name']."/";
  607. }
  608. }
  609. $add_detail = "";
  610. foreach($save_ids as $sid){
  611. if(!utils::exist_array($sid['id'],$default_ids)){
  612. $add_detail .=$sid['display_name']."/";
  613. }
  614. }
  615. if(!empty($detele_detail)){
  616. $detail.="Detele fields: (".$detele_detail."). ";
  617. }
  618. if(!empty($add_detail)){
  619. $detail.="Add fields: (".$add_detail."). ";
  620. }
  621. if(empty($detail)){
  622. $detail = "The default field has not changed";
  623. }
  624. }
  625. if(($action == "ocean_booking" || $action == "ocean_order") && $operate == "detail"){
  626. $tabel = $action == "ocean_booking" ? "kln_booking" : "kln_ocean";
  627. $serial_no = common::deCode($_GET['a'], 'D');
  628. $sql = "SELECT booking_no,h_bol from public.$tabel where serial_no = '$serial_no' limit 1";
  629. $data = common::excuteObjectSql($sql);
  630. if(!empty($data['booking_no'])){
  631. $detail = 'Booking No.: '.$data['booking_no'];
  632. }else{
  633. $detail = 'HBOL: '.$data['h_bol'];
  634. }
  635. }
  636. if(($action == "ocean_booking" || $action == "ocean_order") && $operate == "save_communication"){
  637. $text = $_POST["text"];
  638. $detail = urldecode($text);
  639. }
  640. if(($action == "ocean_order") && $operate == "ams_isf_log"){
  641. $detail = "Enter AMS/ISF Page";
  642. }
  643. if(($action == "ocean_booking" || $action == "ocean_order" || $action == "opreation_log") && $operate == "excel"){
  644. $detail = "Filter_condition:" . $_REQUEST['excel_filter_condition']." Selected Fields:". $_REQUEST['selected_fields'];
  645. }
  646. //Tracking詳情頁download的file(顯示file名稱)
  647. if(($action == "ocean_order") && $operate == "download"){
  648. $filename = common::deCode($_GET['url'], 'D');
  649. $filename = str_replace("/", DIRECTORY_SEPARATOR, $filename);
  650. $filename = str_replace("\\", DIRECTORY_SEPARATOR, $filename);
  651. $display_name = basename($filename);
  652. if (!file_exists($filename)){
  653. $detail = "Tracking Detail Attachment Download But File Not Exist : $display_name";
  654. }else{
  655. $detail = "Tracking Detail Attachment Download: $display_name";
  656. }
  657. }
  658. //Tracking詳情頁Upload Files(顯示file名稱)
  659. if(($action == "ocean_order") && $operate == "document_upload"){
  660. $detail = "Enter Upload Files page";
  661. }
  662. if(($action == "notifications_rules") && $operate == "notifications_init"){
  663. $detail = "點擊頂部欄的消息鈴鐺進入";
  664. }
  665. if(($action == "system_setting") && $operate == "personal_profile_save"){
  666. if($_REQUEST['save_model'] == "no_profile"){
  667. $detail = "Save Personal Preference: ".common::check_input(utils::jsonFiltration("null", "\"\"", json_encode($_REQUEST)));
  668. }else{
  669. $detail = "Save Basic Information: ".common::check_input(utils::jsonFiltration("null", "\"\"", json_encode($_REQUEST)));
  670. }
  671. }
  672. if(($action == "system_setting") && $operate == "subscribe_notification_init"){
  673. $detail = "點擊進入這個tab頁";
  674. }
  675. if(($action == "system_setting") && $operate == "subscribe_notification_event_update"){
  676. $detail = "保存頁面操作: ".common::check_input(utils::jsonFiltration("null", "\"\"", json_encode($_REQUEST)));
  677. }
  678. if(($action == "monitoring_setting") && $operate == "monitoring_rules_search"){
  679. $detail = "點擊進入這個tab頁";
  680. }
  681. if(($action == "monitoring_setting") && $operate == "monitoring_rules_do"){
  682. $detail = "保存頁面操作: ".common::check_input(utils::jsonFiltration("null", "\"\"", json_encode($_REQUEST)));
  683. }
  684. return $detail;
  685. }
  686. public static function calculateTicks($minValue, $maxValue, $targetTickCount = 10) {
  687. $tickSpacing = ($maxValue - $minValue);
  688. $tickSpacing = intval($tickSpacing);
  689. $interval = ceil($tickSpacing / $targetTickCount);
  690. $len = strlen($interval);
  691. if ($len >1){
  692. $interval = ceil($interval/pow(10,$len-1)) *pow(10,$len-1);
  693. }
  694. return $interval;
  695. }
  696. //只记录Public tracking
  697. public static function single_operation_log_save($user_type,$user_name,$page,$operation,$operation_detail){
  698. $sql = "INSERT INTO public.customer_service_operation_log(user_type, user_name, page, operation, operation_detail,
  699. operation_time)
  700. VALUES ('$user_type', '$user_name', '$page', '$operation', '$operation_detail', now())";
  701. common::excuteUpdateSql($sql);
  702. }
  703. public static function uuid() {
  704. return strtoupper(md5(uniqid("", TRUE) . mt_rand()));
  705. }
  706. public static function count($variable){
  707. if (is_array($variable)) {
  708. $count = count($variable);
  709. } else {
  710. $count = 0;
  711. }
  712. return $count;
  713. }
  714. public static function implode($sp,$variable){
  715. $variable = isset($variable) && is_array($variable) ? $variable : array();
  716. return implode($sp, $variable);
  717. }
  718. public static function in_array($str, $arr){
  719. if (is_array($arr)) {
  720. return in_array($str, $arr);
  721. } else {
  722. return false;
  723. }
  724. }
  725. public static function exist_array($key,$arr){
  726. $flag = false;
  727. foreach($arr as $v){
  728. if($v['id'] == $key ){
  729. $flag = true;
  730. }
  731. }
  732. return $flag;
  733. }
  734. public static function getConpanyForNotify($_schemas,$type){
  735. //如果有多個就留空
  736. $company = "";
  737. if($type == 'ocean'){
  738. $company = $_SESSION['ONLINE_USER']['company_name'];
  739. $company_arr = explode(";",$company);
  740. $temp = array();
  741. foreach($company_arr as $v){
  742. if(!empty($v)){
  743. $temp[] = $v;
  744. }
  745. }
  746. if(utils::count($temp) <= 1){
  747. return $company;
  748. }
  749. }
  750. if($type == 'air'){
  751. $company_id = $_SESSION['ONLINE_USER']['air_customers'];
  752. $company_id_arr = explode(";",$company_id);
  753. $temp = array();
  754. foreach($company_id_arr as $v){
  755. if(!empty($v)){
  756. $temp[] = $v;
  757. }
  758. }
  759. if(utils::count($temp) == 1){
  760. if ($_schemas == "public") {//apex ocean和air 分开
  761. $sql = "SELECT company from ocean.contacts where contact_id = '" . common::check_input($temp[0]) . "' ";
  762. } else {
  763. $sql = "SELECT company from $_schemas.contacts where contact_id = '" . common::check_input($temp[0]) . "' ";
  764. }
  765. $company = common::excuteOneSql($sql);
  766. }
  767. return $company;
  768. }
  769. }
  770. public static function getKlnDocNotifyContent($bol,$file_type,$upload_user_name,$upload_user_email,$company,$date_time){
  771. $report_setting = common::excuteObjectSql("select * from ra_online_auto_report_config where report_type = 'KLN_DOC_Notify' ");
  772. $report_content = $report_setting['report_content'];
  773. $columns = common::excuteListSql("select display_name,model_name,database_column_name,excel_width,order_by from public.ra_online_search_display_cso where model_name = 'KLN_DOC_Notify'");
  774. $missing_packing_th = "<tr>";
  775. foreach ($columns as $colk => $colvalue) {
  776. $missing_packing_th.='<td style="width:'.$colvalue['excel_width'].'pt;border:solid black 1.0pt;background:#1F4E78;padding:0cm 5.4pt 0cm 5.4pt;height:14.25pt">
  777. <p class="MsoNormal" align="left" style="text-align:left"><b><span lang="EN-US" style="font-size:8.0pt;font-family:&quot;Arial&quot;,sans-serif;color:white">'.$colvalue['display_name'].'</span></b></p>
  778. </td>';
  779. }
  780. $missing_packing_th .= "</tr>";
  781. $report_content = str_replace('<{missing_packing_th}>', $missing_packing_th, $report_content);
  782. $data = array(array("h_bol"=>$bol,"file_type"=>$file_type,"upload_by"=>$upload_user_name,"email"=>$upload_user_email,"company"=>$company,"upload_time"=>$date_time."(US/Pacific)"));
  783. $missing_packing_tr = "";
  784. foreach ($data as $rk => $rv) {
  785. $missing_packing_tr .= "<tr>";
  786. foreach ($columns as $ck => $cv) {
  787. if(utils::endWith($cv['display_name'], "email")){
  788. $missing_packing_tr.='<td style="font-size:8.0pt;font-family:&quot;Arial&quot;,sans-serif;color:black;border-top:none;
  789. border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;padding:0cm 5.4pt 0cm 5.4pt;height:14.25pt">
  790. <a href="mailto:'.$rv[$cv['database_column_name']].'">'.$rv[$cv['database_column_name']].'</a>
  791. </td>';
  792. }else{
  793. $missing_packing_tr.='<td style="font-size:8.0pt;font-family:&quot;Arial&quot;,sans-serif;color:black;'
  794. . 'border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;padding:0cm 5.4pt 0cm 5.4pt;height:14.25pt">'.$rv[$cv['database_column_name']].'</td>';
  795. }
  796. }
  797. $missing_packing_tr .= "</tr>";
  798. }
  799. $report_content = str_replace('<{missing_packing_tr}>', $missing_packing_tr, $report_content);
  800. return $report_content;
  801. }
  802. public static function _getSql($ids, $type,$shipment_mode,$sqlWhere) {
  803. $ids_arr = explode(',', $ids);
  804. $sql = "";
  805. if($type == "co2e_orgin"){
  806. $str = "SUM(COALESCE(carbon_emission,0)) as catnum ";
  807. $filed = "shippr_uncode";
  808. } else {
  809. $str = "SUM(COALESCE(carbon_emission,0)) as catnum ";
  810. $filed = "consignee_uncode";
  811. }
  812. $shipment_mode_where = " 1=1 ";
  813. //这里处理为空,目前没有数据
  814. $shipment_mode_where = " transport_mode_extend = '$shipment_mode' ";
  815. $shipment_mode_where .= $sqlWhere;
  816. foreach ($ids_arr as $value) {
  817. if (!empty($value)) {
  818. if (empty($sql)) {
  819. $sql .= "SELECT $str FROM public.kln_ocean where $shipment_mode_where and $filed = '$value'";
  820. } else {
  821. $sql .= " union all SELECT $str from public.kln_ocean where $shipment_mode_where and $filed = '$value'";
  822. }
  823. }
  824. }
  825. return $sql;
  826. }
  827. public static function removeDuplicateArray($array){
  828. $result = array();
  829. foreach ($array as $value) {
  830. //过滤可能的空值,会引起前端页面有数据但无法显示
  831. if(!empty($value)){
  832. if (!utils::in_array($value, $result)) {
  833. $result[] = $value;
  834. }
  835. }
  836. }
  837. return $result;
  838. }
  839. public static function hasMacros($filePath) {
  840. //在 MIME 校验之后,再加一层 ZIP 宏检测(同时查 xl/ 和 word/)
  841. $extension = pathinfo($filePath, PATHINFO_EXTENSION);
  842. if($extension == 'xls' || $extension == 'doc'){
  843. return false;
  844. }
  845. $zip = new ZipArchive();
  846. if ($zip->open($filePath) !== true) {
  847. // 无法打开为 ZIP:可能是 .xls/.doc 或损坏文件
  848. // 由于你只允许 .xlsx/.docx/.pdf,这类文件应已被 MIME 拦截
  849. return false;
  850. }
  851. // 同时检查 Excel 和 Word 的宏路径!
  852. $hasExcelMacro = $zip->locateName('xl/vbaProject.bin') !== false;
  853. $hasWordMacro = $zip->locateName('word/vbaProject.bin') !== false;
  854. $zip->close();
  855. return $hasExcelMacro || $hasWordMacro;
  856. // if ($extension === 'xlsx') {
  857. // // 检查 .xlsx 文件
  858. // $zip = new ZipArchive();
  859. // if ($zip->open($filePath) === TRUE) {
  860. // // 检查是否存在 vbaProject.bin 文件
  861. // $hasMacros = $zip->locateName('xl/vbaProject.bin') !== false;
  862. // $zip->close();
  863. // return $hasMacros;
  864. // } else {
  865. // return false; // 无法打开文件
  866. // }
  867. // }
  868. }
  869. public static function arrayKeyToInt($arr){
  870. $ret = array();
  871. foreach($arr as $key => $val){
  872. $ret[] = $val;
  873. }
  874. return $ret;
  875. }
  876. public static function getDailyAndweeklyFrist($arr){
  877. $numericRecords = count($arr);
  878. $ret = array();
  879. $numericRecords_one = 0;
  880. $numericRecords_two = 0;
  881. foreach($arr as $key => $val){
  882. if($key == 0){
  883. $val["numericRecords"] = $numericRecords;
  884. $ret = $val;
  885. }
  886. if($val["notifiation_type"] == "Departure/Arrival_Delay"){
  887. if(utils::checkExist($val["delay_name"],"Departure_Delay")){
  888. $numericRecords_one +=1;
  889. }
  890. if(utils::checkExist($val["delay_name"],"Arrival_Delay")){
  891. $numericRecords_two +=1;
  892. }
  893. }
  894. if($val["notifiation_type"] == "ETD/ETA_Change"){
  895. if(utils::checkExist($val["date_change_name"],"ETD Change")){
  896. $numericRecords_one +=1;
  897. }
  898. if(utils::checkExist($val["date_change_name"],"ETA Change")){
  899. $numericRecords_two +=1;
  900. }
  901. }
  902. }
  903. //对Delay and change 特殊处理
  904. $ret["numericRecords_one"]= $numericRecords_one;
  905. $ret["numericRecords_two"]= $numericRecords_two;
  906. return $ret;
  907. }
  908. /**
  909. * ocean ->sea
  910. */
  911. public static function converModeToDB($shipment_transport_mode_arr){
  912. $converMode = array();
  913. foreach($shipment_transport_mode_arr as $model){
  914. if (strtolower($model) == "ocean"){
  915. $converMode[] = 'sea';
  916. }else{
  917. $converMode[] = strtolower($model);
  918. }
  919. }
  920. return utils::implode(";",$converMode);
  921. }
  922. /**
  923. * sea ->ocean
  924. */
  925. public static function converModeToDisplay($shipment_transport_mode){
  926. //数据转换前端需要的
  927. $converMode = array();
  928. $shipment_transport_mode_arr = explode(";", $shipment_transport_mode);
  929. foreach($shipment_transport_mode_arr as $model){
  930. if (strtolower($model) == "sea"){
  931. $converMode[] = 'Ocean';
  932. }else{
  933. $converMode[] = ucfirst($model);
  934. }
  935. }
  936. return utils::implode(";",$converMode);
  937. }
  938. public static function compareArrayEq($array1,$array2){
  939. $array1 = empty($array1) ? array():$array1;
  940. $array2 = empty($array2) ? array():$array2;
  941. // 使用array_diff比较并重置键名
  942. $diff1 = array_diff($array1, $array2);
  943. $diff2 = array_diff($array2, $array1);
  944. // 如果结果为空,说明两个数组一样
  945. if (empty($diff1) && empty($diff2)) {
  946. return true;
  947. } else {
  948. return false;
  949. }
  950. }
  951. public static function comvertutcinfo($time_zone){
  952. if(!empty($time_zone)){
  953. if(utils::checkExist($time_zone,"+")){
  954. $time_zone = str_replace('+', '-', $time_zone);
  955. }else{
  956. $time_zone = str_replace('-', '+', $time_zone);
  957. }
  958. }
  959. return $time_zone;
  960. }
  961. public static function arrayOrderBykeys($order,$data_kd,$key){
  962. $orderedData = []; // 用于存储按$order排序后的数据
  963. foreach ($order as $name) {
  964. foreach ($data_kd as $item) {
  965. if ($item[$key] == $name) {
  966. $orderedData[] = $item; // 将找到的元素添加到新数组中
  967. break; // 找到后跳出内层循环,继续外层循环处理下一个id
  968. }
  969. }
  970. }
  971. return $orderedData;
  972. }
  973. /**
  974. * 数组去掉null
  975. */
  976. public static function arrayRemoveNull($array){
  977. foreach ($array as &$value) {
  978. if (is_null($value)) {
  979. $value = '';
  980. }
  981. }
  982. unset($value); // 断开 $value 的引用
  983. return $array;
  984. }
  985. /**
  986. * public.kln_ocean 和 WHERE 的位置关系,进行条件拼接
  987. */
  988. public static function modifyString($input,$sqlWhere) {
  989. $search = 'public.kln_ocean';
  990. $pos = strpos($input, $search);
  991. if ($pos !== false) {
  992. $afterSearch = substr($input, $pos + strlen($search));
  993. $hasWhere = (stripos($afterSearch, 'WHERE') !== false);
  994. if ($hasWhere) {
  995. // 在 WHERE 后插入 1=1
  996. $wherePos = stripos($input, 'WHERE', $pos);
  997. $insertPos = $wherePos + strlen('WHERE');
  998. $sqlWhere =' ' .$sqlWhere.' and ';
  999. return substr_replace($input, $sqlWhere, $insertPos, 0);
  1000. } else {
  1001. // 在 public.kln_ocean 后插入 1=1
  1002. $insertPos = $pos + strlen($search);
  1003. $sqlWhere =' where ' .$sqlWhere.' ';
  1004. return substr_replace($input, $sqlWhere, $insertPos, 0);
  1005. }
  1006. }
  1007. return $input;
  1008. }
  1009. /**
  1010. * LIMIT的处理,或者超过100
  1011. * 如果有limit 给最后一个limit修改
  1012. * 这个处理不了 写在字段里的子查询(select 1 from aa limit 1) as aa,sql会原样返回
  1013. */
  1014. public static function processLimitClause($sql,$limit = 100) {
  1015. $is_limit = false;
  1016. // 去除前后空白
  1017. $sql = trim($sql);
  1018. // 临时保存字符串内容,防止被误匹配
  1019. $placeholder = '__SQL_STRING_PLACEHOLDER__';
  1020. $strings = [];
  1021. // 匹配字符串(包括单引号和 $$ 符号)
  1022. $pattern = "/('(?:[^']|'')*')|(\$(?:.*?)\$)/is";
  1023. // 替换所有字符串为占位符,并保存原内容
  1024. $cleanSql = preg_replace_callback($pattern, function ($match) use (&$strings, $placeholder) {
  1025. $str = $match[1] ?? $match[2];
  1026. $index = count($strings);
  1027. $strings[$index] = $str;
  1028. return $placeholder . $index;
  1029. }, $sql);
  1030. // 正则匹配所有 LIMIT 子句(支持 LIMIT n 和 LIMIT n OFFSET m)
  1031. $pattern = '/\s+LIMIT\s+\d+(\s+OFFSET\s+\d+)?/i';
  1032. preg_match_all($pattern, $cleanSql, $matches, PREG_OFFSET_CAPTURE);
  1033. if (!empty($matches[0])) {
  1034. // 获取最后一个 LIMIT 的位置和内容
  1035. $lastMatch = end($matches[0]);
  1036. $limitStr = $lastMatch[0]; // 完整的 LIMIT 子句,如 " LIMIT 50" 或 " LIMIT 200 OFFSET 10"
  1037. $pos = $lastMatch[1]; // 起始位置
  1038. // 提取 LIMIT 的数字部分
  1039. preg_match('/\d+/', $limitStr, $numMatch);
  1040. $currentLimit = intval($numMatch[0]);
  1041. if ($currentLimit < $limit) {
  1042. // 当前 LIMIT 值更小,不做修改
  1043. $is_limit = true;
  1044. }else{
  1045. // 构造新的 LIMIT 子句,保留可能存在的 OFFSET
  1046. $offsetPart = '';
  1047. if (preg_match('/(.*?)(\s+OFFSET\s+\d+)/i', $limitStr, $offsetMatches)) {
  1048. $offsetPart = $offsetMatches[2]; // 例如 " OFFSET 10"
  1049. }
  1050. $newLimitClause = " LIMIT {$limit}{$offsetPart}";
  1051. // 替换最后一个 LIMIT
  1052. $before = substr($cleanSql, 0, $pos);
  1053. $after = substr($cleanSql, $pos + strlen($limitStr));
  1054. $cleanSql = $before . $newLimitClause . $after;
  1055. }
  1056. } else {
  1057. // 没有 LIMIT,直接加上
  1058. $cleanSql .= " LIMIT {$limit}";
  1059. }
  1060. // 最后恢复原来的字符串内容
  1061. $finalSql = preg_replace_callback("/{$placeholder}(\d+)/", function ($match) use ($strings) {
  1062. return $strings[(int)$match[1]];
  1063. }, $cleanSql);
  1064. return array("sql"=>$finalSql, "is_limit"=>$is_limit);
  1065. }
  1066. /**
  1067. * 替换 single reference
  1068. */
  1069. public static function replacements($data, $template,$new_sql) {
  1070. // 动态构建替换数组(格式:[key] => value)
  1071. $replacements = [];
  1072. foreach ($data as $key => $value) {
  1073. $replacements["{{$key}}"] = $value;
  1074. $replacements["{{{$key}}}"] = $value;
  1075. }
  1076. if(empty($data)){
  1077. $fileds = common::extractSelectFields($new_sql);
  1078. foreach($fileds as $key){
  1079. //如果遇到data没数据,但是有 total_count ,则处理成0
  1080. if($key == "total_count"){
  1081. $replacements["{{$key}}"] = "0";
  1082. $replacements["{{{$key}}}"] = "0";
  1083. } else {
  1084. $replacements["{{$key}}"] = "";
  1085. $replacements["{{{$key}}}"] = "";
  1086. }
  1087. }
  1088. }
  1089. // 执行替换
  1090. error_log("replacements_single:".json_encode($replacements));
  1091. error_log("template_single:".$template);
  1092. $result = strtr($template, $replacements);
  1093. // 输出结果
  1094. return $result;
  1095. }
  1096. /**
  1097. * 替换复杂的reference
  1098. *
  1099. */
  1100. public static function replacementsMultiline($data, $template,$new_sql) {
  1101. //行中所有 {{xxx}} 模板变量都必须在 SQL 查询字段中存在
  1102. //SQL 中可以有比 reference 多的字段,不影响匹配
  1103. //一旦找到第一个符合条件的
  1104. //不依赖任何 {{#EACH ROW}} 或其他模板语法
  1105. //| {{h_bol}} | {{m_bol}} | {{transport_mode}} | {{service}} | 格式
  1106. $explode_data = utils::findFirstTemplateRow($template,$new_sql);
  1107. $explode_str = $explode_data['line'];
  1108. $replaceTemplate = "";
  1109. //检查模板 是否已经带有特定表格的序列
  1110. if(!empty($explode_str) && strpos($template, $explode_str) !== false){
  1111. $spacing = utils::getMarkDownTableSpacing($template,$explode_str);
  1112. $parts = explode($explode_str, $template,2);
  1113. // 生成所有行
  1114. $generatedRows = [];
  1115. foreach ($data as $row) {
  1116. $replacements = [];
  1117. foreach ($row as $key => $value) {
  1118. $replacements["{{{$key}}}"] = $value;
  1119. }
  1120. $generatedRows[] = strtr($explode_str, $replacements);
  1121. }
  1122. if(empty($generatedRows) && empty($data)){
  1123. $generatedRows[] = "No Data";
  1124. }
  1125. //如果 SQL字段是有多余未匹配的字段 调用一次个体替换
  1126. $mapping = $explode_data['mapping'];
  1127. if(!$mapping){
  1128. $parts[0] = utils::replacements($data[0],$parts[0],$new_sql);
  1129. $parts[1] = utils::replacements($data[0],$parts[1],$new_sql);
  1130. }
  1131. $replaceTemplate = $parts[0] . implode($spacing, $generatedRows) . $parts[1];
  1132. }else{
  1133. //全文替换 上面统一有excuteListSql 这里的结果要变一下
  1134. $replaceTemplate = utils::replacements($data[0],$template,$new_sql);
  1135. }
  1136. return $replaceTemplate;
  1137. }
  1138. // 在 reference 中查找第一个符合要求的 | ... | 行
  1139. public static function findFirstTemplateRow($reference, $sql) {
  1140. $sqlFields = common::extractSelectFields($sql);
  1141. if (empty($sqlFields)) return null;
  1142. $lines = preg_split('/\r\n|\r|\n/', $reference);
  1143. foreach ($lines as $line) {
  1144. $line = trim($line);
  1145. // 检查是否是以 | 开头和结尾的表格行
  1146. if (strpos($line, '|') !== 0 || substr($line, -1) !== '|') continue;
  1147. // 提取该行中的所有 {{xxx}} 模板变量
  1148. preg_match_all('/\{\{(\w+)\}\}/', $line, $matches);
  1149. $templateVars = $matches[1];
  1150. preg_match_all('/(?<=\|)([^|]+)(?=\|)/', $line, $matchesTwo);
  1151. // 去除每个匹配项前后的空白字符
  1152. $cells = $matchesTwo[1];
  1153. if (empty($templateVars) || count($templateVars) <> count($cells)) continue;
  1154. // 检查每个变量是否都在 SQL 字段中:这里逻辑是无效的,这里是按模板取的,sql查询有多余字段不影响,也不影响单独去渲染
  1155. foreach ($templateVars as $var) {
  1156. if (!utils::in_array(strtolower($var), array_map('strtolower', $sqlFields))) {
  1157. continue; // 跳出当前循环,继续检查下一行
  1158. }
  1159. }
  1160. $mapping = true;
  1161. //检查 SQL 字段是否有未匹配的字段
  1162. if(count($sqlFields) <> count($templateVars)){
  1163. $mapping = false;
  1164. }
  1165. // 所有变量都匹配成功,返回这一行
  1166. return array("line"=>$line,"mapping" => $mapping);
  1167. }
  1168. return array("line"=>null,"mapping" =>true);; // 没有找到匹配行
  1169. }
  1170. /**
  1171. * 替换复杂的reference 固定问题 分开
  1172. */
  1173. public static function replacementsFixedMultilineForFixed($data, $template,$explode_str) {
  1174. //| {{h_bol}} | {{m_bol}} | {{transport_mode}} | {{service}} | 格式
  1175. $replaceTemplate = "";
  1176. //检查模板 是否已经带有特定表格的序列
  1177. if(strpos($template, $explode_str) !== false){
  1178. $spacing = utils::getMarkDownTableSpacing($template,$explode_str);
  1179. $parts = explode("$explode_str", $template,2);
  1180. // 生成所有行
  1181. $generatedRows = [];
  1182. foreach ($data as $row) {
  1183. $replacements = [];
  1184. foreach ($row as $key => $value) {
  1185. $replacements["{{{$key}}}"] = $value;
  1186. }
  1187. $generatedRows[] = strtr($explode_str, $replacements);
  1188. }
  1189. $replaceTemplate = $parts[0] . implode($spacing, $generatedRows) . $parts[1];
  1190. }else{
  1191. //有异常,模板原样返回
  1192. $replaceTemplate = $template;
  1193. }
  1194. return $replaceTemplate;
  1195. }
  1196. /**
  1197. * 替换 single reference Fixed
  1198. */
  1199. public static function replacementsFixed($data, $template,$fileds) {
  1200. // 动态构建替换数组(格式:[key] => value)
  1201. $replacements = [];
  1202. foreach ($data as $key => $value) {
  1203. $replacements["{{$key}}"] = $value;
  1204. $replacements["{{{$key}}}"] = $value;
  1205. }
  1206. if(empty($data)){
  1207. foreach($fileds as $key){
  1208. $replacements["{{$key}}"] = "";
  1209. $replacements["{{{$key}}}"] = "";
  1210. }
  1211. }
  1212. // 执行替换
  1213. $result = strtr($template, $replacements);
  1214. // 输出结果
  1215. return $result;
  1216. }
  1217. public static function getMarkDownTableSpacing($str,$search){
  1218. //$str = "|--------------|\n sdsds| E1205546127 | ";
  1219. //$search = "| E1205546127 |";
  1220. // 查找搜索字符串的位置
  1221. $pos = strpos($str, $search);
  1222. if ($pos !== false) {
  1223. // 从搜索字符串前面开始向前查找 "|" 的位置
  1224. for ($i = $pos - 1; $i >= 0; $i--) {
  1225. if ($str[$i] === '|') {
  1226. // 提取两个位置之间的内容
  1227. $result = substr($str, $i + 1, $pos - $i - 1);
  1228. return $result;
  1229. }
  1230. }
  1231. } else {
  1232. return "\n";
  1233. }
  1234. }
  1235. public static function uniqueGroupbyData($unique_filed,$groups_filed,$rows){
  1236. $uniqueData = [];
  1237. $hBolSeen = [];
  1238. //需要去重
  1239. if(!empty($unique_filed)){
  1240. foreach ($rows as $row) {
  1241. $hBol = $row[$unique_filed]."_".$row[$groups_filed];
  1242. if (!isset($hBolSeen[$hBol])) {
  1243. $uniqueData[] = $row;
  1244. $hBolSeen[$hBol] = true;
  1245. }
  1246. }
  1247. } else {
  1248. //不需要去重
  1249. $uniqueData = $rows;
  1250. }
  1251. //分组计数
  1252. $dateGroups = [];
  1253. if(!empty($groups_filed)){
  1254. foreach ($uniqueData as $item) {
  1255. $date = $item[$groups_filed];
  1256. if (!isset($dateGroups[$date])) {
  1257. $dateGroups[$date] = 0;
  1258. }
  1259. $dateGroups[$date]++;
  1260. }
  1261. }
  1262. return $dateGroups;
  1263. }
  1264. public static function getDmoeSqlForAi($type){
  1265. $data= array();
  1266. $data["Show shipments delayed in the last 30 days."] = "select count(*)
  1267. from public.kln_record kr
  1268. inner join LATERAL (select h_bol from public.kln_ocean oo where oo.serial_no = kr.serial_no and <{ExtendHand_KLN}> ) m on true
  1269. where kr.log_type like '%Delay'
  1270. and kr.log_time >= CURRENT_DATE - INTERVAL '30 day'
  1271. and kr.event_date is not null and kr.event_old_date is not null
  1272. and (kr.event_date||' '||COALESCE(kr.event_time,'00:00'))::timestamp >= (kr.event_old_date||' '||COALESCE(kr.event_old_time,'00:00'))::timestamp;select oo.h_bol,oo.place_of_receipt_exp,oo.place_of_delivery_exp,oo.serial_no,oo.order_from,
  1273. kr.log_type,kr.event_old_date, kr.event_old_time,kr.event_date, kr.event_time,
  1274. (EXTRACT(DAY FROM ((event_date||' '||COALESCE(event_time,'00:00'))::timestamp - (event_old_date||' '||COALESCE(event_old_time,'00:00'))::timestamp))) as duration
  1275. from public.kln_record kr
  1276. inner join LATERAL (select h_bol, place_of_receipt_exp, place_of_delivery_exp,serial_no,order_from
  1277. from public.kln_ocean oo where oo.serial_no = kr.serial_no and <{ExtendHand_KLN}> ) oo on true
  1278. where kr.log_type like '%Delay'
  1279. and kr.log_time >= CURRENT_DATE - INTERVAL '30 day'
  1280. and kr.event_date is not null and kr.event_old_date is not null
  1281. and (kr.event_date||' '||COALESCE(kr.event_time,'00:00'))::timestamp >= (kr.event_old_date||' '||COALESCE(kr.event_old_time,'00:00'))::timestamp
  1282. order by kr.log_time desc limit 10";
  1283. $data["Shipments arriving in the next 7 days."] = "select count(*)
  1284. from (
  1285. SELECT oo.serial_no,h_bol, place_of_receipt_exp, place_of_delivery_exp,m.description,eta,order_from, o.cargo_type
  1286. FROM public.kln_ocean oo
  1287. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1288. from public.ocean o where o.serial_no = oo.serial_no) o on true
  1289. left join LATERAL (select a.code,a.description
  1290. from public.ocean_milestone a
  1291. inner join public.customer_service_milestone_sno s
  1292. on a.code = s.code
  1293. and s.type = 'sea'
  1294. and a.serial_no = oo.serial_no
  1295. and a.act_date is not null
  1296. order by s.sno desc limit 1) m on true
  1297. WHERE <{ExtendHand_KLN}> and oo.transport_mode = 'sea' and order_from = 'public' and m.code <> '' limit 10
  1298. ) t;select serial_no,h_bol,place_of_receipt_exp,place_of_delivery_exp,description,eta,order_from,cargo_type
  1299. from (
  1300. SELECT oo.serial_no,h_bol, place_of_receipt_exp, place_of_delivery_exp,m.description,eta,order_from, o.cargo_type
  1301. FROM public.kln_ocean oo
  1302. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1303. from public.ocean o where o.serial_no = oo.serial_no) o on true
  1304. left join LATERAL (select a.code,a.description
  1305. from public.ocean_milestone a
  1306. inner join public.customer_service_milestone_sno s
  1307. on a.code = s.code
  1308. and s.type = 'sea'
  1309. and a.serial_no = oo.serial_no
  1310. and a.act_date is not null
  1311. order by s.sno desc limit 1) m on true
  1312. WHERE <{ExtendHand_KLN}> and oo.transport_mode = 'sea' and order_from = 'public' and m.code <> '' limit 20
  1313. ) t order by eta";
  1314. $data["List shipments with milestone updates in the last 7 days."] = "select count(*)
  1315. from (
  1316. select serial_no
  1317. from (SELECT oo.serial_no from public.ocean_milestone a
  1318. inner join public.customer_service_milestone_sno s on a.code = s.code
  1319. inner join public.kln_ocean oo on oo.serial_no = a.serial_no
  1320. where s.type = 'sea'
  1321. and a.act_date is not null
  1322. ) po
  1323. )t;
  1324. select serial_no,order_from,h_bol, description,update_date_format,update_date,
  1325. COALESCE(m.jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1326. COALESCE(m.jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1327. from (
  1328. select serial_no,order_from,h_bol,description,to_char(update_date,'Mon DD') as update_date_format,update_date,code
  1329. from (SELECT oo.serial_no,oo.order_from,oo.h_bol,s.description,COALESCE(a.update_date, a.create_date) as update_date,a.code
  1330. from public.ocean_milestone a
  1331. inner join public.customer_service_milestone_sno s on a.code = s.code
  1332. inner join public.kln_ocean oo on oo.serial_no = a.serial_no
  1333. where s.type = 'sea'
  1334. and a.act_date is not null
  1335. ) po
  1336. )t left join LATERAL (select public.getTimeAndLocationForKln(serial_no,code,''::text)::jsonb as jsonb_data) m on true
  1337. order by update_date limit 10;
  1338. select aa.update_date_format, COUNT(*) AS total_count
  1339. from (
  1340. select DISTINCT ON (h_bol) h_bol, update_date_format
  1341. from (
  1342. select h_bol,to_char(update_date,'Mon DD') as update_date_format
  1343. from (SELECT oo.h_bol,COALESCE(a.update_date, a.create_date) as update_date
  1344. from public.ocean_milestone a
  1345. inner join public.kln_ocean oo on oo.serial_no = a.serial_no
  1346. where a.act_date is not null
  1347. ) po
  1348. )t order by h_bol
  1349. ) aa
  1350. group by aa.update_date_format order by aa.update_date_format ";
  1351. $data["What is the current status of my active shipments?"] ="SELECT count(*)
  1352. FROM public.kln_ocean oo
  1353. WHERE <{ExtendHand_KLN}> and ((oo.ata is not null and oo.ata >= CURRENT_DATE - INTERVAL '3 months' AND oo.ata < CURRENT_DATE)
  1354. or not exists( select 1 from public.ocean_milestone a where a.serial_no = oo.serial_no and a.act_date is not null and a.code = 'IFFDEL')) and oo.transport_mode = 'sea' and order_from = 'public';with oo as(
  1355. SELECT h_bol, place_of_receipt_exp, place_of_delivery_exp,serial_no,transport_mode,order_from
  1356. FROM public.kln_ocean oo
  1357. WHERE <{ExtendHand_KLN}> and ((oo.ata is not null and oo.ata >= CURRENT_DATE - INTERVAL '3 months' AND oo.ata < CURRENT_DATE)
  1358. or not exists( select 1 from public.ocean_milestone a where a.serial_no = oo.serial_no and a.act_date is not null and a.code = 'IFFDEL')) and oo.transport_mode = 'sea' and order_from = 'public' order by id limit 10
  1359. )
  1360. SELECT oo.*,mil.description,mil.act_date,mil.act_time,o.cargo_type,
  1361. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1362. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1363. from oo
  1364. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1365. from public.ocean o where o.serial_no = oo.serial_no) o on true
  1366. left join LATERAL (select a.code,s.description,to_char(a.act_date, 'YYYY-MM-DD') as act_date ,a.act_time
  1367. from public.ocean_milestone a
  1368. left join public.customer_service_milestone_sno s on a.code = s.code
  1369. and s.type = 'sea'
  1370. and a.serial_no = oo.serial_no
  1371. and a.act_date is not null
  1372. order by s.sno desc limit 1) mil on true
  1373. left join LATERAL (select public.getTimeAndLocationForKln(oo.serial_no,mil.code,''::text)::jsonb as jsonb_data) lt on true
  1374. where oo.transport_mode = 'sea' and order_from = 'public'
  1375. union all
  1376. SELECT oo.*,mil.description,mil.act_date,mil.act_time,o.cargo_type,
  1377. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1378. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1379. from oo
  1380. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1381. from sfs.ocean o where o.serial_no = oo.serial_no) o on true
  1382. left join LATERAL (select a.code,s.description,to_char(a.act_date, 'YYYY-MM-DD') as act_date ,a.act_time
  1383. from public.ocean_milestone a
  1384. left join public.customer_service_milestone_sno s on a.code = s.code
  1385. and s.type = 'air'
  1386. and a.serial_no = oo.serial_no
  1387. and a.act_date is not null
  1388. order by s.sno desc limit 1) mil on true
  1389. left join LATERAL (select public.getTimeAndLocationForKln(oo.serial_no,mil.code,''::text)::jsonb as jsonb_data) lt on true
  1390. where oo.transport_mode = 'sea' and order_from = 'sfs'
  1391. union all
  1392. SELECT oo.*,mil.description,mil.act_date,mil.act_time,o.cargo_type,
  1393. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1394. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1395. from oo
  1396. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1397. from public.ocean o where o.serial_no = oo.serial_no) o on true
  1398. left join LATERAL (select a.code,s.description,to_char(a.act_date, 'YYYY-MM-DD') as act_date ,a.act_time
  1399. from public.air_milestone a
  1400. left join public.customer_service_milestone_sno s on a.code = s.code
  1401. and s.type = 'air'
  1402. and a.serial_no = oo.serial_no
  1403. and a.act_date is not null
  1404. order by s.sno desc limit 1) mil on true
  1405. left join LATERAL (select public.getTimeAndLocationForKln(oo.serial_no,mil.code,''::text)::jsonb as jsonb_data) lt on true
  1406. where oo.transport_mode = 'air' and order_from = 'public'
  1407. union all
  1408. SELECT oo.*,mil.description,mil.act_date,mil.act_time,o.cargo_type,
  1409. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1410. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1411. from oo
  1412. inner join LATERAL (select case when is_hazardous = 't' then 'Dangerous Goods'::text else 'General'::text end as cargo_type
  1413. from sfs.ocean o where o.serial_no = oo.serial_no) o on true
  1414. left join LATERAL (select a.code,s.description,to_char(a.act_date, 'YYYY-MM-DD') as act_date ,a.act_time
  1415. from sfs.air_milestone a
  1416. left join public.customer_service_milestone_sno s on a.code = s.code
  1417. and s.type = 'air'
  1418. and a.serial_no = oo.serial_no
  1419. and a.act_date is not null
  1420. order by s.sno desc limit 1) mil on true
  1421. left join LATERAL (select public.getTimeAndLocationForKln(oo.serial_no,mil.code,''::text)::jsonb as jsonb_data) lt on true
  1422. where oo.transport_mode = 'air' and order_from = 'sfs'";
  1423. $data["List shipments with container status updates in the last 7 days."] = "select count(*)
  1424. FROM ra_online_container_status s
  1425. LEFT JOIN oc_container oc ON s.status_id = oc.status_id
  1426. LEFT JOIN ocean o ON o.serial_no::text = oc.serial_no::text
  1427. LEFT JOIN public.ra_online_edi_event e on s.event_base = e.ra_name
  1428. WHERE o.status::text <> 'Cancelled'::text
  1429. and is_display = true
  1430. and s.insert_date <= CURRENT_DATE AND s.insert_date >='2023-02-23'
  1431. and exists(select 1 from kln_ocean oo where <{ExtendHand_KLN}> and oo.serial_no = o.serial_no);select oo.serial_no,oo.order_from,s.event_base as event,s.container_no,
  1432. to_char(to_timestamp(s.event_date, 'YYYYMMDD'), 'YYYY-MM-DD') as eventdate,
  1433. to_char(to_timestamp(s.event_date, 'YYYYMMDD'),'Mon DD') as _eventdate,
  1434. to_char(to_timestamp(s.event_time, 'HH24MI'), 'HH24:MI') as eventtime,
  1435. (select time_zone from public.city_timezone where uncode = s.event_code) as timezone,
  1436. e.description,
  1437. s.event_city as uncity
  1438. FROM ra_online_container_status s
  1439. LEFT JOIN oc_container oc ON s.status_id = oc.status_id
  1440. LEFT JOIN ocean o ON o.serial_no::text = oc.serial_no::text
  1441. LEFT JOIN public.ra_online_edi_event e on s.event_base = e.ra_name
  1442. LEFT JOIN public.kln_ocean oo ON oo.serial_no::text = o.serial_no::text
  1443. WHERE o.status::text <> 'Cancelled'::text
  1444. and is_display = true
  1445. and s.insert_date <= CURRENT_DATE AND s.insert_date >='2023-02-23'
  1446. and exists(select 1 from kln_ocean oo where <{ExtendHand_KLN}> and oo.serial_no = o.serial_no) limit 10;select aa._eventdate, COUNT(*) AS total_count
  1447. from (select DISTINCT ON (s.container_no) s.container_no,
  1448. to_char(to_timestamp(s.event_date, 'YYYYMMDD'),'Mon DD') as _eventdate
  1449. FROM ra_online_container_status s
  1450. LEFT JOIN oc_container oc ON s.status_id = oc.status_id
  1451. LEFT JOIN ocean o ON o.serial_no::text = oc.serial_no::text
  1452. LEFT JOIN public.ra_online_edi_event e on s.event_base = e.ra_name
  1453. WHERE o.status::text <> 'Cancelled'::text
  1454. and is_display = true
  1455. and s.insert_date <= CURRENT_DATE AND s.insert_date >='2023-02-23'
  1456. and exists(select 1 from kln_ocean oo where <{ExtendHand_KLN}> and oo.serial_no = o.serial_no)
  1457. order by s.container_no
  1458. )aa group by _eventdate order by _eventdate";
  1459. $data["Today's shipments summary."] = "select count(*)
  1460. from (
  1461. select oo.serial_no
  1462. from (
  1463. select t.serial_no from (
  1464. SELECT
  1465. a.serial_no,
  1466. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1467. from public.ocean_milestone a
  1468. left join public.customer_service_milestone_sno s on a.code = s.code
  1469. where s.type = 'sea'
  1470. and a.act_date is not null
  1471. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1472. )t WHERE rn = 1
  1473. ) po inner join public.kln_ocean oo on oo.serial_no = po.serial_no and (<{ExtendHand_KLN}>)
  1474. union all
  1475. select oo.serial_no
  1476. from (
  1477. select t.serial_no from (
  1478. SELECT
  1479. a.code,a.serial_no,
  1480. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1481. from public.air_milestone a
  1482. left join public.customer_service_milestone_sno s on a.code = s.code
  1483. where s.type = 'sea'
  1484. and a.act_date is not null
  1485. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1486. )t WHERE rn = 1
  1487. ) pa inner join public.kln_ocean oo on oo.serial_no = pa.serial_no and (<{ExtendHand_KLN}>)
  1488. union all
  1489. select oo.serial_no
  1490. from (
  1491. select t.serial_no from (
  1492. SELECT
  1493. a.serial_no,
  1494. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1495. from sfs.air_milestone a
  1496. left join public.customer_service_milestone_sno s on a.code = s.code
  1497. where s.type = 'sea'
  1498. and a.act_date is not null
  1499. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1500. )t WHERE rn = 1
  1501. ) sa inner join public.kln_ocean oo on oo.serial_no = sa.serial_no and (<{ExtendHand_KLN}>)
  1502. )t;select *
  1503. from (
  1504. select *,oo.serial_no,oo.order_from,oo.h_bol,oo.transport_mode,oo.place_of_receipt_exp, oo.place_of_delivery_exp,
  1505. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1506. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1507. from (
  1508. select *,public.getTimeAndLocationForKln(t.serial_no,t.code,''::text)::jsonb as jsonb_data
  1509. from (
  1510. SELECT
  1511. case when a.code = 'IFFDEP' then 'Departure'
  1512. when a.code = 'IFFARR' then 'Arrived'
  1513. when a.code = 'IFFDEL' then 'Delivered'
  1514. else s.description end as action_type,
  1515. a.update_date,a.code,a.serial_no,
  1516. to_char(a.update_date, 'Mon_DD_YYYY') as _update_date,
  1517. to_char(a.act_date, 'YYYY-MM-DD') as act_date ,
  1518. a.act_time,
  1519. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1520. from public.ocean_milestone a
  1521. left join public.customer_service_milestone_sno s on a.code = s.code
  1522. where s.type = 'sea'
  1523. and a.act_date is not null
  1524. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1525. )t WHERE rn = 1
  1526. ) po inner join public.kln_ocean oo on oo.serial_no = po.serial_no
  1527. union all
  1528. select *,oo.serial_no,oo.order_from,oo.h_bol,oo.transport_mode,oo.place_of_receipt_exp, oo.place_of_delivery_exp,
  1529. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1530. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1531. from (
  1532. select *,public.getTimeAndLocationForKln(t.serial_no,t.code,''::text)::jsonb as jsonb_data
  1533. from (
  1534. SELECT
  1535. case when a.code = 'IFFDEP' then 'Departure'
  1536. when a.code = 'IFFARR' then 'Arrived'
  1537. when a.code = 'IFFDEL' then 'Delivered'
  1538. else s.description end as action_type,
  1539. a.update_date,a.code,a.serial_no,
  1540. to_char(a.update_date, 'Mon_DD_YYYY') as _update_date,
  1541. to_char(a.act_date, 'YYYY-MM-DD') as act_date ,
  1542. a.act_time,
  1543. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1544. from public.air_milestone a
  1545. left join public.customer_service_milestone_sno s on a.code = s.code
  1546. where s.type = 'sea'
  1547. and a.act_date is not null
  1548. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1549. )t WHERE rn = 1
  1550. ) pa inner join public.kln_ocean oo on oo.serial_no = pa.serial_no
  1551. union all
  1552. select *,oo.serial_no,oo.order_from,oo.h_bol,oo.transport_mode,oo.place_of_receipt_exp, oo.place_of_delivery_exp,
  1553. COALESCE(jsonb_data->>'milestone','')::jsonb->>'timezone' as timezone,
  1554. COALESCE(jsonb_data->>'milestone','')::jsonb->>'locations' as locations
  1555. from (
  1556. select *,public.getTimeAndLocationForKln(t.serial_no,t.code,''::text)::jsonb as jsonb_data
  1557. from (
  1558. SELECT
  1559. case when a.code = 'IFFDEP' then 'Departure'
  1560. when a.code = 'IFFARR' then 'Arrived'
  1561. when a.code = 'IFFDEL' then 'Delivered'
  1562. else s.description end as action_type,
  1563. a.update_date,a.code,a.serial_no,
  1564. to_char(a.update_date, 'Mon_DD_YYYY') as _update_date,
  1565. to_char(a.act_date, 'YYYY-MM-DD') as act_date ,
  1566. a.act_time,
  1567. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1568. from sfs.air_milestone a
  1569. left join public.customer_service_milestone_sno s on a.code = s.code
  1570. where s.type = 'sea'
  1571. and a.act_date is not null
  1572. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1573. )t WHERE rn = 1
  1574. ) sa inner join public.kln_ocean oo on oo.serial_no = sa.serial_no
  1575. )t limit 10;select sum(case when (action_type='Departure') then 1 else 0 end) as dep,
  1576. sum(case when (action_type='Arrived') then 1 else 0 end) as arr,
  1577. sum(case when (action_type='Delivered') then 1 else 0 end) as del
  1578. from (
  1579. select action_type
  1580. from (
  1581. select t.action_type,t.serial_no from (
  1582. SELECT
  1583. case when a.code = 'IFFDEP' then 'Departure'
  1584. when a.code = 'IFFARR' then 'Arrived'
  1585. when a.code = 'IFFDEL' then 'Delivered'
  1586. else s.description end as action_type,
  1587. a.serial_no,
  1588. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1589. from public.ocean_milestone a
  1590. left join public.customer_service_milestone_sno s on a.code = s.code
  1591. where s.type = 'sea'
  1592. and a.act_date is not null
  1593. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1594. )t WHERE rn = 1
  1595. ) po inner join public.kln_ocean oo on oo.serial_no = po.serial_no and (<{ExtendHand_KLN}>)
  1596. union all
  1597. select action_type
  1598. from (
  1599. select t.action_type,t.serial_no from (
  1600. SELECT
  1601. case when a.code = 'IFFDEP' then 'Departure'
  1602. when a.code = 'IFFARR' then 'Arrived'
  1603. when a.code = 'IFFDEL' then 'Delivered'
  1604. else s.description end as action_type,
  1605. a.serial_no,
  1606. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1607. from public.air_milestone a
  1608. left join public.customer_service_milestone_sno s on a.code = s.code
  1609. where s.type = 'sea'
  1610. and a.act_date is not null
  1611. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1612. )t WHERE rn = 1
  1613. ) pa inner join public.kln_ocean oo on oo.serial_no = pa.serial_no and (<{ExtendHand_KLN}>)
  1614. union all
  1615. select action_type
  1616. from (
  1617. select t.action_type,t.serial_no from (
  1618. SELECT
  1619. case when a.code = 'IFFDEP' then 'Departure'
  1620. when a.code = 'IFFARR' then 'Arrived'
  1621. when a.code = 'IFFDEL' then 'Delivered'
  1622. else s.description end as action_type,
  1623. a.serial_no,
  1624. ROW_NUMBER() OVER(PARTITION BY a.serial_no ORDER BY s.sno DESC) AS rn
  1625. from sfs.air_milestone a
  1626. left join public.customer_service_milestone_sno s on a.code = s.code
  1627. where s.type = 'sea'
  1628. and a.act_date is not null
  1629. --and a.update_date >= CURRENT_DATE AND a.update_date < CURRENT_DATE + INTERVAL '1 day'
  1630. )t WHERE rn = 1
  1631. ) sa inner join public.kln_ocean oo on oo.serial_no = sa.serial_no and (<{ExtendHand_KLN}>)
  1632. )t";
  1633. $data["Sort my active shipments by earliest arrival date."] = "select to_char(oo.eta,'DD-Mon') as eta, oo.h_bol,oo.transport_mode, oo.place_of_receipt_exp, oo.place_of_delivery_exp,oo.serial_no,oo.order_from,
  1634. case when oo.eta - CURRENT_DATE <= 0 then '< 1 days'::text
  1635. else (oo.eta - CURRENT_DATE)||' days'::text end as day_to_arr
  1636. from public.kln_ocean oo where 1=1 order by eta limit 10";
  1637. return $data[$type];
  1638. }
  1639. //AES 加密
  1640. public static function AES_128_CBC_Encrypt($data,$key = "fT5!R1k$7Mv@4Q9X",$iv = '1234567890123456'){
  1641. //$key = 'fT5!R1k$7Mv@4Q9X'; // 密钥应该是16字节(128位),24字节(192位)或32字节(256位)
  1642. $method = 'AES-128-CBC';
  1643. //$iv = '1234567890123456';
  1644. // 加密
  1645. $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
  1646. // 编码为可打印的字符串,如Base64
  1647. $encrypted = base64_encode($encrypted);
  1648. return $encrypted;
  1649. }
  1650. /**
  1651. * 解密decrypt
  1652. */
  1653. public static function AES_encrypted($encrypted_string,$isbase64_encode = true,$key = "fT5!R1k$7Mv@4Q9X",$iv = '1234567890123456'){
  1654. //$key = 'fT5!R1k$7Mv@4Q9X'; // 16 bytes key
  1655. //$iv = '1234567890123456'; // 16 bytes IV
  1656. if($isbase64_encode){
  1657. $decrypted = openssl_decrypt(base64_decode($encrypted_string), 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
  1658. }else{
  1659. $decrypted = openssl_decrypt($encrypted_string, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
  1660. }
  1661. return $decrypted;
  1662. }
  1663. /**
  1664. * 去重显示 pono
  1665. */
  1666. public static function outDisplayForMergeForDISTINCT($ocPoNo, $itemPoNo){
  1667. if ($ocPoNo === null && $itemPoNo === null) {
  1668. return null;
  1669. }
  1670. if (trim($ocPoNo) == trim($itemPoNo)) {
  1671. return $ocPoNo;
  1672. }
  1673. $parts = [];
  1674. if (!empty($ocPoNo)) $parts[] = $ocPoNo;
  1675. if (!empty($itemPoNo)) $parts[] = $itemPoNo;
  1676. return implode(',', $parts);
  1677. }
  1678. }
  1679. ?>