Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811
[kivitendo-erp.git] / SL / DB / Helper / Attr.pm
1 package SL::DB::Helper::Attr;
2
3 use strict;
4
5 sub auto_make {
6   my ($package, %params) = @_;
7
8   for my $col ($package->meta->columns) {
9     next if $col->primary_key_position; # don't make attr helper for primary keys
10     _make_by_type($package, $col->name, $col->type);
11   }
12
13   return $package;
14 }
15
16 sub make {
17   my ($package, %params) = @_;
18
19   for my $name (keys %params) {
20     my @types = ref $params{$name} eq 'ARRAY' ? @{ $params{$name} } : ($params{$name});
21     for my $type (@types) {
22       _make_by_type($package, $name, $type);
23     }
24   }
25   return $package;
26 }
27
28
29
30 sub _make_by_type {
31   my ($package, $name, $type) = @_;
32   _as_number     ($package, $name, places => -2) if $type =~ /numeric | real | float/xi;
33   _as_null_number($package, $name, places => -2) if $type =~ /numeric | real | float/xi;
34   _as_percent    ($package, $name, places =>  2) if $type =~ /numeric | real | float/xi;
35   _as_number     ($package, $name, places =>  0) if $type =~ /int/xi;
36   _as_null_number($package, $name, places =>  0) if $type =~ /int/xi;
37   _as_date       ($package, $name)               if $type =~ /date | timestamp/xi;
38   _as_timestamp  ($package, $name)             if $type =~ /timestamp/xi;
39   _as_bool_yn    ($package, $name)               if $type =~ /bool/xi;
40 }
41
42 sub _as_number {
43   my $package     = shift;
44   my $attribute   = shift;
45   my %params      = @_;
46
47   $params{places} = 2 if !defined($params{places});
48
49   no strict 'refs';
50   *{ $package . '::' . $attribute . '_as_number' } = sub {
51     my ($self, $string) = @_;
52
53     $self->$attribute($::form->parse_amount(\%::myconfig, $string)) if @_ > 1;
54
55     return $::form->format_amount(\%::myconfig, $self->$attribute, $params{places});
56   };
57 }
58
59 sub _as_null_number {
60   my $package     = shift;
61   my $attribute   = shift;
62   my %params      = @_;
63
64   $params{places} = 2 if !defined($params{places});
65
66   no strict 'refs';
67   *{ $package . '::' . $attribute . '_as_null_number' } = sub {
68     my ($self, $string) = @_;
69
70     $self->$attribute($string eq '' ? undef : $::form->parse_amount(\%::myconfig, $string)) if @_ > 1;
71
72     return defined $self->$attribute ? $::form->format_amount(\%::myconfig, $self->$attribute, $params{places}) : '';
73   };
74 }
75
76 sub _as_percent {
77   my $package     = shift;
78   my $attribute   = shift;
79   my %params      = @_;
80
81   $params{places} = 2 if !defined($params{places});
82
83   no strict 'refs';
84   *{ $package . '::' . $attribute . '_as_percent' } = sub {
85     my ($self, $string) = @_;
86
87     $self->$attribute($::form->parse_amount(\%::myconfig, $string) / 100) if @_ > 1;
88
89     return $::form->format_amount(\%::myconfig, 100 * $self->$attribute, $params{places});
90   };
91
92   return 1;
93 }
94
95 sub _as_date {
96   my $package     = shift;
97   my $attribute   = shift;
98   my %params      = @_;
99
100   no strict 'refs';
101   *{ $package . '::' . $attribute . '_as_date' } = sub {
102     my ($self, $string) = @_;
103
104     if (@_ > 1) {
105       if ($string) {
106         my ($yy, $mm, $dd) = $::locale->parse_date(\%::myconfig, $string);
107         $self->$attribute(DateTime->new(year => $yy, month => $mm, day => $dd));
108       } else {
109         $self->$attribute(undef);
110       }
111     }
112
113     return $self->$attribute
114       ? $::locale->reformat_date(
115           { dateformat => 'yy-mm-dd' },
116           ( ($self->$attribute eq 'now' || $self->$attribute eq 'now()')
117              ? DateTime->now
118              : $self->$attribute
119           )->ymd,
120           $::myconfig{dateformat}
121         )
122       : undef;
123   };
124
125   return 1;
126 }
127
128 sub _as_timestamp {
129   my $package     = shift;
130   my $attribute   = shift;
131   my %params      = @_;
132
133   my $accessor    = sub {
134     my ($precision, $self, $string) = @_;
135
136     $self->$attribute($string ? $::locale->parse_date_to_object($string) : undef) if @_ > 2;
137
138     my $dt = $self->$attribute;
139     return undef unless $dt;
140
141     $dt = DateTime->now if !ref($dt) && ($dt eq 'now');
142
143     return $::locale->format_date_object($dt, precision => $precision);
144   };
145
146   no strict 'refs';
147   *{ $package . '::' . $attribute . '_as_timestamp'    } = sub { $accessor->('minute',      @_) };
148   *{ $package . '::' . $attribute . '_as_timestamp_s'  } = sub { $accessor->('second',      @_) };
149   *{ $package . '::' . $attribute . '_as_timestamp_ms' } = sub { $accessor->('millisecond', @_) };
150
151   return 1;
152 }
153
154 sub _as_bool_yn {
155   my ($package, $attribute, %params) = @_;
156
157   no strict 'refs';
158   *{ $package . '::' . $attribute . '_as_bool_yn' } = sub {
159     my ($self) = @_;
160
161     if (@_ > 1) {
162       die 'not an accessor';
163     }
164
165     return !defined $self->$attribute ? ''
166          :          $self->$attribute ? $::locale->text('Yes')
167          :                              $::locale->text('No');
168   }
169 }
170
171 1;
172
173
174 1;
175
176 __END__
177
178 =encoding utf-8
179
180 =head1 NAME
181
182 SL::DB::Helper::Attr - attribute helpers
183
184 =head1 SYNOPSIS
185
186   use SL::DB::Helper::Attr;
187   SL::DB::Helper::Attr::make($class,
188     method_name => 'numeric(15,5)',
189     datemethod  => 'date'
190   );
191   SL::DB::Helper::Attr::auto_make($class);
192
193 =head1 DESCRIPTION
194
195 Makes attribute helpers.
196
197 =head1 FUNCTIONS
198
199 see for yourself.
200
201 =head1 BUGS
202
203 None yet.
204
205 =head1 AUTHOR
206
207 Sven Schöling <s.schoeling@linet-services.de>,
208 Moritz Bunkus <m.bunkus@linet-services.de>
209
210 =cut