Revision f50ddd66
Von Moritz Bunkus vor mehr als 11 Jahren hinzugefügt
SL/DB/Helper/TransNumberGenerator.pm | ||
---|---|---|
9 | 9 |
use List::Util qw(max); |
10 | 10 |
|
11 | 11 |
use SL::DB::Default; |
12 |
use SL::PrefixedNumber; |
|
12 | 13 |
|
13 | 14 |
sub oe_scoping { |
14 | 15 |
SL::DB::Manager::Order->type_filter($_[0]); |
... | ... | |
50 | 51 |
|
51 | 52 |
return $number if $self->id && $number; |
52 | 53 |
|
53 |
my $re = '^(.*?)(\d+)$'; |
|
54 |
my %conditions = $scoping_conditions ? ( query => [ $scoping_conditions->($spec_type) ] ) : (); |
|
55 |
my @numbers = map { $_->$number_column } @{ $self->_get_manager_class->get_all(%conditions) }; |
|
56 |
my %numbers_in_use = map { ( $_ => 1 ) } @numbers; |
|
57 |
@numbers = grep { $_ } map { my @matches = m/$re/; @matches ? $matches[-1] * 1 : undef } @numbers; |
|
58 |
|
|
59 |
my $defaults = SL::DB::Default->get; |
|
60 |
my $number_range = $defaults->$number_range_column; |
|
61 |
my @matches = $number_range =~ m/$re/; |
|
62 |
my $prefix = (2 != scalar(@matches)) ? '' : $matches[ 0]; |
|
63 |
my $ref_number = !@matches ? '1' : $matches[-1]; |
|
64 |
my $min_places = length($ref_number); |
|
65 |
|
|
66 |
my $new_number = $fill_holes_in_range ? $ref_number : max($ref_number, @numbers); |
|
67 |
my $new_number_full = undef; |
|
68 |
|
|
69 |
while (1) { |
|
70 |
$new_number = $new_number + 1; |
|
71 |
my $new_number_s = $new_number; |
|
72 |
$new_number_s =~ s/\.\d+//g; |
|
73 |
$new_number_full = $prefix . ('0' x max($min_places - length($new_number_s), 0)) . $new_number_s; |
|
74 |
last if !$numbers_in_use{$new_number_full}; |
|
75 |
} |
|
76 |
|
|
77 |
$defaults->update_attributes($number_range_column => $new_number_full) if $params{update_defaults}; |
|
78 |
$self->$number_column($new_number_full) if $params{update_record}; |
|
79 |
|
|
80 |
return $new_number_full; |
|
54 |
my %conditions = $scoping_conditions ? ( query => [ $scoping_conditions->($spec_type) ] ) : (); |
|
55 |
my @numbers = map { $_->$number_column } @{ $self->_get_manager_class->get_all(%conditions) }; |
|
56 |
my %numbers_in_use = map { ( $_ => 1 ) } @numbers; |
|
57 |
|
|
58 |
my $defaults = SL::DB::Default->get; |
|
59 |
my $sequence = SL::PrefixedNumber->new(number => $defaults->$number_range_column); |
|
60 |
|
|
61 |
$sequence->set_to_max(@numbers) if !$fill_holes_in_range; |
|
62 |
|
|
63 |
my $new_number = $sequence->get_next; |
|
64 |
$new_number = $sequence->get_next while $numbers_in_use{$new_number}; |
|
65 |
|
|
66 |
$defaults->update_attributes($number_range_column => $new_number) if $params{update_defaults}; |
|
67 |
$self->$number_column($new_number) if $params{update_record}; |
|
68 |
|
|
69 |
return $new_number; |
|
81 | 70 |
} |
82 | 71 |
|
83 | 72 |
sub create_trans_number { |
SL/Form.pm | ||
---|---|---|
62 | 62 |
use SL::Menu; |
63 | 63 |
use SL::MoreCommon qw(uri_encode uri_decode); |
64 | 64 |
use SL::OE; |
65 |
use SL::PrefixedNumber; |
|
65 | 66 |
use SL::Request; |
66 | 67 |
use SL::Template; |
67 | 68 |
use SL::User; |
... | ... | |
3189 | 3190 |
my ($var) = $sth->fetchrow_array; |
3190 | 3191 |
$sth->finish; |
3191 | 3192 |
|
3192 |
if ($var =~ m/\d+$/) { |
|
3193 |
my $new_var = (substr $var, $-[0]) * 1 + 1; |
|
3194 |
my $len_diff = length($var) - $-[0] - length($new_var); |
|
3195 |
$var = substr($var, 0, $-[0]) . ($len_diff > 0 ? '0' x $len_diff : '') . $new_var; |
|
3196 |
|
|
3197 |
} else { |
|
3198 |
$var = $var . '1'; |
|
3199 |
} |
|
3200 |
|
|
3193 |
$var = SL::PrefixedNumber->new(number => $var)->get_next; |
|
3201 | 3194 |
$query = qq|UPDATE defaults SET $fld = ?|; |
3202 | 3195 |
do_query($self, $dbh, $query, $var); |
3203 | 3196 |
|
SL/PrefixedNumber.pm | ||
---|---|---|
1 |
package SL::PrefixedNumber; |
|
2 |
|
|
3 |
use strict; |
|
4 |
|
|
5 |
use parent qw(Rose::Object); |
|
6 |
|
|
7 |
use Carp; |
|
8 |
use List::Util qw(max); |
|
9 |
|
|
10 |
use Rose::Object::MakeMethods::Generic |
|
11 |
( |
|
12 |
scalar => [ qw(number) ], |
|
13 |
'scalar --get_set_init' => [ qw(_state) ], |
|
14 |
); |
|
15 |
|
|
16 |
sub init__state { |
|
17 |
my ($self) = @_; |
|
18 |
|
|
19 |
croak "No 'number' set" if !defined($self->number); |
|
20 |
|
|
21 |
my @matches = $self->number =~ m/^(.*?)(\d+)$/; |
|
22 |
my @matches2 = $self->number =~ m/^(.*[^\d])$/; |
|
23 |
my $prefix = @matches2 ? $matches2[0] : (2 != scalar(@matches)) ? '' : $matches[ 0],; |
|
24 |
my $ref_number = !@matches ? '0' : $matches[-1]; |
|
25 |
my $min_places = length $ref_number; |
|
26 |
|
|
27 |
return { |
|
28 |
prefix => $prefix, |
|
29 |
ref_number => $ref_number, |
|
30 |
min_places => $min_places, |
|
31 |
}; |
|
32 |
} |
|
33 |
|
|
34 |
sub get_current { |
|
35 |
my ($self) = @_; |
|
36 |
|
|
37 |
return $self->format($self->_state->{ref_number}); |
|
38 |
} |
|
39 |
|
|
40 |
sub get_next { |
|
41 |
my ($self) = @_; |
|
42 |
|
|
43 |
return $self->set_to($self->_state->{ref_number} + 1); |
|
44 |
} |
|
45 |
|
|
46 |
sub format { |
|
47 |
my ($self, $number) = @_; |
|
48 |
|
|
49 |
my $state = $self->_state; |
|
50 |
$number =~ s/\.\d+//g; |
|
51 |
|
|
52 |
return $state->{prefix} . ('0' x max($state->{min_places} - length($number), 0)) . $number; |
|
53 |
} |
|
54 |
|
|
55 |
sub set_to { |
|
56 |
my ($self, $new_number) = @_; |
|
57 |
|
|
58 |
my $state = $self->_state; |
|
59 |
$state->{ref_number} = $new_number; |
|
60 |
|
|
61 |
return $self->number($self->format($new_number)); |
|
62 |
} |
|
63 |
|
|
64 |
sub set_to_max { |
|
65 |
my ($self, @numbers) = @_; |
|
66 |
|
|
67 |
return $self->set_to(max map { SL::PrefixedNumber->new(number => $_)->_state->{ref_number} } @numbers); |
|
68 |
} |
|
69 |
|
|
70 |
1; |
|
71 |
__END__ |
|
72 |
|
|
73 |
=pod |
|
74 |
|
|
75 |
=encoding utf8 |
|
76 |
|
|
77 |
=head1 NAME |
|
78 |
|
|
79 |
SL::PrefixedNumber - Increment a number prefixed with some text |
|
80 |
|
|
81 |
=head1 SYNOPSIS |
|
82 |
|
|
83 |
my $number = SL::PrefixedNumber->new(number => 'FB000042')->get_next; |
|
84 |
print $number; # FB000043 |
|
85 |
|
|
86 |
=head1 FUNCTIONS |
|
87 |
|
|
88 |
=over 4 |
|
89 |
|
|
90 |
=item C<format $number> |
|
91 |
|
|
92 |
Returns C<$number> formatted according to the rules in C<$self>. Does |
|
93 |
not modify C<$self>. E.g. |
|
94 |
|
|
95 |
my $sequence = SL::PrefixedNumber->new('FB12345'); |
|
96 |
print $sequence->format(42); # FB00042 |
|
97 |
print $sequence->get_next; # FB12346 |
|
98 |
|
|
99 |
=item C<get_current> |
|
100 |
|
|
101 |
Returns the current number in the sequence (formatted). Does not |
|
102 |
modify C<$self>. |
|
103 |
|
|
104 |
=item C<get_next> |
|
105 |
|
|
106 |
Returns the next number in the sequence (formatted). Modifies C<$self> |
|
107 |
accordingly so that calling C<get_next> multiple times will actually |
|
108 |
iterate over the sequence. |
|
109 |
|
|
110 |
=item C<set_to $number> |
|
111 |
|
|
112 |
Sets the current postfix to C<$number> but does not change the |
|
113 |
prefix. Returns the formatted new number. E.g.: |
|
114 |
|
|
115 |
my $sequence = SL::PrefixedNumber->new(number => 'FB000042'); |
|
116 |
print $sequence->set_to(123); # FB000123 |
|
117 |
print $sequence->get_next; # FB000124 |
|
118 |
|
|
119 |
=item C<set_to_max @numbers> |
|
120 |
|
|
121 |
Sets the current postfix to the maximum of all the numbers listed in |
|
122 |
C<@numbers>. All those numbers can be prefixed numbers. Returns the |
|
123 |
formatted maximum number. E.g. |
|
124 |
|
|
125 |
my $sequence = SL::PrefixedNumber->new(number => 'FB000042'); |
|
126 |
print $sequence->set_to_max('FB000123', 'FB999', 'FB00001'); # FB000999 |
|
127 |
print $sequence->get_next; # FB001000 |
|
128 |
|
|
129 |
=back |
|
130 |
|
|
131 |
=head1 BUGS |
|
132 |
|
|
133 |
Nothing here yet. |
|
134 |
|
|
135 |
=head1 AUTHOR |
|
136 |
|
|
137 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt> |
|
138 |
|
|
139 |
=cut |
SL/TransNumber.pm | ||
---|---|---|
7 | 7 |
use Carp; |
8 | 8 |
use List::MoreUtils qw(any none); |
9 | 9 |
use SL::DBUtils; |
10 |
use SL::PrefixedNumber; |
|
10 | 11 |
|
11 | 12 |
use Rose::Object::MakeMethods::Generic |
12 | 13 |
( |
... | ... | |
129 | 130 |
my $number = $business_number; |
130 | 131 |
($number) = selectfirst_array_query($form, $self->dbh, qq|SELECT $filters{numberfield} FROM defaults|) if !$number; |
131 | 132 |
$number ||= ''; |
133 |
my $sequence = SL::PrefixedNumber->new(number => $number); |
|
132 | 134 |
|
133 | 135 |
do { |
134 |
if ($number =~ m/\d+$/) { |
|
135 |
my $new_number = substr($number, $-[0]) * 1 + 1; |
|
136 |
my $len_diff = length($number) - $-[0] - length($new_number); |
|
137 |
$number = substr($number, 0, $-[0]) . ($len_diff > 0 ? '0' x $len_diff : '') . $new_number; |
|
138 |
|
|
139 |
} else { |
|
140 |
$number = $number . '1'; |
|
141 |
} |
|
136 |
$number = $sequence->get_next; |
|
142 | 137 |
} while ($numbers_in_use{$number}); |
143 | 138 |
|
144 | 139 |
if ($self->save) { |
t/prefixed_number.t | ||
---|---|---|
1 |
use Test::More tests => 14; |
|
2 |
use Test::Exception; |
|
3 |
|
|
4 |
use strict; |
|
5 |
|
|
6 |
use lib 't'; |
|
7 |
use utf8; |
|
8 |
|
|
9 |
use Data::Dumper; |
|
10 |
use Support::TestSetup; |
|
11 |
|
|
12 |
use_ok 'SL::PrefixedNumber'; |
|
13 |
|
|
14 |
sub n { |
|
15 |
return SL::PrefixedNumber->new(number => $_[0]); |
|
16 |
} |
|
17 |
|
|
18 |
is(n('FB4711' )->get_next, 'FB4712', 'increment FB4711'); |
|
19 |
is(n('4711' )->get_next, '4712', 'increment 4711'); |
|
20 |
is(n('FB54UFB4711')->get_next, 'FB54UFB4712', 'increment FB54UFB4711'); |
|
21 |
is(n('FB' )->get_next, 'FB1', 'increment FB'); |
|
22 |
is(n('' )->get_next, '1', 'increment ""'); |
|
23 |
is(n('0042-FB' )->get_next, '0042-FB1', 'increment 0042-FB'); |
|
24 |
my $o = n('0042-FB'); |
|
25 |
$o->get_next; |
|
26 |
is($o->get_next, '0042-FB2', 'increment 0042-FB twice'); |
|
27 |
|
|
28 |
is(n('FB4711')->set_to(54), 'FB0054', 'set FB4711 to 54'); |
|
29 |
$o = n('FB4711'); |
|
30 |
$o->set_to(54); |
|
31 |
is($o->get_next, 'FB0055', 'set FB4711 to 54 then increment'); |
|
32 |
|
|
33 |
is(n('FB121231')->get_current, 'FB121231', 'set FB121231 get current'); |
|
34 |
is(n('FB121231')->format(42), 'FB000042', 'set FB121231 format 42'); |
|
35 |
is(n('FB123123')->set_to_max('FB0711', 'FB911', 'FB8'), 'FB000911', 'set FB123123 max FB000911'); |
|
36 |
|
|
37 |
throws_ok { n()->get_next } qr/no.*number/i, 'get_next without number set'; |
Auch abrufbar als: Unified diff
SL::PrefixedNumber -- Nummernkreisartige Nummer erhöhen ohne Datenbank