diff -ru bin/cgi-bin/customer.pl ./bin/cgi-bin/customer.pl
--- bin/cgi-bin/customer.pl	2004-08-18 12:48:59 +0400
+++ ./bin/cgi-bin/customer.pl	2005-01-19 23:48:08 +0300
@@ -57,6 +57,7 @@
 use Kernel::System::CustomerUser;
 use Kernel::System::CustomerGroup;
 use Kernel::System::Permission;
+use Kernel::System::Serial;
 use Kernel::Output::HTML::Generic;
 
 # --
@@ -407,6 +408,34 @@
         $GetParams{$Entry->[0]} = $CommonObject{ParamObject}->GetParam(Param => $Entry->[1]) || '';
     }
     $GetParams{ValidID} = 1;
+    # check for serial
+    my ($Serial, $SerialID);;
+    if ($CommonObject{ConfigObject}->{CheckSerials}) {
+	$SerialID = $CommonObject{ParamObject}->GetParam(Param => 'SerialID') || '';
+	if ($SerialID eq "") {
+            $Serial = 0;
+	}
+	else {
+            $Serial = Kernel::System::Serial->new(
+                ConfigObject => $CommonObject{ConfigObject},
+                LogObject => $CommonObject{LogObject},
+                DBObject => $CommonObject{DBObject},
+                CustomerID => $GetParams{UserEmail},
+            );
+            if (! $Serial->Unused(SerialNumber => $SerialID)) {
+                $Serial = 0;
+            }
+        }
+	if(!$Serial) {
+            print $CommonObject{LayoutObject}->CustomerHeader(Area => 'Core', Title => 'Error');
+            print $CommonObject{LayoutObject}->CustomerWarning(
+                Message => "Incorrect serial number.",
+                Comment => 'Please press Back and try again.'
+            );
+            print $CommonObject{LayoutObject}->CustomerFooter();
+            exit 0;
+        }
+    }
     # check needed params
     if (!$GetParams{UserCustomerID}) {
         $GetParams{UserCustomerID} = $GetParams{UserEmail};
@@ -434,6 +463,17 @@
             ValidID => 1,
             UserID => $CommonObject{ConfigObject}->Get('CustomerPanelUserID'),
         )) {
+             if ($CommonObject{ConfigObject}->{CheckSerials} && $Serial) {
+                $Serial->Add(SerialNumber => $SerialID);
+             }
+             else {
+                 print $CommonObject{LayoutObject}->CustomerHeader(Area => 'Core', Title => 'Error');
+                 print $CommonObject{LayoutObject}->CustomerWarning(
+                     Message => "Incorrect serial number.",
+                     Comment => 'Please press Back and try again.'
+                 );
+                 print $CommonObject{LayoutObject}->CustomerFooter();
+             }
             # send notify email
             my $EmailObject = Kernel::System::Email->new(%CommonObject);
             my $Body = $CommonObject{ConfigObject}->Get('CustomerPanelBodyNewAccount')
diff -ru Kernel/Modules/CustomerSerialOverView.pm ./Kernel/Modules/CustomerSerialOverView.pm
--- Kernel/Modules/CustomerSerialOverView.pm	2005-01-20 00:23:28 +0300
+++ ./Kernel/Modules/CustomerSerialOverView.pm	2005-01-20 00:28:09 +0300
@@ -0,0 +1,91 @@
+# --
+# Kernel/Modules/CustomerSerialOverView.pm - a simple test module
+# Copyright (C) 2005 Igor Muratov <migor@altlinux.org>
+# --
+# $Id$
+# --
+# This software comes with ABSOLUTELY NO WARRANTY. For details, see
+# the enclosed file COPYING for license information (GPL). If you
+# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
+# --
+
+package Kernel::Modules::CustomerSerialOverView;
+
+use strict;
+use Kernel::System::Serial;
+
+use vars qw($VERSION);
+$VERSION = '$Revision$';
+$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;
+
+# --
+sub new {
+    my $Type = shift;
+    my %Param = @_;
+
+    # allocate new hash for object
+    my $Self = {}; 
+    bless ($Self, $Type);
+
+    # get common objects
+    foreach (keys %Param) {
+        $Self->{$_} = $Param{$_};
+    }
+
+	# check needed objects
+	foreach (qw(DBObject LayoutObject LogObject)) {
+		die "Got no $_!" if (!$Self->{$_});
+	}
+
+    return $Self;
+}
+# --
+sub Run {
+    my $Self = shift;
+    my %Param = @_;
+
+	# checks
+	if (!$Self->{UserCustomerID}) {
+		my $Output = $Self->{LayoutObject}->CustomerHeader(Title => 'Error');
+		$Output .= $Self->{LayoutObject}->CustomerError(Message => 'Need CustomerID!!!');
+		$Output .= $Self->{LayoutObject}->CustomerFooter();
+	}
+
+    # get page header
+    my $Output = $Self->{LayoutObject}->CustomerHeader(Title => 'My Serials');
+    $Output .= $Self->{LayoutObject}->CustomerNavigationBar();
+	print $Output; $Output = '';
+
+    # get the data
+	my $Serial = Kernel::System::Serial->new(
+		DBObject => $Self->{DBObject},
+		LogObject => $Self->{LogObject},
+		CustomerID => $Self->{UserCustomerID}
+	);
+
+	# Show table header
+	print "<table><tr></tr>";
+
+	# show serials
+	my $OutputTable = "";
+	my $Counter = 0;
+	foreach my $SerialID ($Serial->GetAll()) {
+		$Counter++;
+		$OutputTable .= $Self->{LayoutObject}->CustomerSerialViewTable(%{$SerialID});
+	}
+
+	#
+	$Output .= $Self->{LayoutObject}->CustomerSerialView(
+		StatusTable => $OutputTable,
+		ShowClosed => $Self->{ShowClosed}
+	);
+
+    # get page footer
+    $Output .= $Self->{LayoutObject}->CustomerFooter();
+
+    # return page
+    return $Output;
+}
+
+# --
+1;
diff -ru Kernel/Modules/CustomerSerialRegister.pm ./Kernel/Modules/CustomerSerialRegister.pm
--- Kernel/Modules/CustomerSerialRegister.pm	2005-01-20 00:23:43 +0300
+++ ./Kernel/Modules/CustomerSerialRegister.pm	2005-01-20 00:28:17 +0300
@@ -0,0 +1,93 @@
+# --
+# Kernel/Modules/CustomerSerialRegister.pm - a simple test module
+# Copyright (C) 2005 Igor Muratov <migor@altlinux.org>
+# --
+# $Id$
+# --
+# This software comes with ABSOLUTELY NO WARRANTY. For details, see
+# the enclosed file COPYING for license information (GPL). If you
+# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
+# --
+
+package Kernel::Modules::CustomerSerialRegister;
+
+use strict;
+use Kernel::System::Serial;
+
+use vars qw($VERSION);
+$VERSION = '$Revision$';
+$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;
+
+# --
+sub new {
+    my $Type = shift;
+    my %Param = @_;
+
+    # allocate new hash for object
+    my $Self = {}; 
+    bless ($Self, $Type);
+
+    # get common objects
+    foreach (keys %Param) {
+        $Self->{$_} = $Param{$_};
+    }
+
+	# check needed objects
+	foreach (qw(DBObject LayoutObject LogObject ParamObject)) {
+		die "Got no $_!" if (!$Self->{$_});
+	}
+
+	$Self->{SerialID} = $Self->{ParamObject}->GetParam(Param => 'SerialID');
+
+    return $Self;
+}
+# --
+sub Run {
+    my $Self = shift;
+    my %Param = @_;
+
+	# checks
+	if (!$Self->{UserCustomerID}) {
+		my $Output = $Self->{LayoutObject}->CustomerHeader(Title => 'Error');
+		$Output .= $Self->{LayoutObject}->CustomerError(Message => 'Need CustomerID!!!');
+		$Output .= $Self->{LayoutObject}->CustomerFooter();
+	}
+
+    # get page header
+    my $Output = $Self->{LayoutObject}->CustomerHeader(Title => 'Register New Serial');
+    $Output .= $Self->{LayoutObject}->CustomerNavigationBar();
+    print $Output; $Output = '';
+
+    # if there no serial number
+    if (!$Self->{SerialID}) {
+        $Output .= $Self->{LayoutObject}->Output(TemplateFile => 'CustomerSerialRegister');
+    }
+    else {
+        my $Serial = Kernel::System::Serial->new(
+            ConfigObject => $Self->{ConfigObject},
+            LogObject => $Self->{LogObject},
+            DBObject => $Self->{DBObject},
+            CustomerID => $Self->{UserCustomerID},
+        );
+        if ($Serial->Unused(SerialNumber => $Self->{SerialID})) {
+            if ($Serial->Add(SerialNumber => $Self->{SerialID})) {
+                $Output .= "<h4>Number registered</h4>\n";
+            }
+            else {
+                $Output .= "<h4>Bad serial number</h4>\n";
+            }
+        }
+        else {
+            $Output .= "<h4>Alredy registered</h4>\n";
+        }
+    }
+
+    # get page footer
+    $Output .= $Self->{LayoutObject}->CustomerFooter();
+
+    # return test page
+    return $Output;
+}
+
+# --
+1; 
diff -ru Kernel/Output/HTML/Customer.pm ./Kernel/Output/HTML/Customer.pm
--- Kernel/Output/HTML/Customer.pm	2004-06-22 15:44:08 +0400
+++ ./Kernel/Output/HTML/Customer.pm	2005-01-10 19:19:22 +0300
@@ -127,6 +127,18 @@
     return $Self->Output(TemplateFile => 'CustomerNavigationBar', Data => \%Param);
 }
 # --
+sub CustomerSerialView {
+    my $Self = shift;
+    my %Param = @_;
+    return $Self->Output(TemplateFile => 'CustomerSerialView', Data => \%Param);
+}
+# --
+sub CustomerSerialViewTable {
+    my $Self = shift;
+    my %Param = @_;
+    return $Self->Output(TemplateFile => 'CustomerSerialViewTable', Data => \%Param);
+}
+# --
 sub CustomerError {
     my $Self = shift;
     my %Param = @_;
diff -ru Kernel/System/Serial.pm ./Kernel/System/Serial.pm
--- Kernel/System/Serial.pm	2005-01-20 00:26:45 +0300
+++ ./Kernel/System/Serial.pm	2005-01-20 00:27:43 +0300
@@ -0,0 +1,156 @@
+# --
+# Kernel/System/Serial.pm - lib for serial funktions
+# Copyright (C) 2005 Igor Muratov <migor@altlinux.org>
+# --
+# $Id$
+# --
+# This software comes with ABSOLUTELY NO WARRANTY. For details, see 
+# the enclosed file COPYING for license information (GPL). If you 
+# did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
+# --
+
+package Kernel::System::Serial;
+
+use strict;
+use Kernel::System::StdResponse;
+use Kernel::System::Group;
+use Kernel::System::CustomerGroup;
+
+use vars qw($VERSION);
+$VERSION = '$Revision$';
+$VERSION =~ s/^\$.*:\W(.*)\W.+?$/$1/;
+
+=head1 NAME
+
+Kernel::System::Serial - serial numbers lib
+
+=head1 SYNOPSIS
+
+All serail number functions. E. g. to add serial or other functions.
+
+=head1 PUBLIC INTERFACE
+
+=over 4
+
+=cut
+
+# --
+sub new {
+    my $Type = shift;
+    my %Param = @_;
+
+    # allocate new hash for object
+    my $Self = {}; 
+    bless ($Self, $Type);
+
+    $Self->{CustomerID} = $Param{CustomerID} || ''; #die "Got no CustomerID!";
+
+    # check needed objects
+    foreach (qw(DBObject LogObject)) {
+        $Self->{$_} = $Param{$_} || die "Got no $_!";
+    }
+
+    return $Self;
+}
+
+# check serial if exists
+sub Unused {
+    my $Self = shift;
+    my %Param = @_;
+    my $Counter;
+    my $SerialNumber = $Param{SerialNumber} || die "Undefined serial number";
+    my $CustomerID = $Param{CustomerID} || $Self->{CustomerID};
+
+    my $SQL = "SELECT count(*) FROM serial_numbers WHERE ".
+        " serial_number=\'".$SerialNumber."\'".
+        " AND user_id=\"\"".
+        " AND valid_till IS NULL";
+    $Self->{DBObject}->Prepare(SQL => $SQL);
+
+    while (my @RowTmp = $Self->{DBObject}->FetchrowArray()) {
+        $Counter = $RowTmp[0];
+    }
+
+    return $Counter;
+}
+
+# Associate serial number to customer and group id
+sub Add {
+    my $Self = shift;
+    my %Param = @_;
+    my @Serials;
+    my $SerialNumber = $Param{SerialNumber} || die "Undefined serial number";
+    my $CustomerID = $Param{CustomerID} || $Self->{CustomerID};
+    my $CheckDate = $Param{CheckDate} || 'CURRENT_DATE()';
+    my $Period = $Param{Period} || 60;
+
+    if ($Self->Unused(SerialNumber => $SerialNumber)) {
+	my $SQL = "START TRANSACTION;";
+        $Self->{DBObject}->Do(SQL => $SQL);
+
+        $SQL = "UPDATE serial_numbers set ".
+            " user_id=\'".$CustomerID."\'".
+            ",valid_till=ADDDATE(".$CheckDate.", INTERVAL ".$Period." DAY) ".
+            " WHERE user_id = '' AND valid_till is NULL ".
+            " AND serial_number = \'".$SerialNumber."\';";
+        $Self->{DBObject}->Do(SQL => $SQL);
+
+	$SQL .= "SELECT \@user:=user_id,\@group:=group_id FROM serial_numbers ".
+	    " WHERE serial_number = \'".$SerialNumber."\';";
+        $Self->{DBObject}->Do(SQL => $SQL);
+	
+        $SQL .= "INSERT INTO group_customer_user ".
+            " (user_id,group_id,permission_key,permission_value) ".
+	    " VALUES (\@user,\@group,\'ro\',1),(\@user,\@group,\'rw\',1) ";
+        $Self->{DBObject}->Do(SQL => $SQL);
+
+	$SQL = "COMMIT;";
+        $Self->{DBObject}->Do(SQL => $SQL);
+
+        $Self->{LogObject}->Log(
+            Message => 'Serial '.$SerialNumber.' has registered by '.$CustomerID.'.',
+            Priority => 'info',
+        );
+        return 1;
+    }
+    else {
+        $Self->{LogObject}->Log(
+            Message => 'Serial '.$SerialNumber.' can not be registered by '.$CustomerID.".",
+            Priority => 'info',
+        );
+        return 0;
+    }
+}
+
+# return all valid serial numbers for customer
+sub GetAll {
+    my $Self = shift;
+    my %Param = @_;
+    my @Serials;
+    my $CustomerID = $Param{CustomerID} || $Self->{CustomerID};
+	my $CheckDate = $Param{CheckDate} || 'CURRENT_DATE()';
+
+    my $SQL = "SELECT serial_number,DATE_FORMAT(valid_till, '%d, %M %Y'),name as product,valid_till>now() as valid ".
+		" FROM serial_numbers,queue ".
+		" WHERE serial_numbers.group_id = queue.group_id ".
+		" AND ".
+		" user_id = \'".$CustomerID."\'".
+		" AND ".
+		" valid_till >= ".$CheckDate.
+		" ORDER BY valid_till DESC";
+    $Self->{DBObject}->Prepare(SQL => $SQL);
+
+    while (my @RowTmp = $Self->{DBObject}->FetchrowArray()) {
+        push @Serials, {
+			Number => $RowTmp[0],
+			ValidTill => $RowTmp[1],
+			Product => $RowTmp[2],
+			Valid => $RowTmp[3],
+		};
+    }
+    return @Serials;
+}
+
+# --
+1;
+
diff -ru Kernel/Language/ru.pm ./Kernel/Language/ru.pm
--- Kernel/Language/ru.pm	2005-01-20 00:20:39 +0300
+++ ./Kernel/Language/ru.pm	2005-01-20 01:12:49 +0300
@@ -1207,6 +1207,16 @@
       'store' => '���������',
       'tickets' => '������',
       'valid' => '��������� ������',
+
+      # Serials
+      'Serial Overview' => '������ �������� �������',
+      'Serial register' => '�������� �������� �����',
+      'New serial' => '����� �������� �����',
+      'Serial' => '�����',
+      'Serials overview' => '������ �������',
+      'Serial Number' => '�������� �����',
+      'Product' => '�������',
+      'Valid till' => '������������ ��',
     );
 
     # $$STOP$$
diff -u Kernel/Config/Defaults.pm ./Kernel/Config/Defaults.pm
--- Kernel/Config/Defaults.pm 2004-10-18 12:47:11 +0400
+++ ./Kernel/Config/Defaults.pm   2005-01-20 11:18:29 +0300
@@ -2184,6 +2184,8 @@
 
     $Self->{'Module::Permission'}->{'SystemStats'} = ['admin', 'stats'];
 
+    # Serial Numbers
+    $Self->{CheckSerials} = 0;
 
     # --------------------------------------------------- #
 }
