近端时间,领导提了一个需求。说是微信中的发票管理下面带有二维码,通过扫描二维码就可以开票,省去了每次开票都要仔细的核对发票信息的麻烦。
领导要求我们自己的app中发票管理尽量向微信靠拢。 通过查找资料,了解了制作发票二维码的流程,特意在这里记录一下。
1. 国税局发布的制作二维码规范
国家税务总局办公厅关于采用二维码便捷纳税人开具增值税发票有关事项的通知
2. 自己的理解
根据上面的规范,明白需要把公司的信息(企业名称,纳税人识别号,注册地址,联系电话,开户行名称,开户行账号)等字符串整合成一个字符串。
格式如下:起始符 + 版本号 + base64(企业名称</>纳税人识别号</>注册地址联系电话</>开户行名称开户行账号</>CRC) + 结束符
- CRC是把(企业名称</>纳税人识别号</>注册地址联系电话</>开户行名称开户行账号</>)括号中的字符串生成一个验证码
- base64是把(企业名称</>纳税人识别号</>注册地址联系电话</>开户行名称开户行账号</>CRM验证码)这个字符串加密。
注意:开户行名称开户行账号 是在两个</>之间的一个字符串,但是需要在开户行名称和开户行账号中间加一个“|”的英文符号。注册地址联系电话 也是需要在中间添加“|”。这个规范中没写,但是必须添加的。不添加会在解析时当成一个字符串,而不是显示各自的信息。
在线验证网址:
3. 使用CRC验证的经验
根据上面的规范,CRM验证使用的是CRC-16算法,高位在前,低位在后。在通过对比,发现CRC-16/CCITT- FALSE 和 CRC16_XMODEM两个都满足。所以我就选择了使用CRC-16/CCITT- FALSE来生成验证码。
在IOS中我是使用的 喝小酒的网摘的文章中的C语言编写的方法。大概代码如下:
// 转码,返回的是unsigned short
unsigned short CRC16_CCITT_FALSE(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
return (wCRCin) ;
}
/// 需要把上面方法返回的unsign short 转化为二进制类型
+ (NSString *)getBinaryByDecimal:(NSInteger)decimal {
NSString *binary = @"";
while (decimal) {
binary = [[NSString stringWithFormat:@"%ld", decimal % 2] stringByAppendingString:binary];
if (decimal / 2 < 1) {
break;
}
decimal = decimal / 2 ;
}
if (binary.length % 4 != 0) {
NSMutableString *mStr = [[NSMutableString alloc]init];;
for (int i = 0; i < 4 - binary.length % 4; i++) {
[mStr appendString:@"0"];
}
binary = [mStr stringByAppendingString:binary];
}
return binary;
}
调用方法:
+ (NSString *)stringCRC16_CCITT_FALSEWithData:(NSData *)data dataLength:(NSInteger)dataLength {
unsigned short wcrcin = CRC16_CCITT_FALSE((Byte *)[data bytes], (int)dataLength);
//十进制转二进制
return [NSString getBinaryByDecimal:wcrcin];
}
4. base64加密。
base64加密这个网上都有,并且也有第三方的文件,原理我也不太明白。可以自己去网上搜索,这个比较常见。
5. 完成效果
生成二维码以后,需要使用微信公众号上的《国税发票助手》来验证,切记别用微信自己的,刚开始就犯了这个错误,微信是自己开发的,只能用微信的格式来扫描分享。
6. 总结
需要注意如下:
开户行名称开户行账号 两个信息中间一定要加“|”。
CRC生成验证时。我查资料JAVA使用的CRC-16验证方法生成的二进制编码跟C语言生成的不一样。因为测试的时候在线测试使用JAVA生成的二进制可以用,就一直纠结为什么不一样。不过使用C语言生成的通过测试也能用。