区块链电子票据

什么是电子票据

电子票据,是指由财政部门监管的,行政事业单位在依法收取政府非税收入或者从事非营利性活动收取财物时,运用计算机和信息网络技术开具、存储、传输和接收的数字电文形式的凭证。其基本特征是以数字信息代替纸质文件、以电子签名代替手工签章,通过网络手段进行传输流转,通过计算机等电子载体进行存储保管。其基本要素包括票据名称、票据代码、票据号码、缴款人、收款项目、标准、收款金额、开票单位、开票人、开票日期、开票单位签章、财政部门监制签章。
按照《会计基础工作规范》和《会计档案管理办法》有关要求生成的财政电子票据,是单位财务收支和会计核算的原始凭证,是财政、审计等部门进行监督检查的重要依据。

什么是区块链电子票据

区块链电子票据主要指充分运用区块链技术,着力建设科学完善的财政电子票据系统,实现财政电子票据开具、管理、传输、查询、存储、报销入账和社会化应用等全流程区块链控制。

政策背景

2017年6月19日,财政部关于印发《关于稳步推进财政电子票据管理改革的试点方案》的通知(财综〔2017〕32号)。开展财政电子票据管理改革试点工作,推广运用财政电子票据,推进财政电子票据管理改革,全面提高财政票据社会需求便捷度,提升财政票据监管水平和效率。

2017年11月22日,财政部颁发《财政部关于做好财政电子票据管理改革 第二批试点有关工作的通知》财综〔2017〕66号。要求进一步推进财政电子票据管理改革。

2018年11月6日,财政部颁发《关于全面推开财政电子票据管理改革的通知》财综〔2018〕62 号。为深化“放管服”改革部署,贯彻“互联网+政务服务”要求,保障个人所得税改革顺利实施,提升财政票据监管效能,决定全面推开财政电子票据管理改革。

设计根据
《医疗收费票据使用管理办法》(财综〔2012〕73号)
《医疗收费票据使用管理办法》(财综〔2013〕40号)
《关于稳步推进财政电子票据管理改革的试点方案》(财综〔2017〕32号)
《中华人民共和国电子签名法》
《国务院办公厅关于转发国家发展改革委等部门推进“互联网+政务服务”开展信息惠民试点实施方案的通知》(国办发〔2016〕23号)
《财政票据管理办法》(财政部令第70号)
《会计档案管理办法》(财政部 国家档案局令第79号)

蚂蚁区块链电子票据整体解决方案

image.png

接入说明

接入前置条件

  1. 接入蚂蚁区块链Baas服务:https://tech.antfin.com/docs/2/73764
  2. 签约了发票管家内部接口包,发邮件申请,申请模板如下:

邮箱:antinvoice@service.alipay.com;
邮件格式:
接入模式:区块链电子票据
主体:【公司名称】
申请人:
申请人手机号:
公司支付宝账号:
创建的APPID:
公司简介:
说明:我们将在2个工作日内进行审核并通知您审核结果,审批通过我们将【服务商简称】和【配置申请表】提供给您。

配置文件说明
所有sdk的相关配置都放在sdk.properties中,以下是示例值
biz.sdk.primary=106.14.138.788080
biz.sdk.backups=47.100.229.160 8080;47.100.210.169 8080;106.14.189.99 8080
biz.sdk.ssl_key=/key_pkcs8.pem
biz.sdk.ssl_cert=/client-sdk/cert.pem
biz.sdk.ssl_key_password=password
biz.sdk.trust_store=/Users/hansong.xhs/Projects/Baas/client-sdk/trust.keystore
biz.sdk.trust_store_password=mychain

ISV RSA私钥,对应公钥提供给技术支持
isv_private_key=xxxx
ISV 公钥
isv_public_key=xxxx
支付宝开放平台公钥
alipay_public_key=xxxx
应用私钥,开放平台申请,RSA2
app_private_key=xxxx
开放平台网关地址
open_home_request_url=xxxxx
应用id
app_id=xxxxx

票据上链

image.png

票据上链流程如上图所示:

  1. 调用KMS接口获取用户的公钥,该接口通过支付宝开放平台提供。
  2. 使用用户公钥加密数据,票面的敏感数据将会使用用户的公钥进行加密。
  3. 将加密后的数据上链,上链之后区块链会返回票据的hash,作为票据在链上唯一的ID

区块链票据sdk已经将上面的流程全部封装好,接入方只需要将相应参数配置好,就能够将票据上链。
接口说明

方法名 com.alipay.antinvoice.blockchain.medical.MxClient#uploadMedicalInvocie
入参 MedicalInvoiceInfo 票据主信息
EncryptMedicalInfo 待加密的票据信息
出参 Response 区块链上链结果
MedicalInvoiceInfo
invoiceProvince String 发票省份
hospitalCode String 医院编码
invoiceNo String 发票号码
invoiceCode String 发票代码
invoiceDate String 开票日期
invoiceType String 发票类型
idTypeCode String 证件类型编码
idHash String 证件号码HASH值
visitDateStart String 就诊日期起
visitDateEnd String 就诊日期止
visitNo String 就诊号/住院号
encryptContent String 加密内容

EncryptMedicalInfo
invoicePdfUrl String 发票PDF下载链接
idNo String 证件号
exeOrgCode String 执收单位编码
exeOrgName String 执收单位名称
name String 姓名
invoiceTotalAmount String 总费用
selfPayAmount String 自费金额
visitType String 就诊类型
insuranceTypeName String 社会医疗保险类型名称
visitDeptName String 就诊科室名称
visitDeptCode String 就诊科室编码
deptAdmissionToName String 入院科室名称
deptAdmissionToCode String 入院科室编码
deptDischargeFromName String 出院科室名称
deptDischargeFromCode String 出院科室编码
insuranceTypeCode String 社会医疗保险类型编码
dischargeDateTime String 出院日期
admissionDateTime String 入院日期
overalAmount String 统筹支付金额
thirdAmount String 第三方支付金额
feeExtendData FeeExtendData 费用扩展信息
feeDetailDataList List 费用明细记录(项目清单)住院清单没有
FeeDetailData
costCategoryCode String 医疗费用类别编码
costCategoryName String 医疗费用类别名称
itemCode String 收费项目编码
itemName String 收费项目名称
itemSpec String 项目规格
amount String 项目规格
costs String 应收费用
charges String 实收费用
insuranceItemType String 医保项目类型
insuranceRate String 医保报销比例
FeeExtendData
thirdAmountDetail Map<String, String> 第三方支付金额明细
overalAmountDetail Map<String, String> 统筹支付金额明细
selfAmountDetail Map<String, String> 自费金额明细

代码示例

   // 加载 客户端配置文件.
        Properties p = new Properties();
        p.load(newFileInputStream("/client-sdk/sdk.properties"));
        MxClient mxClient = newMxClient(p);

//用户身份证号
        String id = "6300001968072000000";
        //待加密的数据
        EncryptMedicalInfo encryptMedicalInfo = new EncryptMedicalInfo();
        encryptMedicalInfo.setInvoicePdfUrl(
            "https:xx");
        encryptMedicalInfo.setIdNo(id);
encryptMedicalInfo.setExeOrgCode("331000ZHS_QKL_10000002");
encryptMedicalInfo.setExeOrgName("台州中心医院");
        encryptMedicalInfo.setName("李明");
encryptMedicalInfo.setInvoiceTotalAmount("1000.00");
        encryptMedicalInfo.setSelfPayAmount("10.10");
encryptMedicalInfo.setVisitType("OUTPATIENT");
encryptMedicalInfo.setInsuranceTypeName("社保");
encryptMedicalInfo.setVisitDeptName("内科");

        FeeExtendData feeExtendData = newFeeExtendData();
        feeExtendData.getSelfAmountDetail().put("历年医保账户", "4124.13");
feeExtendData.getSelfAmountDetail().put("现金支付金额", "10.11");
encryptMedicalInfo.setFeeExtendData(feeExtendData);

        FeeDetailData feeDetailData = newFeeDetailData();
        feeDetailData.setItemName("中草药");
feeDetailData.setCosts("10.19");
        List<FeeDetailData>feeDetailDataList = new ArrayList<FeeDetailData>();
feeDetailDataList.add(feeDetailData);
encryptMedicalInfo.setFeeDetailDataList(feeDetailDataList);


        // 构造存证数据
        MedicalInvoiceInfomedicalInvoiceInfo = new MedicalInvoiceInfo();
medicalInvoiceInfo.setInvoiceNo("12345613");
medicalInvoiceInfo.setInvoiceCode("1097644325");
        medicalInvoiceInfo.setInvoiceType("FINANCIAL_ELECTRONIC_BILL");
        String date ="2018-10-06";
medicalInvoiceInfo.setInvoiceDate(date);
medicalInvoiceInfo.setInvoiceProvince("浙江");
medicalInvoiceInfo.setIdTypeCode("IDENTITY_CARD");
        medicalInvoiceInfo.setHospitalCode("100007629");
medicalInvoiceInfo.setIdHash(md5(id));
medicalInvoiceInfo.setVisitNo("331000ZHS_QKL_10000002-2018102412");
medicalInvoiceInfo.setVisitDateEnd(date);
medicalInvoiceInfo.setVisitDateStart(date);

 Response<TransactionDO> response =mxClient.uploadMedicalInvocie(medicalInvoiceInfo, encryptMedicalInfo);
        if (response.isSuccess()) {
            // 发送成功,业务系统保留 Transaction Hash 与业务数据关联
System.out.println(response.getData().getTxHashValue());
        } else {
            System.out.println(response);
        }

票据作废记录上链

票据作废是将已经上链的票据标记为作废的操作,当票据作废之后,开票方需要将票据作废的结果上链。
接口说明

方法名 com.alipay.antinvoice.blockchain.medical.MxClient#uploadInvalidRecord
入参 MedicalInvoiceInvalidRecord 作废记录
invoiceHash 关联的票据hash
出参 Response 区块链上链结果
MedicalInvoiceInvalidRecord
invoiceNo String 发票号码
invoiceCode String 发票代码
reason String 作废原因

代码示例

// 加载 客户端配置文件.
        Properties p = new Properties();
        p.load(newFileInputStream("/Users/hansong.xhs/Projects/Baas/client-sdk/sdk.properties"));
        MxClient mxClient = newMxClient(p);

        MedicalInvoiceInvalidRecordrecord = new MedicalInvoiceInvalidRecord();
        record.setInvoiceCode("10987644325");
record.setInvoiceNo("123456713");
        record.setReason("作废");
        String orderTxHash ="687dd9df8a41069a6cef40126640830471998a27be316d165237951932542e27";
        
        Response<TransactionDO>response = mxClient.uploadInvalidRecord(record, orderTxHash);
        if (response.isSuccess()) {
            // 发送成功,业务系统保留 Transaction Hash 与业务数据关联
System.out.println(response.getData().getTxHashValue());
        } else {
            System.out.println(response);
        }

票据报销记录上链

票据报销是由报销的单位例如保险公司在用户使用票据进行报销之后,将报销记录上链的操作。
接口说明

方法名 com.alipay.antinvoice.blockchain.medical.MxClient#uploadInvoiceReimburse
入参 MedicalInvoiceReimbursement 报销记录
invoiceHash 关联的票据hash
出参 Response 区块链上链结果
MedicalInvoiceReimbursement
invoiceCode String 发票代码
invoiceNo String 发票号码
insuranceCompany String 保险公司名称
reportNo String 报案号
reimbursementStatus String 报销状态
reimbursementAmount Integer 报销金额,可空

代码示例

     // 加载 客户端配置文件.
        Properties p = new Properties();
        p.load(newFileInputStream("/Users/hansong.xhs/Projects/Baas/client-sdk/sdk.properties"));
        MxClient mxClient = newMxClient(p);

        MedicalInvoiceReimbursementreimbursement = new MedicalInvoiceReimbursement();
reimbursement.setInvoiceNo("123456713");
reimbursement.setInvoiceCode("10987644325");
reimbursement.setReportNo("0987654321");
reimbursement.setInsuranceCompany("蚂蚁保险");
        reimbursement.setReimbursementStatus("EXPENSE_PROCESSING");
        String orderTxHash ="687dd9df8a41069a6cef40126640830471998a27be316d165237951932542e27";
        Response<TransactionDO>response = mxClient.uploadInvoiceReimburse(reimbursement, orderTxHash);
        if (response.isSuccess()) {
            // 发送成功,业务系统保留 Transaction Hash 与业务数据关联
System.out.println(response.getData().getTxHashValue());
        } else {
            System.out.println(response);
        }

onlineServer