1 package SL::DB::RecordTemplate;
5 use DateTime::Format::Strptime;
6 use List::Util qw(first);
8 use SL::DB::MetaSetup::RecordTemplate;
9 use SL::DB::Manager::RecordTemplate;
11 __PACKAGE__->meta->add_relationship(
12 record_template_items => {
13 type => 'one to many',
14 class => 'SL::DB::RecordTemplateItem',
15 column_map => { id => 'record_template_id' },
19 __PACKAGE__->meta->initialize;
21 sub items { goto &record_template_items; }
23 sub _replace_variables {
24 my ($self, %params) = @_;
26 foreach my $sub (@{ $params{fields} }) {
27 my $value = $params{object}->$sub;
28 next if ($value // '') eq '';
30 $value =~ s{ <\% ([a-z0-9_]+) ( \s+ format \s*=\s* (.*?) \s* )? \%> }{
31 my ($key, $format) = ($1, $3);
34 if (!$params{variables}->{$key}) {
38 $new_value = DateTime::Format::Strptime->new(
42 )->format_datetime($params{variables}->{$key}->[0]);
45 $new_value = $params{variables}->{$1}->[1]->($params{variables}->{$1}->[0]);
52 $params{object}->$sub($value);
56 sub _generate_variables {
57 my ($self, $reference_date) = @_;
59 $reference_date //= DateTime->today_local;
61 $::locale->text('January'), $::locale->text('February'), $::locale->text('March'), $::locale->text('April'), $::locale->text('May'), $::locale->text('June'),
62 $::locale->text('July'), $::locale->text('August'), $::locale->text('September'), $::locale->text('October'), $::locale->text('November'), $::locale->text('December'),
66 current_quarter => [ $reference_date->clone->truncate(to => 'month'), sub { $_[0]->quarter } ],
67 previous_quarter => [ $reference_date->clone->truncate(to => 'month')->subtract(months => 3), sub { $_[0]->quarter } ],
68 next_quarter => [ $reference_date->clone->truncate(to => 'month')->add( months => 3), sub { $_[0]->quarter } ],
70 current_month => [ $reference_date->clone->truncate(to => 'month'), sub { $_[0]->month } ],
71 previous_month => [ $reference_date->clone->truncate(to => 'month')->subtract(months => 1), sub { $_[0]->month } ],
72 next_month => [ $reference_date->clone->truncate(to => 'month')->add( months => 1), sub { $_[0]->month } ],
74 current_month_long => [ $reference_date->clone->truncate(to => 'month'), sub { $month_names[ $_[0]->month - 1 ] } ],
75 previous_month_long => [ $reference_date->clone->truncate(to => 'month')->subtract(months => 1), sub { $month_names[ $_[0]->month - 1 ] } ],
76 next_month_long => [ $reference_date->clone->truncate(to => 'month')->add( months => 1), sub { $month_names[ $_[0]->month - 1 ] } ],
78 current_year => [ $reference_date->clone->truncate(to => 'year'), sub { $_[0]->year } ],
79 previous_year => [ $reference_date->clone->truncate(to => 'year')->subtract(years => 1), sub { $_[0]->year } ],
80 next_year => [ $reference_date->clone->truncate(to => 'year')->add( years => 1), sub { $_[0]->year } ],
82 reference_date => [ $reference_date->clone, sub { $::locale->format_date(\%::myconfig, $_[0]) } ],
88 sub _text_column_names {
89 my ($self, $object) = @_;
90 return map { $_->name } grep { ref($_) =~ m{::Text} } @{ $object->meta->columns };
93 sub substitute_variables {
94 my ($self, $reference_date) = @_;
96 my $variables = $self->_generate_variables($reference_date);
97 my @text_columns = $self->_text_column_names($self);
99 $self->_replace_variables(
101 variables => $variables,
102 fields => \@text_columns,
105 @text_columns = $self->_text_column_names(SL::DB::RecordTemplateItem->new);
107 foreach my $item (@{ $self->items }) {
108 $self->_replace_variables(
110 variables => $variables,
111 fields => \@text_columns,
116 sub template_name_to_use {
117 my ($self, @names) = @_;
119 return first { ($_ // '') ne '' } (@names, $self->template_name, $::locale->text('unnamed record template'));
131 SL::DB::RecordTemplate — Templates for accounts receivable
132 transactions, accounts payable transactions and generic ledger
141 An alias for C<record_template_items>.
143 =item C<substitute_variables> C<[$reference_date]>
145 Texts in record templates can contain placeholders. This function
146 replaces those placeholders by their actual value. Placeholders use
147 the syntax C<E<lt>%variableE<gt>> or C<E<lt>%variable format=…E<gt>>
148 for a custom format (see L<DateTime::Format::Strptime> for available
149 formatting characters).
151 The variables are calculated based on C<$reference_date> which must be
152 an instance of L<DateTime> if given. If left out, it defaults to the
155 Supported variables are:
159 =item * C<current_quarter>, C<previous_quarter>, C<next_quarter> — the
160 quarter as a number between 1 and 4 inclusively
162 =item * C<current_month>, C<previous_month>, C<next_month> — the
163 month as a number between 1 and 12 inclusively
165 =item * C<current_month_long>, C<previous_month_long>,
166 C<next_month_long> — the month's name (e.g. C<August>).
168 =item * C<current_year>, C<previous_year>, C<next_year> — the
171 =item * C<reference_date> — the reference date in the user's date style
180 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>