package com.yihu.jw.hospital.prescription.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yihu.jw.entity.base.org.BaseOrgDO;
import com.yihu.jw.entity.base.patient.BasePatientDO;
import com.yihu.jw.entity.hospital.prescription.*;
import com.yihu.jw.hospital.prescription.dao.*;
import com.yihu.jw.hospital.prescription.service.entrance.util.SFUtils;
import com.yihu.jw.org.dao.BaseOrgDao;
import com.yihu.jw.patient.dao.BasePatientDao;
import com.yihu.jw.util.date.DateUtil;
import com.yihu.jw.utils.sfutils.HttpClientUtils;
import com.yihu.jw.utils.sfutils.SHAUtils;
import com.yihu.mysql.query.BaseJpaService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.*;

/**
 *  门诊物流服务
 * lith 2019.06.04
 */
@Service
public class PrescriptionExpressageService extends BaseJpaService<WlyyPrescriptionExpressageDO, PrescriptionExpressageDao> {
    private static Logger logger = LoggerFactory.getLogger(PrescriptionExpressageService.class);


    //顺丰快递接口请求地址

    @Value("${express.sf_url}")
    private String sf_url;
    
    //顺丰快递接口接入编码

    @Value("${express.sf_code}")
    private String sf_code;

    //顺丰快递接口checkword

    @Value("${express.sf_check_word}")
    private String sf_check_word;

    @Autowired
    private SFUtils SFUtils;

    @Autowired
    private JpaTransactionManager transactionManager;

    //处方日志
    @Autowired
    private WlyyOutpatientExpressageLogDao outpatientExpressageLogDao;

    @Autowired
    private PrescriptionDao prescriptionDao;

    @Autowired
    private WlyyExpressagePriceDao expressagePriceDao;

    @Autowired
    private PrescriptionExpressageLogDao prescriptionExpressageLogDao;

    @Autowired
    private PrescriptionExpressageDao prescriptionExpressageDao;

    @Autowired
    private BaseOrgDao baseOrgDao;

    @Autowired
    private OutpatientDao outpatientDao;
    
    @Autowired
    private BasePatientDao basePatientDao;

    @Autowired
    private PrescriptionLogDao prescriptionLogDao;
    @Autowired
    PrescriptionService prescriptionService;

    @Autowired
    private SfConfigDao sfConfigDao;

    private PrescriptionExpressageService(){}

    public PrescriptionExpressageService(String sf_url,String sf_code,String sf_check_word){
        this.sf_url = sf_url;
        this.sf_code = sf_code;
        this.sf_check_word = sf_check_word;
    }


    /**
     * 组装请求参数，发送请求
     * @param xml
     * @return
     * @throws Exception
     */
    private String SFExpressPost(String xml)throws Exception{
        String verifyCode = SFUtils.verifyCodeSFXmlStr(xml,sf_check_word);
//        List<NameValuePair> params = new ArrayList<>();
//        params.add(new BasicNameValuePair("xml", xml));
//        params.add(new BasicNameValuePair("verifyCode", verifyCode));
    
//        JSONObject j =  addOrder();
//        j.put("xml",xml);
//        j.put("verifyCode",verifyCode);
        
//        String re = HttpClientUtils.doPost(sf_url, j.toJSONString(), ContentType.APPLICATION_JSON);
        return null;
    }

    /**
     * 校验返回的xml报文
     * @param responseXml
     * @param title
     */
    private void verificationResponXml(String responseXml,String title) throws Exception {
        String error = "";
        if (StringUtils.isBlank(responseXml)) {
            // 如果返回的XML报文为空，请求也算失败
            //保存http日志
            error = title + "，返回的XML为空！";
            logger.info(error);
            throw new Exception(error);
        }else{
//          报错的报文示例<Response service="ScopeService"><Head>ERR</Head><ERROR code="8014">校验码错误 </ERROR></Response>
            Document doc = DocumentHelper.parseText(responseXml);
            String headvalue = doc.selectSingleNode("/Response/Head").getText();
            if(StringUtils.isNotBlank(headvalue) && "ERR".equals(headvalue)){
                //错误代码
                String errorCode = "";
                //错误代对应的文字
                String errorMessage = doc.selectSingleNode("/Response/ERROR").getText();
                Document error_doc = doc.selectSingleNode("/Response/ERROR").getDocument();
                Element root = error_doc.getRootElement();
                List<?> child = root.elements();
                for (Object o : child){
                    Element e = (Element) o;
                    errorCode = e.attributeValue("code");
                }
                error = title+","+errorCode+","+errorMessage;
                logger.info(error);
                throw new Exception(error);
            }
        }
    }


    /**
     * 查询派送地址是否属于顺丰的派送范围
     * @param d_address 派送地址
     * @return
     */
    public Boolean getSFOrderFilterService(String d_address) throws Exception {

        boolean result = false;

        String xml = SFUtils.getSFOrderFilterXml(d_address,sf_code,"","","","");

        String re = this.SFExpressPost(xml);

//        String re = "<Response service=\"OrderFilterService\"><Head>OK</Head><Body><OrderFilterResponse orderid=\"TE201407020016\" filter_result=\"2\" origincode=\"755\" remark=\"2\"/></Body></Response>";

        //xml验证
        verificationResponXml(re,"查询派送地址是否有效失败！");


        Document doc = DocumentHelper.parseText(re);
        String headvalue = doc.selectSingleNode("/Response/Head").getText();
        Element root = doc.getRootElement();
        if(StringUtils.isNotBlank(headvalue) && "OK".equals(headvalue)) {
            //是否能派送：1：人工确认；2：可收派；3：不可以收派
            String filter_result = "";

            Element firstWorldElement = root.element("Body");

            List<Element> elements = firstWorldElement.elements();

            for (Element o : elements){
                filter_result = o.attributeValue("filter_result");
            }

            if(StringUtils.isNotBlank(filter_result) && "2".equals(filter_result)){
                result = true;
            }
        }
        return result;


    }

    /**
     * 向顺丰快递下订单
     * @param sfexpress_obj
     * @return
     * @throws Exception
     */
    public WlyyPrescriptionExpressageDO postSFOrderService(WlyyPrescriptionExpressageDO sfexpress_obj) throws Exception {

        //获取医生所处的医院详细地址,作为寄件人地址
        WlyyOutpatientDO outpatientDO = outpatientDao.findOne(sfexpress_obj.getOutpatientId());
        BaseOrgDO hospital = baseOrgDao.findByCode(outpatientDO.getHospital());
        BasePatientDO basePatientDO = basePatientDao.findById(outpatientDO.getPatient());

        JSONObject params = SFUtils.postSFOrderServiceV2(sfexpress_obj,hospital,basePatientDO);
        String re = this.SFExpressPostV2(params);
        //xml验证
        logger.info("顺丰快递下订单：re"+re);
        verificationResponV2(re);

        JSONObject respone = JSONObject.parseObject(re);
//        String re = "{\"success\":true,\"message\":null,\"code\":\"SUCCESS\",\"result\":{\"successResult\":[{\"mailNo\":\"SF1023527844982\",\"bspOrderNo\":\"2c9081aa724b941501724eb3d0e40036\"}]}}";
//        JSONObject respone = JSONObject.parseObject(re);

        String mailno = "";//顺丰运单号
        String bspOrderNo = "";//顺丰业务号
        
        JSONArray successResult =  respone.getJSONObject("result").getJSONArray("successResult");
        
        if(!successResult.isEmpty()){
            JSONObject object = successResult.getJSONObject(0);
            mailno = object.getString("mailNo");
            bspOrderNo = object.getString("bspOrderNo");
        }
    
        logger.info("顺丰快递下订单：mailno"+mailno);
    
        
//        mailno = respone.getJSONObject("result").getJSONArray("successResult").getJSONObject(0).getString("mailNo");
        
        sfexpress_obj.setMailno(mailno);
        sfexpress_obj.setBspOrderNo(bspOrderNo);
        return sfexpress_obj;
    }


    /**
     * 顺丰面单查询
     * @param sfexpress_obj
     * @return
     * @throws Exception
     */
    public JSONObject postSFOrderQueryService(WlyyPrescriptionExpressageDO sfexpress_obj) throws Exception {

        //获取医生所处的医院详细地址,作为寄件人地址
        WlyyOutpatientDO outpatientDO = outpatientDao.findOne(sfexpress_obj.getOutpatientId());

        String orderNo=sfexpress_obj.getBspOrderNo();
        String re = this.SFExpressQueryPostV2(orderNo);
        //xml验证
        logger.info("顺丰快递面单查询：re"+re);
        verificationResponV2(re);

        JSONObject respone = JSONObject.parseObject(re);
        String mailno = "";//顺丰运单号

        JSONArray successResult =  respone.getJSONArray("result");
        JSONObject object = new JSONObject();
        if(!successResult.isEmpty()){
             object = successResult.getJSONObject(0);
        }
        return object;
    }

    /**
     * 向顺丰快递取消订单
     * @param sfexpress_obj
     * @return
     * @throws Exception
     */
    public String postOrderConfirmService(WlyyPrescriptionExpressageDO sfexpress_obj) throws Exception {

        //获取医生所处的医院详细地址,作为寄件人地址
        WlyyOutpatientDO outpatientDO = outpatientDao.findOne(sfexpress_obj.getOutpatientId());
        BaseOrgDO hospital = baseOrgDao.findByCode(outpatientDO.getHospital());

        String xml = SFUtils.SFOrderConfirmXml(sf_code,sfexpress_obj.getId(),sfexpress_obj.getMailno(),2);
        logger.info("顺丰快递取消订单请求：xml"+xml);
        String re = this.SFExpressPost(xml);
//        String re = "<Response service=\"OrderService\"><Head>OK</Head><Body><OrderResponse filter_result=\"2\" destcode=\"592\" mailno=\"444844978335\" origincode=\"592\" orderid=\"6daa6baec5fd4b65a1b023a8b60e2e91\"/></Body></Response>";

        //xml验证
        logger.info("顺丰快递取消订单结果：re"+re);
        verificationResponXml(re,"顺丰快递取消订单失败！");

        Document doc = DocumentHelper.parseText(re);
        String headvalue = doc.selectSingleNode("/Response/Head").getText();
        if(StringUtils.isNotBlank(headvalue) && "OK".equals(headvalue)) {
            Element root = doc.getRootElement();
            if (root.element("Body") != null)     //包含OrderResponse节点
            {
                root = root.element("Body");
            }
            String res_status = "";
            List<?> child = root.elements();
            for (Object o : child) {
                Element e = (Element) o;
                // 1：客户订单号与顺丰运单不匹配 2 ：操作成功
                res_status = e.attributeValue("res_status");
            }
            if(StringUtils.isNotBlank(res_status) && !"2".equals(res_status)){
                logger.info("顺丰快递取消订单失败：门诊编号："+sfexpress_obj.getOutpatientId());
                throw new Exception("顺丰快递取消订单失败：客户订单号与顺丰运单不匹配");
            }
        }
        return "取消成功";
    }

    /**
     * 调用顺丰接口获取物流路由日志，与本地匹配，进行增量修改,并返回完整日志列表
     * @param prescription
     * @param sfexpress_obj
     * @param sfexpresslogList
     * @return
     */
    public List<WlyyPrescriptionExpressageLogDO> getRoutInfos(WlyyPrescriptionDO prescription, WlyyPrescriptionExpressageDO sfexpress_obj, List<WlyyPrescriptionExpressageLogDO> sfexpresslogList) throws Exception {
        String xml = SFUtils.getRoutInfos(sfexpress_obj,sf_code);
        String re = this.SFExpressPost(xml);
        //xml验证
        verificationResponXml(re,"查询顺丰快递路由信息失败！");
        Document doc = DocumentHelper.parseText(re);
        String headvalue = doc.selectSingleNode("/Response/Head").getText();
        if(StringUtils.isNotBlank(headvalue) && "OK".equals(headvalue)) {
            Element root = doc.getRootElement();
            if (root.element("Body") != null)     //取报文根节点
            {
                root = root.element("Body");
            }
            List<?> child = root.elements();
            String mailno = "";
            Map<String,List<WlyyPrescriptionExpressageLogDO>> wayroutlsit = new HashMap<>();
            for (Object o : child) {
                Element e = (Element) o;
                mailno = e.attributeValue("mailno");
                //判断快递单号不为空，且和我们本地的一致
                if(StringUtils.isNotBlank(mailno) &&
                        sfexpress_obj.getMailno().equals(mailno)){

                    //解析报文，结合本地数据返回最终的日志结果
                    return this.xmltologlist(e,sfexpresslogList,sfexpress_obj);
                }else{
                    continue;
                }
            }
        }
        return null;
    }

    private List<WlyyPrescriptionExpressageLogDO> xmltologlist(Element e, List<WlyyPrescriptionExpressageLogDO> sfexpresslogList, WlyyPrescriptionExpressageDO sfexpress_obj)throws Exception{

        //获取本地所有路由信息的时间集
        Set<String> routAcceptTimeSet = new HashSet<>();
        for (WlyyPrescriptionExpressageLogDO log: sfexpresslogList) {
            routAcceptTimeSet.add(DateUtil.dateToStrLong(log.getAcceptTime()));
        }

        List<?> child = e.elements();

        List<WlyyPrescriptionExpressageLogDO> newroutinfolist = new ArrayList<>();

        //用于判断新节点是否包含了"已收件"的节点
        boolean isContainEndRoutInfo = false;

        for (Object o : child) {
            Element routinfoe = (Element) o;
            String accept_time = routinfoe.attributeValue("accept_time");
            String accept_address = routinfoe.attributeValue("accept_address");
            String accept_remark = routinfoe.attributeValue("remark");
            String opcode = routinfoe.attributeValue("opcode");

            //和时间集作比对，过滤已存在的
            if(!routAcceptTimeSet.contains(accept_time)){
                WlyyPrescriptionExpressageLogDO newlogobj = new WlyyPrescriptionExpressageLogDO();
                newlogobj.setAcceptTime(DateUtil.strToDate(accept_time));
                newlogobj.setAcceptAddress(accept_address);
                newlogobj.setAcceptRemark(accept_remark);
                newlogobj.setOpCode(opcode);
                newlogobj.setId(UUID.randomUUID().toString().replace("-",""));
                newlogobj.setOutpatientId(sfexpress_obj.getOutpatientId());
                newlogobj.setExpressageId(sfexpress_obj.getId());
                newlogobj.setCreateTime(new Date());
                newroutinfolist.add(newlogobj);
                sfexpresslogList.add(newlogobj);
                //aopcode=80，为已签收
                if("80".equals(opcode)){
                    isContainEndRoutInfo = true;
                }
            }
        }


        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别，开启新事务
        TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
        try {

            //如果有新增的路由信息，则添加到数据库
            if(!newroutinfolist.isEmpty()){
                prescriptionExpressageLogDao.save(newroutinfolist);
            }

            //如果路由信息节点包含了"已收件"节点，这修改处方派送状态为完成，增加物流派送日志为完成
            if(isContainEndRoutInfo){
                //修改处方状态为完成
                prescriptionDao.updateStatus( 100,new Date(),sfexpress_obj.getId());

                //保存门诊处方配送成功的日志
                WlyyOutpatientExpressageLogDO outpatiExpressLog = new WlyyOutpatientExpressageLogDO();
                outpatiExpressLog.setOutpatientId(sfexpress_obj.getOutpatientId());
                outpatiExpressLog.setId(UUID.randomUUID().toString());
                outpatiExpressLog.setType(8);
                outpatiExpressLog.setCreateTime(new Date());
                outpatiExpressLog.setFlag(1);
                outpatiExpressLog.setStatus(100);
                outpatientExpressageLogDao.save(outpatiExpressLog);
            }

            //事务提交
            transactionManager.commit(status);
        } catch (Exception ex) {
            //报错事务回滚
            transactionManager.rollback(status);
        }


        return sfexpresslogList;
    }

    /**
     * 解析顺丰推送过来的路由信息，和本地数据匹配并进行增量更新）
     * @param xml
     * @return
     * @throws Exception
     */
    public void SFRoutePushService(String xml) throws Exception{
        Document doc = DocumentHelper.parseText(xml);
        Element root = doc.getRootElement();
        if (root.element("Body") != null)     //包含WaybillRoute节点
        {
            root = root.element("Body");
        }
        List<?> child = root.elements();

        Map<String,List<WlyyPrescriptionExpressageLogDO>> wayroutlsit = new HashMap<>();
        for (Object o : child) {
            Element routinfoe = (Element) o;
            WlyyPrescriptionExpressageLogDO sflog = new WlyyPrescriptionExpressageLogDO();
            String accept_time = routinfoe.attributeValue("acceptTime");
            String accept_address = routinfoe.attributeValue("acceptAddress");
            String accept_remark = routinfoe.attributeValue("remark");
            String opcode = routinfoe.attributeValue("opCode");
            String mailno = routinfoe.attributeValue("mailno");
            String orderid = routinfoe.attributeValue("orderid");

            sflog.setAcceptTime(DateUtil.strToDate(accept_time));
            sflog.setAcceptAddress(accept_address);
            sflog.setAcceptRemark(accept_remark);
            sflog.setOpCode(opcode);
            sflog.setExpressageId(orderid);
            sflog.setId(UUID.randomUUID().toString());
            sflog.setCreateTime(new Date());
            if(wayroutlsit.keySet().contains(mailno)){
                wayroutlsit.get(mailno).add(sflog);
            }else{
                List<WlyyPrescriptionExpressageLogDO> newsflogs = new ArrayList<>();
                newsflogs.add(sflog);
                wayroutlsit.put(mailno,newsflogs);
            }
        }

        if(!wayroutlsit.keySet().isEmpty()){
            for (String mailno:wayroutlsit.keySet()) {
                List<WlyyPrescriptionExpressageLogDO> pushSFLogs = wayroutlsit.get(mailno);
                //同一个快递单号的执行一个事务操作
                this.saveSFPushRoutInfos(mailno,pushSFLogs);
            }
        }
    }


    /**
     * 解析顺丰推送过来的路由信息，和本地数据匹配并进行增量更新）
     * @param waybillRoute
     * @return
     * @throws Exception
     */
    public void SFRoutePushServiceNew(String waybillRoute) throws Exception{
        JSONObject object = JSONObject.parseObject(waybillRoute);
        Map<String,List<WlyyPrescriptionExpressageLogDO>> wayroutlsit = new HashMap<>();
        logger.info("顺丰入参："+object);
        WlyyPrescriptionExpressageLogDO sflog = new WlyyPrescriptionExpressageLogDO();
        String accept_time = object.getString("acceptTime");
        String accept_address = object.getString("acceptAddress");
        String accept_remark = object.getString("remark");
        String opcode = object.getString("opCode");
        String mailno = object.getString("mailNo");
        String orderid = object.getString("orderId");
        String id = object.getString("id");

        String signStr = "id="+id+"&mailNo="+mailno+"&orderId="+orderid+"&opCode="+opcode+"&secretKey="+sf_check_word;
        String signLocal = SHAUtils.SHA512(signStr);
        logger.info("signStr"+signLocal);
        String sign = object.getString("sign");
        if (signLocal.equalsIgnoreCase(sign)){
            sflog.setAcceptTime(DateUtil.stampToDate(accept_time));
            sflog.setAcceptAddress(accept_address);
            sflog.setAcceptRemark(accept_remark);
            sflog.setOpCode(opcode);
            sflog.setExpressageId(orderid);
            sflog.setId(UUID.randomUUID().toString());
            sflog.setCreateTime(new Date());
            if(wayroutlsit.keySet().contains(mailno)){
                wayroutlsit.get(mailno).add(sflog);
            }else{
                List<WlyyPrescriptionExpressageLogDO> newsflogs = new ArrayList<>();
                newsflogs.add(sflog);
                wayroutlsit.put(mailno,newsflogs);
            }

            if(!wayroutlsit.keySet().isEmpty()){
                for (String mailNo1:wayroutlsit.keySet()) {
                    List<WlyyPrescriptionExpressageLogDO> pushSFLogs = wayroutlsit.get(mailNo1);
                    //同一个快递单号的执行一个事务操作
                    this.saveSFPushRoutInfos(mailNo1,pushSFLogs);
                }
            }
        }else {
            throw new Exception("签名无效");
        }
    }

    /**
     * 同一个快递单号的执行一个事务操作
     * @param mailno
     * @param pushSFLogs
     */
    public void saveSFPushRoutInfos(String mailno,List<WlyyPrescriptionExpressageLogDO> pushSFLogs){

        //根据快递单号获取处方配送详细信息
        WlyyPrescriptionExpressageDO sfexpress = prescriptionExpressageDao.findByPrescriptionExpressMailno(mailno);
        //根据门诊id获取处方详细信息
        List<WlyyPrescriptionDO> sfprescription = prescriptionDao.findByOutpatientId(sfexpress.getOutpatientId());
        //根据快递单号获取本地的路由信息
        List<WlyyPrescriptionExpressageLogDO> localroutinfos = prescriptionExpressageLogDao.queryByOutpatientId(sfexpress.getOutpatientId());
        //需要增量更新到本地的路由信息集合
        List<WlyyPrescriptionExpressageLogDO> newroutinfolist = new ArrayList<>();

        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事务隔离级别，开启新事务
        TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态
        try {

            //用于判断新节点是否包含了"已收件"的节点
            boolean isContainEndRoutInfo = false;

            //获取本地所有路由信息的时间集
            Set<String> routAcceptTimeSet = new HashSet<>();
            for (WlyyPrescriptionExpressageLogDO log: localroutinfos) {
                routAcceptTimeSet.add(DateUtil.dateToStrLong(log.getAcceptTime()));
            }

            for (WlyyPrescriptionExpressageLogDO pushlog: pushSFLogs) {

                //判断是否有已收件的路由节点
                if("80".equals(pushlog.getOpCode())||"8000".equals(pushlog.getOpCode())||"130".equals(pushlog.getOpCode())){
                    isContainEndRoutInfo = true;
                }

                if(routAcceptTimeSet.contains(DateUtil.dateToStrLong(pushlog.getAcceptTime()))){
                    continue;
                }else{
                    pushlog.setOutpatientId(sfexpress.getOutpatientId());
                    pushlog.setPrescriptionId(sfprescription.get(0).getId());
                    newroutinfolist.add(pushlog);
                }
            }

            //如果有新增的路由信息，则添加到数据库
            if(!newroutinfolist.isEmpty()){
                prescriptionExpressageLogDao.save(newroutinfolist);
            }
            //向患者微信推送模板写消息
            pushRouteLogToPatient(newroutinfolist);
            //如果路由信息节点包含了"已收件"节点，则修改处方状态为完成，增加物流派送日志为完成
            if(isContainEndRoutInfo){
                //修改处方状态为完成
                prescriptionDao.updateStatusByOutPatientId( 100,new Date(),sfexpress.getOutpatientId());
                /*List<WlyyPrescriptionDO> wlyyPrescriptionDOs = prescriptionDao.findByOutpatientId(sfexpress.getOutpatientId());
                if (wlyyPrescriptionDOs.size()>0){
                    WlyyPrescriptionDO wlyyPrescriptionDO=wlyyPrescriptionDOs.get(0);
                    wlyyPrescriptionDO.setStatus(100);
                    wlyyPrescriptionDO.setFinishTime(new Date());
                    prescriptionDao.save(wlyyPrescriptionDO);

                }*/
                //处方日志
                for (int i=0;i<sfprescription.size();i++){
                    WlyyPrescriptionDO prescriptionDO = sfprescription.get(i);
                    if (prescriptionDO.getStatus()>=32){
                        WlyyPrescriptionLogDO prescriptionLogDO = new WlyyPrescriptionLogDO();
                        prescriptionLogDO.setCreateTime(new Date());
                        prescriptionLogDO.setStatus(100);
                        prescriptionLogDO.setOutpatientId(prescriptionDO.getOutpatientId());
                        prescriptionLogDO.setPrescriptionCode(prescriptionDO.getPatientCode());
                        prescriptionLogDO.setUserCode(prescriptionDO.getPatientCode());
                        prescriptionLogDO.setUserName(prescriptionDO.getPatientName());
                        prescriptionLogDO.setUserType(1);
                        prescriptionLogDO.setDatajson("处方完成");
                        prescriptionLogDao.save(prescriptionLogDO);
                        logger.info("更新处方日志");
                    }
                }



                //保存配送成功的日志
                WlyyOutpatientExpressageLogDO outpatiExpressLog = new WlyyOutpatientExpressageLogDO();
                outpatiExpressLog.setOutpatientId(sfexpress.getOutpatientId());
                outpatiExpressLog.setId(UUID.randomUUID().toString());
                outpatiExpressLog.setType(8);
                outpatiExpressLog.setCreateTime(new Date());
                outpatiExpressLog.setFlag(1);
                outpatiExpressLog.setStatus(100);
                outpatientExpressageLogDao.save(outpatiExpressLog);
            }
            //事务提交
            transactionManager.commit(status);
        } catch (Exception ex) {
            //报错事务回滚
            transactionManager.rollback(status);
        }


    }
    //发送微信模板消息
    public void pushRouteLogToPatient(List<WlyyPrescriptionExpressageLogDO> routinfolist){
        boolean isSend = true;//防止80和8000同时存在多向患者端多发一条消息
        for (WlyyPrescriptionExpressageLogDO wlyyPrescriptionExpressageLogDO:routinfolist){
            if ("50".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())||
                    "204".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())||
            "80".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())||"8000".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())){
                if ("80".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())||"8000".equalsIgnoreCase(wlyyPrescriptionExpressageLogDO.getOpCode())){
                    if (isSend){
                        prescriptionService.sendSFWxTemplate(wlyyPrescriptionExpressageLogDO.getOutpatientId(),wlyyPrescriptionExpressageLogDO.getPrescriptionId(),wlyyPrescriptionExpressageLogDO.getOpCode());
                        isSend= false;
                    }
                }else {
                    prescriptionService.sendSFWxTemplate(wlyyPrescriptionExpressageLogDO.getOutpatientId(),wlyyPrescriptionExpressageLogDO.getPrescriptionId(),wlyyPrescriptionExpressageLogDO.getOpCode());

                }
            }
        }

    }
    /**
     * 根据收寄地址获取快递费用
     * @param d_province 省份名称
     * @param d_city     城市名称
     * @return
     */
    public WlyyExpressagePriceDO getSFExpressPrice(String d_province, String d_city) throws Exception{
        String end_address_name = "";

        if("厦门市".equals(d_city)){
            end_address_name = "同城";
        }else{
            if("福建省".equals(d_province)){
                end_address_name = "省内";
            }else{
                end_address_name = "%"+d_province.replaceAll("省","")+"%";
            }
        }
//        end_address_name = "%"+end_address_name.replaceAll("省","").replaceAll("市","")+"%";
        WlyyExpressagePriceDO sfprice =  expressagePriceDao.getExprePriceByIdAndEndAdressName("shunfeng",end_address_name);
        return sfprice;
    }

    /**
     * 根据处方快递订单号判断是否下单成功
     * 如果下单成功，保存处方物流记录，保存配送日志
     * @param sfexpress_obj
     * @return
     * @throws Exception
     */
    public boolean sfOrderSearchService(WlyyPrescriptionExpressageDO sfexpress_obj)  throws Exception{

        boolean go_on = false;

        String xml = SFUtils.sfOrderSearchService(sfexpress_obj.getId(),sf_code);
        String re = this.SFExpressPost(xml);

        try {
            //xml验证
            verificationResponXml(re,"订单处理失败！");

            Document doc = DocumentHelper.parseText(re);
            String headvalue = doc.selectSingleNode("/Response/Head").getText();
            if(StringUtils.isNotBlank(headvalue) && "OK".equals(headvalue)) {
                //是否能派送：1：人工确认；2：可收派；3：不可以收派
                String filter_result = "";
                String orderid = "";//业务订单号
                String mailno = "";//顺丰运单号
                String destCode = "";//目的地区域代码

                //错误代对应的文字
                Document redoc = doc.selectSingleNode("/Response/Body/Orderresponse").getDocument();
                Element root = redoc.getRootElement();
                List<?> child = root.elements();
                for (Object o : child) {
                    Element e = (Element) o;
                    filter_result = e.attributeValue("filter_result");
                    orderid = e.attributeValue("orderid");
                    mailno = e.attributeValue("mailno");
                    destCode = e.attributeValue("destCode");
                }

                if(StringUtils.isBlank(mailno)){
                    logger.info("顺丰快递下订单失败：未获取到快递单号！"+sfexpress_obj.getOutpatientId());
                    return true;
                }

                if(StringUtils.isNotBlank(filter_result) && "1".equals(filter_result)){
                    logger.info("顺丰快递下订单失败：派送地址需人工审核，处方编号："+sfexpress_obj.getOutpatientId());
                    return true;
                }

                if(StringUtils.isNotBlank(filter_result) && "3".equals(filter_result)){
                    logger.info("顺丰快递下订单失败：派送地址不可派送，处方编号："+sfexpress_obj.getOutpatientId());
                    return true;
                }

                sfexpress_obj.setMailno(mailno);
                sfexpress_obj.setCityCode(destCode);
            }

            //如果成功获取到快递单号，则保存处方物流记录，保存配送日志
            //修改处方状态为配送中
            prescriptionDao.updateStatus(sfexpress_obj.getOutpatientId(),65);

            //保存处方物流记录
            prescriptionExpressageDao.save(sfexpress_obj);

            //保存配送日志
            WlyyOutpatientExpressageLogDO outpatiExpressLog = new WlyyOutpatientExpressageLogDO();
            outpatiExpressLog.setOutpatientId(sfexpress_obj.getOutpatientId());
            outpatiExpressLog.setId(UUID.randomUUID().toString());
            outpatiExpressLog.setType(8);
            outpatiExpressLog.setCreateTime(new Date());
            outpatiExpressLog.setFlag(1);
            outpatiExpressLog.setStatus(100);
            outpatientExpressageLogDao.save(outpatiExpressLog);


        }catch (Exception ex){
            logger.info("顺丰快递下订单失败：派送地址不可派送，处方编号："+sfexpress_obj.getOutpatientId());
            //如果订单处理失败，则可以继续下单
            go_on = true;
        }

        return go_on;

    }

    public boolean sfOrderSearchServiceJustSearch(WlyyPrescriptionExpressageDO sfexpress_obj)  throws Exception{

        String xml = SFUtils.sfOrderSearchService(sfexpress_obj.getId(),sf_code);
        String re = this.SFExpressPost(xml);

        boolean reslut = false;

        try {
            //xml验证
            verificationResponXml(re,"订单处理失败！");

            Document doc = DocumentHelper.parseText(re);
            String headvalue = doc.selectSingleNode("/Response/Head").getText();
            if(StringUtils.isNotBlank(headvalue) && "OK".equals(headvalue)) {
                Element root = doc.getRootElement();
                if (root.element("Body") != null)     //包含OrderResponse节点
                {
                    root = root.element("Body");
                }

                //是否能派送：1：人工确认；2：可收派；3：不可以收派
                String filter_result = "";
                String orderid = "";//业务订单号
                String mailno = "";//顺丰运单号
                List<?> child = root.elements();
                for (Object o : child) {
                    Element e = (Element) o;
                    filter_result = e.attributeValue("filter_result");
                    orderid = e.attributeValue("orderid");
                    mailno = e.attributeValue("mailno");
                }
                if(StringUtils.isNotBlank(filter_result) && "3".equals(filter_result)){
                    logger.info("顺丰快递下订单失败：派送地址不可派送，处方编号："+sfexpress_obj.getOutpatientId());
                    throw new Exception("顺丰快递下订单失败：派送地址不可派送");
                }

                if(StringUtils.isBlank(mailno)){
                    logger.info("顺丰快递下订单失败：未获取到快递单号！"+sfexpress_obj.getOutpatientId());
                    throw new Exception("顺丰快递下订单失败：未获取到快递单号！");
                }
            }



        }catch (Exception ex){
            logger.info("顺丰快递下订单失败：派送地址不可派送，处方编号："+sfexpress_obj.getOutpatientId());
            //如果订单处理失败，则可以继续下单
            throw new Exception(ex.getMessage());
        }

        return reslut;
    }

    public String getRoutInfosSearch(WlyyPrescriptionExpressageDO sfexpress_obj)throws Exception {
        String xml = SFUtils.getRoutInfos(sfexpress_obj,sf_code);
        String re = this.SFExpressPost(xml);

        return xml;
    }


    /**
     * 1，保存快递单号增
     * 2，加处方物流记录为配送
     * 3，修改处方状态为配送配送中
     *
     * @param prescriptionExpressage
     * @throws Exception
     */
    @Transactional
    public void updatePrescriptionExpressage(WlyyPrescriptionExpressageDO prescriptionExpressage) throws Exception {

        //修改门诊处方状态为配送配送中
        prescriptionDao.updateStatus(prescriptionExpressage.getId(), 32);

        //保存处方物流记录
        prescriptionExpressageDao.save(prescriptionExpressage);

        //保存门诊配送日志
        WlyyOutpatientExpressageLogDO prescriptionLog = new WlyyOutpatientExpressageLogDO();
        prescriptionLog.setOutpatientId(prescriptionExpressage.getOutpatientId());
        // 类型: -1 失效 1HIS对接 2易联众对接  3创建处方 4 审核  5付款 6 配送 7完成 8物流对接
        prescriptionLog.setType(8);
        // -2 患者自己取消 -1 审核不通过 , 0 审核中, 10 审核通过/待支付 ,21支付失败  20 配药中/支付成功, 21 等待领药 ,30 配送中 ,100配送成功/已完成
        prescriptionLog.setStatus(30);
        prescriptionLog.setCreateTime(new Date());
        prescriptionLog.setFlag(1);
        outpatientExpressageLogDao.save(prescriptionLog);
    }
    
    
    /**
     * 组装请求参数，发送请求
     * @param params
     * @return
     * @throws Exception
     */
    private String SFExpressPostV2(JSONObject params)throws Exception{
        params.put("version","1.0");
        params.put("timestamp","4070916000000");
        logger.info("timestamp"+params.getString("timestamp"));
        String sign = SHAUtils.SHA512(params.toJSONString()+sf_check_word);
        String url =sf_url+"/api/open/api/addOrder?hospitalCode="+sf_code+"&sign="+sign;
    
        logger.info("顺丰快递下订单：sf_url"+url);
        logger.info("顺丰快递下订单：params"+params.toString());
        
        
        String re = HttpClientUtils.doPost(url, params.toJSONString(), ContentType.APPLICATION_JSON);
        return re;
    }


    /**
     * 查询面单组装请求参数，发送请求
     * @param params
     * @return
     * @throws Exception
     */
    private String SFExpressQueryPostV2(String params)throws Exception{
      /*  params.put("version","1.0");
        params.put("timestamp",new Date().getTime());*/
        String sign = SHAUtils.SHA512(params+sf_check_word);
        String url =sf_url+"/api/open/api/listSelfPrintDO?hospitalCode="+sf_code+"&sign="+sign+"&version=1.0"+"&timestamp=4070916000000&orderNo="+params;

        logger.info("顺丰快递面单查询：sf_url"+url);
        logger.info("顺丰快递面单查询：params"+params.toString());


        String re = HttpClientUtils.doGet(url);
        return re;
    }
    
    /**
     * 校验返回的报文
     * @param response
     */
    private void verificationResponV2(String response) throws Exception {
        String error = "";
        if (StringUtils.isBlank(response)) {
            // 如果返回的XML报文为空，请求也算失败
            //保存http日志
            error = "返回的报文为空！";
            logger.info(error);
            throw new Exception(error);
        }else{
            JSONObject object = JSONObject.parseObject(response);
//          报错的报文示例<Response service="ScopeService"><Head>ERR</Head><ERROR code="8014">校验码错误 </ERROR></Response>
            Boolean success = object.getBoolean("success");
            String message = object.getString("message");
            if(StringUtils.isNotBlank(message) && !success){
                //错误代码
                String errorCode = object.getString("code");
                error = "顺丰快递接口请求失败："+errorCode+","+message;
                logger.info(error);
                throw new Exception(error);
            }
        }
    }

//    public JSONObject addSFOrder(WlyyPrescriptionExpressageDO expressageDO){
//
//        SfConfigDO sfConfigDO = sfConfigDao.findOne("sfconfig");
//
//        JSONObject param = new JSONObject();
//        param.put("timestamp",new Date());
//        param.put("version","1.0");
//        JSONArray orderThirds = new JSONArray();
//        JSONObject order = new JSONObject();
//        order.put("bspOrderNo",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//        order.put("",);
//    }
}
