The EPCglobal tag data standards provides a calculation for the GTIN (global trade item number) check digit during SGTIN (serialized global trade item number) decoding. However, this algorithm although mathematically correct does not work computationally due to different methods of handling modulus for negative numbers.
The tag data standards document defines the calculation for the GTIN check digit as:
d14 = (-3(d1 + d3 + d5 + d7 + d9 + d11 + d13) - (d2 + d4 + d6 + d8 + d10 + d12)) mod 10
The algorithm in the tag data standards document will always lead to calculating the modulus of a negative. Therefore, the check digit will usually be incorrect. For example, -57 mod 10 should mathematically be 3 not -7 as calculated by the .NET Framework and CALC.EXE for that matter (Microsoft Excel returns 3.)
But, taking into account the complication from calculating modulus on negative numbers, as well as factoring in UCC-12, EAN/UCC-13, and EAN/UCC-14 GTIN formats you get a slightly more complex algorithm that the following helper class illustrates. This helper class leverages the EPC expansion pack for the GlobeRanger iMotion EdgeWare platform in order to parse either the 64-bit or 96-bit SGTIN values. You could also substitute your own parsing algorithm.
Imports:
using System;
using Globeranger.Core.Epc.Encoding;
using Globeranger.Core.Epc.Encoding.Sgtin;
Class:
public class GtinResolver
{
public static string CheckDigitFromGtin(string gtin)
{
switch (gtin.Length)
{
case 11: // UCC-12 format
return CheckDigitFromGtin12(gtin);
case 12: // UCC-13 format
return CheckDigitFromGtin13(gtin);
case 13: // UCC-14 format
return CheckDigitFromGtin14(gtin);
default:
throw new NotSupportedException("Unsupported GTIN format");
}
}
private static string CheckDigitFromGtin12(string gtin)
{
int[] digits = ToIntArray(gtin);
int checkValue = 10 - ((((digits[0] + digits[2] + digits[4] + digits[6]
+ digits[8] + digits[10]) * 3) + (digits[1] + digits[3] + digits[5]
+ digits[7] + digits[9])) % 10);
return checkValue.ToString();
}
private static string CheckDigitFromGtin13(string gtin)
{
int[] digits = ToIntArray(gtin);
int checkValue = 10 - (((digits[1] + digits[3] + digits[5] + digits[7]
+ digits[9] + digits[11]) * 3 + (digits[0] + digits[2]
+ digits[4] + digits[6] + digits[8] + digits[10])) % 10);
return checkValue.ToString();
}
private static string CheckDigitFromGtin14(string gtin)
{
int[] digits = ToIntArray(gtin);
int checkValue = 10 - ((((digits[0] + digits[2] + digits[4] + digits[6]
+ digits[8] + digits[10] + digits[12]) * 3)
+ (digits[1] + digits[3] + digits[5] + digits[7] + digits[9]
+ digits[11])) % 10);
return checkValue.ToString();
}
public static string FromEncodedSgtin64Urn(string urn, string companyPrefix)
{
Sgtin64BitPayload payload = new Sgtin64BitPayload(urn);
string gtin = payload.ItemReference.Substring(0, 1)
+ companyPrefix + payload.ItemReference.Substring(1);
string checkDigit = CheckDigitFromGtin(gtin);
return gtin + checkDigit;
}
public static string FromEncodedSgtin96Urn(string urn)
{
Sgtin96BitPayload payload = new Sgtin96BitPayload(urn);
string gtin = payload.ItemReference.Substring(0, 1)
+ payload.CompanyPrefix + payload.ItemReference.Substring(1);
string checkDigit = CheckDigitFromGtin(gtin);
return gtin + checkDigit;
}
private static int[] ToIntArray(string value)
{
int[] digits = new int[value.Length];
for (int i = 0; i < digits.Length; i++)
{
digits[i] = int.Parse(value.Substring(i, 1));
}
return digits;
}
}