package com.ywt.outpatient.taihe.rpc.provider;

import com.fasterxml.jackson.databind.JsonNode;
import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.doctor.DoctorHisCode;
import com.ywt.gapi.doctor.DoctorService;
import com.ywt.gapi.doctor.GetDoctorHisCodeRequest;
import com.ywt.gapi.doctor.GetDoctorHisCodeResponse;
import com.ywt.gapi.ordercenter.OrderCenterService;
import com.ywt.gapi.taihe.outpaitent.*;
import com.ywt.gapi.third.taihe.PaymentItem;
import com.ywt.gapi.third.taihe.TaiheService;
import com.ywt.outpatient.taihe.rpc.core.PagedList;
import com.ywt.outpatient.taihe.rpc.core.SqlHelper;
import com.ywt.outpatient.taihe.rpc.core.utils.Checker;
import com.ywt.outpatient.taihe.rpc.core.utils.DateUtil;
import com.ywt.outpatient.taihe.rpc.core.utils.MoneyUtil;
import com.ywt.outpatient.taihe.rpc.core.utils.StringHelper;
import com.ywt.outpatient.taihe.rpc.domain.entity.center.MedicalCardRepository;
import com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrderDetailRepository;
import com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrderRepository;
import com.ywt.outpatient.taihe.rpc.domain.enums.OutpatientStatus;
import com.ywt.outpatient.taihe.rpc.domain.enums.PaymentStatus;
import com.ywt.outpatient.taihe.rpc.domain.enums.PaymentStatusEnum;
import com.ywt.outpatient.taihe.rpc.domain.enums.RefundStatus;
import com.ywt.outpatient.taihe.rpc.domain.models.OutpatientConfig;
import com.ywt.outpatient.taihe.rpc.service.Constants;
import com.ywt.outpatient.taihe.rpc.service.IdGenerator;
import com.ywt.outpatient.taihe.rpc.service.common.ConfigProvider;
import com.ywt.outpatient.taihe.rpc.domain.entity.center.MedicalCard;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 太和医院门诊缴费业务类
 *
 * @author johnson lin
 * @date 2019-05-29 3:31 PM
 */
@DubboService
public class TaiheOutpatientProvider extends DubboTaiheOutpatientServiceTriple.TaiheOutpatientServiceImplBase{
    private static Logger logger = LoggerFactory.getLogger(TaiheOutpatientProvider.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private SqlHelper sqlHelper;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private OutpatientOrderRepository outpatientOrderRepository;

    @Autowired
    private OutpatientOrderDetailRepository outpatientOrderDetailRepository;

    @DubboReference
    private DoctorService doctorServiceBlockingStub;

    @DubboReference
    private TaiheService taiheServiceBlockingStub;

    @Autowired
    private MedicalCardRepository medicalCardRepository;

    @Autowired
    private ConfigProvider configProvider;


    /**
     * 获取门诊缴费单详情
     * 对于未缴费的门诊缴费单，会同步线下缴费状态和最新的处方费用
     *
     * @param request          {@link GetOutpatientDetailRequest}
     */
    @Override
    public GetOutpatientDetailResponse getOutpatientDetail(GetOutpatientDetailRequest request) {
        GetOutpatientDetailResponse.Builder builder = GetOutpatientDetailResponse.newBuilder();
        try {
            com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getFirstByOrderIdAndDeletedFalse(request.getOrderId());
            if (outpatientOrder == null) {
                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("门诊缴费单不存在");
                return builder.build();
            }

            //同步缴费状态、缴费金额
            syncOutpatientOrderInfo(outpatientOrder);

            com.ywt.gapi.taihe.outpaitent.OutpatientOrder gOutpatientOrder = com.ywt.gapi.taihe.outpaitent.OutpatientOrder.newBuilder()
                    .setOrderId(Checker.getIntegerValue(outpatientOrder.getOrderId()))
                    .setOrderNo(Checker.getStringValue(outpatientOrder.getOrderNo()))
                    .setCreateTime(DateUtil.convertToTimestamp(outpatientOrder.getCreateTime()))
                    .setHospitalId(outpatientOrder.getHospitalId())
                    .setHospitalName(outpatientOrder.getHospitalName())
                    .setDeptCode(Checker.getStringValue(outpatientOrder.getDeptCode()))
                    .setDeptName(Checker.getStringValue(outpatientOrder.getDeptName()))
                    .setDoctorCode(Checker.getStringValue(outpatientOrder.getDoctorCode()))
                    .setDoctorName(Checker.getStringValue(outpatientOrder.getDoctorName()))
                    .setTotal(outpatientOrder.getTotal())
                    .setReimbursement(outpatientOrder.getReimbursement())
                    .setIndividual(outpatientOrder.getIndividual())
                    .setPaymentStatus(outpatientOrder.getPaymentStatus())
                    .setOutpatientStatus(outpatientOrder.getOutpatientStatus())
                    .setUserId(outpatientOrder.getUserId())
                    .setHisPatientId(outpatientOrder.getHisPatientId())
                    .setPayName(Checker.getStringValue(outpatientOrder.getPayName()))
                    .setPatientAge(Checker.getIntegerValue(outpatientOrder.getPatientAge()))
                    .setPatientName(Checker.getStringValue(outpatientOrder.getPatientName()))
                    .setPatientSex(Checker.getIntegerValue(outpatientOrder.getPatientSex()))
                    .setPrescriptionDate(DateUtil.convertToTimestamp(outpatientOrder.getPrescriptionDate()))
                    .setHisOrderNo(outpatientOrder.getHisOrderNo())
                    .build();
            builder.setCode(ResultCode.SUCCEED_VALUE).setOrder(gOutpatientOrder).build();
        } catch (Exception e) {
            logger.error("getOutpatientDetail({}): {}", request, e.getMessage(), e);
            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO).build();
        } finally {
            return builder.build();
        }
    }

    /**
     * 获取门诊缴费单列表
     *
     * @param request          {@link GetOutpatientListRequest}
     */
    @Override
    public GetOutpatientListResponse getOutpatientList(GetOutpatientListRequest request) {
        GetOutpatientListResponse.Builder builder = GetOutpatientListResponse.newBuilder();

        try {
            if (request.getUserId() <= 0) {
                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("invalid userId");
                return builder.build();
            }

            final String fields = "*";
            final String orderBy = "create_time desc";
            String whereSql = "user_id = ? and payment_status = ? and deleted = 0";
            Object[] args = new Object[]{request.getUserId(), PaymentStatus.SUCCESS.getValue()};
            int[] argTypes = new int[]{Types.INTEGER, Types.INTEGER};

            List<com.ywt.gapi.taihe.outpaitent.OutpatientOrder> lst = new LinkedList<>();
            PagedList<com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder> pagedList = sqlHelper.getPagedList(
                    request.getPageIndex(), request.getPageSize(), fields, whereSql, orderBy, com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder.class, args, argTypes);

            if (pagedList.getItems() != null) {
                String selfPay = "0.00元";
                String insuranceFee = "0.00元";
                String insuranceFundfee = "0.00元";
                String insuranceSelfFee = "0.00元";
                String insuranceOtherFee = "0.00元";

                for (com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder item : pagedList.getItems()) {
                    String statusName = "已支付";
                    if (item.getRefundStatus() != null && item.getRefundStatus() == RefundStatus.SUCCESS.getValue()) {
                        statusName = "已退款";
                    }
                    if (!Checker.isNone(item.getInsTxReturnStr())) {

                        JsonNode node = JsonSerializer.readToNode(item.getInsTxReturnStr());
                        if (node != null) {
                            String selfPayStr = extracted(node, "cash_fee");
                            selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
                            String insFeeStr = extracted(node, "insurance_fee");
                            insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
                            String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
                            insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
                            String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
                            insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
                            String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
                            insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
                        }
                    }
                    String insDetail = "（微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + "）";

                    com.ywt.gapi.taihe.outpaitent.OutpatientOrder order = com.ywt.gapi.taihe.outpaitent.OutpatientOrder.newBuilder()
                            .setOrderId(Checker.getIntegerValue(item.getOrderId()))
                            .setOrderNo(Checker.getStringValue(item.getOrderNo()))
                            .setHisOrderNo(Checker.getStringValue(item.getHisOrderNo()))
                            .setCreateTime(DateUtil.convertToTimestamp(item.getCreateTime()))
                            .setHospitalId(item.getHospitalId())
                            .setHospitalName(item.getHospitalName())
                            .setDeptCode(Checker.getStringValue(item.getDeptCode()))
                            .setDeptName(Checker.getStringValue(item.getDeptName()))
                            .setDoctorCode(Checker.getStringValue(item.getDoctorCode()))
                            .setDoctorName(Checker.getStringValue(item.getDoctorName()))
                            .setTotal(item.getTotal())
                            .setReimbursement(item.getReimbursement())
                            .setIndividual(item.getIndividual())
                            .setPaymentStatus(item.getPaymentStatus())
                            .setOutpatientStatus(item.getOutpatientStatus())
                            .setUserId(item.getUserId())
                            .setHisPatientId(item.getHisPatientId())
                            .setPayName(Checker.getStringValue(item.getPayName()))
                            .setStatusName(statusName)
                            .setPatientName(Checker.getStringValue(item.getPatientName()))
                            .setPatientSex(Checker.getIntegerValue(item.getPatientSex()))
                            .setInvoiceNo(Checker.getStringValue(item.getInvoiceNo()))
                            .setSelfPay(selfPay)
                            .setInsurance(insuranceFee)
                            .setInsDetail(insDetail)
                            .build();
                    lst.add(order);
                }
            }

            builder.setCode(ResultCode.SUCCEED_VALUE)
                    .setCount(pagedList.getTotal())
                    .setTotalPage(pagedList.getTotalPage())
                    .addAllOrder(lst)
                    .build();
        } catch (Exception e) {
            logger.error("getOutpatientList({}): {}", request, e.getMessage(), e);
            builder.setCode(ResultCode.APP_EXCEPTION_VALUE).setMsg(Constants.ERROR_INFO);
        } finally {
            return builder.build();
        }
    }

    private String extracted(JsonNode node, String key) {
        if (Checker.isNone(node)) {
            return "0";
        }
        JsonNode jn = node.get(key);
        if (jn != null) {
            String value = jn.asText();
            return value;
        } else {
            return "0";
        }
    }

    /**
     * 当缴费单未支付成功时，同步缴费单信息（支付状态、缴费金额）
     *
     * @param outpatientOrder {@link OutpatientOrder}
     */
    private void syncOutpatientOrderInfo(com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder) {
        //判断是否已线下缴费
        if (outpatientOrder.getPaymentStatus() != PaymentStatus.SUCCESS.getValue() &&
                outpatientOrder.getPaymentStatus() != PaymentStatus.PROCESSING.getValue()) {
            com.ywt.gapi.third.taihe.GetOutpatientListRequest req = com.ywt.gapi.third.taihe.GetOutpatientListRequest.newBuilder()
                    .setPatientId(outpatientOrder.getHisPatientId())
                    //类型：1-门诊待缴费记录 2-门诊已缴费记录 3-门诊已退费记录
                    .setType(1)
                    .setHospitalId(Checker.getIntegerValue(outpatientOrder.getHospitalId()))
                    .build();
            com.ywt.gapi.third.taihe.GetOutpatientListResponse res = taiheServiceBlockingStub.getOutpatientList(req);
            if (res.getCode() != ResultCode.SUCCEED_VALUE) {
                throw new RuntimeException("同步缴费状态失败，" + res.getMsg());
            }

            String sql;
            Object[] args;
            int[] argTypes;

            List<PaymentItem> items = res.getPaymentList();
            if (items != null && items.size() > 0 &&
                    items.stream().anyMatch(p -> p.getHisOrdNum().equals(outpatientOrder.getHisOrderNo()))) {
                //线下未缴费，同步最新的处方费用
                PaymentItem paymentItem = items.stream().filter(
                        p -> p.getHisOrdNum().equals(outpatientOrder.getHisOrderNo()))
                        .collect(Collectors.toList()).get(0);
                outpatientOrder.setTotal(paymentItem.getTotalFee());
                outpatientOrder.setReimbursement(paymentItem.getMedInsFee());
                outpatientOrder.setIndividual(paymentItem.getSelfFee());
                outpatientOrderRepository.save(outpatientOrder);

                sql = "update orders set order_amount = ? where id = ?";
                args = new Object[]{outpatientOrder.getTotal() / 100.0, outpatientOrder.getOrderId()};
                argTypes = new int[]{Types.DECIMAL, Types.INTEGER};
                jdbcTemplate.update(sql, args, argTypes);
            } else {
                //线下已缴费，更新状态
                outpatientOrder.setPaymentStatus(PaymentStatus.SUCCESS.getValue());
                outpatientOrder.setOutpatientStatus(OutpatientStatus.PAID.getValue());
                outpatientOrderRepository.save(outpatientOrder);

                sql = "update orders set payment_status = ? where id = ?";
                args = new Object[]{PaymentStatus.SUCCESS.getValue(), outpatientOrder.getOrderId()};
                argTypes = new int[]{Types.INTEGER, Types.INTEGER};
                jdbcTemplate.update(sql, args, argTypes);
            }
        }
    }

    @Override
    public GetMedicalCardInfoByPatientIdResponse getMedicalCardInfoByPatientId(GetMedicalCardInfoByPatientIdRequest request) {
        GetMedicalCardInfoByPatientIdResponse.Builder builder = GetMedicalCardInfoByPatientIdResponse.newBuilder();
        try {
            String hisPatientId = request.getHisPatientId();
            int hospitalId = request.getHospitalId() > 0 ? request.getHospitalId() : Constants.TAIHE_HOSPITAL_ID;
            int userId = request.getUserId();
            MedicalCard medicalCard = null;
            StringBuilder where = new StringBuilder("status = 1");
            if (userId > 0) {
                where.append(" and user_id = ").append(userId);
            }
            if (!StringHelper.isNullOrEmpty(hisPatientId)) {
                where.append(" and his_patient_id = ").append(hisPatientId);
            }
            where.append(" and hospital_id = ").append(hospitalId);
            String sql = String.format("select * from ywt_center.medical_card where %s limit 1;", where.toString());
//            System.out.println(sql);
            try {
                medicalCard = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(MedicalCard.class));
            } catch (DataAccessException e) {
                logger.error("TaiheOutpatientService#getMedicalCardInfoByPatientId(sql = {}):\n {}", sql, e.getMessage(), e);
            }
            if (medicalCard == null) {
                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到就诊卡信息");
            } else {

                builder.setCode(ResultCode.SUCCEED_VALUE)
                        .setMsg("")
                        .setUserId(Checker.getIntegerValue(medicalCard.getUserId()))
                        .setHospitalId(Checker.getIntegerValue(medicalCard.getHospitalId()))
                        .setCardNo(Checker.getStringValue(medicalCard.getCardNo()))
                        .setCardType(Checker.getStringValue(medicalCard.getCardType()))
                        .setPatientName(Checker.getStringValue(medicalCard.getPatientName()))
                        .setMobile(Checker.getStringValue(medicalCard.getMobile()))
                        .setSex(Checker.getIntegerValue(medicalCard.getSex()))
                        .setBirthday(Checker.getStringValue(medicalCard.getBirthday()))
                        .setAddress(Checker.getStringValue(medicalCard.getAddress()))
                        .setTelephoneNo(Checker.getStringValue(medicalCard.getTelephoneNo()))
                        .setDocumentId(Checker.getStringValue(medicalCard.getDocumentId()))
                        .setBalance(Checker.getIntegerValue(medicalCard.getBalance()))
                        .setIdTypeCode(Checker.getStringValue(medicalCard.getIdTypeCode()))
                        .setIdTypeDesc(Checker.getStringValue(medicalCard.getIdTypeDesc()))
                        .setIdNo(Checker.getStringValue(medicalCard.getIdNo()))
                        .setInsureCardNo(Checker.getStringValue(medicalCard.getInsureCardNo()))
                        .setAccInfo(Checker.getStringValue(medicalCard.getAccInfo()))
                        .setPatientType(Checker.getStringValue(medicalCard.getPatientType()))
                        .setStatus(Checker.getIntegerValue(medicalCard.getStatus()))
                        .setHisPatientId(Checker.getStringValue(medicalCard.getHisPatientId()))
                        .setCardId(medicalCard.getId())
                        .setGuardian(Checker.getStringValue(medicalCard.getGuardian()));
            }
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getMedicalCardInfoByPatientId(request={}):\n {}", request, e.getMessage(), e);
        } finally {
            return builder.build();
        }
    }

    @Override
    public GetOutpatientOrderByHisOrderNoResponse getOutpatientOrderByHisOrderNo(GetOutpatientOrderByHisOrderNoRequest request) {
        GetOutpatientOrderByHisOrderNoResponse.Builder builder = GetOutpatientOrderByHisOrderNoResponse.newBuilder();
        try {
            String hisOrderNo = request.getHisOrderNo();
            String invoiceNo = request.getInvoiceNo();
            com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
            if (outpatientOrder == null) {
                // 找不到订单返回空单号
                builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("找不到订单信息").setOrderNo("");
            } else {
                // 如果发票号已经修改，需要更新数据库
                String ivcNo = Checker.getStringValue(outpatientOrder.getInvoiceNo());
                if (!Checker.isNone(invoiceNo) && !ivcNo.equals(invoiceNo)) {
                    outpatientOrder.setInvoiceNo(invoiceNo);
                    outpatientOrderRepository.save(outpatientOrder);
                }
                builder.setCode(ResultCode.SUCCEED_VALUE)
                        .setMsg("")
                        .setHospitalId(Checker.getIntegerValue(outpatientOrder.getHospitalId()))
                        .setHospitalName(Checker.getStringValue(outpatientOrder.getHospitalName()))
                        .setDeptName(Checker.getStringValue(outpatientOrder.getDeptName()))
                        .setDoctorName(Checker.getStringValue(outpatientOrder.getDoctorName()))
                        .setTotal(Checker.getIntegerValue(outpatientOrder.getTotal()))
                        .setReimbursement(Checker.getIntegerValue(outpatientOrder.getReimbursement()))
                        .setIndividual(Checker.getIntegerValue(outpatientOrder.getIndividual()))
                        .setPaymentStatus(Checker.getIntegerValue(outpatientOrder.getPaymentStatus()))
                        .setOutpatientStatus(Checker.getIntegerValue(outpatientOrder.getOutpatientStatus()))
                        .setUserId(Checker.getIntegerValue(outpatientOrder.getUserId()))
                        .setOrderId(Checker.getIntegerValue(outpatientOrder.getOrderId()))
                        .setOrderNo(Checker.getStringValue(outpatientOrder.getOrderNo()))
                        .setHisPatientId(Checker.getStringValue(outpatientOrder.getHisPatientId()))
                        .setHisClinicCode(Checker.getStringValue(outpatientOrder.getHisClinicCode()))
                        .setHisOrderNo(Checker.getStringValue(outpatientOrder.getHisOrderNo()))
                        .setPayUrl(Checker.getStringValue(outpatientOrder.getMedPayUrl()))
                        .setMedTransId(Checker.getStringValue(outpatientOrder.getMedTransId()))
                        .setPayAppId(Checker.getStringValue(outpatientOrder.getMedPayAppId()));
            }
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getOutpatientOrderByHisOrderNo(request={}):\n {}", request, e.getMessage(), e);
        } finally {
            return builder.build();
        }
    }

    @Override
    public BaseResult saveOutpatientOrderDetails(SaveOutpatientOrderDetailsRequest request) {
        BaseResult.Builder builder = BaseResult.newBuilder();
        try {
            String hisOrderNo = request.getHisOrderNo();
            List<OutpatientOrderDetail> details = request.getDetailList();
            if (!Checker.isNone(details)) {
                details.forEach(d -> {
                    // 根据 hisOrderNo & code 判断是否已有记录，没有才插入
                    int count = outpatientOrderDetailRepository.countByHisOrderNoAndCode(hisOrderNo, Checker.getStringValue(d.getItemCode()));
                    if (count <= 0) {
                        com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrderDetail detail = new com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrderDetail();
                        detail.setHisOrderNo(Checker.getStringValue(hisOrderNo));
                        detail.setCreateTime(new Date());
                        detail.setUpdateTime(new Date());
                        detail.setDeleted(0);
                        detail.setId(0);
                        detail.setName(Checker.getStringValue(d.getItemName()));
                        detail.setPrice(Checker.getIntegerValue(d.getItemPrice()));
                        detail.setCode(Checker.getStringValue(d.getItemCode()));
                        detail.setNumber(Checker.getStringValue(d.getItemNumber()));
                        detail.setSpec(Checker.getStringValue(d.getItemSpec()));
                        detail.setUnit(Checker.getStringValue(d.getItemUnit()));
                        detail.setTotalFee(Checker.getIntegerValue(d.getItemTotalFee()));
                        outpatientOrderDetailRepository.save(detail);
                    }
                });
            }
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#saveOutpatientOrderDetails(request={}):\n {}", request, e.getMessage(), e);
            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
        }
    }

    @Override
    public GetOutpatientOrderDetailResponse getOutpatientOrderDetail(GetOutpatientOrderDetailRequest request) {
        GetOutpatientOrderDetailResponse.Builder builder = GetOutpatientOrderDetailResponse.newBuilder();
        try {
            String hisOrderNo = request.getHisOrderNo();
            List<com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrderDetail> list = outpatientOrderDetailRepository.getByHisOrderNo(hisOrderNo);
            List<OutpatientOrderDetail> results = new LinkedList<>();
            com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
            list.forEach(i -> {
                OutpatientOrderDetail d = OutpatientOrderDetail.newBuilder()
                        .setItemName(i.getName())
                        .setItemPrice(i.getPrice())
                        .setItemCode(i.getCode())
                        .setItemNumber(i.getNumber())
                        .setItemSpec(i.getSpec())
                        .setItemUnit(i.getUnit())
                        .setItemTotalFee(i.getTotalFee())
                        .build();
                results.add(d);
            });
            String patientName = "";
            int patientAge = 0;
            int patientSex = 0;
            String invoiceNo = "";
            String selfPay = "0.00元";
            String insuranceFee = "0.00元";
            String insuranceFundfee = "0.00元";
            String insuranceSelfFee = "0.00元";
            String insuranceOtherFee = "0.00元";
            //判断是否使用医保， 0使用了医保， 1纯自费
            int type = 0;
            if (outpatientOrder != null) {
                patientName = Checker.getStringValue(outpatientOrder.getPatientName());
                patientAge = Checker.getIntegerValue(outpatientOrder.getPatientAge());
                patientSex = Checker.getIntegerValue(outpatientOrder.getPatientSex());
                invoiceNo = Checker.getStringValue(outpatientOrder.getInvoiceNo());
                if (!Checker.isNone(outpatientOrder.getInsTxReturnStr())) {

                    JsonNode node = JsonSerializer.readToNode(outpatientOrder.getInsTxReturnStr());
                    if (node != null) {
                        String selfPayStr = extracted(node, "cash_fee");
                        selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
                        String insFeeStr = extracted(node, "insurance_fee");
                        insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
                        String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
                        insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
                        String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
                        insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
                        String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
                        insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
                    }
                } else {
                    type = 1;
                }
            } else {
                type = 1;
            }
            String insDetail = "（微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + "）";
            builder.setCode(ResultCode.SUCCEED_VALUE)
                    .setMsg("操作成功")
                    .setPatientAge(patientAge)
                    .setPatientSex(patientSex)
                    .setPatientName(patientName)
                    .setInvoiceNo(invoiceNo)
                    .setSelfPay(selfPay)
                    .setInsurance(insuranceFee)
                    .setInsDetail(insDetail)
                    .setType(type)
                    .addAllDetail(results);
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getOutpatientOrderDetail(request={}):\n {}", request, e.getMessage(), e);
            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
        }
    }

    @Override
    public GetMedicalCardInfoByPatientIdResponse getMedicalCardInfoById(GetMedicalCardInfoByIdRequest request) {
        GetMedicalCardInfoByPatientIdResponse.Builder builder = GetMedicalCardInfoByPatientIdResponse.newBuilder();
        try {
            int cardId = request.getId();
            MedicalCard medicalCard;
            medicalCard = medicalCardRepository.getById(cardId);
            if (medicalCard == null) {
                builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到就诊卡信息");
            } else {
                builder.setCode(ResultCode.SUCCEED_VALUE)
                        .setMsg("")
                        .setUserId(Checker.getIntegerValue(medicalCard.getUserId()))
                        .setHospitalId(Checker.getIntegerValue(medicalCard.getHospitalId()))
                        .setCardNo(Checker.getStringValue(medicalCard.getCardNo()))
                        .setCardType(Checker.getStringValue(medicalCard.getCardType()))
                        .setPatientName(Checker.getStringValue(medicalCard.getPatientName()))
                        .setMobile(Checker.getStringValue(medicalCard.getMobile()))
                        .setSex(Checker.getIntegerValue(medicalCard.getSex()))
                        .setBirthday(Checker.getStringValue(medicalCard.getBirthday()))
                        .setAddress(Checker.getStringValue(medicalCard.getAddress()))
                        .setTelephoneNo(Checker.getStringValue(medicalCard.getTelephoneNo()))
                        .setDocumentId(Checker.getStringValue(medicalCard.getDocumentId()))
                        .setBalance(Checker.getIntegerValue(medicalCard.getBalance()))
                        .setIdTypeCode(Checker.getStringValue(medicalCard.getIdTypeCode()))
                        .setIdTypeDesc(Checker.getStringValue(medicalCard.getIdTypeDesc()))
                        .setIdNo(Checker.getStringValue(medicalCard.getIdNo()))
                        .setInsureCardNo(Checker.getStringValue(medicalCard.getInsureCardNo()))
                        .setAccInfo(Checker.getStringValue(medicalCard.getAccInfo()))
                        .setPatientType(Checker.getStringValue(medicalCard.getPatientType()))
                        .setStatus(Checker.getIntegerValue(medicalCard.getStatus()))
                        .setHisPatientId(Checker.getStringValue(medicalCard.getHisPatientId()))
                        .setCardId(medicalCard.getId())
                        .setGuardian(Checker.getStringValue(medicalCard.getGuardian()));
            }
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getMedicalCardInfoById(request={}):\n {}", request, e.getMessage(), e);
            builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage());
        } finally {
            return builder.build();
        }
    }

    @Override
    public UpdateOutpatientOrderResponse updateOutpatientOrder(UpdateOutpatientOrderRequest request) {
        UpdateOutpatientOrderResponse.Builder builder = UpdateOutpatientOrderResponse.newBuilder();
        try {
            String hisOrderNo = request.getHisOrderNo();
            String invoiceNo = request.getInvoiceNo();
            if (!Checker.isNone(hisOrderNo) && !Checker.isNone(invoiceNo)) {
                com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByHisOrderNo(hisOrderNo);
                if (outpatientOrder != null) {
                    outpatientOrder.setInvoiceNo(invoiceNo);
                    outpatientOrderRepository.save(outpatientOrder);
                    builder.setCode(ResultCode.SUCCEED_VALUE).setMsg("操作成功");
                } else {
                    builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg("找不到门诊缴费单记录");
                }
            } else {
                builder.setCode(ResultCode.PARAMETER_ERROR_VALUE).setMsg("订单号或发票号不能为空");
            }
            logger.info("updateOutpatientOrder():\n {} \nhisOrderNo: {}, invoiceNo: {}", builder.getMsg(), hisOrderNo,
                    invoiceNo);
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#updateOutpatientOrder(request={}):\n {}", request, e.getMessage(), e);
            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();

        }
    }

    @Override
    public GetLatestOutpatientOrderResponse getLatestOutpatientOrder(GetLatestOutpatientOrderRequest request) {
        GetLatestOutpatientOrderResponse.Builder builder = GetLatestOutpatientOrderResponse.newBuilder();
        int doctorId = request.getDoctorId();
        int userId = request.getUserId();
        int hospitalId = request.getHospitalId();
        try {
            // 根据 doctorId 获取 doctorCode
            GetDoctorHisCodeRequest getDoctorHisCodeRequest = GetDoctorHisCodeRequest.newBuilder()
                    .setDoctorId(doctorId)
                    .setHospitalId(hospitalId)
                    .build();
            GetDoctorHisCodeResponse response = doctorServiceBlockingStub.getDoctorHisCode(getDoctorHisCodeRequest);
            if (response.getResult().getCode() == ResultCode.SUCCEED) {
                DoctorHisCode doctorHisCode = response.getDoctorHisCode();
                String doctorCode = Checker.getStringValue(doctorHisCode.getDoctorCode());
                com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder order =
                        outpatientOrderRepository.getLatestOutpatientOrder(doctorCode, userId, hospitalId);
                if (order != null) {
                    builder.setCreateTime(DateUtil.convertToTimestamp(order.getCreateTime()));
                    builder.setCode(ResultCode.SUCCEED_VALUE);
                    builder.setInfo("操作成功");
                } else {
                    builder.setCode(ResultCode.APP_ERROR_VALUE);
                    builder.setInfo("找不到记录");
                }
            } else {
                builder.setCode(ResultCode.APP_ERROR_VALUE);
                builder.setInfo("找不到医生信息");
            }
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getLatestOutpatientOrder(request={}):\n {}", request, e.getMessage(), e);
            return builder.setCode(ResultCode.APP_ERROR_VALUE).setInfo(e.getMessage()).build();
        }
    }

    @Override
    public GetOutPatientConfigResponse getOutpatientConfigs(GetOutPatientConfigRequest request) {
        int hospitalId = request.getHospitalId();
        GetOutPatientConfigResponse.Builder builder = GetOutPatientConfigResponse.newBuilder();
        try {
            OutpatientConfig config = configProvider.getOutpatientConfig(hospitalId);
            if (config != null) {
                builder.setNotifyUrl(Checker.getStringValue(config.getNotifyUrl()));
                builder.setReturnUrl(Checker.getStringValue(config.getReturnUrl()));
                builder.setOpenId(Checker.getStringValue(config.getOpenId()));
                builder.setHospitalId(Checker.getIntegerValue(config.getHospitalId()));
                builder.setInsuSupportCardType(Checker.getStringValue(config.getInsuSupportCardType()));
            }
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getOutpatientConfigs(request={}):\n {}", request, e.getMessage(), e);
            return builder.build();
        }
    }

    /**
     * 判断是否有未支付的门诊缴费订单
     */
    @Override
    public CheckHasOutstandingOutpatientOrderResponse checkHasOutstandingOutpatientOrder(CheckHasOutstandingOutpatientOrderRequest request) {
        int userId = request.getUserId();
        int hospitalId = Checker.getIntegerValue(request.getHospitalId());
        int type = Checker.getIntegerValue(request.getType());
        logger.info("-----checkHasOutstandingOutpatientOrder-----");
        logger.info("payment_status:" + PaymentStatusEnum.Pending.getValue() + "\tuserId:" + userId + "\thospitalId:" + hospitalId);
        CheckHasOutstandingOutpatientOrderResponse.Builder builder = CheckHasOutstandingOutpatientOrderResponse.newBuilder();
        try {
            boolean hasOutstandingOutpatientOrder = false;
            if (userId > 0 && type == 1) {
                // 查找当天未支付的门诊缴费订单
                String startPattern = "yyyy-MM-dd 00:00:00";
                String createTimeStart = DateUtil.formatDate(new Date(), startPattern);
                Date createTimeStartDate = DateUtil.parseDate(createTimeStart, "");

                String endPattern = "yyyy-MM-dd 23:59:59";
                String createTimeEnd = DateUtil.formatDate(new Date(), endPattern);
                Date createTimeEndDate = DateUtil.parseDate(createTimeEnd, "");
                ArrayList<Object> paramList = new ArrayList<>();
                String sql = "select count(1) from outpatient_order where payment_status = ? and user_id = ? and create_time >= ? and create_time <= ?";
                paramList.add(PaymentStatusEnum.Pending.getValue());
                paramList.add(userId);
                paramList.add(createTimeStartDate);
                paramList.add(createTimeEndDate);
                if (hospitalId > 0) {
                    sql += " and hospital_id = ? ";
                    paramList.add(hospitalId);
                }
                int count = jdbcTemplate.queryForObject(sql, paramList.toArray(), Integer.class);
                logger.info("createTimeStart:" + createTimeStart + "\tcreateTimeEnd:" + createTimeEnd + "\tcreateTimeStartDate:" + createTimeStartDate + "\tcreateTimeEndDate:" + createTimeEndDate + "\tcount:" + count);
                hasOutstandingOutpatientOrder = count > 0 ? true : false;
            }
            builder.setCode(ResultCode.SUCCEED_VALUE);
            builder.setMsg("操作成功");
            builder.setHasOutstandingOutpatientOrder(hasOutstandingOutpatientOrder);
            return builder.build();
        } catch (Exception e) {
            logger.error("TaiheOutpatientService#getOutpatientConfigs(request={}):\n {}", request, e.getMessage(), e);
            return builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage()).build();
        }
    }

    @Override
    public GetOutpatientOrderDetailByInvoiceResponse getOutpatientOrderByInvoiceNo(GetOutpatientOrderDetailByInvoiceRequest request) {
        GetOutpatientOrderDetailByInvoiceResponse.Builder builder = GetOutpatientOrderDetailByInvoiceResponse.newBuilder();
        try {
            String invoiceNo = request.getInvoiceNo();
            com.ywt.outpatient.taihe.rpc.domain.entity.center.OutpatientOrder outpatientOrder = outpatientOrderRepository.getByInvoiceNo(invoiceNo);
            String selfPay = "0.00元";
            String insuranceFee = "0.00元";
            String insuranceFundfee = "0.00元";
            String insuranceSelfFee = "0.00元";
            String insuranceOtherFee = "0.00元";
            //判断是否使用医保， 0使用了医保， 1纯自费
            int type = 0;

            if (!Checker.isNone(outpatientOrder) && !Checker.isNone(outpatientOrder.getInsTxReturnStr())) {

                JsonNode node = JsonSerializer.readToNode(outpatientOrder.getInsTxReturnStr());
                if (node != null) {
                    String selfPayStr = extracted(node, "cash_fee");
                    selfPay = MoneyUtil.cent2Yuan(Integer.parseInt(selfPayStr)) + "元";
                    String insFeeStr = extracted(node, "insurance_fee");
                    insuranceFee = MoneyUtil.cent2Yuan(Integer.parseInt(insFeeStr)) + "元";
                    String insuranceFundfeeStr = extracted(node, "insurance_fund_fee");
                    insuranceFundfee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceFundfeeStr)) + "元";
                    String insuranceSelfFeeStr = extracted(node, "insurance_self_fee");
                    insuranceSelfFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceSelfFeeStr)) + "元";
                    String insuranceOtherFeeStr = extracted(node, "insurance_other_fee");
                    insuranceOtherFee = MoneyUtil.cent2Yuan(Integer.parseInt(insuranceOtherFeeStr)) + "元";
                }
            } else{
                type = 1;
            }
            String insDetail = "（微信支付:" + insuranceOtherFee + "; 医保个账扣款:" + insuranceSelfFee + "; 医保统筹扣款:" + insuranceFundfee + "）";
            builder.setCode(ResultCode.SUCCEED_VALUE)
                    .setSelfPay(selfPay)
                    .setInsurance(insuranceFee)
                    .setInsDetail(insDetail)
                    .setType(type);

        } catch (Exception e) {
            logger.error("TaiheOutpatientService# getOutpatientOrderByInvoiceNo(request={}):\n {}", request, e.getMessage(), e);
            builder.setCode(ResultCode.APP_ERROR_VALUE).setMsg(e.getMessage());
        } finally {
            return builder.build();
        }
    }
}