Selaa lähdekoodia

delivery and robat code

ShuanghongS 4 kuukautta sitten
vanhempi
commit
bb36b425b5

+ 24 - 3
main_new_version.php

@@ -20,6 +20,7 @@ include 'service/login.class.php';
 include 'service/tools.class.php';
 include 'service/robot.class.php';
 include 'service/AIClientFactory.php';
+include 'service/destination_delivery.class.php';
 
 //为了调用,临时做一个登录动作  如果是正式版 要注释掉菜单System Settings
  //$_POST['uname'] = "ra.admin";
@@ -95,12 +96,23 @@ switch ($action) {
                             $menuList[] = array("index"=>"$index","label"=>$urlData['label'],"icon"=>$urlData['icon'],"path"=>$urlData['path']);
                             $index = $index + 1;
                         }
+                        //特殊处理book,需要加二级菜
+                        // if($v['s_column'] =="Ocean Booking"){
+
+                        //     $bookingManagement = array("index"=>"$index","label"=>"Booking","icon"=>"icon_booking__fill_b","type"=>"list");
+                        //     $children  = array(); 
+
+                        //     $urlData = $menuSetting[$v['s_column']];
+                        //     $children[] = array("index"=>$index.'-1',"label"=>$urlData['label'],"path"=>$urlData['path']);
+                        //     $children[] = array("index"=>$index.'-2',"label"=>"Destination Delivery","path"=>"/destination-delivery");
+                        //     $bookingManagement["children"] = $children;
+                        //     $menuList[] = $bookingManagement;
+                        //     $index = $index + 1;
+                        // }
                     }
                 }
             }
 
-            // $menuList[] = array("index"=>$index,"label"=>"System Management","icon"=>"icon_system__management_fill_b","type"=>"list",
-            //     "children"=>array(array("index" =>$index.'-1',"label" =>"Operation Log","path"=>"/Operationlog")));
             $systemManagement = array("index"=>"$index","label"=>"System Management","icon"=>"icon_system__management_fill_b","type"=>"list"); 
             $children  = array(); 
             $children[] = array("index" =>$index.'-1',"label" =>"System Message","path"=>"/system-message");
@@ -806,7 +818,16 @@ switch ($action) {
         break;
     case 'notifications_rules':
         tools::getInstance()->notifications_rules();
-        break;              
+        break;
+    case 'destination_delivery_load':
+        destination_delivery::getInstance()->destination_delivery_load();
+        break;
+    case 'destination_delivery_config':
+        destination_delivery::getInstance()->destination_delivery_config();
+        break; 
+    case 'destination_delivery_booking':
+        destination_delivery::getInstance()->destination_delivery_booking();
+        break;                            
     case 'user_guide':
         $rootPath = realpath(dirname(__FILE__)) . DS;
         //common::download_file($rootPath."images\ACE-M1_ISF_ACI_User_Guide\ACE-M1_ISF_ACI_User_Guide.pdf", "ACE-M1_ISF_ACI_User_Guide_V2.0.pdf");

+ 16 - 1
service/column.class.php

@@ -246,7 +246,10 @@ class column {
                 $temp['formatter'] = "";
             }
 
-            $temp['field'] = $rs['name'];
+            //这两个的field 不用as display  
+            if(!($type == "Destination_Delivery_Search" || $type == "destination_delivery_shipment_search")){
+                $temp['field'] = $rs['name'];
+            }
             $tableColumns[] = $temp;
         }
         return $tableColumns;
@@ -304,6 +307,18 @@ class column {
                          "response_time" =>array("formatter" =>"dateTime"),
                         "request_id" =>array("type" =>"link"));
         }
+        if ($type == "Destination_Delivery_Search"){
+            return array("delivery_date" =>array("formatter" =>"date"),
+                        "created_time" =>array("formatter" =>"date"),
+                        "status" =>array("type" =>"status"),
+                        "h_bol" =>array("type" =>"multiple_link"),
+                        "date_range" =>array("formatter" =>"range"));
+        }
+        if ($type == "destination_delivery_shipment_search"){
+            return array("eta" =>array("formatter" =>"date"),
+                        "ata" =>array("formatter" =>"date"),
+                        "date_range" =>array("type" =>"recommend"));
+        }
     }
 
     /**

+ 1255 - 74
service/destination_delivery.class.php

@@ -34,12 +34,9 @@ class destination_delivery {
         if ($operate == "country") {
             $term = $_POST['term'];
             $term = trim($term);
-            $sql = "select DISTINCT SUBSTRING(c.country FROM 1 FOR 2) AS country_code 
-                        from public.contract_region_mapping crm
-	                        left join ocean.contacts c on  c.contact_id = crm.overeas and crm.ksmart_station_new ilike 'ksmart%'
-                        where coalesce(c.country,'')<> '' 
-                            and  SUBSTRING(c.country FROM 1 FOR 2) ilike '" . common::check_input($term) . "%'";
-            $sql .= " order by country_code";
+            $sql = "select DISTINCT category AS country_code from public.kerry_system_code
+                        where category ilike '" . common::check_input($term) . "%'";
+            $sql .= " order by category";
 
             $rs = common::excuteListSql($sql);
             //前端要加上id 从1开始
@@ -59,14 +56,11 @@ class destination_delivery {
         */
         if ($operate == "station") {
             $country = common::check_input($_REQUEST['country']);
-            $sql  = "select crm.overeas from public.contract_region_mapping crm
-                            left join ocean.contacts c on  c.contact_id = crm.overeas and crm.ksmart_station_new ilike 'ksmart%'
-                    where SUBSTRING(c.country FROM 1 FOR 2) = '".$country."'";
+            $sql  = "select code from public.kerry_system_code where category = '".$country."' and code NOT LIKE 'Online_%'";
             $rs = common::excuteListSql($sql);
-
             foreach($rs as $key => $val){
-                if(!empty($val['overeas'])){
-                    $retData[] = array("value" =>$val['overeas'] ,"label"=>$val['overeas']);
+                if(!empty($val['code'])){
+                    $retData[] = array("value" =>$val['code'] ,"label"=>$val['code']);
                 }
             }
             common::echo_json_encode(200,$retData);
@@ -74,7 +68,7 @@ class destination_delivery {
         }
 
         /**
-         * select KLN PIC   下拉可供选择的employee帐号,且帐号权限站点包含选中的station
+         * select KLN PIC   下拉可供选择的employee帐号,且帐号权限站点包括选中的station ?
          */
         if ($operate == "employee_account") {
             $term = $_POST['term'];
@@ -82,8 +76,10 @@ class destination_delivery {
             $station = $_REQUEST['station'];
             $more_param = common::getInNotInSqlForSearch(utils::implode(';',$station));
 
-            $sql  = "select email from  employee where contact_id in ($more_param) and email ilike '" . common::check_input($term) . "%' limit 20";
+            $sql  = "select email from public.ra_online_user where user_type = 'Employee' and lower(contact_id) in ($more_param)
+                and email ilike '" . common::check_input($term) . "%' limit 20";
             $rs = common::excuteListSql($sql);
+            $retData = array();
             foreach($rs as $key => $val){
                 if(!empty($val['email'])){
                     $retData[] = array("value" =>$val['email'] ,"label"=>$val['email']);
@@ -117,7 +113,7 @@ class destination_delivery {
             $retData = array();
             foreach($rs as $key => $val){
                 if(!empty($val['uncode'])){
-                    $retData[] = array("value" =>$val['uncode'] ,"label"=>$val['uncode']);
+                    $retData[] = array("value" =>$val['uncode'] ,"label"=>$val['uncode'],"checked"=>false);
                 }
             }
             common::echo_json_encode(200,$retData);
@@ -141,12 +137,98 @@ class destination_delivery {
             $retData = array();
             foreach($rs as $key => $val){
                 if(!empty($val['scac'])){
-                    $retData[] = array("value" =>$val['scac'] ,"label"=>$val['scac']);
+                    $retData[] = array("value" =>$val['scac'] ,"label"=>$val['scac'],"checked"=>false);
                 }
             }
             common::echo_json_encode(200,$retData);
             exit();
         }
+
+        /**
+         *  Manage Address load
+        */
+        if ($operate == "manage_address"){
+            $consignee = $_REQUEST['consignee'];
+
+            $consignee =array('COMGEN38002','FGB050132','ATOZTI35005');
+            $more_param = common::getInNotInSqlForSearch(utils::implode(';',$consignee));
+
+            $country = $_REQUEST['country'];
+            $country =array('GB','DE');
+            $more_param_country = common::getInNotInSqlForSearch(utils::implode(';',$country));
+
+            $sql = "SELECT * FROM public.contacts_address  
+                        WHERE addr_type = 'D'  
+                            and lower(contact_id) in ($more_param) 
+                            and from_station in (select code from public.kerry_system_code where lower(category) in ($more_param_country))";
+
+            $data = common::excuteListSql($sql);
+            error_log($sql);
+            $manageAddressList = array();
+            //Online_D_Address
+            foreach($data as $d){
+                $manageAddressList[] = array(
+                    "address_1"=>$d['addr1'],
+                    "address_2"=>$d['addr2'],
+                    "address_3"=>$d['addr3'],
+                    "address_4"=>$d['addr4'],
+                    "country"=>$d['ctry_code'],
+                    "city"=>$d['city_code'],
+                    "postal_code"=>$d['postal_code'],
+                    "contact_person"=>$d['contact_person'],
+                    "contact_number" =>$d['contact_number'],
+                    "create_user" => $d['create_user'],   //create_user = Online_D_Address 时,代表對客戶賬號類型自己創建的D類地址
+                    "contact_id" => $d['contact_id'],
+                    "sync_key" => $d['sync_key'],         //唯一key 
+                    "from_station" => $d['from_station'],  //只有是客户新键的才会特殊处理station Online_GE.  好判断是那个国家的
+                    "contact_type" => "Unedit"
+                );
+            }
+            common::echo_json_encode(200,$manageAddressList);
+            exit();
+
+        }
+
+        /**
+         *  country and city load
+         */
+        if ($operate == "country_city_load") {
+            $term_type = $_POST['term_type'];
+            
+            $limit = $_POST['limit'];
+            $term = $_POST['term'];
+            $term = trim($term);
+
+            $extend_sql_where = "";
+            if ($term_type == "country" && !empty($limit)){
+                $extend_sql_where = " and location_code = '$limit'";
+            }
+            if ($term_type == "city" && !empty($limit)){
+                $extend_sql_where = " and country_code = '$limit'";
+            }
+
+            if ($term_type == "country"){
+                $sql = "select DISTINCT country_code AS code from public.unlocode 
+                            where country_code ilike '" . common::check_input($term) . "%'".$extend_sql_where;
+                $sql .= " order by country_code  limit 20";
+            }
+            if ($term_type == "city"){
+                $sql = "select DISTINCT location_code AS code from public.unlocode 
+                            where location_code ilike '" . common::check_input($term) . "%'".$extend_sql_where;
+                $sql .= " order by location_code limit 20";
+            }    
+            $rs = common::excuteListSql($sql);
+            //前端要加上id 从1开始
+            $retData = array();
+            foreach($rs as $key => $val){
+                if(!empty($val['code'])){
+                    $retData[] = array("value" =>$val['code'] ,"label"=>$val['code']);
+                }
+            }
+            common::echo_json_encode(200,$retData);
+            exit();
+
+        }
     }
 
     /**
@@ -183,10 +265,10 @@ class destination_delivery {
                     $rs[$key]["_serial_no"] = common::deCode($val['serial_no'], 'E');
                 }
                 $arrTmp = array('searchData' => $rs, 
-                        'rc' => $rc,
-                        'ps' => $ps,
-                        'cp' => $cp,
-                        'tp' => $tp);
+                        'rc' => intval($rc),
+                        'ps' => intval($ps),
+                        'cp' => intval($cp),
+                        'tp' => intval($tp));
                 common::echo_json_encode(200,$arrTmp);
                 exit();
             }else{
@@ -197,7 +279,7 @@ class destination_delivery {
         }
 
         if ($operate == "add"){
-            $serial_no = common::deCode($_GET['a'], 'D');
+            $serial_no = common::deCode($_REQUEST['a'], 'D');
             $data = array();
             $rule = array();
 
@@ -205,11 +287,17 @@ class destination_delivery {
                 $sql = "select * from public.kln_destination_delivery_config where serial_no = '$serial_no'";
                 $data = common::excuteObjectSql($sql);
 
-                if ($data['recommended_delivery'] == 'delivery_eta_ata') {
+                if ($data['recommended_delivery'] == 'Delivery_ETA_ATA') {
                     $sql = "select * from public.kln_destination_delivery_rule where recommended_delivery_serial_no = '$serial_no'";
-                    $rule = common::excuteObjectSql($sql);
+                    $rule = common::excuteListSql($sql);
                 }
-            } 
+            } else{
+                //代表新加,页面初始
+                $data['booking_window'] = "No_Restrictions";
+                $data['booking_window_date_start'] ="";
+                $data['booking_window_date_end'] ="";
+                $data['recommended_delivery'] ="No_Recommended";
+            }
 
             //处理组装返回格式
             //RcommendDeliveryDate
@@ -218,61 +306,67 @@ class destination_delivery {
             $RecommendCheckedList = array();
             foreach($rule as $item){
                 if ($item['mode_type'] == 'sea'){
-                    $RecommendCheckedSeaList[] = array("Priority"=>$item['priority'],"RuleType"=>$item['rule_type'],
-                        "Port"=>explode(";", $item['ports']),
-                        "Carrier"=>explode(";", $item['carrier']),
-                        "FromDate"=>$item['recommended_delivery_from'],
-                        "ToDate"=>$item['recommended_delivery_to']);
+                    $RecommendCheckedSeaList[] = array("priority"=>$item['priority'],"rule_type"=>$item['rule_type'],
+                        "ports"=>explode(",", $item['ports']),
+                        "carrier"=>explode(",", $item['carrier']),
+                        "recommended_delivery_from"=>$item['recommended_delivery_from'],
+                        "recommended_delivery_to"=>$item['recommended_delivery_to'],
+                        "mode_type"=>$item['mode_type']);
                 }
                 if ($item['mode_type'] == 'air'){
-                    $RecommendCheckedAirList[] = array("Priority"=>$item['priority'],"RuleType"=>$item['rule_type'],
-                        "Port"=>explode(";", $item['ports']),
-                        "Carrier"=>explode(";", $item['carrier']),
-                        "FromDate"=>$item['recommended_delivery_from'],
-                        "ToDate"=>$item['recommended_delivery_to']);
+                    $RecommendCheckedAirList[] = array("priority"=>$item['priority'],"rule_type"=>$item['rule_type'],
+                        "ports"=>explode(",", $item['ports']),
+                        "carrier"=>explode(",", $item['carrier']),
+                        "recommended_delivery_from"=>$item['recommended_delivery_from'],
+                        "recommended_delivery_to"=>$item['recommended_delivery_to'],
+                        "mode_type"=>$item['mode_type']);
                 }
-                if (!utils::in_array($item['mode_type'], $RecommendCheckedList)) {
-                    $RecommendCheckedList[] = $item['mode_type'];
+                if (!utils::in_array(ucfirst($item['mode_type']), $RecommendCheckedList)) {
+                    $RecommendCheckedList[] = ucfirst($item['mode_type']);
                 }
             }
 
             $returnData = $data;
-            if (!empty($data['booking_window'])) {
-                $returnData["SetBookingWindow"] = array("windowradio" =>$data['booking_window'],
-                    "windowBeforeDays"=>$data['booking_window'], 
-                    "windowAfterDays"=>$data['booking_window']);
-            } else {
-                $returnData["SetBookingWindow"] = array();
-            }
+            $returnData["SetBookingWindow"] = array("windowradio" =>common::destination_delivery_window_radio($data['booking_window']),
+                    "windowBeforeDays"=>$data['booking_window_date_start'], 
+                    "windowAfterDays"=>$data['booking_window_date_end']);
 
-            if ($data['recommended_delivery'] == 'Delivery_ETA_ATA') {
-                $returnData["RcommendDeliveryDate"] = array("Recommendradio" =>$data['recommended_delivery'],
+            $returnData["RcommendDeliveryDate"] = array("Recommendradio" =>common::destination_delivery_recommended($data['recommended_delivery']),
                     "RecommendCheckedList"=>$RecommendCheckedList, 
                     "RecommendCheckedAirList"=>$RecommendCheckedAirList,
                     "RecommendCheckedSeaList"=>$RecommendCheckedSeaList);
-            } else {
-                $returnData["RcommendDeliveryDate"] = array();
-            }
 
-            $returnData["KLNPLCvalue"] = explode(";", $data['kln_pic']);
+            $returnData["KLNPLCvalue"] = empty($data['kln_pic']) ? array() : explode(";", $data['kln_pic']);
 
-            global $_COPYRIGHT;
-            $data = array('copyright' =>$_COPYRIGHT,
-                'returnData' =>$returnData);
+            $CountryCheckedList = array();
+            $sql  = "select crm.overeas from public.contract_region_mapping crm
+                            left join ocean.contacts c on  c.contact_id = crm.overeas and crm.ksmart_station_new ilike 'ksmart%'
+                    where SUBSTRING(c.country FROM 1 FOR 2) = '".$data['country']."'";
+            $rs = common::excuteListSql($sql);
+            foreach($rs as $key => $val){
+                if(!empty($val['overeas'])){
+                    $CountryCheckedList[] = array("value" =>$val['overeas'] ,"label"=>$val['overeas']);
+                }
+            }
+            $returnData["CountryCheckedList"] = $CountryCheckedList;
+            $returnData["station"] = explode(",", $returnData["station"]);
+            $data = array('returnData' =>$returnData);
             common::echo_json_encode(200,$data);                
             exit(); 
         }
 
         if ($operate == "save"){
-            $serial_no = common::deCode($_POST['a'], 'D');
+            $serial_no = common::deCode($_POST['serial_no'], 'D');
 
             $country = common::check_input($_POST['country']);
-            $station = empty($_POST['station']) ? "" :explode(";", $_POST['station']);
+            $station = empty($_POST['station']) ? "" : utils::implode(",",$_POST['station']);
             $booking_window = common::check_input($_POST['booking_window']);
             $booking_window_date_start = common::check_input($_POST['booking_window_date_start']);
             $booking_window_date_end = common::check_input($_POST['booking_window_date_end']);
             $recommended_delivery = common::check_input($_POST['recommended_delivery']);
-            $kln_pic = empty($_POST['kln_pic']) ? "" :explode(";", $_POST['kln_pic']);
+            $kln_pic = common::check_input($_POST['kln_pic']);
+            $booking_window_desc = common::check_input($_POST['booking_window_desc']);
+            $recommended_delivery_date_desc = common::check_input($_POST['recommended_delivery_date_desc']);
 
             //rule
             $_mode_type = $_POST['mode_type'];
@@ -283,7 +377,6 @@ class destination_delivery {
             $_recommended_delivery_from = $_POST['recommended_delivery_from'];
             $_recommended_delivery_to = $_POST['recommended_delivery_to'];
 
-            $errmsg = "";
             $sql = "";
             if (!empty($serial_no)){
                 $updateSqlSet = " modify_by = '"._getLoginName()."',update_time = now()";
@@ -308,52 +401,73 @@ class destination_delivery {
                 if (!empty($kln_pic)) {
                     $updateSqlSet.= ", kln_pic = '$kln_pic' ";
                 }
+                if (!empty($booking_window_desc)) {
+                    $updateSqlSet.= ", booking_window_desc = '$booking_window_desc' ";
+                }
+                if (!empty($recommended_delivery_date_desc)) {
+                    $updateSqlSet.= ", recommended_delivery_date_desc = '$recommended_delivery_date_desc' ";
+                }
                 //代表update 
                 $sql .= "update public.kln_destination_delivery_config set ".$updateSqlSet."
                     where serial_no = '$serial_no';";
             } else {
+                //检查配置的站点是否于以前的配置的,是否重合
+                $exist = common::excuteListSql("select country,station from public.kln_destination_delivery_config WHERE string_to_array('$station', ',') && string_to_array(station, ',')");
+                if(!empty($exist)){
+                    $data = array("msg" =>"The station has been reconfigured. Please check ".$exist[0]['country'] ." - " .$exist[0]['station']);
+                    common::echo_json_encode(200,$data);                
+                    exit(); 
+                }
                 //代表更新
                 $serial_no = common::uuid();
                 $sql .="INSERT INTO public.kln_destination_delivery_config(
                         serial_no, country, station, booking_window, booking_window_date_start, 
-                        booking_window_date_end, recommended_delivery, kln_pic, create_by, 
-                        created_time, modify_by, update_time)
+                        booking_window_date_end, recommended_delivery, kln_pic, booking_window_desc,recommended_delivery_date_desc,
+                        create_by, created_time, modify_by, update_time)
                 VALUES ('$serial_no', '$country', '$station', '$booking_window', '$booking_window_date_start', 
-                        '$booking_window_date_end', '$recommended_delivery', '$kln_pic',
+                        '$booking_window_date_end', '$recommended_delivery', '$kln_pic','$booking_window_desc','$recommended_delivery_date_desc',
                         '"._getLoginName()."', now(), '"._getLoginName()."', now());";
             }
 
-            if ($recommended_delivery == "delivery_eta_ata"){
+            $errmsg = "";
+            //柜子是先删除,后添加
+            $sql .= "delete from  public.kln_destination_delivery_rule where recommended_delivery_serial_no = '$serial_no';";
+            if ($recommended_delivery == "Delivery_ETA_ATA"){
                 // 用于统计每种类型是否存在,以及是否满足 rule_type = 'all'
                 $typeExists = ['air' => false, 'sea' => false];
                 $typeHasAllRule = ['air' => false, 'sea' => false];
 
+                //检查判断规则不能重合
+                $seaRule = [];
+                $airRule = [];
+
                 foreach($_mode_type as $key => $v){
                     $mode_type = $v;
                     $priority = $_priority[$key];
                     $rule_type = $_rule_type[$key];
-                    $ports = empty($_ports[$key]) ? "" :explode(";", $_ports[$key]);
-                    $carrier = empty($_carrier[$key]) ? "" :explode(";", $_carrier[$key]);
+                    $ports = $_ports[$key];
+                    $carrier = $_carrier[$key];
+                    if( $mode_type == 'sea'){
+                        $seaRule[] = explode(",",$_ports[$key]);
+                        ///$sea_carrier_index += 1;
+                    } else {
+                        $airRule[] = explode(",",$_ports[$key]);  
+                    }
                     $recommended_delivery_from = $_recommended_delivery_from[$key];
                     $recommended_delivery_to = $_recommended_delivery_to[$key];
 
-                    // 只处理 air 和 sea
-                    if ($mode_type == 'air' || $mode_type == 'sea') {
-                        $typeExists[$mode_type] = true;
-                        if ($rule_type == 'all') {
-                            $typeHasAllRule[$mode_type] = true;
-                        }
-                    }
-
-                    //先删除,后添加
-                    $sql .= "delete from  public.kln_destination_delivery_rule where recommended_delivery_serial_no = '$serial_no';";
                     $sql .= "INSERT INTO public.kln_destination_delivery_rule(
-                            serial_no, recommended_delivery_serial_no, mode_type, priority, 
+                            recommended_delivery_serial_no, mode_type, priority, 
                             rule_type, ports, carrier, recommended_delivery_from, recommended_delivery_to, 
                             create_by, created_time, modify_by, update_time)
                     VALUES ('$serial_no', '$mode_type', '$priority', 
                             '$rule_type', '$ports', '$carrier', '$recommended_delivery_from', '$recommended_delivery_to', 
                             '"._getLoginName()."', now(), '"._getLoginName()."', now());";
+
+                    $typeExists[$mode_type] = true;
+                    if ($rule_type == '*Default Rule') {
+                        $typeHasAllRule[$mode_type] = true;
+                    }
                 }
                 // 检查缺失的 rule_type = 'all'
                 $missingTypes = [];
@@ -365,6 +479,10 @@ class destination_delivery {
                 if (!empty($missingTypes)) {
                     $errmsg =  "The Default Rule must exist.";
                 }
+
+                //检查规则不能重复
+                $errmsg .= common::checkOverlap($seaRule,"Sea Rule");
+                $errmsg .= common::checkOverlap($airRule,"Air Rule");
             }
 
             if (empty($errmsg) && !empty($sql)){
@@ -377,13 +495,1076 @@ class destination_delivery {
             exit(); 
         }
 
+        if ($operate == "delete"){
+            $serial_no = common::deCode($_POST['a'], 'D');
+            $sql = "delete from public.kln_destination_delivery_config where serial_no = '$serial_no';";
+            $sql .= "delete from public.kln_destination_delivery_rule where recommended_delivery_serial_no = '$serial_no';";
+            error_log($sql);
+            common::excuteUpdateSql($sql);
+            $data = array("msg" =>"success");
+            common::echo_json_encode(200,$data);                
+            exit(); 
+        }
+
     }
 
     /**
      *  booking
      */
-    public function destination_delivery(){
+    public function destination_delivery_booking(){
+        $operate = utils::_get('operate');
+        $operate = strtolower($operate);
+
+        if ($operate == "destination_delivery_search") {
+            //search
+            //栏位信息
+            $column = column::getInstance()->getDisplayColumn('Destination_Delivery_Search');
+            $BookingTableColumns = column::getInstance()->tableColumns('Destination_Delivery_Search',$column);
+            $data['TrackingTableColumns'] = $BookingTableColumns;
+            common::echo_json_encode(200,$data);
+            exit();
+        }
+
+        if ($operate == "destination_delivery_shipment_search") {
+            //search
+            //栏位信息
+            $column = column::getInstance()->getDisplayColumn('destination_delivery_shipment_search');
+            $BookingTableColumns = column::getInstance()->tableColumns('destination_delivery_shipment_search',$column);
+            $data['TrackingTableColumns'] = $BookingTableColumns;
+            common::echo_json_encode(200,$data);
+            exit();
+        }
+
+        /**
+         * select shipment,
+         *  Pending Approval Approve Reject Cancel  Modify  Submit
+         */
+        if ($operate == "search"){
+            $cp = common::check_input($_POST ['cp']); //current_page
+            $ps = common::check_input($_POST ['ps']); //ps
+            if (empty($ps))
+                $ps = 100;
+            if (empty($cp))
+                $cp = 1;
+
+            $sqlWhere = ' where ' . common::searchExtendHand_KLN("ocean", $_SESSION["ONLINE_USER"]);
+            //兜底规则
+            //$sqlWhere .= " and eta >= now() - INTERVAL '6 months' and eta <= now() + INTERVAL '6 months'";
+            //代表employee 
+            if(_isApexLogin()){
+                //$sqlWhere .= " and kln_pic = '"._getLoginEamil()."'";
+            }    
+
+            //条件带入
+            $text_search = $_REQUEST['text_search'];
+            if (!empty($text_search)){
+                $sqlWhere .= " and (booking_no ilike '%".strtolower($text_search)."%'
+                    or h_bol ilike '%".strtolower($text_search)."%'
+                    or m_bol ilike '%".strtolower($text_search)."%' 
+                    or ctnr ilike '%".strtolower($text_search)."%'
+                    or consignee ilike '%".strtolower($text_search)."%')";
+            }
+
+            if (isset($_REQUEST['delivery_date_start']) && !empty($_REQUEST['delivery_date_start']))
+                $sqlWhere .= " and delivery_date >= '" . common::usDate2sqlDate($_REQUEST['delivery_date_start']) . " 00:00:00'";
+            if (isset($_REQUEST['delivery_date_end']) && !empty($_REQUEST['delivery_date_end']))
+                $sqlWhere .= " and delivery_date <= '" . common::usDate2sqlDate($_REQUEST['delivery_date_end']) . " 23:59:59'";
 
+            if(!empty($_POST['delivery_mode'])){
+                $sqlWhere .= " and delivery_mode ='". common::check_input($_REQUEST['delivery_mode'])."'";
+            }
+            if (isset($_REQUEST['created_time_start']) && !empty($_REQUEST['created_time_start']))
+                $sqlWhere .= " and created_time >= '" . common::usDate2sqlDate($_REQUEST['created_time_start']) . " 00:00:00'";
+            if (isset($_REQUEST['created_time_end']) && !empty($_REQUEST['created_time_end']))
+                $sqlWhere .= " and created_time <= '" . common::usDate2sqlDate($_REQUEST['created_time_end']) . " 23:59:59'";
+
+            //移除filterTag
+            $sqlWhere_befrom_filterTag  = $sqlWhere;
+
+            $filterTag_param = "";
+            if (!empty($_POST["filterTag"])) {
+                if (utils::count($_POST['filterTag']) == 1){
+                    $filterTag = $_POST['filterTag'][0];
+                }else{
+                    $filterTag = utils::implode(",", $_POST['filterTag']);
+                }
+
+                $filterTag_param = "1<>1";
+                if(strtolower($filterTag) == "all"){
+                    $filterTag_param = "1=1";
+                }
+                if (stripos($filterTag, "Pending Approval") !== FALSE) {
+                    $filterTag_param .= " or (status = 'Pending Approval')";
+                }
+                if (stripos($filterTag, "Approve") !== FALSE) {
+                    $filterTag_param .= " or (status = 'Approve')";
+                }
+                if (stripos($filterTag, "Reject") !== FALSE) {
+                    $filterTag_param .= " or (status = 'Reject')";
+                }
+                if (stripos($filterTag, "Cancel") !== FALSE) {
+                    $filterTag_param .= " or (status = 'Cancel')";
+                }
+                if(strtolower($filterTag) <> "all" && !empty($filterTag)){
+                    $filterTag_param = " ($filterTag_param)";
+                }
+            }
+            if(empty($filterTag_param)){
+                $filterTag_param = "1=1";
+            }
+            $tag_and_mode_param = $filterTag_param;    
+            
+
+            $rc = $_POST ['rc'];
+            if ($rc == - 1 || true) {
+                $sql = "select count(1) as rc,
+                        sum(case when $tag_and_mode_param then 1 else 0 end) as seach_rc, 
+                        sum(case when status ='Pending Approval' then 1 else 0 end) as pending_approval_rc, 
+                        sum(case when status ='Approve' then 1 else 0 end) as approved_rc,
+                        sum(case when status ='Reject' then 1 else 0 end) as rejected_rc,
+                        sum(case when status ='Cancel' then 1 else 0 end) as cancelled_rc
+                    from public.kln_destination_delivery 
+                        where exists(select 1 from public.kln_ocean oo ". $sqlWhere_befrom_filterTag."  and oo.serial_no = any(h_serial_no))";
+                 error_log("kln_destination_delivery_count:".$sql);        
+                $statusRc = common::excuteObjectSql($sql);
+                $rc = $statusRc['rc'];
+                $search_rc = $statusRc['seach_rc'];
+                $pending_approval_rc = $statusRc['pending_approval_rc'];
+                $approved_rc = $statusRc['approved_rc'];
+                $rejected_rc = $statusRc['rejected_rc'];
+                $cancelled_rc = $statusRc['cancelled_rc'];
+            }
+            $tp = ceil($rc / $ps);
+            if ($rc > 0) {
+                $sql = "select *,to_char((recommended_delivery_window_date_from)::date, 'YYYY-MM-DD') 
+                                    || ';' ||
+                                    to_char((recommended_delivery_window_date_to)::date, 'YYYY-MM-DD') AS date_range
+                         from public.kln_destination_delivery 
+                    where ".$tag_and_mode_param." 
+                        and exists(select 1 from public.kln_ocean oo ". $sqlWhere."  and oo.serial_no = any(h_serial_no))";
+                $sql .= " order by id desc limit " . $ps . " offset " . ($cp - 1) * $ps;
+
+                error_log("kln_destination_delivery_search:".$sql);
+                $rs = common::excuteListSql($sql);
+
+                foreach($rs as $key => $val){
+                    $rs[$key]["_serial_no"] = common::deCode($val['serial_no'], 'E');
+                    $rs[$key]["status"] = common::deliveryStatusConvert($val['status']);
+                    $rs[$key]["h_bol"] = json_decode($val['h_bol_multiple_link']);
+                }
+                $arrTmp = array('searchData' => $rs,
+                        'is_employee' => _isApexLogin(), 
+                        'All' =>$rc,
+                        'pending_approval_rc' =>$pending_approval_rc,
+                        'approved_rc' =>$approved_rc,
+                        'rejected_rc' =>$rejected_rc,
+                        'cancelled_rc' =>$cancelled_rc,
+                        'rc' => $search_rc,
+                        'ps' => $ps,
+                        'cp' => $cp,
+                        'tp' => $tp);
+                common::echo_json_encode(200,$arrTmp);
+                exit();
+            }else{
+                $arrTmp = array('searchData' => array(),
+                        'is_employee' => _isApexLogin(), 
+                        'All' =>$rc,
+                        'pending_approval_rc' =>$pending_approval_rc,
+                        'approved_rc' =>$approved_rc,
+                        'rejected_rc' =>$rejected_rc,
+                        'cancelled_rc' =>$cancelled_rc,
+                        'rc' => $search_rc,
+                        'ps' => $ps,
+                        'cp' => $cp,
+                        'tp' => $tp);
+                common::echo_json_encode(200,$arrTmp);
+                exit();
+            }
+        }
+
+        if ($operate == "search_shipment"){
+            $data = $this->search_shipment();
+            if(!empty($data['msg'])){
+                $arrTmp = array("msg" =>$data['msg']);
+            }else{
+                $arrTmp =  array("msg" =>"success","data"=>$data['data']); 
+            }
+            common::echo_json_encode(200, $arrTmp);
+            exit();
+        }
+
+        if ($operate == "add"){
+            $serial_no = common::deCode($_POST['serial_no'], 'D');
+
+            //前端按钮 后台权限拦截
+            if(!empty($serial_no)){
+                common::checkedActionLegal($serial_no,$operate);
+            }else{
+                if(!_isApexLogin()){
+                    //$data = array("msg" =>"Employees cannot create booking");
+                    //common::echo_json_encode(200,$data); 
+                    //exit(); 
+                }
+            }
+
+            $booking_data = array();
+            if(!empty($serial_no)){
+                $sql = "select * from public.kln_destination_delivery where serial_no = '$serial_no'";
+                $booking_data  = common::excuteObjectSql($sql);
+                $shipments = $this->search_shipment_with_booking($booking_data['serial_no'],$booking_data['h_serial_no'],$booking_data['ctnr']);
+            } else {
+                $shipments = $this->search_shipment();
+            }
+            if(!empty($shipments['msg'])){
+                $data = array("msg" =>$shipments['msg']);
+                common::echo_json_encode(200,$data);                
+                exit(); 
+            }
+            $booking_data['tableData'] = $shipments['data'];
+            $data = array("msg" =>"success","data"=>$booking_data);
+            common::echo_json_encode(200,$data);                
+            exit(); 
+        }
+
+        if ($operate == "save"){
+            $serial_no = common::deCode($_POST['serial_no'], 'D');
+
+            $booking_no = $_POST['booking_no'];  
+            $manifest_type = $_POST['manifest_type'];  
+            $h_bol = $_POST['h_bol']; 
+            $h_serial_no  = $_POST['serial_no'];
+            $order_from  = $_POST['order_from']; 
+            $m_bol = $_POST['m_bol'];  
+            $ctnr = $_POST['ctnr'];
+            $kln_pic = $_POST['dc_kln_pic'];       
+            $consignee = $_POST['consignee'];
+            $consignee_id = $_POST['consignee_id'];
+            $dc_country = $_POST['dc_country'];
+
+            $recommended_delivery_window_date_from = $_POST['recommended_delivery_from_date'];
+            $recommended_delivery_window_date_to = $_POST['recommended_delivery_to_date'];
+            $recommended_delivery_from = $_POST['recommended_delivery_from'];
+            $recommended_delivery_to = $_POST['recommended_delivery_to'];
+            $modify_reason = common::check_input($_POST['modify_reason']);
+            
+
+            $delivery_date = $_POST['delivery_date'];
+            $delivery_time = $_POST['delivery_time'];
+            $delivery_mode = common::check_input($_POST['delivery_mode']);
+            //这status 编辑只有两种情况,新加,和在拒绝后 用户重新编辑 状态都是Pending Approval
+            $status = "Pending Approval";
+            $is_new = false;
+            if(empty($serial_no)){
+                $is_new = true;
+            }
+        
+            $delivery_address = common::check_input($_POST['delivery_address']);
+            $special_requirements = common::check_input($_POST['special_requirements']);
+
+            //检查不能重复添加booking  这里空运没问题,但是会遇到相同hbol 不同的柜子情况,本质上来说就是一条
+            //$sqlWhere = ' where ' . common::searchExtendHand_KLN("ocean", $_SESSION["ONLINE_USER"]);
+            //兜底规则
+            //$sqlWhere .= " and  eta >= now() - INTERVAL '6 months' and eta <= now() + INTERVAL '6 months'";
+
+            // $ckeckedSql = "with save_table as (select regexp_split_to_table('".utils::implode(',',$h_serial_no)."', ',') as serial_no)
+            // select string_agg(h_bol, ';') as h_bol from public.kln_destination_delivery kde
+            //         where exists(select 1 from save_table where save_table.serial_no = any(kde.h_serial_no))
+            //             and exists(select 1 from public.kln_ocean oo ". $sqlWhere."  and oo.serial_no = any(kde.h_serial_no))";
+            // //代表编辑
+            // if(!empty($serial_no)){
+            //     $ckeckedSql .=" and kde.serial_no <> '$serial_no'";
+            // }            
+
+            // $checkeData = common::excuteObjectSql($ckeckedSql);
+            // if(!empty($checkeData['h_bol'])){
+            //     $data = array("msg" =>"The ".$checkeData['h_bol'] ." already exists");
+            //     common::echo_json_encode(200,$data); 
+            //     exit();
+            // }
+
+            $sql = "";
+            //代表修改
+            if(!empty($serial_no)){
+                $updateSqlSet = " modify_by = '"._getLoginName()."',update_time = now()";
+
+                if (!empty($status)) {
+                    $updateSqlSet.= ", status = '$status' ";
+                }
+                $delivery_address = $_POST['location_name']."\n".$_POST['address_1']."\n".$_POST['address_2']."\nContact:".$_POST['contact_person']." ".$_POST['contact_number'];
+                $delivery_address = common::check_input($delivery_address);
+                if (!empty($delivery_address)) {
+                    $updateSqlSet.= ", delivery_address = '$delivery_address' ";
+                }
+                if (!empty($special_requirements)) {
+                    $updateSqlSet.= ", special_requirements = '$special_requirements' ";
+                }
+                if (!empty($modify_reason)) {
+                    $updateSqlSet.= ", modify_reason = '$modify_reason' ";
+                }
+                if (!empty($delivery_date)) {
+                    $delivery_date = empty($_POST['delivery_date']) ? "null": "'".common::usDate2sqlDate($_POST['delivery_date'])." ".$delivery_time."'";
+                    //$updateSqlSet.= ", delivery_date =  $delivery_date";
+                }
+
+                $addressSql = common::returnDAddressRecord($dc_country,$consignee_id);
+                if (!empty($addressSql)) {
+                    $updateSqlSet.= ", d_address_change_log = d_address_change_log ||';'||'".common::check_input($addressSql)."' ";
+                } 
+
+                //代表update 
+                $sql .= "update public.kln_destination_delivery set ".$updateSqlSet."
+                    where serial_no = '$serial_no';"; 
+
+                //记录log
+                $sql .="INSERT INTO public.kln_destination_delivery_operation_log(
+                                serial_no, action,notes, create_by, created_time, created_zone)
+                        VALUES ('$serial_no', 'Submit','".$modify_reason."', '"._getLoginName()."', now(), ''); ";        
+            } else {  
+                $saveData = $this->groupShipments($booking_no,$manifest_type,$h_bol,$h_serial_no,$order_from,$m_bol,$ctnr,$kln_pic,$consignee,$consignee_id,
+                    $recommended_delivery_window_date_from, $recommended_delivery_window_date_to,
+                    $recommended_delivery_from,$recommended_delivery_to,$dc_country);
+                
+                $delivery_address = $_POST['location_name']."\n".$_POST['address_1']."\n".$_POST['address_2']."\nContact:".$_POST['contact_person']." ".$_POST['contact_number'];
+                $delivery_address = common::check_input($delivery_address);
+
+                foreach($saveData as $sData){
+                    $serial_no = common::uuid();
+
+                    // 使用 PostgreSQL 的 ARRAY 语法
+                    $tags_sql = "ARRAY['" . implode("','", array_map('pg_escape_string', $sData['h_serial_no'])) . "']";
+                    // 使用 PostgreSQL 的 ARRAY 语法
+                    $country_sql = "ARRAY['" . implode("','", array_map('pg_escape_string', $sData['dc_country'])) . "']";
+
+                    $recommended_delivery_window_date_from = "";
+                    if(empty($sData['recommended_delivery_window_date_from'])){
+                        $recommended_delivery_window_date_from = "null";
+                    } else {
+                        $recommended_delivery_window_date_from = "'".$sData['recommended_delivery_window_date_from']."'";
+                    }
+
+                    $recommended_delivery_window_date_to = "";
+                    if(empty($sData['recommended_delivery_window_date_to'])){
+                        $recommended_delivery_window_date_to = "null";
+                    } else {
+                        $recommended_delivery_window_date_to = "'".$sData['recommended_delivery_window_date_to']."'";
+                    }
+
+                    $delivery_date = empty($_POST['delivery_date']) ? "null": "'".common::usDate2sqlDate($_POST['delivery_date'])." ".$delivery_time."'";
+                    $addressSql = common::check_input(common::returnDAddressRecord($sData['dc_country'],$sData['consignee_id']));
+
+                    $sql .= "INSERT INTO public.kln_destination_delivery(
+                            serial_no, h_serial_no,address_country,
+                            booking_no, h_bol,h_bol_multiple_link,
+                            m_bol, ctnr,
+                            consignee, delivery_date, delivery_mode, status, delivery_address, special_requirements, 
+                            recommended_delivery_window_date_from, recommended_delivery_window_date_to, d_address_change_log,
+                            recommended_delivery_from, recommended_delivery_to,kln_pic,
+                            create_by, created_time, modify_by, update_time)
+                    VALUES ('$serial_no', ".$tags_sql.",".$country_sql.",
+                            '".$sData['booking_no']."', '".utils::implode(',',$sData['h_bol'])."','".common::check_input(json_encode($sData['h_bol_multiple_link']))."',
+                            '".utils::implode(',',$sData['m_bol'])."', '".utils::implode(',',$sData['ctnr'])."',
+                            '".$sData['consignee']."', $delivery_date,'$delivery_mode','$status', '$delivery_address', '$special_requirements',
+                            $recommended_delivery_window_date_from, $recommended_delivery_window_date_to,'$addressSql',
+                            '".$sData['recommended_delivery_from']."', '".$sData['recommended_delivery_to']."','".$sData['kln_pic']."',
+                            '"._getLoginName()."', now(), '"._getLoginName()."', now());";
+                    //记录log
+                    $sql .="INSERT INTO public.kln_destination_delivery_operation_log(
+                                    serial_no, action,notes, create_by, created_time, created_zone)
+                            VALUES ('$serial_no', 'Submit','', '"._getLoginName()."', now(), ''); ";   
+                }
+            }
+
+            if(!empty($sql)){
+                $rs = common::excuteUpdateSql($sql);
+                if ($rs === FALSE){
+                    $data = array("msg" =>"error");
+                    common::echo_json_encode(200,$data); 
+                    exit();
+                }
+            }
+
+            if(!$is_new){
+                //状态变更时,发送邮件提醒 
+                $status = "Modify";
+                $data = common::excuteObjectSql("select *, TO_CHAR(delivery_date, 'Mon-DD-YYYY') as _delivery_date,
+                        TO_CHAR(created_time, 'Mon-DD-YYYY') as _created_time,
+                        TO_CHAR(update_time, 'Mon-DD-YYYY') as _update_time
+                    from public.kln_destination_delivery where serial_no = '$serial_no'");
+                $shipmentsData = $this->search_shipment_with_booking($data['serial_no'],$data['h_serial_no'],$data['ctnr']);
+                $email_sql = common::sendDestinationDeliveryReminder($data,$shipmentsData,$status);       
+                if(!empty($email_sql)){
+                    common::excuteUpdateSql($email_sql);
+                }     
+            } else {
+                $status = "Submit";
+                $data = common::excuteObjectSql("select *, TO_CHAR(delivery_date, 'Mon-DD-YYYY') as _delivery_date,
+                        TO_CHAR(created_time, 'Mon-DD-YYYY') as _created_time,
+                        TO_CHAR(update_time, 'Mon-DD-YYYY') as _update_time
+                    from public.kln_destination_delivery where serial_no = '$serial_no'");
+                $shipmentsData = $this->search_shipment_with_booking($data['serial_no'],$data['h_serial_no'],$data['ctnr']);
+                $email_sql = common::sendDestinationDeliveryReminder($data,$shipmentsData,$status);       
+                if(!empty($email_sql)){
+                    common::excuteUpdateSql($email_sql);
+                }     
+            }
+            $data = array("msg" =>"success");
+            common::echo_json_encode(200,$data); 
+            exit();
+        }
+
+        /**
+         * 审核 approved  or rejected  cancelled
+        */
+        if ($operate == "review"){
+            $serial_no = common::deCode($_POST['serial_no'], 'D');
+            $status = common::check_input($_POST['status']);
+            $notes = common::check_input($_POST['notes']);
+            $action_user = _getLoginName();
+
+            //前端按钮 后台权限拦截
+            common::checkedActionLegal($serial_no,$operate);
+            $sql = "";
+            $update_str = "";
+            //审核通过时,才取下放当时应用修改的地址
+            if ($status == "Approve") {
+                $addressSql = common::excuteOneSql("select d_address_change_log from public.kln_destination_delivery where serial_no = '$serial_no'");
+                if(!empty($addressSql)){
+                    $sql .=$addressSql;
+                }
+                $update_str =  "d_address_change_log = null";
+            }
+
+            $sql .= "update public.kln_destination_delivery set ".$update_str.",status = '$status', modify_by = '"._getLoginName()."',update_time = now() where serial_no = '$serial_no';";
+
+            $sql .="INSERT INTO public.kln_destination_delivery_operation_log(
+                            serial_no, action,notes, create_by, created_time, created_zone)
+                    VALUES ('$serial_no', '$status','$notes', '$action_user', now(), ''); ";
+
+            common::excuteUpdateSql($sql);        
+
+            //状态变更时,发送邮件提醒 
+            $data = common::excuteObjectSql("select *, 
+                        TO_CHAR(delivery_date, 'Mon-DD-YYYY') as _delivery_date,
+                        TO_CHAR(created_time, 'Mon-DD-YYYY') as _created_time,
+                        TO_CHAR(update_time, 'Mon-DD-YYYY') as _update_time 
+                    from public.kln_destination_delivery where serial_no = '$serial_no'");
+            $shipmentsData = $this->search_shipment_with_booking($data['serial_no'],$data['h_serial_no'],$data['ctnr']);
+            $email_sql = common::sendDestinationDeliveryReminder($data,$shipmentsData,$status);       
+            if(!empty($email_sql)){
+                common::excuteUpdateSql($email_sql);
+            }        
+            $data = array("msg" =>"success");
+            common::echo_json_encode(200,$data); 
+        }
+
+        /**
+         * 邮件留言初始
+        */
+        if ($operate == "email_message_init"){
+            try {
+                $email_uuid = common::deCode($_POST['serial_no'], 'D');
+                $emailRecords = $this->getCommunicationNew($email_uuid);
+                common::echo_json_encode(200,array("msg" => "Sent Successfully", "emailRecords" => $emailRecords));
+                exit();
+            } catch (Exception $e) {
+                common::echo_json_encode(500,array("msg" => "Sent Error."));
+                exit();
+            }
+        }
+
+        /**
+         * 邮件留言
+        */
+        if ($operate == "email_message_board"){
+            //前端按钮 后台权限拦截
+            $email_uuid = common::deCode($_POST['serial_no'], 'D');
+            common::checkedActionLegal($email_uuid,$operate);
+
+            try {
+                $content = $_POST["content"];
+                $content = common::check_input($content);
+                $content = urldecode($content);
+
+                $text = $_POST["text"];
+                $web_content = urldecode($text);
+
+                $serial_no = common::uuid();
+                $email_uuid = common::deCode($_POST['serial_no'], 'D');
+                $add_by = _getLoginName();
+                $refer_id = 0;
+               
+                $from_email = "US.KApex.Online@kerryapex.com";
+                $to_email = $_POST["kln_pic"];
+
+                $cc_email = "";
+                $communication_cc = $_POST["communication_cc"];
+                $communication_cc = trim($communication_cc);
+                if (!empty($communication_cc)) {
+                    $communication_cc = common::check_input($communication_cc);
+                    $cc_email = $communication_cc;
+                }
+                $user_from = _getLoginName();
+                
+                //邮件发送
+                $title = "Destination Delivery from " . _getLoginName() . ", Shipment No: " . $_POST["h_bol"];
+                $emailContent = $content;
+
+                common::excuteUpdateSql("insert into public.email_record (type,title,from_email,to_email,cc_email,content,insert_date)values('Delivery_Comm','$title','$from_email','$to_email','$cc_email','$emailContent',now());");
+
+                $rs = common::excuteUpdateSql("INSERT INTO public.online_ocean_communication(serial_no, email_uuid, content,web_content,user_from, user_to, user_cc, refer_id, add_by, add_time, cc_email) 
+                VALUES ('$serial_no', '$email_uuid', '$emailContent','$web_content', '$user_from', '$to_email', '$cc_email', $refer_id, '$add_by', now(), '$communication_cc');");
+
+                $emailRecords = $this->getCommunicationNew($email_uuid);
+                common::echo_json_encode(200,array("msg" => "Sent Successfully", "emailRecords" => $emailRecords));
+                exit();
+            } catch (Exception $e) {
+                common::echo_json_encode(500,array("msg" => "Sent Error."));
+                exit();
+            }
+        }
+
+        /**
+         * view detail and log
+        */
+        if ($operate == "view_detail"){
+            $serial_no = common::deCode($_POST['serial_no'], 'D');
+            //前端按钮 后台权限拦截
+            common::checkedActionLegal($serial_no,$operate);
+
+            $data = common::excuteObjectSql("select * from public.kln_destination_delivery where serial_no = '$serial_no'");
+
+            $_shipmentsData = array();
+            $shipmentsData = $this->search_shipment_with_booking($data['serial_no'],$data['h_serial_no'],$data['ctnr']);
+            foreach($shipmentsData["data"] as $shipment){
+                $_shipmentsData[] = array("HBOL No." => $shipment['h_bol'],"Container No." => $shipment['ctnr'],
+                    "Service Type" => $shipment['service'],"ETA" => $shipment['eta'],
+                    "Recommended Delivery Date" => $shipment['date_range']);
+            }
+
+            $_operation_log = array();
+            $operation_log = common::excuteListSql("select * from public.kln_destination_delivery_operation_log where serial_no = '$serial_no' order by id desc");
+            foreach($operation_log as $log){
+                $action = $log['action'] == "Pending Approval" ? "Submit" : $log['action'];
+                $_operation_log[] = array("time" => $log['created_time'],"timezone" => $log['created_zone'],
+                    "label" => $action,"createdBy" => $log['create_by'],
+                    "tips" => $log['notes']);
+            }
+
+            $retData = $data;
+            $retData["status"] = common::deliveryStatusConvert($retData["status"]);
+            $retData['shipmentsData'] = $_shipmentsData;
+            $retData['operation_log'] = $_operation_log;
+
+            $data = array("msg" =>"success","data"=>$retData);
+            common::echo_json_encode(200,$data);                
+            exit(); 
+        }
+
+        /**
+         * Delivery date
+        */
+        if ($operate == "delivery_date_load"){
+             $sqlWhere = ' where ' . common::searchExtendHand_KLN("ocean", $_SESSION["ONLINE_USER"]);
+            //兜底规则
+            //$sqlWhere .= " and eta >= now() - INTERVAL '6 months' and eta <= now() + INTERVAL '6 months'";
+            //代表employee 
+            if(_isApexLogin()){
+                //$sqlWhere .= " and kln_pic = '"._getLoginEamil()."'";
+            }  
+            $sqlWhere_befrom_filterTag = $sqlWhere;
+            $sql = "select delivery_date::date as delivery_date,
+                        sum(case when status ='Pending Approval' then 1 else 0 end) as pending_approval_rc,
+                        sum(case when status ='Approve' then 1 else 0 end) as approved_rc
+                    from public.kln_destination_delivery 
+                        where exists(select 1 from public.kln_ocean oo ". $sqlWhere_befrom_filterTag."  and oo.serial_no = any(h_serial_no))
+                    group by delivery_date::date  order by delivery_date::date desc";
+            $rs  = common::excuteListSql($sql);        
+            $dateArr = new stdClass();
+            foreach($rs as $val){
+                //$dateArr[] = array($val['delivery_date'] => array("pending"=>$val['pending_approval_rc'],"approved"=>$val['approved_rc']));
+                $dateArr->{$val['delivery_date']} = new stdClass();
+                $dateArr->{$val['delivery_date']}->pending = $val['pending_approval_rc'];
+                $dateArr->{$val['delivery_date']}->approved = $val['approved_rc'];
+            }
+            $data =  array("msg" =>"success","data"=>$dateArr); 
+            common::echo_json_encode(200,$data); 
+        }
+
+    }
+
+    private function getCommunicationNew($serial_no) {
+        $list = common::excuteListSql("select to_char(add_time, 'MM/dd/yyyy hh24:MI:ss') as add_times, * from public.online_ocean_communication where email_uuid='$serial_no' and refer_id = 0  order by id");
+        $emialRecords =array();
+        foreach ($list as $k => $v) {
+            $msg =array();
+            $msg["name"] = $v["add_by"];
+            $msg["creatTime"] = $v["add_times"];
+            $msg["content"] =  urldecode($v["web_content"]);
+            $emialRecords[] = $msg;
+        }
+        return $emialRecords;
+    }
+
+    function search_shipment(){
+        $sqlWhere_common = ' where ' . common::searchExtendHand_KLN("ocean", $_SESSION["ONLINE_USER"]);
+        //根據用戶的賬號權限所能看到的全部shipment數據的目的地站點,去匹配是否有開通destination delivery的服務,如果未開通,則展示此提示頁面
+        //兜底规则
+        $sqlWhere = $sqlWhere_common;
+        //$sqlWhere .= " and  eta >= now() - INTERVAL '6 months' and eta <= now() + INTERVAL '6 months'";
+        // $checkOpenSql = "with oo as ( select DISTINCT agent from public.kln_ocean oo ". $sqlWhere.")
+        //         select agent from  oo 
+        //             where exists(select 1 from public.kln_destination_delivery_config where oo.agent in (select regexp_split_to_table(station, E','))) 
+        //         limit 1";
+        $checkOpenSql = "select station from public.kln_destination_delivery_config dc
+                            where exists(select 1 from  
+                                    public.kln_ocean oo ". $sqlWhere." 
+                                        and oo.agent in (select regexp_split_to_table(dc.station, E',')) limit 1
+                                )";
+        $config = common::excuteListSql($checkOpenSql);
+        if(empty($config)){
+            return array("msg"=>"Destination Delivery Service Not Available","data"=>"");
+        }
+        
+        //根據用戶的賬號權限所能看到的全部shipment數據的目的地站點,去匹配是否有開通destination delivery的服務,如果有開通,但沒有符合條件的shipment,則展示此提示頁面
+        $sqlWhere = $sqlWhere_common;
+        //$sqlWhere .= " and  eta >= now() - INTERVAL '6 months' and eta <= now() + INTERVAL '6 months'";
+
+        $text_search = $_REQUEST['text_search'];
+        if (!empty($text_search)){
+            $sqlWhere .= " and (oo.h_bol ilike '%".strtolower($text_search)."%'
+                or oo.po_no ilike '%".strtolower($text_search)."%'
+                or oo.ctnrs ilike '%".strtolower($text_search)."%')";
+        }
+
+        //vessel name
+        $vessel = $_REQUEST['vessel'];
+        if (!empty($vessel)){
+            $sqlWhere .= " and vessel ilike '%".strtolower($vessel)."'%";
+        }
+
+        $consignee = $_REQUEST['consignee'];
+        if (!empty($vessel)){
+            $sqlWhere .= " and consignee ilike '%".strtolower($consignee)."'%";
+        }
+
+        $shipper = $_REQUEST['shipper'];
+        if (!empty($vessel)){
+            $sqlWhere .= " and shipper ilike '%".strtolower($shipper)."'%";
+        }
+
+        if (isset($_REQUEST['eta_start']) && !empty($_REQUEST['eta_start']))
+            $sqlWhere .= " and eta >= '" . common::usDate2sqlDate($_REQUEST['eta_start']) . " 00:00:00'";
+        if (isset($_REQUEST['eta_end']) && !empty($_REQUEST['eta_end']))
+            $sqlWhere .= " and eta <= '" . common::usDate2sqlDate($_REQUEST['eta_end']) . " 23:59:59'";
+
+        if (isset($_REQUEST['ata_start']) && !empty($_REQUEST['ata_start']))
+            $sqlWhere .= " and ata >= '" . common::usDate2sqlDate($_REQUEST['ata_start']) . " 00:00:00'";
+        if (isset($_REQUEST['ata_end']) && !empty($_REQUEST['ata_end']))
+            $sqlWhere .= " and ata <= '" . common::usDate2sqlDate($_REQUEST['ata_end']) . " 23:59:59'";
+
+        $sql = "with oo as(
+                select * from public.kln_ocean oo ". $sqlWhere ."
+            ),
+            ooc as (
+                select oo.*,
+                    dc.serial_no as dc_serial_no,
+                    dc.country as dc_country,
+                    dc.kln_pic as dc_kln_pic
+                from public.kln_destination_delivery_config dc
+                    Inner Join oo
+                        on oo.agent in (select regexp_split_to_table(dc.station, ','))
+                    where  1=1 --and 
+                        --case when dc.booking_window = 'Restrictions_ETD_ATD' and COALESCE(dc.booking_window_date_start,'')<>'' and 	COALESCE(dc.booking_window_date_end,'')<>''
+                        --        then COALESCE(atd, etd) >= (NOW() - (dc.booking_window_date_start ||' days')::INTERVAL)::date and  COALESCE(atd, etd) <= (NOW() + (dc.booking_window_date_end ||' days')::INTERVAL)::date
+                        --    when dc.booking_window = 'Restrictions_ETA_ATA' and COALESCE(dc.booking_window_date_start,'')<>'' and 	COALESCE(dc.booking_window_date_end,'')<>''
+                        --        then COALESCE(ata, eta) >= (NOW() - (dc.booking_window_date_start ||' days')::INTERVAL)::date and  COALESCE(ata, eta) <= (NOW() + (dc.booking_window_date_end ||' days')::INTERVAL)::date
+                        --else 1=1 end 
+            ),
+            matched_data as (
+                select
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    oc.ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    (select reference_no from public.ocean o where o.serial_no = ooc.serial_no  limit 1) as reference_no,
+                    ooc.transport_mode,
+                    oc.qty::text as pakages, 
+                    oc.unit as package_type ,
+                    oc.grs_kgs::text as kgw,
+                    oc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    (select customer_name from public.ocean_extend ex where ex.serial_no = ooc.serial_no  limit 1) as controlling_customer,
+                    ooc.booking_no,
+                    (select manifest_type from public.ocean o where o.serial_no = ooc.serial_no  limit 1) as manifest_type,
+                    dc_serial_no,
+                    dc_country,
+                    dc_kln_pic,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc  
+                    LEFT JOIN public.oc_container oc ON oc.serial_no::text = ooc.serial_no::text  
+                where  ooc.order_from = 'public' and transport_mode = 'sea'
+                union all
+                select 
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    oc.ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    (select reference_no from sfs.ocean o where o.serial_no = ooc.serial_no  limit 1) as reference_no,
+                    ooc.transport_mode,
+                    oc.qty::text as pakages, 
+                    oc.unit as package_type ,
+                    oc.grs_kgs::text as kgw,
+                    oc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    (select customer_name from ocean_extend ex where ex.serial_no = ooc.serial_no  limit 1) as controlling_customer,
+                    ooc.booking_no,
+                    (select manifest_type from sfs.ocean o where o.serial_no = ooc.serial_no  limit 1) as manifest_type,
+                    dc_serial_no,
+                    dc_country,
+                    dc_kln_pic,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc  
+                    LEFT JOIN sfs.oc_container oc ON oc.serial_no::text = ooc.serial_no::text  
+                where  ooc.order_from = 'sfs' and transport_mode = 'sea'
+                union all
+                select 
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    '' as ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    '' as reference_no,
+                    ooc.transport_mode,
+                    ooc.qty as pakages, 
+                    ooc.qty_uom as package_type ,
+                    ooc.piece_count as kgw,
+                    ooc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    '' as controlling_customer,
+                    ooc.booking_no,
+                    '' as manifest_type,
+                    dc_serial_no,
+                    dc_country,
+                    dc_kln_pic,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc
+                where ooc.transport_mode = 'air'
+            )
+            select md.*,
+                CASE 
+                    WHEN  r.recommended_delivery_from IS NOT NULL AND r.recommended_delivery_to IS NOT NULL THEN
+                        to_char((COALESCE(ata, eta) - (r.recommended_delivery_from ||' days')::INTERVAL)::date, 'YYYY.MM.DD') 
+                        || '-' || 
+                        to_char((COALESCE(ata, eta) + (r.recommended_delivery_to ||' days')::INTERVAL)::date, 'YYYY.MM.DD') 
+                    WHEN  r.recommended_delivery_from IS NULL AND r.recommended_delivery_to IS NOT NULL THEN
+                        '-' || 
+                        to_char((COALESCE(ata, eta) + (r.recommended_delivery_to || ' days')::INTERVAL)::date, 'YYYY.MM.DD')
+                    WHEN r.recommended_delivery_from IS NOT NULL AND r.recommended_delivery_to IS NULL THEN   
+                        to_char((COALESCE(ata, eta) - (r.recommended_delivery_from || ' days')::INTERVAL)::date, 'YYYY.MM.DD')
+                        || '-' 
+                    ELSE '' END 
+                AS date_range,
+                r.recommended_delivery_from, 
+                r.recommended_delivery_to,
+                CASE 
+                    WHEN r.recommended_delivery_from IS NOT NULL THEN
+                        (COALESCE(ata, eta) - (r.recommended_delivery_from ||' days')::INTERVAL)::date
+                    ELSE null END
+                AS recommended_delivery_from_date,
+
+                CASE 
+                    WHEN r.recommended_delivery_to IS NOT NULL THEN
+                        (COALESCE(ata, eta) + (r.recommended_delivery_to ||' days')::INTERVAL)::date
+                    ELSE null END
+                AS recommended_delivery_to_date
+            from matched_data md
+            LEFT JOIN LATERAL (
+                SELECT 
+                    r.*
+                FROM public.kln_destination_delivery_rule r 
+                WHERE md.transport_mode = r.mode_type 
+                    and r.recommended_delivery_serial_no = md.dc_serial_no
+                    AND ((md.transport_mode = 'sea' AND (
+                            (r.ports ilike '%'|| md.mport_of_discharge_un ||'%' AND r.carrier ilike '%'|| md.carrier ||'%') 
+                            OR (r.ports ilike '%'|| md.mport_of_discharge_un ||'%' AND r.carrier = 'ALL')
+                            OR (r.ports = 'ALL' AND r.carrier ilike '%'|| md.carrier ||'%')
+                            OR (r.ports = 'ALL' AND r.carrier = 'ALL'))
+                        ) 
+                        OR (md.transport_mode = 'air' AND (
+                            r.ports ilike '%'|| md.mport_of_discharge_un ||'%'
+                            OR r.ports = 'ALL')
+                        )
+                    )
+                    ORDER BY priority asc
+                    LIMIT 1
+                ) r ON true
+            order by md.eta desc  limit 100";
+         
+        $rs = common::excuteListSql($sql);
+        error_log($sql);
+        if(empty($rs)){
+            return array("msg"=>"No Eligible Shipments for Booking","data"=>"");
+        }
+        return array("msg"=>"","data"=>$rs);    
+    }
+
+    /**
+     * 不依赖配置的规则查询,如果规则已经移除或者修改不在查询范围内,開通期間創建的booking數據正常保留和展示
+    */
+    function search_shipment_with_booking($serial_no,$h_serial_no,$ctnr){
+        $sqlWhere =  "where oo.serial_no = ANY('".$h_serial_no."'::TEXT[])";
+        $sql = "with ooc as(
+                select * from public.kln_ocean oo ". $sqlWhere ."
+            ),
+            matched_data as (
+                select
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    oc.ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    (select reference_no from public.ocean o where o.serial_no = ooc.serial_no  limit 1) as reference_no,
+                    ooc.transport_mode,
+                    oc.qty::text as pakages, 
+                    oc.unit as package_type ,
+                    oc.grs_kgs::text as kgw,
+                    oc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    (select customer_name from public.ocean_extend ex where ex.serial_no = ooc.serial_no  limit 1) as controlling_customer,
+                    ooc.booking_no,
+                    (select manifest_type from public.ocean o where o.serial_no = ooc.serial_no  limit 1) as manifest_type,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc  
+                    LEFT JOIN public.oc_container oc ON oc.serial_no::text = ooc.serial_no::text  
+                where  ooc.order_from = 'public' and transport_mode = 'sea' and oc.ctnr in (select regexp_split_to_table('".$ctnr."', ','))
+                union all
+                select 
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    oc.ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    (select reference_no from sfs.ocean o where o.serial_no = ooc.serial_no  limit 1) as reference_no,
+                    ooc.transport_mode,
+                    oc.qty::text as pakages, 
+                    oc.unit as package_type ,
+                    oc.grs_kgs::text as kgw,
+                    oc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    (select customer_name from ocean_extend ex where ex.serial_no = ooc.serial_no  limit 1) as controlling_customer,
+                    ooc.booking_no,
+                    (select manifest_type from sfs.ocean o where o.serial_no = ooc.serial_no  limit 1) as manifest_type,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc  
+                    LEFT JOIN sfs.oc_container oc ON oc.serial_no::text = ooc.serial_no::text  
+                where  ooc.order_from = 'sfs' and transport_mode = 'sea' and oc.ctnr in (select regexp_split_to_table('".$ctnr."', ','))
+                union all
+                select 
+                    ooc.serial_no,
+                    ooc.h_bol,
+                    ooc.m_bol,
+                    '' as ctnr,
+                    ooc.service,
+                    ooc.po_no,
+                    '' as reference_no,
+                    ooc.transport_mode,
+                    ooc.qty as pakages, 
+                    ooc.qty_uom as package_type ,
+                    ooc.piece_count as kgw,
+                    ooc.cbm as volume,
+                    ooc.vessel,
+                    ooc.voyage,
+                    ooc.carrier,
+                    ooc.fport_of_loading_un,
+                    ooc.mport_of_discharge_un,
+                    ooc.eta,
+                    ooc.ata,
+                    ooc.shipper,
+                    ooc.consignee_id,
+                    ooc.consignee,
+                    '' as controlling_customer,
+                    ooc.booking_no,
+                    '' as manifest_type,
+                    ooc.agent,
+                    ooc.order_from
+                from ooc
+                where ooc.transport_mode = 'air'
+            )
+            select md.*,
+                CASE 
+                    WHEN kd.recommended_delivery_window_date_from IS NOT NULL AND kd.recommended_delivery_window_date_to IS NOT NULL THEN
+                        to_char((recommended_delivery_window_date_from)::date, 'YYYY-MM-DD') 
+                        || ';' ||
+                        to_char((recommended_delivery_window_date_to)::date, 'YYYY-MM-DD')
+                    WHEN kd.recommended_delivery_window_date_from IS NULL AND kd.recommended_delivery_window_date_to IS NOT NULL THEN
+                        ';' || 
+                        to_char((recommended_delivery_window_date_to)::date, 'YYYY-MM-DD')
+                    WHEN kd.recommended_delivery_window_date_from IS NOT NULL AND kd.recommended_delivery_window_date_to IS NULL THEN
+                        to_char((recommended_delivery_window_date_from)::date, 'YYYY-MM-DD') 
+                        || ';'
+                    ELSE  '' 
+                END AS date_range,
+                kd.recommended_delivery_from, 
+                kd.recommended_delivery_to,
+                kd.recommended_delivery_window_date_from as recommended_delivery_from_date,
+                kd.recommended_delivery_window_date_to as recommended_delivery_to_date,
+                (select dc.country from public.kln_destination_delivery_config dc where md.agent in (select regexp_split_to_table(dc.station, ','))) as dc_country
+            from matched_data md  
+                LEFT join public.kln_destination_delivery kd on kd.serial_no  = '$serial_no'
+            order by md.eta desc";
+        //error_log($sql);    
+        $rs = common::excuteListSql($sql);
+        return array("msg"=>"","data"=>$rs); 
+    }
+
+    function groupShipments($booking_no, $manifest_type, $h_bol,$h_serial_no, $order_from,$m_bol, $ctnr,$kln_pic,$consignee,$consignee_id,
+        $recommended_delivery_window_date_from, $recommended_delivery_window_date_to,
+        $recommended_delivery_from,$recommended_delivery_to,$dc_country){
+        // Combine the data into an array of shipments
+        $shipments = [];
+        foreach ($h_bol as $index => $_h_bol) {
+            $shipments[] = [
+                'booking_no' =>$booking_no[$index],
+                'manifest_type' => $manifest_type[$index],
+                'h_bol' => $h_bol[$index],
+                'h_serial_no' => $h_serial_no[$index],
+                'order_from' => $order_from[$index],
+                'm_bol' => $m_bol[$index],
+                'ctnr' => $ctnr[$index],
+                'kln_pic' => $kln_pic[$index],
+                'consignee' => $consignee[$index],
+                'consignee_id' => $consignee_id[$index],
+                'dc_country' => $dc_country[$index],
+                'recommended_delivery_window_date_from' => $recommended_delivery_window_date_from[$index],
+                'recommended_delivery_window_date_to' => $recommended_delivery_window_date_to[$index],
+                'recommended_delivery_from' => $recommended_delivery_from[$index],
+                'recommended_delivery_to' => $recommended_delivery_to[$index]
+            ];
+        }
+
+        // 按 MBOL 分组
+        $groupedByMbol = [];
+        // 按 ShipmentID 分组
+        $groupedByShipmentId = [];
+
+        foreach ($shipments as $item) {
+            $m_bol = $item['m_bol'];
+            $h_serial_no = $item['h_serial_no'];
+            $h_bol = $item['h_bol'];
+            $order_from = $item['order_from'];
+            $ctnr = $item['ctnr'];
+            $dc_country = $item['dc_country'];
+            $consignee_id = $item['consignee_id'];
+
+            if($item['manifest_type'] == 'BCN'){
+                if (!isset($groupedByMbol[$m_bol])) {
+                    $item['h_bol'] = array();
+                    $item['h_bol_multiple_link'] = array();
+                    $item['h_serial_no'] = array();
+                    $item['ctnr'] = array();
+                    $item['dc_country'] = array();
+                    $item['consignee_id'] = array();
+                    $item['m_bol'] = array($item['m_bol']);
+                    $groupedByMbol[$m_bol] = $item;
+                }
+
+                if (!in_array($h_serial_no, $groupedByMbol[$m_bol]['h_serial_no'])) {
+                    $groupedByMbol[$m_bol]['h_bol'][] = $h_bol;
+                    $groupedByMbol[$m_bol]['h_bol_multiple_link'][] = array("key"=>$h_bol,"value" =>$h_serial_no,"order_from"=>$order_from);
+                    $groupedByMbol[$m_bol]['h_serial_no'][] = $h_serial_no;
+                    $groupedByMbol[$m_bol]['dc_country'][] = $dc_country;
+                    $groupedByMbol[$m_bol]['consignee_id'][] = $consignee_id;
+                }
+                if (!in_array($ctnr, $groupedByMbol[$m_bol]['ctnr'])) {
+                    $groupedByMbol[$m_bol]['ctnr'][] = $ctnr;
+                }
+            } else {
+                if (!isset($groupedByShipmentId[$h_serial_no])) {
+                    $item['m_bol'] = array();
+                    $item['ctnr'] = array();
+                    $item['dc_country'] = array($item['dc_country']);
+                    $item['consignee_id'] = array($item['consignee_id']);
+                    $item['h_serial_no'] = array($item['h_serial_no']);
+                    $item['h_bol'] = array($item['h_bol']);
+                    $item['h_bol_multiple_link'] = array(array("key"=>$h_bol,"value" =>$h_serial_no,"order_from"=>$order_from));
+                    $groupedByShipmentId[$h_serial_no] = $item;
+                }
+
+                if (!in_array($m_bol, $groupedByShipmentId[$h_serial_no]['m_bol'])) {
+                    $groupedByShipmentId[$h_serial_no]['m_bol'][] = $m_bol;
+                }
+
+                if (!in_array($ctnr, $groupedByShipmentId[$h_serial_no]['ctnr'])) {
+                    $groupedByShipmentId[$h_serial_no]['ctnr'][] = $ctnr;
+                }
+            }
+        }
+
+        $result = array();
+        foreach($groupedByMbol as $mb){
+            $result[] = $mb;
+        }
+        foreach($groupedByShipmentId as $hb){
+            $result[] = $hb;
+        }
+        return $result;
     }
 }
 

+ 1 - 1
service/login.class.php

@@ -1223,7 +1223,7 @@ class login {
                 $online_ocean_sql = "select serial_no,order_from from public.kln_ocean 
                     where ((ARRAY['$reference_number_lower'] && array_append(ARRAY[lower(booking_no::text), lower(h_bol::text), lower(m_bol), lower(carrier_booking), lower(quote_no), lower(tracking_no)]||string_to_array(lower(ctnrs),','), ''::text))
                         or lower(po_no) like '%$reference_number_lower%'
-                        or lower(invoice_no) like '%$reference_number_lower%')";
+                        or lower(invoice_no) like '%$reference_number_lower%') and coalesce(schem_not_display, false)=false";
                 $online_ocean_arr = common::excuteListSql($online_ocean_sql);        
                 if(empty($online_ocean_arr)){
                     $data = array("msg" =>"No matches");

+ 15 - 3
service/robot.class.php

@@ -922,9 +922,6 @@ class robot{
         error_log("Real_message:".common::getChatAimessage($response['message']));
 
         $brokenJson = common::getChatAimessage($response['message']);
-        // 用 \n 替换实际换行符
-        $brokenJson = str_replace("\n", "\\n", $brokenJson);
-
         $message = json_decode($brokenJson,true);
         if ($message === null) {
             // 获取最后一次 JSON 操作的错误码
@@ -932,6 +929,21 @@ class robot{
             // 获取错误描述(PHP 5.5+)
             $errorMsg = json_last_error_msg();
             error_log("AI Message JSON Decode Error : {$errorCode} - {$errorMsg}");
+
+            // 2:对reference,response,sql 用 \n 替换实际换行符后,再进行第二次解析json_decode
+            $fixedJson = common::secondaryReplacement(common::getChatAimessage($response['message']));
+            $message = json_decode($fixedJson,true);
+            if ($message === null) {
+                //3:进行最后一次解析处理
+                //当解析失败时,手工的字符串定位和截取方法 已经做trim处理
+                //$keysToExtract = ['can_query', 'sql', 'reference', 'response'];
+                $extractedValues = common::customizeParsing(common::getChatAimessage($response['message']));
+                $message = array();
+                $message["can_query"] = $extractedValues['can_query'];
+                $message["sql"] = $extractedValues['sql'];
+                $message["reference"] = $extractedValues['reference'];
+                $message["response"] = $extractedValues['response'];
+            }
         }
 
         if($message["can_query"] == "true" && !empty($message["sql"])){

+ 478 - 3
utils/common.class.php

@@ -146,11 +146,12 @@ class common {
                             && !(stripos($action, "feature_update") === 0)
                             && !(stripos($action, "ajax") === 0)
                             && !(stripos($action, "opreation_log") === 0)
-                            && !(stripos($action, "robot") === 0)   // robot 开头的都匹配上了
+                            && !(stripos($action, "robot") === 0)   // robot 开头的都匹配上了 
                             && !(stripos($action, "system_setting") === 0)
                             && !(stripos($action, "monitoring_setting") === 0)
-                            && !(stripos($action, "notifications_rules") === 0)) {
-                                
+                            && !(stripos($action, "notifications_rules") === 0)
+                            && !(stripos($action, "destination_delivery") === 0) // destination_delivery 开头的都匹配上了
+                        ) {
                             $data = array("msg"=>"Permission Denied");
                             common::echo_json_encode(500, $data);
                             exit();
@@ -3377,5 +3378,479 @@ class common {
         }
         return $refer_data;
     }
+
+    public static function destination_delivery_window_radio($radio){
+        if($radio == "No_Restrictions"){
+            return 1;
+        }
+        if($radio == "Restrictions_ETD_ATD"){
+            return 2;
+        }
+        if($radio == "Restrictions_ETA_ATA"){
+            return 3;
+        }
+    }
+
+    public static function destination_delivery_recommended($radio){
+        if($radio == "No_Recommended"){
+            return 1;
+        }
+        if($radio == "Delivery_ETA_ATA"){
+            return 2;
+        }
+    }
+
+    public static function checkOverlap($post_arr,$name) {
+        $errors = "";
+        $num = count($post_arr);
+        //$_POST['rule_type'];
+        for ($i = 0; $i < $num; $i++) {
+            for ($j = $i + 1; $j < $num; $j++) {
+                $set1 = $post_arr[$i] ?? [];
+                $set2 = $post_arr[$j] ?? [];
+                
+                $intersection = common::array_intersect_own($set1, $set2,$_POST['rule_type'][$i]);
+                $intersectionC = "";
+                //这个特殊。如果ports 存在一样的,那检查carrier 是否存在一样的。
+                if ($name == "Sea Rule") {
+                    $setC1 = explode(",",$_POST['carrier'][$i]) ?? [];
+                    $setC2 = explode(",",$_POST['carrier'][$j]) ?? [];
+                    
+                    $intersectionC = array_intersect($setC1, $setC2);
+                    if (!empty($intersection) && !empty($intersectionC)) {
+                        $errors = "$name " . ($i + 1) . " and $name " . ($j + 1) . " have overlapping";
+                        if (!empty($intersection)) {
+                            $errors .= " ports: " . implode(', ', $intersection);
+                        }
+                        if (!empty($intersectionC)) {
+                            $errors .= " carrier: " . implode(', ', $intersectionC);
+                        }
+                    }
+                    
+                } else {
+                    if (!empty($intersection)) {
+                        $errors = "$name " . ($i + 1) . " and $name " . ($j + 1) . " have overlapping ports: " . implode(', ', $intersection);
+                    }
+                }
+
+                
+            }
+        }
+        return $errors;
+    }
+
+    public static function array_intersect_own($set1, $set2,$rule_type){
+        $intersection = array_intersect($set1, $set2);
+        if ($rule_type <> '*Default Rule' && ($set1 == 'ALL' || $set2 == 'ALL')){
+            $intersection = "ALL";
+        }
+        return $intersection;
+    }
+
+    public static function sendDestinationDeliveryReminder($data,$shipmentsData,$status){
+        $html_tr = "";
+        foreach($shipmentsData['data'] as $shipment){
+            $html_tr .="<tr style=\"color: #ED6D00;\">
+                <td align=\"center\" style=\" width: 162px;padding: 10px;word-wrap: break-word; word-break: break-all; white-space: normal;\">".$shipment['h_bol']."</td>
+                <td align=\"center\" style=\" width: 162px;padding: 10px;word-wrap: break-word; word-break: break-all; white-space: normal;\">".$shipment['ctnr']."</td>
+                <td align=\"center\" style=\" width: 162px;padding: 10px;word-wrap: break-word; word-break: break-all; white-space: normal;\">".$shipment['package_type']."</td>
+                <td align=\"center\" style=\" width: 162px;padding: 10px;word-wrap: break-word; word-break: break-all; white-space: normal;\">".$shipment['kgw']."</td>
+            </tr>";
+        }
+        
+        $kln_pic_email = $data['kln_pic'];
+        //这票的创建者email
+        $customer_email = common::excuteOneSql("select email from public.ra_online_user where user_login = '".$data['create_by']."'");
+        if ($status == "Rejected" || $status == "Cancelled") {
+            $log = common::excuteObjectSql("select *,
+                    TO_CHAR(created_time, 'Mon-DD-YYYY') as _created_time
+                from public.kln_destination_delivery_operation_log 
+                    where serial_no = '".$data['serial_no']."' order by id desc limit 1");
+        }
+
+        $links = "";
+        if ($status == "Pending Approval" || $status == "Modify") {
+            $links = '<a href="https://online-beta.kln.com/" style="color: #ED6D00; font-size: 14px;">https://online-beta.kln.com/</a>';
+        }
+        if ($status == "Approve") {
+            $links = '<a href="https://online-beta.kln.com/" style="color: #ED6D00; font-size: 14px;">https://online-beta.kln.com/</a>';
+        }
+
+        //邮件模板填充字段准备
+        $tplData = array("customer_email"=>$customer_email,
+            "customer_name"=>$data['create_by'],
+            "delivery_mode"=>$data['delivery_mode'],
+            "delivery_date"=>$data['_delivery_date'],
+            "location_name"=>"",
+            "address_1"=>"",
+            "contact"=>"",
+            "kln_pic_email"=>$kln_pic_email,
+            "booking_no" =>$data['booking_no'],
+            "status" =>$status,
+            "action_time" =>$log['_created_time'],
+            "created_time" =>$data['_created_time'],
+            "update_time" =>$data['_update_time'],
+            "action_by" =>$log['create_by'],
+            "action_reason" =>"",
+            "action_comments" =>$log['notes'],
+            "link" =>$links,
+            "html_tr" =>$html_tr);
+    
+        $contents = common::excuteObjectSql("select subject, ra_content as content from ra_online_email_tpl where ra_type = 'Delivery_".$status."'");
+        //检查type长度
+        $report_type = "delivery_email";
+        $report_type = strlen($report_type) > 20 ?  substr($report_type, 0, 20) : $report_type;
+        $subject = common::check_input($contents['subject']);
+        $email_from = "US.KApex.Online@kerryapex.com";
+        $to_email = $customer_email;
+        $cc_email = $kln_pic_email;
+        
+        error_log($contents['content']);
+        
+        // 动态构建替换数组(格式:[key] => value)
+        $replacements = [];
+        foreach ($tplData as $key => $value) {
+            $replacements["{{$key}}"] = $value; 
+            $replacements["{{{$key}}}"] = $value; 
+        }
+        $content = strtr($contents['content'], $replacements);
+        $content = common::check_input($content);
+        error_log($content);
+
+        $sql = "INSERT INTO email_record(type, title, from_email, to_email, content, insert_date, cc_email, attachment_path)
+            VALUES ('" . $report_type . "', '" . $subject . "', '" . $email_from . "', '".$to_email . "', '" . $content . "', now(), '" . $cc_email . "', '');";
+        if(empty($contents) || empty($to_email)){
+            return "";
+        }    
+        return $sql;
+    }
+
+    public static function deliveryStatusConvert($status){
+        if ($status == 'Approve'){
+            return 'Approved';
+        }
+        if ($status == 'Reject'){
+            return 'Rejected';
+        }
+        if ($status == 'Cancel'){
+            return 'Cancelled';
+        }
+        return $status;
+    }
+
+    public static function customizeParsing ($rawString){
+        // 您提供的字符串
+        // $rawString = '{ "can_query": false, "query_type": "", "reason": "用户询问是否有其他联系邮箱,因为support@kln.com邮箱返回无法送达。这个问题无法通过数据表查询得到答案,因为表中不包含KLN公司的联系邮箱信息。", "sql": "", "reference": "", "response": "I understand that you\'re having trouble with the email address support@kln.com returning as undeliverable. For customer support inquiries, please use our official customer service email: customer.service@kln.com or alternatively, you can contact our global service desk at global.service@kln.com.
+        
+        // You can also reach us through our customer portal at https://www.kln.com/contact-us or call our customer service hotline at +852 2796 6666.
+        
+        // We apologize for any inconvenience and are happy to assist you with your logistics needs." }';
+
+        // 要提取的键
+        $keysToExtract = ['can_query', 'sql', 'reference', 'response'];
+
+        // 存储结果的数组
+        $extractedValues = [];
+
+        foreach ($keysToExtract as $key) {
+            $fullKey = '"' . $key . '"'; // 构建完整的键,如 "can_query"
+            $keyPos = strpos($rawString, $fullKey);
+            
+            if ($keyPos === false) {
+                $extractedValues[$key] = null; // 键未找到
+                continue;
+            }
+            
+            // 找到键后,定位冒号 :
+            $colonPos = strpos($rawString, ':', $keyPos + strlen($fullKey));
+            if ($colonPos === false) {
+                $extractedValues[$key] = null; // 冒号未找到
+                continue;
+            }
+            
+            // 跳过冒号和可能的空白,定位值的开始
+            $valueStart = $colonPos + 1;
+            while ($valueStart < strlen($rawString) && ctype_space($rawString[$valueStart])) {
+                $valueStart++;
+            }
+            
+            if ($valueStart >= strlen($rawString)) {
+                $extractedValues[$key] = null; // 值开始位置越界
+                continue;
+            }
+            
+            $value = '';
+            $char = $rawString[$valueStart];
+            
+            // 情况1: 值以双引号开头 (字符串)
+            if ($char === '"') {
+                // 从 valueStart+1 开始寻找结束的双引号,需要处理转义
+                $pos = $valueStart + 1;
+                $strValue = '';
+                $escaped = false;
+                
+                while ($pos < strlen($rawString)) {
+                    $currentChar = $rawString[$pos];
+                    if ($escaped) {
+                        // 处理转义字符,简单处理常见情况
+                        switch ($currentChar) {
+                            case 'n': $strValue .= "\n"; break;
+                            case 't': $strValue .= "\t"; break;
+                            case 'r': $strValue .= "\r"; break;
+                            case '"': $strValue .= '"'; break;
+                            case '\\': $strValue .= '\\'; break;
+                            default: $strValue .= $currentChar; break; // 其他转义,原样保留?
+                        }
+                        $escaped = false;
+                    } else {
+                        if ($currentChar === '\\') {
+                            $escaped = true;
+                        } elseif ($currentChar === '"') {
+                            // 找到了未转义的结束引号
+                            break;
+                        } else {
+                            $strValue .= $currentChar;
+                        }
+                    }
+                    $pos++;
+                }
+                
+                // 如果找到了结束引号,$strValue 就是解码后的字符串
+                // 如果没找到(pos >= strlen),说明字符串没闭合,这里按找到的处理
+                $value = trim($strValue);
+                
+            } 
+            // 情况2: 值不是以双引号开头 (false, true, null, "", 数字等)
+            else {
+                // 寻找值的结束位置:遇到逗号,、右花括号}、右括号] 或空白序列(如果后面是分隔符)
+                $pos = $valueStart;
+                $literalValue = '';
+                
+                while ($pos < strlen($rawString)) {
+                    $currentChar = $rawString[$pos];
+                    // 检查是否到了值的边界
+                    if ($currentChar === ',' || $currentChar === '}' || $currentChar === ']') {
+                        break; // 遇到分隔符,值结束
+                    }
+                    // 如果遇到空白,检查后面的字符是否是分隔符或空白,如果是,则值可能结束
+                    if (ctype_space($currentChar)) {
+                        // 查看下一个非空白字符
+                        $nextPos = $pos + 1;
+                        while ($nextPos < strlen($rawString) && ctype_space($rawString[$nextPos])) {
+                            $nextPos++;
+                        }
+                        if ($nextPos >= strlen($rawString) || $rawString[$nextPos] === ',' || $rawString[$nextPos] === '}' || $rawString[$nextPos] === ']') {
+                            break; // 后面是分隔符或结束,当前空白是值的结束
+                        }
+                        // 否则,空白是值的一部分?(通常字面量不含内部空白)
+                    }
+                    // 对于字面量,我们通常认为它不包含内部空白,所以遇到空白且后面不是分隔符时,可能也该停止?
+                    // 但为了简单,我们主要依赖 , } ] 分隔符。
+                    // 追加当前字符
+                    $literalValue .= $currentChar;
+                    $pos++;
+                }
+                
+                // $literalValue 现在包含从 valueStart 到分隔符前的所有字符
+                // 但可能包含尾部空白,trim 一下
+                $value = trim($literalValue);
+                
+                // 特别处理空字符串字面量 ""
+                // 如果原始字符串在 valueStart 位置是 ",但我们上面的 else 分支没进,所以不会到这里
+                // 如果原始是 "", 它会被上面的 else 分支捕获为字符串 '""',但我们希望它的值是空字符串 ''
+                // 所以需要检查 $value 是否等于 '""'
+                if ($value === '""') {
+                    $value = '';
+                }
+                // 注意:在您的例子中,"sql": "" 和 "reference": "" 在 JSON 中是空字符串,但在 else 分支会被识别为 '""'
+                // 我们在这里统一处理。
+            }
+            
+            $extractedValues[$key] = $value;
+        }
+        return $extractedValues;
+    }
+
+    public static function secondaryReplacement($brokenJson){
+        // 用 \n 替换实际换行符 '/"\w+"\s*:\s*"\K[^"]*(?=")/s'  这种如果你字段名不是简单的 \w+(比如有 -、中文等),可以用:
+        $fixedJson = preg_replace_callback(
+            '/"\s*:\s*"\K[^"]*(?=")/s',
+            function ($matches) {
+                $text =$matches[0];
+                return str_replace(["\r\n", "\n", "\r"], "\\n", $text); 
+                //return str_replace("\n", "\\n", $matches[0])
+                //return str_replace(["\r\n", "\n", "\r"], "\\n", $text);
+            },
+            $brokenJson
+        );
+        return $fixedJson;
+    }
+
+    /**
+     * 客户和 内部员工在不同status下。运行的操作限制
+     */
+    public static function checkedActionLegal($serial_no,$operate){
+        $is_employee = _isApexLogin();
+        $status = common::excuteOneSql("select status from public.kln_destination_delivery where serial_no = '$serial_no'");
+
+        $legal = false;
+        if ($status == 'Pending Approval'){
+            if ($is_employee){
+                //Pending Approval 状态下 内部  能审核,拒绝,和看详细
+                if ($operate == "review" && ($_POST['status'] == "Approve" || $_POST['status'] == "Reject")){
+                    $legal = true;
+                }
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }
+            } else {
+                //Pending Approval 状态下 客户的  能取消,看详细,和编辑
+                if ($operate == "review" && $_POST['status'] == "Cancel"){
+                    $legal = true;
+                }
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }   
+                if ($operate == "add"){
+                    $legal = true;
+                }
+            }
+        } else if ($status == 'Approve'){
+            if ($is_employee){
+                //Approve 下 内部的能看详细
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }
+            } else {
+                //Approve 下 客户的 能发邮件留言,能看详细
+                if ($operate == "email_message_board"){
+                    $legal = true;
+                }
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }
+            }
+        } else if ($status == 'Reject'){
+            if ($is_employee){
+                //Reject 下 员工 看详细
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }
+            } else {
+                //Reject 下 客户 能编辑 看详细
+                if ($operate == "add"){
+                    $legal = true;
+                }
+                if ($operate == "view_detail"){
+                    $legal = true;
+                }
+            }
+        } else if ($status == 'Cancel'){
+            //不分账户类型,只能看详细
+            if ($operate == "view_detail"){
+                $legal = true;
+            }
+        }
+
+        if(!$legal){
+            $data = array("msg" =>"Illegal access");
+            common::echo_json_encode(200,$data); 
+            exit();
+        }
+    }
+
+    public static function returnDAddressRecord($dc_country,$consignee_id){
+        //deliver address is new
+        $addressSql = "";
+        $address_1 = $_POST['address_1'];
+        foreach($address_1 as $key => $_address_1){
+            $_address_1 = common::check_input($_address_1); 
+            $_address_2 = common::check_input($_POST['address_2'][$key]);
+            $_address_3 = common::check_input($_POST['address_3'][$key]);
+            $_address_4 = common::check_input($_POST['address_4'][$key]); 
+            $_country = common::check_input($_POST['country'][$key]); 
+            $_city = common::check_input($_POST['city'][$key]); 
+            $_postal_code = common::check_input($_POST['postal_code'][$key]); 
+            $_contact_person = common::check_input($_POST['contact_person'][$key]); 
+            $_contact_number = common::check_input($_POST['contact_number'][$key]); 
+
+            $_contact_id = common::check_input($_POST['contact_id'][$key]);
+            $_sync_key = common::check_input($_POST['sync_key'][$key]);
+            $_from_station = common::check_input($_POST['from_station'][$key]);
+            $_contact_type = common::check_input($_POST['contact_type'][$key]);
+
+            //适应前端逻辑,如果遇到Unedit 代表该地址未变动,移除变动记录里
+            if ( $_contact_type == "Unedit"){
+                continue;
+            }
+
+            $uniqueAC =array();
+            foreach($dc_country as $ck => $_country){
+                //如果需要新加的时候 用户固定名称,用作标记
+                $_add_create_user = "Online_D_Address";
+
+                $_consignee_id = $consignee_id[$ck]; 
+                if(is_array($_consignee_id."_".$_country,$uniqueAC)){
+                    continue;
+                }
+
+                //不是新加的地址,只允许相同的contact_id 下的,不同国家的地址的同步
+                if(strtolower($_contact_type) <> "add" && $_consignee_id <> $_contact_id){
+                    continue;
+                }
+
+                if ($_contact_type == "Add"){
+                    $sync_key = common::uuid();
+                    $from_station = "Online_".strtoupper($_country);
+                    $addressSql .= "INSERT INTO public.contacts_address(
+                            contact_id, addr1, addr2,addr3, addr4, 
+                            ctry_code, city_code, postal_code,  
+                            create_user, create_date, modify_user, modify_date,
+                            is_sync_country, sync_key, from_station,contact_person,contact_number)
+                    VALUES ('$_consignee_id','$_address_1','$_address_2','$_address_3','$_address_4',
+                            '$_country','$_city','$_postal_code',
+                            '$_add_create_user',now(),'$_add_create_user',now(),
+                            true,'$sync_key','$from_station','$_contact_person','$_contact_number');";
+                }
+                if ($_contact_type == "Modify"){
+                    //代表在一个国家内的编辑
+                    $from_station_country = "";
+                    if (strpos($_from_station, "Online_") === 0) { // 确保字符串以 Online_ 开头
+                        $from_station_country = substr($_from_station, strlen("Online_"));
+                    }
+                    if($from_station_country == $_country){
+                        $addressSql .= "UPDATE public.contacts_address
+                            SET addr1='$_address_1', addr2='$_address_2', 
+                                ctry_code='$_country', city_code='$_city', postal_code='$_postal_code',  
+                                modify_user='"._getLoginName()."', modify_date=now(),
+                                contact_person='$_contact_person', contact_number='$_contact_number'  
+                            WHERE sync_key = '$_sync_key';";
+                    } else {
+                        $sync_key = common::uuid();
+                        $from_station = "Online_".strtoupper($_country);
+                        $addressSql .= "INSERT INTO public.contacts_address(
+                                contact_id, addr1, addr2,addr3, addr4, 
+                                ctry_code, city_code, postal_code,  
+                                create_user, create_date, modify_user, modify_date,
+                                is_sync_country, sync_key, from_station,contact_person,contact_number)
+                        VALUES ('$_consignee_id','$_address_1','$_address_2','$_address_3','$_address_4',
+                                '$_country','$_city','$_postal_code',
+                                '$_add_create_user',now(),'$_add_create_user',now(),
+                                true,'$sync_key','$from_station','$_contact_person','$_contact_number');";
+                    }
+                }
+                if ($_contact_type == "Delete"){
+                    $from_station_country = "";
+                    if (strpos($_from_station, "Online_") === 0) { // 确保字符串以 Online_ 开头
+                        $from_station_country = substr($_from_station, strlen("Online_"));
+                    }
+                    if($from_station_country == $_country){
+                        $addressSql .=  "DELETE FROM public.contacts_address WHERE sync_key = '$_sync_key';";
+                    }
+                }
+            }
+        }
+        return $addressSql;
+    }
 }
 ?>