Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision f50ddd66

Von Moritz Bunkus vor mehr als 11 Jahren hinzugefügt

  • ID f50ddd66b0b90f206c762c95770da530cb0b7d69
  • Vorgänger 39d85854
  • Nachfolger 5551a36b

SL::PrefixedNumber -- Nummernkreisartige Nummer erhöhen ohne Datenbank

Unterschiede anzeigen:

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