Quante volte vi hanno chiesto: Come possiamo stampare il codice a barre sui prodotti che vendiamo ?
In merito ai criteri della codifica a barre trovo spesso molte idee ben confuse ed è per questo che cercherò di fare un po' di chiarezza sull'argomento.
Il principio della codifica a barre è di contrassegnare i prodotti con un simbolo che può essere interpretato da un lettore ottico e decodificato in un codice univoco che viene utilizzato come chiave per reperire tutte le informazioni anagrafiche relative al prodotto e necessarie per la stampa di uno scontrino o l'allestimento di una packing list.
L'unità consumatore rappresenta la ‘porzione' di prodotto che può essere acquistata separatamente dal consumatore. Il termine GTIN (Global Trade Item Number) indica il codice UCC/EAN assegnato alle unità consumatore, unità imballo (trade unit) o unità logistiche ossia a tutte le unità commerciali sulle quali è possibile recuperare informazioni predefinite.
La normativa che regola l'assegnazione dei codici prevede vengano rispettati i seguenti punti:
- A tutti i numeri di codice deve essere fatto precedere il prefisso nazionale EAN
- La codifica deve essere esclusivamente numerica e deve rispettare la struttura internazionale EAN
- Le norme adottate devono garantire che due prodotti diversi abbiano due codici diversi
- La codifica è intesa a costituire unicamente un'identificazione e non una classificazione dei prodotti
- La codifica di un prodotto è un fatto puramente tecnico e non deve essere oggetto di negoziazione
Chi è, quindi, responsabile della codifica delle unità consumatore ?
L'assegnazione e l'applicazione del codice compete a chi effettivamente immette sul mercato un prodotto con il proprio nome o marchio e ne stabilisce quindi la confezione e l'etichettatura. La codifica delle unità consumatore è quindi a carico di:
- Un produttore se fabbrica o fa fabbricare all'estero o in Italia il prodotto e lo commercializza sotto un marchio che gli appartiene
- Un esercente, un importatore oppure un grossista se fa fabbricare all'estero o in Italia il prodotto e lo commercializza con un marchio che gli appartiene
- Un distributore se fa fabbricare all'estero o in Italia il prodotto e lo commercializza con un marchio che gli appartiene
Le società multinazionali posso scegliere:
- La codifica centralizzata che prevede sia la casa madre a codificare tutti i prodotti della società secondo le norme UCC/EAN del paese in cui risiede
- La codifica decentrata che prevede l'associazione di ciascuna sede o business unit all'Istituto situato nel rispettivo paese dove provvede a codificare la propria gamma di prodotti
Dopo aver definito cosa s'intende per unità consumatore, passiamo ad illustrare il metodo di codifica UCC/EAN-13 applicato alle unità consumatore a peso fisso.
Il codice a barre UCC/EAN-13 è la rappresentazione grafica di un codice numerico composto da 13 cifre (ognuna compresa tra 0 e 9) ed avente una struttura fissa ben definita. Il codice a barre UCC/EAN-13 consente il riconoscimento dei prodotti a peso fisso destinati al consumatore, non contiene informazioni specifiche come il prezzo, la descrizione o l'unità di misura, ma rappresenta una chiave univoca per interrogare l'anagrafica prodotti del sistema informativo.
La codifica UCC/EAN-13 permette di identificare la nazione, la società proprietaria del marchio ed il prodotto secondo la struttura generale descritta di seguito (fonte: INDICOD-ECR):

dove:
Il Prefisso EAN Nazionale è attribuito da GS1 alle organizzazioni nazionali di codifica (in Italia INDICOD-ECR). I prefissi di pertinenza di INDICOD-ECR e quindi delle organizzazioni Italiane sono da 80 a 83.
Il Codice Proprietario del Marchio è assegnato da INDICOD-ECR ai suoi associati. Questo codice, preceduto dal prefisso EAN Nazionale, permette di identificare in modo univoco un'organizzazione (associata) senza possibilità di equivoco a livello internazionale. Il concatenamento dei due codici rappresenta quindi il prefisso EAN Aziendale.
Il Codice Prodotto rappresenta un insieme di 1000 numeri (da 000 a 999) che l'azienda può utilizzare per identificare i sui prodotti. Per l'assegnazione del codice prodotto si consiglia di utilizzare un progressivo seriale evitando accuratamente qualsiasi intento di classificazione dei prodotti che preveda assegnazione di significati precisi alle varie posizioni delle tre cifre che compongono il codice del prodotto stesso. Qualora il range rappresentato dalle 1000 referenze non sia sufficiente a coprire l'intera gamma di prodotti commercializzati dall'organizzazione, si dovrà richiedere ad INDICOD-ECR (per l'Italia) l'assegnazione di un codice proprietario del marchio di quattro o cinque cifre in modo da poter aumentare il numero di cifre destinate alla codifica dei prodotti.
La Cifra di Controllo è calcolata in funzione delle altre dodici cifre presenti nel codice e ha il compito di garantire che la rappresentazione grafica (codice a barre) sia interpretata correttamente dal lettore ottico.
Dopo un po' di teoria, vediamo in pratica come di può realizzare una procedura operativa di generazione dei codici UCC/EAN-13 da applicare alle unità consumatore GTIN.
Riprendo la struttura generale della funzione UDF_GetCheckDigitSSCC() e della stored procedure USP_GetCodeSSCC() definite nel precedente post in cui si è parlato
dell'etichetta logistica (SSCC). Il codice T-SQL è stato generalizzato e adeguato alla necessità di generare, oltre ai codici SSCC, anche codici UCC/EAN-13 (GTIN-13).
La funzione UDF_GetCheckDigitSSCC() diventerà UDF_GetCheckDigitUCCEAN(), analogamente la stored procedure USP_GetCodeSSCC() diventerà USP_GetCodeUCCEAN().
1. Definizione della tabella CountUCCEAN utilizzata per memorizzare l'ultimo progressivo seriale generato.
-- Drop table DBO.CountUCCEAN
IF OBJECT_ID('CountUCCEAN', 'U') IS NOT NULL
DROP TABLE DBO.CountUCCEAN
GO
-- Create table dbo.CountUCCEAN
CREATE TABLE dbo.CountUCCEAN
(ID INT IDENTITY(1, 1) NOT NULL,
CODICE VARCHAR(4) NOT NULL,
DESCR VARCHAR(40) NOT NULL,
VALMIN INT NOT NULL,
VALMAX INT NOT NULL,
VALORE INT NOT NULL)
GO
-- Creazione indice cluster sul campo dbo.CountUCCEAN.Codice
CREATE UNIQUE CLUSTERED INDEX IDX__CountUCCEAN_Codice ON dbo.CountUCCEAN
(CODICE DESC) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/* Creazione indice Non-Cluster sul campo dbo.CountUCCEAN.ID */
CREATE NONCLUSTERED INDEX [IDX__CountUCCEAN_ID] ON [DBO].[CountUCCEAN]
(ID ASC) ON [PRIMARY]
GO
/* Creazione della chiave primaria sulla tabella dbo.CountUCCEAN */
ALTER TABLE [dbo].[CountUCCEAN] ADD CONSTRAINT PK__CountUCCEAN_ID PRIMARY KEY(ID)
2. Procedo con la creazione della stored procedure USP_GetErrorInfo() che ci permetterà di reperire informazioni sugli eventuali errori.
-- Drop procedure DBO.USP_GetErrorInfo
IF OBJECT_ID('USP_GetErrorInfo', 'P') IS NOT NULL
DROP PROCEDURE DBO.USP_GetErrorInfo
GO
-- Create procedure per la restituzione del tipo di errore
CREATE PROCEDURE USP_GetErrorInfo
AS
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_LINE () AS ErrorLine,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_MESSAGE() AS ErrorMessage
3. Definizione della funzione UDF_GetCheckDigitUCCEAN() utilizzata per determinare la cifra di controllo e della stored procedure USP_GetCodeUCCEAN():
-- Drop function DBO.UDF_GetCheckDigitUCCEAN
IF OBJECT_ID('UDF_GetCheckDigitUCCEAN', 'FN') IS NOT NULL
DROP FUNCTION DBO.UDF_GetCheckDigitUCCEAN
GO
-- Create function dbo.UDF_GetCheckDigitUCCEAN
CREATE FUNCTION dbo.UDF_GetCheckDigitUCCEAN
(@Codice AS VARCHAR(18)) RETURNS SMALLINT
AS BEGIN
/*
Algoritmo per il calcolo della cifra di controllo:
1. Addizionare le cifre in posizione pari
2. Moltiplicare il risultato per 3
3. Addizionare le cifre in posizione dispari
4. Sommare il risultato dei punti 2. e 3.
5. Sottrarre il risultato del punto 4. dal multiplo di 10 superiore
*/
DECLARE @tmpCodice AS VARCHAR(17),
@tmpMulSup AS VARCHAR(8000),
@tmp AS VARCHAR(8000),
@i AS INT,
@j AS INT,
@z AS INT,
@SumCPari AS INT,
@SumCDispari AS INT,
@Lista AS VARCHAR(8000),
@tmpLista AS VARCHAR(8000),
@CheckSum AS SMALLINT
SET @SumCPari = 0
SET @SumCDispari = 0
SET @Lista = ''
SET @tmpLista = ''
SET @tmp = ''
SET @tmpCodice = @Codice
/* 0. Costruzione lista per numerazione */
SET @j = LEN(@tmpCodice) + 1 -- Viene sommato 1 per la posizione della cifra di controllo
SET @i = 1
WHILE (@i <= LEN(@tmpCodice))
BEGIN
SET @Lista = @Lista + '|' + LTRIM(RTRIM(STR(@j))) + ';' + SUBSTRING(@tmpCodice, @i, 1)
--P^.Pos := j;
--P^.C := tmpCodice
;
--Lista.Add(P);
SET @j = (@j - 1)
SET @i = (@i + 1)
END
/* 1. Addizionare le cifre pari */
SET @i = 1
SET @tmpLista = @Lista
--WHILE (@i <= LEN(tmpCodice))
WHILE (CHARINDEX('|', @tmpLista) > 0)
BEGIN
SET @j = CHARINDEX('|', @tmpLista)
SET @z = CHARINDEX(';', @tmpLista)
IF (CAST(SUBSTRING(@tmpLista, (@j + 1), (@z - (@j + 1))) AS INTEGER) % 2) = 0
BEGIN
SET @SumCPari = @SumCPari + CAST(SUBSTRING(@tmpLista, (@z + 1), 1) AS INTEGER)
END
SET @tmpLista = SUBSTRING(@tmpLista, (@z + 2), LEN(@tmpLista))
END
/* 2. Moltiplicare il risultato per 3 (risultato del punto 1) */
SET @SumCPari = (@SumCPari * 3)
/* 3. Addizionare le cifre dispari */
SET @i = 1
SET @tmpLista = @Lista
--WHILE (@i <= LEN(tmpCodice))
WHILE (CHARINDEX('|', @tmpLista) > 0)
BEGIN
SET @j = CHARINDEX('|', @tmpLista)
SET @z = CHARINDEX(';', @tmpLista)
IF (CAST(SUBSTRING(@tmpLista, (@j + 1), (@z - (@j + 1))) AS INTEGER) % 2) <> 0
BEGIN
SET @SumCDispari = @SumCDispari + CAST(SUBSTRING(@tmpLista, (@z + 1), 1) AS INTEGER)
END
SET @tmpLista = SUBSTRING(@tmpLista, (@z + 2), LEN(@tmpLista))
END
/* 4. Sommare SumCPari con SumCDispari */
SET @CheckSum = (@SumCPari + @SumCDispari)
/* 5. Sottrarre il risultato della 4 operazione dal multiplo di 10 superiore
(Se la 4 operazione da come risultato un multiplo di 10, la cifra di
controllo è uguale a ZERO)
*/
IF ((@CheckSum % 10) = 0)
BEGIN
-- Cifra di controllo uguale a ZERO
SET @CheckSum = 0
END
ELSE BEGIN
SET @tmpMulSup = LTRIM(RTRIM(STR(@CheckSum)))
SET @i = 1
WHILE @i <= (LEN(@tmpMulSup) - 1)
BEGIN
SET @tmp = @tmp + SUBSTRING(@tmpMulSup, @i, 1)
IF (@i = LEN(@tmpMulSup) - 1)
BEGIN
SET @tmp = LTRIM(RTRIM(STR(CAST(@tmp AS INTEGER) + 1)))
SET @tmp = @tmp + '0'
END
SET @i = (@i + 1)
END
SET @CheckSum = CAST(@tmp AS INTEGER) - @CheckSum
END
RETURN @CheckSum
END
GO
-- Drop dbo.USP_GetCodeUCCEAN
IF (OBJECT_ID('USP_GetCodeUCCEAN', 'P') IS NOT NULL)
DROP PROCEDURE dbo.USP_GetCodeUCCEAN
GO
-- Create dbo.USP_GetCodeUCCEAN
CREATE PROCEDURE dbo.USP_GetCodeUCCEAN
(@CifraEstensione SMALLINT,
@EANAziendale VARCHAR(9),
@IsUCC12 AS SMALLINT,
@TypeEANUCC AS VARCHAR(4),
@UCCEAN AS VARCHAR(18) OUTPUT)
AS BEGIN
/*
Generazione del codice UCC/EAN per le seguenti codifiche:
1. SSCC - Serial Shipping Container Code (UCC/EAN-128)
Il parametro @TypeEANUCC deve essere impostato a 'SSCC'
2. GTIN - Global Trade Item Number (UCC/EAN-13)
Il parametro @TypeEANUCC deve essere impostato a 'EU13'
Il codice SSCC restituito dalla stored procedure è composto da:
1. Cifra di estensione: compresa tra 0 e 9, la cifra di estensione è utilizzata per aumentare la capacità
dell'SSCC è a discrezione dell'azienda che lo attribuisce
2. Prefisso EAN aziendale
3. Codice sequenziale
4. Cifra di controllo
Il codice GTIN restituito dalla stored procedure è composto da:
2. Prefisso EAN aziendale
3. Codice prodotto
4. Cifra di controllo
*/
DECLARE @MAXVALUE INT,
@FILLNUMBER INT,
@MSG VARCHAR(512)
SET @UCCEAN = ''
BEGIN TRANSACTION
BEGIN TRY
IF (@TypeEANUCC = 'SSCC')
BEGIN
/*
1. Cifra di estensione
E' compresa tra 0 e 9, viene utilizzata per aumentare la capacità
dell'SSCC è a discrezione dell'azienda che lo attribuisce
*/
IF (@CifraEstensione < 0) OR
(@CifraEstensione > 9)
BEGIN
SET @UCCEAN = ''
SET @MSG = 'Cifra di estensione (' + LTRIM(RTRIM(STR(@CifraEstensione))) + ') errata. La cifra di estensione deve essere compresa tra 0 e 9'
RAISERROR(@MSG, 11, 1)
END
ELSE
SET @UCCEAN = LTRIM(RTRIM(STR(@CifraEstensione)))
END
/*
2. Prefisso EAN aziendale
*/
IF (@IsUCC12 = -1)
BEGIN
/*
Se il codice da generare è di tipo UCC-12, le 12 cifre devono essere precedute
da uno zero iniziale: questo riguarda il prefisso EAN Aziendale
*/
SET @UCCEAN = @UCCEAN + '0'
END
IF ((LEN(@EANAziendale) < 7) OR
(LEN(@EANAziendale) > 9))
BEGIN
SET @UCCEAN = ''
SET @MSG = 'Il prefisso EAN aziendale (' + @EANAziendale + ') non è corretto: lunghezza errata.'
RAISERROR(@MSG, 11, 1)
END
ELSE
SET @UCCEAN = @UCCEAN + @EANAziendale
/*
3. Codice sequenziale
*/
IF (Select Id From CountUCCEAN Where (Codice= @TypeEANUCC)) IS NULL
BEGIN
/*
Inserimento record
*/
IF (@TypeEANUCC = 'SSCC')
BEGIN
INSERT INTO CountUCCEAN
(CODICE,
DESCR,
VALORE,
VALMIN,
VALMAX)
VALUES (@TypeEANUCC,
'Serial Shipping Container Code',
0,
1,
2147483647)
END
ELSE IF (@TypeEANUCC = 'EU13') BEGIN
INSERT INTO CountUCCEAN
(CODICE,
DESCR,
VALORE,
VALMIN,
VALMAX)
VALUES (@TypeEANUCC,
'UCC/EAN-13 (GTIN-13)',
-1,
0,
CAST(REPLICATE('9', (13-LEN(@EANAziendale)-1)) AS INT))
END
END
/*
Ricerca valore MAX
*/
SELECT @MAXVALUE = Valore
FROM CountUCCEAN
WHERE (Codice = @TypeEANUCC)
/*
Update progressivo
*/
IF (@TypeEANUCC = 'SSCC')
BEGIN
IF ((@MAXVALUE + 1) <= 2147483647) AND
(LEN(LTRIM(RTRIM(STR((@MAXVALUE + 1))))) <= (18 - LEN(LTRIM(RTRIM(STR(@CifraEstensione)))) - LEN(@EANAziendale) -1))
BEGIN
UPDATE CountUCCEAN SET Valore = (Valore + 1)
WHERE (Codice = @TypeEANUCC)
END
ELSE BEGIN
SET @MAXVALUE = 0
UPDATE CountUCCEAN SET Valore = 1
WHERE (Codice = @TypeEANUCC)
END
SET @FILLNUMBER = (18 -
LEN(LTRIM(RTRIM(STR(@CifraEstensione)))) -
LEN(@EANAziendale) -
LEN(LTRIM(RTRIM(STR(@MAXVALUE + 1)))) -
1)
END
ELSE IF (@TypeEANUCC = 'EU13') BEGIN
IF ((@MAXVALUE + 1) <= CAST(REPLICATE('9', (13-LEN(@EANAziendale)-1)) AS INT))
BEGIN
UPDATE CountUCCEAN SET Valore = (Valore + 1)
WHERE (Codice = @TypeEANUCC)
END
ELSE BEGIN
SET @UCCEAN = ''
SET @MSG = 'Attenzione: Sono stati esauriti i Codici Prodotto, impossibile proseguire.'
RAISERROR(@MSG, 11, 1)
END
SET @FILLNUMBER = (13 -
LEN(@EANAziendale) -
LEN(LTRIM(RTRIM(STR(@MAXVALUE + 1)))) -
1)
END
COMMIT
SET @UCCEAN = (@UCCEAN +
REPLICATE('0', @FILLNUMBER) +
LTRIM(RTRIM(STR(@MAXVALUE + 1))))
SET @UCCEAN = @UCCEAN + LTRIM(RTRIM(STR(dbo.UDF_GetCheckDigitUCCEAN(@UCCEAN))))
END TRY
BEGIN CATCH
-- Esecuzione della procedura di restituzione errori
EXECUTE USP_GetErrorInfo
ROLLBACK
SET @UCCEAN = ''
END CATCH
PRINT @UCCEAN
END
4. Eseguendo la stored procedure USP_GetCodeUCCEAN() con i seguenti parametri di input:
DECLARE @UCCEAN VARCHAR(18)
EXEC USP_GetCodeUCCEAN 0, '801234567', 0, 'EU13', @UCCEAN
PRINT @UCCEAN
Si ottiene il codice UCC/EAN-13 (GTIN-13) 8012345670000 da assegnare ad primo prodotto commercializzato da codificare.