为方便公司开票人员准确快速的开票,通过两周的研究,码出此工具。
(试用下载地址https://download.csdn.net/download/super_farmers/12264989)
在此写下实现过程:



整个软件分为:
1.扫描二维码
手机扫描二维码使用DroidCam软件实现,DroidCam可以把手机做为二维码采集设备(由于机动车二维码的复杂性,手机摄像头像素越高越好);
首先在安装DroidCam软件的电脑端:

DroidCam可以使用wifi/usb两种方式连接手机,本文中使用wifi连接方式(方便);
接着安装手机端:

手机端安装好以后可以在电脑端输入手机端显示的IP地址,测试连接是否正常
在程序中使用下面代码读取摄像头列表会得到:DroidCam字串开头的四个设备,除编号为3的设备,其它均可使用。

    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();foreach (const QCameraInfo &cameraInfo, cameras) {ui->Camera_List->addItem(cameraInfo.description());}
获取到设备以后,显示视频及截图代码:
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();foreach (const QCameraInfo &cameraInfo, cameras) {if (cameraInfo.description() == ui->Camera_List->currentText()){// 摄像头实例m_Camera = new QCamera(cameraInfo);// 模式、视频采集器m_Camera->setCaptureMode(QCamera::CaptureStillImage);m_Camera->setViewfinder(m_ViewFinder);// 开始获取视频m_Camera->start();// 定时器定时截图 m_ImageCapture->capture(QDir::currentPath() + "/code");m_Timer->start(2000);// 截图m_ImageCapture = new QCameraImageCapture(m_Camera);m_ImageCapture->setCaptureDestination(QCameraImageCapture::CaptureToFile);// 由slot_imageSaved槽处理截取的图像connect(m_ImageCapture, SIGNAL(imageSaved(int,QString)), this, SLOT(slot_imageSaved(int,QString)));}}
至此扫码功能实现完成。

2.识别二维码
Qt识别二维码有QZxing库(),经测试,这个库对机动车二维码无能为力,最终选择一个商业二维码识别控件PsyQrDcd这个要注册授权的,不然识别出只有"AAAAA…"(http://www.psytec.co.jp/),这个识别率很高,速度也非常快。在这一步由于使用第三方库,没什么好说的,使用函数DecodePictureFile设置二维码文件路径,GetDecodeData函数读取结果。
3.数据解密
这一步是本软件最核心的一步,因防伪等各种原因,二维码读取到的内容为des加密后base64编码的一串文本。解码不了数据,一切白搭。这里可以调用大神做的接口,没有解密能力的可以参考(https://vehcode.scznnet.cn:449/QRcodeDoc.html#15614)。调用接口需要编译了openssl的Qt版本,因为接口是https协议的,我之前编译的Qt没有openssl,重新编译了下QT(好崩溃,需要静态编译的同学编译openssl一定不要加–debug选项,不然你得重编译);数据解密后得到64个字段,开具发票只用到其中10个字段(生产企业名称|车辆类型|车辆型号|产地|合格证号|发动机号码|车辆识别号VIN|吨位|限乘人数|车辆名称),其中车辆类型对应开票系统中产品分类名称,用此名称从产品分类名称中获取分类编码,这个分类编译在生成发票的时候要用。
4.生成发票
依照《增值税发票税控开票软件数据接口规范3.0》中描述的机动车发票导入接口生成XML文档,模板如下:

<?xml version="1.0" encoding="gbk"?>
<business><body><djh>djh</djh>                      //单据号(30字符)<bmb_bbh>bmb_bbh</bmb_bbh>             //编码表版本号(20个字符)<fpdm>fpdm</fpdm>                  //发票代码(10个字符)<fphm>fphm</fphm>                    //发票号码(8个字符)<gfdwmc>gfdwmc</gfdwmc>           //购方单位名称(72个字符)<sfzhm>sfzhm</sfzhm>               //身份证号码/组织机构代码(22个字符)<gfdwsbh>gfdwsbh</gfdwsbh>           //购方单位识别号(20个字符)<cllx>cllx</cllx>                 //车辆类型(40个字符)<cpxh>cpxh</cpxh>                    //厂牌型号(60个字符)<cd>cd</cd>                          //产地(32个字符)<hgzh>hgzs</hgzh>                  //合格证书(50个字符)<jkzmsh>jkzmsh</jkzmsh>          //进口证明书号(36个字符)<sjdh>sjdh</sjdh>                  //商检单号(32个字符)<fdjhm>fdjhm</fdjhm>             //发动机号码(60个字符)<clsbdh>clsbdh</clsbdh>             //车辆识别代号(23个字符)<scqymc>scqymc</scqymc>            //生产企业名称(80个字符)<jshj>jshj</jshj>                  //价税合计<dh>dh</dh>                           //电话(40个字符)<zh>zh</zh>                        //账号(40个字符)<dz>dz</dz>                        //地址(80个字符)<khyh>khyh</khyh>                  //开户银行(80个字符)<zzssl>zzssl</zzssl>             //增值税税率(实际税率)<zzsse>zzsse</zzsse>             //增值税税额<bhsj>bhsj</bhsj>                    //不含税价<dw>dw</dw>                           //吨位(8个字符)<xcrs>xcrs</xcrs>                   //限乘人数(12个字符)<spbm> spbm</spbm>                   //商品编码(19个字符)<zxbm>zxbm </zxbm>                   //自行编码(20个字符)<yhzcbs>yhzcbs</yhzcbs>              //优惠政策标识(1个字符)  0:不使用,1:使用<lslbs>lslbs</lslbs>               //税率标识空(1个字符):非零税率,0:出口退税,1:免税,2:不征收,3普通零税率<zzstsgl>zzstsgl</zzstsgl>         //增值税特殊管理(50个字符)</body>
</business>
单据号可自定义;编码版本为税收分类编码的版本号,可以在最新税收分类编码文档中获取,发票代码,发票号码留空,增值税税率(13% 要填入 0.13)
这里有个小写金额转大写的功能,,自行实现耗时一下午(开始想的太简单了)只实现 了最大千亿的转换(应该够了吧),代码奉上:
QString Invoice::AmountsConverted(double amount)
{QStringList cnNumber = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};// 拆分整数与小数部分QString strAmount, strInteger, strDecimal;  // 金额字符串, 整数部分, 小数部分strAmount.setNum(amount, 'f', 2);strInteger = strAmount.split('.').at(0);strDecimal = strAmount.split('.').at(1);QStringList strlInteger, strlDecimal;strlInteger = strInteger.split("");strlInteger.removeFirst(); strlInteger.removeLast();    //移除首尾空值strlDecimal = strDecimal.split("");strlDecimal.removeFirst(); strlDecimal.removeLast();    //移除首尾空值// 构建汉字列表QStringList strlCnInteger, strlCnDecimal;foreach (QString str, strlInteger) {strlCnInteger << cnNumber.at(str.toInt());}foreach (QString str, strlDecimal) {strlCnDecimal << cnNumber.at(str.toInt());}// 整数部分添加单位int nCount = strlInteger.size() - 1;     // 总共多少位bool yflag = false, sflag = false, bflag = false, qflag = false, wflag = false;int nStep = 0;for(int i = nCount; i >= 0; i--){switch (nStep++){case 0:         // 元if (strlInteger.at(i) == "0") strlCnInteger.removeAt(i);elseyflag = true;break;case 1:         // 拾if (strlInteger.at(i) == "0"){if (!yflag)strlCnInteger.removeAt(i);}else if (strlInteger.at(i) != "0")strlCnInteger.insert(i + 1, "拾"), sflag = true;break;case 2:         // 百if (strlInteger.at(i) == "0"){if (!yflag && !sflag)strlCnInteger.removeAt(i);if (yflag && !sflag)strlCnInteger.removeAt(i);}else if (strlInteger.at(i) != "0")strlCnInteger.insert(i + 1, "佰"), bflag = true;break;case 3:         // 仟if (strlInteger.at(i) == "0"){if (!yflag && !sflag && !bflag)strlCnInteger.removeAt(i);if ((yflag || sflag) && !bflag)strlCnInteger.removeAt(i);}else if (strlInteger.at(i) != "0")strlCnInteger.insert(i + 1, "仟"), qflag = true;break;case 4:         // 万if (!wflag){if (strlInteger.at(i) == "0"){if (!qflag)strlCnInteger.removeAt(i);strlCnInteger.insert(i, "万");yflag = false;wflag = true;}elsestrlCnInteger.insert(i + 1, "万"), yflag = true, wflag = true;}else        // 亿{if (strlInteger.at(i) == "0"){strlCnInteger.removeAt(i);strlCnInteger.insert(i, "亿");yflag = false;}elsestrlCnInteger.insert(i + 1, "亿"), yflag = true;}nStep = 1; sflag = bflag = qflag = false;break;}}// 小数部分添加单位// 分if (strlDecimal.at(1) == "0"){strlCnDecimal.removeAt(1);}else{strlCnDecimal.insert(2, "分");}// 角if (strlDecimal.at(0) == "0"){if (strlDecimal.at(1) == "0")strlCnDecimal.removeAt(0);}else{strlCnDecimal.insert(1, "角");}QString result = strlCnInteger.join("") + "圆" + strlCnDecimal.join("") + "整";return result;
}

5.开票导入:
这里没什么说的,生成发票XML后,在开票界面导入就成。

X.openssl des加解密的学习:
在openssl中以evp模式使用des等加解密方便快捷,但一定要注意数据类型的转换,简要代码如下:

// 生成key及iv  len为返回key的长度,
int len = EVP_BytesToKey(/*方式*/, /*hex*/, NULL, /*密钥*/, /*密钥长度*/, /*强度*/, key, iv);
// ctx上下文结构申请内存 (在构造函数中)
m_evp_ctx = EVP_CIPHER_CTX_new();// 加解密过程// 释放dtx上下文结构内存 (在析构函数中)
EVP_CIPHER_CTX_free(m_evp_ctx);
// 加密
QString Common::des_EnCrypto(QString Text)
{QByteArray bText = Text.toUtf8();unsigned char *inText = (unsigned char*)bText.data();int inTextLen = bText.length();unsigned char *outText = (unsigned char*)malloc(inTextLen + 8);int outLen, outFinalLent, outTotalLen;EVP_CIPHER_CTX_reset(m_evp_ctx);int ret = EVP_EncryptInit(m_evp_ctx, EVP_des_cbc(), m_des_key, m_des_iv);if (ret != 1){EVP_CIPHER_CTX_reset(m_evp_ctx);return QString();}ret = EVP_EncryptUpdate(m_evp_ctx, outText, &outLen, inText, inTextLen);if (ret != 1){EVP_CIPHER_CTX_reset(m_evp_ctx);return QString();}else{EVP_EncryptFinal(m_evp_ctx, outText + outLen, &outFinalLent);outTotalLen = outLen + outFinalLent;}EVP_CIPHER_CTX_reset(m_evp_ctx);return QString::fromUtf8(QByteArray((char*)outText, outTotalLen).toHex());
}
// 解密
QString Common::des_DeCrypto(QString Text)
{QByteArray bText = QByteArray::fromHex(Text.toUtf8());unsigned char *inText = (unsigned char*)bText.data();int inTextLen = bText.length();unsigned char *outText = (unsigned char*)malloc(inTextLen + 8);int outLen, outFinalLent, outTotalLen;EVP_CIPHER_CTX_reset(m_evp_ctx);int ret = EVP_DecryptInit(m_evp_ctx, EVP_des_cbc(), m_des_key, m_des_iv);if (ret != 1){EVP_CIPHER_CTX_reset(m_evp_ctx);return QString();}ret = EVP_DecryptUpdate(m_evp_ctx, outText, &outLen, inText, inTextLen);if (ret != 1){EVP_CIPHER_CTX_reset(m_evp_ctx);return QString();}else{EVP_DecryptFinal(m_evp_ctx, outText + outLen, &outFinalLent);outTotalLen = outLen + outFinalLent;}EVP_CIPHER_CTX_reset(m_evp_ctx);return QString::fromUtf8((char*)outText, outTotalLen);
}

机动车合格证手机扫码开票实现方式相关推荐

  1. java实现手机扫码登录客户端

    为什么手机登录记住密码后不用再次登录        在了解扫码登录之前我们先了解一下其他内容, 首先为了安全,手机端它是不会存储你的登录密码的.但是在日常使用过程中,我们应该会注意到,只有在你的应用下 ...

  2. 手机扫码登录实现原理

    最近接到一个需求,要求用手机扫码实现用户登录,这是近几年比较流行的登录方式.这样确实是实现用户体验至上,操作简单,方便实用.拿到需求之后,我与后端大哥商量后,敲定了具体的实施方案.其实重要的还是要弄懂 ...

  3. 刷脸支付不需要掏手机扫码很是方便

    "不需要掏手机扫码,很是方便."该超市收银员表示,顾客对刷脸支付非常感兴趣,一是觉得新鲜,二是觉得方便快捷,前后只需要几秒钟就能搞定.记者了解到,目前在中心城区部分超市中推广使用的 ...

  4. 手机扫码报修系统有哪些功能?

    概述: 什么是扫码报修系统,有哪些优势呢? 扫码报修系统是指单位员工遇到故障后使用手机扫码完成的故障提交,区别于其他故障报修软件,无需注册登录,下载安装,这也是这两年主流的故障报修系统. 业务场景: ...

  5. IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

    本文原文由作者Amazing10原创发布于公众号业余码农,收录时有改动,感谢原作者的技术分享. 1.引言 某天中午,吃完午饭,摊在自己的躺椅上,想趁吃饱喝足的午后时间静静享受独自的静谧. 干点什么好呢 ...

  6. 手机扫码登陆网页的原理实现

    微信,淘宝等许多应用通过手机扫码登陆,是如何实现的? 这里以微信页面为例: 浏览器请求微信服务端,微信的server端返回给浏览器一个唯一的UID,前端将其封装到一个二维码中,并且发一个长链接请求携带 ...

  7. 手机扫码传文件免安装免流工具教程

    手机免安装0流量传输文件必备神器扫二维码即可传送文件,只要有一个手机有这软件就能传,软件可以传送视频软件文档音乐还有其他文件如压缩包等等,非常方便实用! 视频教程: 手机免安装0流量扫码传文件神器实际 ...

  8. 实现手机扫码直接拨打电话

    1,需求 二维码的出现方便了人们对信息的查询.简单扫一扫二维码就能访问网站.收付款.查阅服务信息等.但能否实现扫码就能拨打电话呢?如果可以的话,在名片上打印一个二维码岂不是更方便了?还有,在某些服务场 ...

  9. 微信小程序上传后 进行性手机扫码阅览 发现白屏的解决

    目录 问题: 微信小程序上传后 进行性手机扫码阅览 发现白屏的解决 1.上传时没有勾选保护 2.请求的域名没有配置 问题: 微信小程序上传后 进行性手机扫码阅览 发现白屏的解决 1.上传时没有勾选保护 ...

  10. 微信开发之扫码开票解决方案

    微信开发之扫码开票提供两种解决方案 微信公众号方案 通过扫码获取二维码中的参数,然后通过微信自建平台扫码,设置参数,获取授权页面,申请开票,调用中间开票系统进行开票,然后插入微信卡包,支持在线预览,支 ...

最新文章

  1. python之内置函数
  2. GPUImage滤镜中的shader代码分析,及自定义滤镜
  3. 单片机烧录软件编写_单片机技术系列之一:单片机概述
  4. python中align_Python中如何自动化对齐?
  5. python中xrange和range的区别
  6. CRM的使用是讲究技巧的
  7. 阿里云 API 签名机制的 Python 实现
  8. moocpython123输入若干数、每行输入一个数值作业_MOOC嵩天@python123作业
  9. unity3d android 实时阴影,Unity移动端实时阴影绘制
  10. 服务器响应submit,任务操作:submitJob (REST)
  11. 微博java版_新浪微博JAVA通用版
  12. 【python】Windows系统中python解释器下载及安装过程
  13. java实现NC数据等值线等值面可视化
  14. 【Matlab学习笔记】数据拟合polyfit与polyval
  15. 易语言mysql 记录集_求一个易语言返回mysqlcha询结果记录集的例子
  16. Win11应用商店打不开怎么办?
  17. # UDIG配图(sld)
  18. 【HTTP】HTPP学习笔记
  19. 聚观早报 | 苏宁易购入驻美团外卖;今日头条接入抖音电商
  20. weblogic子服务器显示状态RESUMING,长期等待状态

热门文章

  1. kafka consumer 如何设置每次重启时从最新数据开始读取
  2. win10一直正在检查更新_受够了WIN10自动更新?阿虚教你一键禁止!
  3. 在线图片文字识别html,识别文字在线_识别图片文字的在线方法是什么?
  4. 图片自适应手机屏幕大小
  5. 来自H3C的降维打击:H3C BX54鲸路由评测体验
  6. GhostXP_SP3雨林木风纯净版Y7.0(09年12月更新版) 【雪豹】
  7. 黑苹果Mac OS 12镜像下载 DMG
  8. Retrofit基本使用
  9. 搭建Ubuntu虚拟机
  10. 【BFS】Oliver的救援