通知书上的号码组成规则如下:
名称 | 长度 | 例子 | 备注 |
区域码 | 2 | 01 | 区域编码 |
通知书类型 | 1 | 1 | 5 单位系统开具缴款通知书
|
年份码 | 2 | 05 | 两位年份码。开出通知书的年份。 |
序列号 | 8 | 00000001 | 自动递增的序列号。每一个单位(以用户所在实际单位为准,不限于顶级单位)都拥有一组独立的自增长序列号。 |
特征码 | 1 | 0 | 0 党政网非税系统
1 互联网非税系统 |
校验位 | 2 | 01 | 参考后面的计算法则 |
一个完整的通知书号码样例如下:
0111000000156006
校验位的计算法则如下:
A = ∑(ai×Wi)(mod 11)
A | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
校验位 | 01 | 00 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 |
其中:
i —-表示号码字符从右至左不包括校验码在内的位置序号;
ai—-表示第i位置上的号码字符值;
Wi—-表示第i位置上的加权因子,其数值依据公式Wi=2i mod 11计算得出。
例如:号码内容为0111000000156006
其中最后两位为校验位,现在要验证最后两位‘06’是否正确,可以进行如下变换处理。
i | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
ai | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 5 | 6 | 0 |
Wi | 5 | 8 | 4 | 2 | 1 | 6 | 3 | 7 | 9 | 10 | 5 | 8 | 4 | 2 |
ai×Wi | 0 | 8 | 4 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 40 | 24 | 2 |
根据公式可以得到校验位:
∑(ai×Wi) mod 11
=(0+8+4+2+0+0+0+0+0+0+5+40+24+0) mod 11
= 83 mod 11
= 6
查上表得到当A=‘6’时,校验位为‘06’,所以该号码0110100000015606是有效的。
C#代码实现如下:
/// <summary>
///根据14位通知书编码返回16位编码(14通知书编码+2效验码)
/// </summary>
/// <param name="keyCode"></param>
/// <returns></returns>
public static string getVerifcationCode(string keyCode)
{
if(string.IsNullOrEmpty(keyCode))
{
throw new Exception("参数keyCode的值为null或者为空");
}
if (!Regex.IsMatch(keyCode.Trim(),@"^\d{14}$"))
{
throw new Exception("参数keyCode的长度或者格式不符合约定");
}
string[] verCodeA = new string[] { "01", "00", "10", "09", "08", "07", "06", "05", "04", "03", "02"};
int len = keyCode.Trim().Length, sum = 0, ai = 0, wi = 0;
for (int i = 0; i < keyCode.Trim().Length; i++)
{
ai = int.Parse(keyCode[i].ToString());
wi = (int)(Math.Pow(2, len) % 11);
sum+=(ai*wi);
len--;
}
return keyCode + verCodeA[sum % 11];
}
Microsoft Sqlserver SQL脚本实现方式:
if exists(select * from sysobjects where type='fn' and name='NoTax_getVerCode')
begin
drop function NoTax_getVerCode
end
go
/*
计算通知书效验码并返回通知书+效验码
*/
CREATE FUNCTION NoTax_getVerCode(@keyword varchar(20))
RETURNS VARCHAR(50) AS
BEGIN
declare @verCodeA table(ide int,code varchar(4));
declare @index int,@wi int,@ai int,@sum int,@i int,@icdoe int;
select @index=14,@wi=0,@ai=0,@sum=0,@i=1,@icdoe=0;
if(len(@keyword)<>14)
begin
return '';
end
insert into @verCodeA(ide,code)
select 0,'01' union select 1,'00' union select 2,'10' union select 3,'09' union select 4,'08' union select 5,'07'
union select 6,'06' union select 7,'05' union select 8,'04' union select 9,'03' union select 10,'02'
while(@index>0)
begin
set @ai=substring(@keyword,@i,1);
set @wi=(power(2,@index))%11;
set @sum=@sum+(@ai*@wi);
set @index=@index-1;
set @i=@i+1;
end
set @icdoe=@sum%11;
select @keyword=@keyword+code from @verCodeA where ide=(@icdoe)
return @keyword;
END
/*
print dbo.NoTax_getVerCode('01517000000010')
print dbo.NoTax_getVerCode('01517000000020')
print dbo.NoTax_getVerCode('01517000000030')
print dbo.NoTax_getVerCode('01517000000040')
print dbo.NoTax_getVerCode('01517000000050')
*/
至此简单的使用C#和SQL脚本实现了效验码的计算。
转载请注明:清风亦平凡 » 深圳非税通知书与校验码