<?php
/* @todo 处理ETP报文
 *
 */
class Service_ShipBatchEtpXmlProcess {

    private $_error                   = array();
    private $_sbCode;
    private $_xml;
    private $_shipBatchXml;
    private $_date;
    private $_scheme;
    private $_port;
    private $_host;
    private $_service;
    private $_content                 = array();
    private $_agentCode               = '';
    private $_agentName               = '';
    private $_apiKey;
    private $_post;

    public function __construct() {
        $this->_date = date('Y-m-d H:i:s');
    }

    protected function setSbCode( $sbCode ) {
        $this->_sbCode = $sbCode;
    }
    /* @todo:获取错误
     * @return boolean
     */
    public function getError() {
        return $this->_error;
    }
    /* @todo:添加错误
     * @return boolean
     */
    protected function addError( $error ) {
        $this->_error[] = $error;
    }

    /* @todo:添加ETP备案清单（注意ftp_message_sendlist的sb_code是ship_batch_xml的sub_sb_code）
     * @return boolean
     */
    public function addEtpXml( $sbCode ) {
        $this->setSbCode( $sbCode );
        $this->checkSbCode();
        if( !empty( $this->_error ) ) {
            return false;
        }
        if( false === $this->hasGsOrder() ) {
            if( empty( $this->_error ) ) {
                return true;
            } else {
                return false;
            }
        }
        $adapter = Common_Common::getAdapter();
        $adapter->beginTransaction();
        try{
            $this->addXml();
            $this->addXmlDetail();
            $this->addSendList();
            $this->addReferenceSendList();
            $adapter->commit();
        } catch( Exception $e ) {
            $adapter->rollBack();
            $this->addError( $e->getMessage() );
            return false;
        }
        return true;
    }

    /* @todo:添加ETP备案清单（注意ftp_message_sendlist的sb_code是ship_batch_xml的sub_sb_code）
     * @return boolean
     */
    public function addEtpXmlWithoutTransaction( $sbCode ) {
        $this->setSbCode( $sbCode );
        $this->checkSbCode();
        if( !empty( $this->_error ) ) {
            return false;
        }
        if( false === $this->hasGsOrder() ) {
            return false;
        }

        try{
            $this->addXml();
            $this->addXmlDetail();
            $this->addSendList();
            $this->addReferenceSendList();
        } catch( Exception $e ) {
            $this->addError( $e->getMessage() );
            return false;
        }
        return true;
    }

    /* @todo：检查sb_code
     * @return none;
     */
    protected function checkSbCode() {
        if( is_null( $this->_sbCode ) || $this->_sbCode === '' ) {
            $this->addError('出区单号不能为空');
            return;
        }
        $xml = Service_ShipBatchXml::getByField( $this->_sbCode, 'sub_sb_code');
        if( empty( $xml ) ) {
            $this->addError('ship_batch_xml不存在此单号的数据');
            return;
        }
        //$result = Service_ShipBatchEtpXml::getByCondition( array( 'sb_code' => $xml['sb_code'],'sub_sb_code' => $this->_sbCode ) );
        $result = Service_ShipBatchEtpXml::getByField( $this->_sbCode, 'sub_sb_code');
        if( !empty( $result ) ) {
            $this->addError('出区单已生成ETP备案清单，无需重复生成');
            return;
        }

        $xmlDetailTotal = Service_ShipBatchXmlDetail::getByCondition( array( 'sub_sb_code' => $this->_sbCode ), 'count(*)' );
        if( $xmlDetailTotal == 0 ) {
            $this->addError('ship_batch_xml_detail不存在此单号的数据');
            return;
        }
        $sendList = Service_FtpMessageSendlist::getByField( $this->_sbCode, 'refercence_no');
        if( empty( $sendList ) || $sendList['fml_status'] != 3 ) {
            $this->addError('海关审核不通过，或者Ftp_message_sendlist不存在此单号的数据');
            return;
        }
        $shipBatch = Service_ShipBatch::getByField( $xml['sb_code'], 'sb_code' );
        $xml['fml_send_time'] = $sendList['fml_send_time'];
        $xml['sb_ship_time'] = !empty( $shipBatch ) ? $shipBatch['sb_ship_time'] : '';
        $this->_shipBatchxml       = $xml;
    }
    //检查出区单是否有GS的订单
    protected function hasGsOrder() {
        $flag = false;
        $bags = Service_ShipBatchDetail::getByCondition( array( 'sb_code' => $this->_shipBatchxml['sb_code'] ) );
        if( empty( $bags ) ) {
            $this->addError('找不到装袋数据');
            return $flag;
        }

        $huanQiu = Service_CustomerProcess::$HuanQiu;
        foreach( $bags as $value) {
            $detail = Service_OutboundBagDetail::getByCondition( array( 'ob_no' => $value['ob_no'] ) );
            if( empty( $detail ) ) {
                $this->addError('找不到装袋数据');
                break;
            }
            foreach ( $detail as $v ) {
                $order = Service_Orders::getByField( $v['order_code'], 'order_code' );
                if( $huanQiu == Service_CustomerProcess::getOwner( $order['customer_code'] )) {
                    $flag = true;
                    break 2;
                }
                //含有分销平台的客户也传备案清单
                $customer = Service_Customer::getByField($order['customer_code'],'customer_code');
                if($customer['customer_platform']=='FX'){
                    $flag = true;
                    break 2;
                }
                /*if($order['platform']=='1'){
                    $flag = true;
                    break 2;
                }*/
            }
        }
        if( !$flag ) {
         $this->addError( '此出区单不含有环球或者sino的订单，不用生成ETP备案清单' );
        }
        return $flag;
    }
    /* @todo：添加ETP备案清单主表
     * @return none;
     */
    protected function addXml() {
        $add = array(
            'sb_code'                => $this->_shipBatchxml['sb_code'],
            'sub_sb_code'           => $this->_shipBatchxml['sub_sb_code'],
            'gross_wt'               => $this->_shipBatchxml['gross_wt'],
            'net_wt'                 => $this->_shipBatchxml['net_wt'],
            'pack_no'                => $this->_shipBatchxml['pack_no'],
            'sbex_add_time'         => $this->_date,
            'sbex_update_time'      => $this->_date,
            'total_price'            => $this->_shipBatchxml['total_price'],
            'refercence_form_id'    => $this->_shipBatchxml['refercence_form_id'],
            'status'                  => 1,
            'remark'                  => $this->_shipBatchxml['remark'],
            'customs_audit_status'  => $this->_shipBatchxml['fml_status'],
            'ship_time'               => $this->_shipBatchxml['sb_ship_time'],
            'send_time'               => $this->_shipBatchxml['fml_send_time'],
        );
        $id = Service_ShipBatchEtpXml::add( $add );
        if( !$id )
            throw new Exception('添加Ship_batch_etp_xml数据失败');

        $add['sbex_id'] = $id;
        $this->_xml      = $add;
    }
    /* @todo：添加ETP备案清单明细
     * @return none;
     */
    protected function addXmlDetail() {
        $page       = 1;
        $pageSize   = 100;
        //获取子表数据
        $condition = array( 'sub_sb_code' => $this->_xml['sub_sb_code'] );

        while ( $subDetailRows = Service_ShipBatchXmlDetail::getByCondition( $condition, '*',$pageSize, $page, 'sbxd_id') ) {
            $condition['sbxd_id_gt'] = $subDetailRows[ count( $subDetailRows ) - 1 ]['sbxd_id'];
            foreach( $subDetailRows as $detailRow) {

                $tmpRow = $detailRow;
                unset( $tmpRow['sbx_id'] );
                unset( $tmpRow['sbxd_id'] );
                $tmpRow['sbex_id'] = $this->_xml['sbex_id'];

                //通过goods_id查找客户
                if( !isset( $companyArray[ $detailRow['goods_id'] ] ) ) {

                    $product = Service_Product::getByField( $detailRow['goods_id'], 'goods_id' );
                    if( empty( $product ) )
                        throw new Exception('找不到goods_id: '.$detailRow['goods_id'].' 的产品信息');

                    $customer = Service_Customer::getByField( $product['customer_code'], 'customer_code' );
                    if( empty( $customer ) )
                        throw new Exception('找不到customer_code: '.$product['customer_code'].' 的客户信息');

                    $formType = '';
                    if( Service_CustomerProcess::$HuanQiu == Service_CustomerProcess::getOwner( $product['customer_code'] ) ) {
                        if( !$customer['form_type'] )
                            throw new Exception( $product['customer_code'].'是环球的客户，请先去【客户管理】设置业务类型');

                        $formType = $customer['form_type'];
                    } else {
                        if( $customer['form_type'] )
                            $formType = $customer['form_type'];
                        else
                            $formType = 'I211';//非环球客户先默认是分送集报
                    }
                    $companyArray[ $detailRow['goods_id'] ] = $customer['trade_name'];
                    $formTypeArray[ $detailRow['goods_id'] ] = $formType;
                }

                $tmpRow['list_mode']      = $formTypeArray[ $detailRow['goods_id'] ];
                $tmpRow['company_name']  = $companyArray[ $detailRow['goods_id'] ];

                $result = Service_ShipBatchEtpXmlDetail::add( $tmpRow );
                if( !$result )
                    throw new Exception('添加Ship_batch_etp_xml_detail数据失败');
            }
        }
    }
    /* @todo：添加ETP发送队列
     * @return none;
     */
    protected function addSendList() {
        //添加发送队列
        $add = array(
            'sbex_id'               => $this->_xml['sbex_id'],
            'sb_code'               => $this->_xml['sb_code'],
            'sub_sb_code'          => $this->_xml['sub_sb_code'],
            'sbexs_failed_count'  => 0,
            'sbexs_add_time'       => $this->_date,
        );
        $result = Service_ShipBatchEtpXmlSendlist::add( $add );
        if( !$result)
            throw new Exception('添加Ship_batch_etp_xml_sendlist数据失败');
    }

    /* @todo：添加ETP订单关系发送队列
     * @return none;
     */
    protected function addReferenceSendList() {
        //只插入一条数据就行了，这个表是一个出区单一条数据的，而ftp_message_sendlist是一个字出区单一条数据
        $total = Service_ShipBatchEtpXml::getByCondition(  array( 'sb_code' => $this->_xml['sb_code'] ), 'count(*)');
        if( $total == 1 ) {
            //添加发送队列
            $add = array(
                'sbex_id'               => $this->_xml['sbex_id'],
                'sb_code'               => $this->_xml['sb_code'],
                'sbers_failed_count'  => 0,
                'sbers_add_time'       => $this->_date,
            );
            $result = Service_ShipBatchEtpReferenceSendlist::add( $add );
            if( !$result)
                throw new Exception('添加Ship_batch_etp_reference_sendlist数据失败');
        }
    }

    protected function initService( $service ) {
        $etp = new Common_Etp();
        $this->_scheme = $etp->getScheme();
        $this->_host = $etp->getHost();
        $this->_port = $etp->getPort();
        $this->_service = $etp->getService( $service );
        $this->_apiKey = $etp->getApiKey();
    }

    /* @todo:调用ETPjava接口发送备案报文
     * @return array
     */
    public function sendXmlToEtp( $sbCode ) {
        $this->setXml( $sbCode );
        $this->initService('createRecord');

        if( !empty( $this->_error ) ) {
            $msg = implode( ',', $this->_error );
            $result = Service_ShipBatchEtpXmlSendlist::update( array(
                'remark'               => $msg,
                'last_send_time'      => $this->_date,
            ), $this->_xml['sub_sb_code'], 'sub_sb_code' );
            return false;
        }
        $flag = false;
        $this->setPost();
        $result = $this->doRequest();
        if( $result === false )
            return false;

        $adapter = Common_Common::getAdapter();
        $adapter->beginTransaction();
        try{
            //更新备案清单状态
            if( $result['state'] == 1 ) {
                $update = array(
                    'send_etp_time'      => $this->_date,
                    'sbex_update_time'  => $this->_date,
                    'status'              => 3,
                    'remark'              => '发送成功',
                );
                $r = Service_ShipBatchEtpXmlSendlist::delete( $this->_xml['sub_sb_code'], 'sub_sb_code');
                if( !$r )
                    throw new Exception('删除发送队列失败');

                $flag = true;
            } else {
                if( !empty( $result['error'] ) ) {
                    foreach( $result['error'] as $value ) {
                        $this->addError( 'code: '.$value['errorCode'].', msg: '.$value['errorMsg'] );
                    }
                } else {
                    $this->addError( $result['message'] );
                }
                $msg = implode( ',', $this->_error );

                $update = array(
                    'send_etp_time'      => $this->_date,
                    'sbex_update_time'  => $this->_date,
                    'status'              => 2,
                    'remark'              => $msg,
                );
                $r = Service_ShipBatchEtpXmlSendlist::update( array(
                    'sbexs_failed_count' => $this->_xml['sbexs_failed_count'] + 1,
                    'remark'               => $msg,
                    'last_send_time'      => $this->_date,
                ), $this->_xml['sub_sb_code'], 'sub_sb_code' );
                if( !$r )
                    throw new Exception('更新发送队列失败');

            }
            $r = Service_ShipBatchEtpXml::update( $update, $this->_xml['sbex_id'], 'sbex_id');
            if( !$r )
                throw new Exception('更新ship_batch_etp_xml状态失败');

            $adapter->commit();
        } catch( Exception $e ) {
            $adapter->rollBack();
            $this->addError( $e->getMessage() );
        }
        return $flag;
    }

    /* @todo:调用ETPjava接口发送出区单与订单关系
     * @return array
     */
    public function sendOrderReferenceToEtp( $sbCode ) {
        $this->setReference( $sbCode );
        $this->initService('sendOrderReference');

        if( !empty( $this->_error ) ) {
            $msg = implode( ',', $this->_error );
            $result = Service_ShipBatchEtpReferenceSendlist::update( array(
                'sbers_failed_count' => $this->_xml['sbers_failed_count'] + 1,
                'remark'               => $msg,
                'last_send_time'      => $this->_date,
            ), $this->_xml['sb_code'], 'sb_code' );
            return false;
        }
        $flag = false;
        $this->setPost();
        $result = $this->doRequest();
        if( $result === false )
            return false;

        $adapter = Common_Common::getAdapter();
        $adapter->beginTransaction();
        try{
            //更新备案清单状态
            if( $result['state'] == 1 ) {
                $result = Service_ShipBatchEtpReferenceSendlist::delete( $this->_xml['sb_code'], 'sb_code');
                if( !$result )
                    throw new Exception('删除发送队列失败');

                $flag = true;
            } else {
                if( !empty( $result['error'] ) ) {
                    foreach( $result['error'] as $value ) {
                        $this->addError( 'code: '.$value['errorCode'].', msg: '.$value['errorMsg'] );
                    }
                } else {
                    $this->addError( $result['message'] );
                }
                $msg = implode( ',', $this->_error );

                $result = Service_ShipBatchEtpReferenceSendlist::update( array(
                    'sbers_failed_count' => $this->_xml['sbers_failed_count'] + 1,
                    'remark'               => $msg,
                    'last_send_time'      => $this->_date,
                ), $this->_xml['sb_code'], 'sb_code' );
                if( !$result )
                    throw new Exception('更新发送队列失败');

            }

            $adapter->commit();
        } catch( Exception $e ) {
            $adapter->rollBack();
            $this->addError( $e->getMessage() );
        }
        return $flag;
    }

    protected function setXml( $sbCode ) {
        $sbCode = trim( $sbCode );
        if( $sbCode === '' )
            $this->addError('出区单号不能为空');

        $xml = Service_ShipBatchEtpXml::getByField( $sbCode, 'sub_sb_code' );
        if( empty( $xml ) ) {
            $this->addError('ship_batch_etp_xml没有sub_sb_code='.$sbCode.' 的数据');
            return;
        }
        if( $xml['status'] == 3 ) {
            $this->addError('备案清单sub_sb_code='.$sbCode.' 的数据已经发送成功了，无须重复发送');
            return;
        }
        $sendList = Service_ShipBatchEtpXmlSendlist::getByField( $sbCode, 'sub_sb_code' );
        if( empty( $sendList ) ) {
            $this->addError('ship_batch_etp_xml_sendlist找不到sub_sb_code='.$xml['sb_code'].' 的数据');
            return;
        }
        $xmlAttr = Service_ShipBatchAttribute::getByField( $xml['sb_code'], 'sb_code' );
        if( empty( $xmlAttr ) ) {
            $this->addError('ship_batch_attribute找不到sb_code='.$xml['sb_code'].' 的数据');
            return;
        }
        $xmlDetail = Service_ShipBatchEtpXmlDetail::getByCondition( array( 'sub_sb_code' => $sbCode ) );
        if( empty( $xmlDetail ) ) {
            $this->addError('ship_batch_etp_xml_detail没有sub_sb_code='.$sbCode.' 的数据');
            return;
        }
        $xml['sbexs_failed_count'] = $sendList['sbexs_failed_count'];

        $this->_xml = $xml;
        $this->_content = array(
            'formListId'             => $xml['refercence_form_id'],
            'boundryPort'            => $xmlAttr['ie_port'],
            'bussinessType'          => $xmlAttr['form_type'],
            'outboundDate'           => $xml['ship_time'],
            'declareDate'            => $xml['send_time'],
            'declareCompCode'       => $this->_agentCode,
            'declareCompName'       => $this->_agentName,
            'transportationMode'    => $xmlAttr['traf_mode'],
            'conveyance'             => $xmlAttr['traf_name'],
            'transactionMode'       => $xmlAttr['trans_mode'],
            'supervisionMode'       => $xmlAttr['trade_mode'],
            'grossWeight'            => $xml['gross_wt'],
            'netWeight'              => $xml['net_wt'],
            'consignee'              => $xmlAttr['consignee'],
            'soCode'                  => $xml['sub_sb_code'],
            'recordDetailList'      => array(),
        );
        foreach( $xmlDetail as $value ) {
            $this->_content['recordDetailList'][] = array(
                'formListId'                => $xml['refercence_form_id'],
                'compName'                  => $value['company_name'],
                'listMode'                  => $value['list_mode'],
                'no'                         => $value['g_no'],
                'mergerNo'                  => $value['merger_g_no'],
                'mergerMode'                => $value['merger_mode'],
                'goodsCode'                 => $value['goods_id'],
                'hsCode'                     => $value['code_ts'],
                'hsNameCn'                   => $value['g_name_cn'],
                'hsNameEn'                   => $value['g_name_en'],
                'declarationElements'      => $value['g_model'],
                'declarationPrice'          => $value['decl_price'],
                'declarationCurrency'       => $value['curr'],
                'declarationTotal'           => $value['decl_total'],
                'qty'                          => $value['g_qty'],
                'unit'                         => $value['g_unit'],
                'policyQty1'                  => $value['qty_1'],
                'policyUnit1'                 => $value['unit_1'],
                'policyQty2'                  => $value['qty_2'],
                'policyUnit2'                 => $value['unit_2'],
                'originCountry'               => $value['origin_country'],
            );
        }
    }

    protected function setReference( $sbCode ) {
        $sbCode = trim( $sbCode );
        if( $sbCode === '' )
            $this->addError('出区单号不能为空');

        $sendList = Service_ShipBatchEtpReferenceSendlist::getByField( $sbCode, 'sb_code' );
        if( empty( $sendList ) ) {
            $this->addError('ship_batch_etp_reference_sendlist找不到sb_code='.$sbCode.' 的数据');
            return;
        }

        $this->_xml = $sendList;

        $this->_content = array( 'soCode' => $sbCode,'formListId'=>array(),'orderList'=>array());

        $formListId = Service_ShipBatchEtpXml::getByCondition( array( 'sb_code' => $sbCode ) );
        if( empty( $formListId ) ) {
            $this->addError('ship_batch_etp_xml找不到sb_code='.$sbCode.' 的数据');
            return;
        }
        foreach( $formListId as $value ) {
            $this->_content['formListId'][] = $value['refercence_form_id'];
        }

        $shipBatchDetail = Service_ShipBatchDetail::getByCondition( array( 'sb_code' => $sbCode ) );
        if( empty( $shipBatchDetail ) ) {
            $this->addError('ship_batch_detail找不到sb_code='.$sbCode.' 的数据');
            return;
        }

        $sellers = array();
        foreach( $shipBatchDetail as $value ) {
            $bag = Service_OutboundBagDetail::getByCondition( array( 'ob_no' => $value['ob_no'] ) );
            if( empty( $bag ) ) {
                $this->addError('outbound_bag_detail找不到ob_no='.$value['ob_no'].' 的数据');
                return;
            }
            foreach( $bag as $v ) {
                $order = Service_Orders::getByField( $v['order_code'], 'order_code' );
                if( empty( $order ) ) {
                    $this->addError('orders找不到order_code='.$v['order_code'].' 的数据');
                    return;
                }
                if( !isset( $sellers[ $order['customer_code'] ] ) ) {
                    $seller = Service_Customer::getByField( $order['customer_code'], 'customer_code');
                    if( empty( $seller ) ) {
                        $this->addError('customer找不到customer_code='.$order['customer_code'].' 的数据');
                        return;
                    }
                    $sellers[ $order['customer_code'] ] = $seller['trade_name'];
                }
                $this->_content['orderList'][] = array(
                    'referenceNo' => $order['reference_no'],
                    'plateCode' => 'globalsource'//$sellers[ $order['customer_code'] ],
                );
            }
        }
    }

    protected function setPost() {
        $content = json_encode( $this->_content );
        $postArr = array(
            'appKey'=>$this->_apiKey,
            'timestamp'=>time(),
            'version'=>'1.0',
            'content'=>$content
        );
        $this->_post = $postArr;
    }

    public function doRequest(){
        $httpClient = new Common_HttpClient( $this->_scheme.'://'.$this->_host,$this->_port );
        $httpClient->setDebug(true);
        $isSuccessful = $httpClient->post( $this->_service, $this->_post );
        if( !$isSuccessful ) {
            $this->addError( $httpClient->getError() );
            return false;
        }

        $content = $httpClient->getContent();
        $result = $this->getResult( $content );
        return $result;
    }

    /**
     * @将数据处理成统一的格式
     *  $mark =1记录到api访问请求的日志中.否则不记录
     */
    private function getResult( $data ){
        $result = array(
            'state'=>'0',
            'message'=>'',
            'error'=>array(
            )
        );
        $info = json_decode($data,true);
        if(!empty($info) && is_array($info)){
            if($info['ack']=='Success'){
                $result['state']='1';
                $result['message'] = $info['ack'];
            }elseif($info['ack']=='Failure'){
                $error = array(
                    'errorCode'=>$info['errorCode'],
                    'errorMsg'=>$info['errorMsg'].( isset( $info['reference'] ) ? $info['reference'] : '')
                );
                $result['error'][]=$error;
            }else{
                $result['message'] = "未知接口返回标示:".$info['ack'];
            }
        }else{
            $result['message'] = '接口返回数据['.var_export($data,true).']无法解析.';
        }
        return $result;
    }
}