9be3774e502a2de2f74547908d8638cbe37a8714
[kivitendo-erp.git] / SL / DB / Helper / AccountingPeriod.pm
1 package SL::DB::Helper::AccountingPeriod;
2
3 use strict;
4 use SL::Locale::String qw(t8);
5
6 use parent qw(Exporter);
7 use SL::DBUtils;
8 our @EXPORT = qw(get_balance_starting_date get_balance_startdate_method_options);
9
10 use Carp;
11
12 sub get_balance_startdate_method_options {
13   [
14     { title => t8("After closed period"),                       value => "closed_to"                   },
15     { title => t8("Start of year"),                             value => "start_of_year"               },
16     { title => t8("All transactions"),                          value => "all_transactions"            },
17     { title => t8("Last opening balance or all transactions"),  value => "last_ob_or_all_transactions" },
18     { title => t8("Last opening balance or start of year"),     value => "last_ob_or_start_of_year"    },
19   ]
20 }
21
22 sub get_balance_starting_date {
23   my ($self, $asofdate, $startdate_method) = @_;
24
25   $asofdate         ||= DateTime->today_local;
26   $startdate_method ||= $::instance_conf->get_balance_startdate_method;
27
28   unless ( ref $asofdate eq 'DateTime' ) {
29     $asofdate = $::locale->parse_date_to_object($asofdate);
30   };
31
32   my $dbh = $::form->get_standard_dbh;
33
34
35   # We could use the following objects to determine the starting date for
36   # calculating the balance from asofdate (the reference date for the balance):
37   # * start_of_year - 1.1., no deviating fiscal year supported
38   # * closed_to - all transactions since the books were last closed
39   # * last_ob - all transactions since last opening balance transaction (usually 1.1.)
40   # * mindate - all transactions in database
41
42   my $start_of_year = $asofdate->clone();
43   $start_of_year->set_day(1);
44   $start_of_year->set_month(1);
45
46   # closedto assumes that we only close the books at the end of a fiscal year,
47   # never during the fiscal year. If this assumption is valid closedto should
48   # also work for deviating fiscal years. But as the trial balance (SuSa)
49   # doesn't yet deal with deviating fiscal years, and it is useful to also close
50   # the books after a month has been exported via DATEV, this method of
51   # determining the starting date isn't recommended and is not the default.
52
53   my $closedto = $::instance_conf->get_closedto;
54   if ($closedto) {
55     $closedto = $::locale->parse_date_to_object($closedto);
56     $closedto->subtract(years => 1) while ($asofdate - $closedto)->is_negative;
57     $closedto->add(days => 1);
58   };
59
60   my ($query, $startdate, $last_ob, $mindate);
61   $query = qq|select max(transdate) from acc_trans where ob_transaction is true and transdate <= ?|;
62   ($last_ob) = selectrow_query($::form, $dbh, $query, $::locale->format_date(\%::myconfig, $asofdate));
63   $last_ob = $::locale->parse_date_to_object($last_ob) if $last_ob;
64
65   $query = qq|select min(transdate) from acc_trans|;
66   ($mindate) = selectrow_query($::form, $dbh, $query);
67   $mindate = $::locale->parse_date_to_object($mindate);
68
69   # the default method is to use all transactions ($mindate)
70
71   if ( $startdate_method eq 'closed_to' and $closedto ) {
72     # if no closedto is configured use default
73     return $::locale->format_date(\%::myconfig, $closedto);
74
75   } elsif ( $startdate_method eq 'start_of_year' ) {
76
77     return $::locale->format_date(\%::myconfig, $start_of_year);
78
79   } elsif ( $startdate_method eq 'all_transactions' ) {
80
81     return $::locale->format_date(\%::myconfig, $mindate);
82
83   } elsif ( $startdate_method eq 'last_ob_or_all_transactions' and $last_ob ) {
84     # use default if there are no ob transactions
85
86     return $::locale->format_date(\%::myconfig, $last_ob);
87
88   } elsif ( $startdate_method eq 'last_ob_or_start_of_year' ) {
89
90     if ( $last_ob ) {
91       return $::locale->format_date(\%::myconfig, $last_ob);
92     } else {
93       return $::locale->format_date(\%::myconfig, $start_of_year);
94     };
95
96   } else {
97     # default action, also used for closedto and last_ob_or_all_transactions if
98     # there are no valid dates
99
100     return $::locale->format_date(\%::myconfig, $mindate);
101   };
102
103 };
104
105 1;
106 __END__
107
108 =pod
109
110 =encoding utf8
111
112 =head1 NAME
113
114 SL::DB::Helper::AccountingPeriod - Helper functions for calculating dates relative to the financial year
115
116 =head1 FUNCTIONS
117
118 =over 4
119
120 =item C<get_balance_startdate_method_options>
121
122 Returns an arrayref of translated options for determining the startdate of a
123 balance period or the yearend period. To be used as the options for a dropdown.
124
125 =item C<get_balance_starting_date $date $startdate_method>
126
127 Given a date this method calculates and returns the starting date of the
128 financial period relative to that date, according to the configured
129 balance_startdate_method in the client configuration. The returned date is
130 locale-formatted and can be used for SQL queries.
131
132 If $date isn't a DateTime object a date string is assumed, which then gets
133 date-parsed.
134
135 If no argument is passed the current day is assumed as default.
136
137 If no startdate method is passed, the default method from defaults is used.
138
139 =back
140
141 =head1 BUGS
142
143 Nothing here yet.
144
145 =head1 AUTHOR
146
147 G. Richardson E<lt>information@kivitendo-premium.deE<gt>
148
149 =cut