Merge branch 'b-3.6.1' into mebil
[kivitendo-erp.git] / sql / Pg-upgrade2 / convert_drafts_to_record_templates.pl
1 # @tag: convert_drafts_to_record_templates
2 # @description: Umwandlung von existierenden Entwürfen in Buchungsvorlagen für die Finanzbuchhaltung
3 # @depends: create_record_template_tables
4 package SL::DBUpgrade2::convert_drafts_to_record_templates;
5
6 use strict;
7 use utf8;
8
9 use parent qw(SL::DBUpgrade2::Base);
10
11 use SL::DBUtils;
12 use SL::YAML;
13
14 sub prepare_statements {
15   my ($self) = @_;
16
17   $self->{q_draft} = qq|
18     SELECT description, form, employee_id
19     FROM drafts
20     WHERE module = ?
21 |;
22
23   $self->{q_template} = qq|
24     INSERT INTO record_templates (
25       template_name, template_type,  customer_id,    vendor_id,
26       currency_id,   department_id,  project_id,     employee_id,
27       taxincluded,   direct_debit,   ob_transaction, cb_transaction,
28       reference,     description,    ordnumber,      notes,
29       ar_ap_chart_id
30     ) VALUES (
31       ?, ? ,?, ?,
32       ?, ? ,?, ?,
33       ?, ? ,?, ?,
34       ?, ? ,?, ?,
35       ?
36     )
37     RETURNING id
38 |;
39
40   $self->{q_item} = qq|
41     INSERT INTO record_template_items (
42       record_template_id,
43       chart_id, tax_id,  project_id,
44       amount1,  amount2, source, memo
45     ) VALUES (
46       ?,
47       ?, ?, ?,
48       ?, ?, ?, ?
49     )
50 |;
51
52   $self->{h_draft}    = $self->dbh->prepare($self->{q_draft})    || die;
53   $self->{h_template} = $self->dbh->prepare($self->{q_template}) || die;
54   $self->{h_item}     = $self->dbh->prepare($self->{q_item})     || die;
55 }
56
57 sub fetch_auxilliary_data {
58   my ($self) = @_;
59
60   $self->{default_currency_id}  = selectfirst_hashref_query($::form, $self->dbh, qq|SELECT currency_id FROM defaults|)->{currency_id};
61   $self->{chart_ids_by_accno}   = { selectall_as_map($::form, $self->dbh, qq|SELECT id, accno FROM chart|,      'accno', 'id') };
62   $self->{currency_ids_by_name} = { selectall_as_map($::form, $self->dbh, qq|SELECT id, name  FROM currencies|, 'name',  'id') };
63 }
64
65 sub finish_statements {
66   my ($self) = @_;
67
68   $self->{h_item}->finish;
69   $self->{h_template}->finish;
70   $self->{h_draft}->finish;
71 }
72
73 sub migrate_ar_drafts {
74   my ($self) = @_;
75
76   $self->{h_draft}->execute('ar') || die $self->{h_draft}->errstr;
77
78   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
79     my $draft       = SL::YAML::Load($draft_record->{form});
80     my $currency_id = $self->{currency_ids_by_name}->{$draft->{currency}};
81     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
82
83     next unless $currency_id;
84
85     my @values = (
86       # template_name, template_type, customer_id, vendor_id,
87       $draft_record->{description} // $::locale->text('unnamed record template'),
88       'ar_transaction',
89       $draft->{customer_id} || undef,
90       undef,
91
92       # currency_id, department_id, project_id, employee_id,
93       $currency_id,
94       $draft->{department_id}    || undef,
95       $draft->{globalproject_id} || undef,
96       $employee_id,
97
98       # taxincluded,   direct_debit, ob_transaction, cb_transaction,
99       $draft->{taxincluded}  ? 1 : 0,
100       $draft->{direct_debit} ? 1 : 0,
101       0,
102       0,
103
104       # reference, description, ordnumber, notes,
105       undef,
106       undef,
107       $draft->{ordnumber},
108       $draft->{notes},
109
110       # ar_ap_chart_id
111       $self->{chart_ids_by_accno}->{$draft->{ARselected}},
112     );
113
114     $self->{h_template}->execute(@values) || die $self->{h_template}->errstr;
115     my ($template_id) = $self->{h_template}->fetchrow_array;
116
117     foreach my $row (1..$draft->{rowcount}) {
118       my ($chart_accno) = split m{--}, $draft->{"AR_amount_${row}"};
119       my ($tax_id)      = split m{--}, $draft->{"taxchart_${row}"};
120       my $chart_id      = $self->{chart_ids_by_accno}->{$chart_accno // ''};
121       my $amount        = $::form->parse_amount($self->{format}, $draft->{"amount_${row}"});
122
123       # $tax_id may be 0 as there's an entry in tax with id = 0.
124       # $chart_id must not be 0 as there's no entry in chart with id = 0.
125       next unless $chart_id && (($tax_id // '') ne '');
126
127       @values = (
128         # record_template_id,
129         $template_id,
130
131         # chart_id, tax_id, project_id,
132         $chart_id,
133         $tax_id,
134         $draft->{"project_id_${row}"} || undef,
135
136         # amount1, amount2, source, memo
137         $amount,
138         undef,
139         undef,
140         undef,
141       );
142
143       $self->{h_item}->execute(@values) || die $self->{h_item}->errstr;
144     }
145   }
146 }
147
148 sub migrate_ap_drafts {
149   my ($self) = @_;
150
151   $self->{h_draft}->execute('ap') || die $self->{h_draft}->errstr;
152
153   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
154     my $draft       = SL::YAML::Load($draft_record->{form});
155     my $currency_id = $self->{currency_ids_by_name}->{$draft->{currency}};
156     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
157
158     next unless $currency_id;
159
160     my @values = (
161       # template_name, template_type, customer_id, vendor_id,
162       $draft_record->{description} // $::locale->text('unnamed record template'),
163       'ap_transaction',
164       undef,
165       $draft->{vendor_id} || undef,
166
167       # currency_id, department_id, project_id, employee_id,
168       $currency_id,
169       $draft->{department_id}    || undef,
170       $draft->{globalproject_id} || undef,
171       $employee_id,
172
173       # taxincluded,   direct_debit, ob_transaction, cb_transaction,
174       $draft->{taxincluded}   ? 1 : 0,
175       $draft->{direct_credit} ? 1 : 0,
176       0,
177       0,
178
179       # reference, description, ordnumber, notes,
180       undef,
181       undef,
182       $draft->{ordnumber},
183       $draft->{notes},
184
185       # ar_ap_chart_id
186       $self->{chart_ids_by_accno}->{$draft->{APselected}},
187     );
188
189     $self->{h_template}->execute(@values) || die $self->{h_template}->errstr;
190     my ($template_id) = $self->{h_template}->fetchrow_array;
191
192     foreach my $row (1..$draft->{rowcount}) {
193       my ($chart_accno) = split m{--}, $draft->{"AP_amount_${row}"};
194       my ($tax_id)      = split m{--}, $draft->{"taxchart_${row}"};
195       my $chart_id      = $self->{chart_ids_by_accno}->{$chart_accno // ''};
196       my $amount        = $::form->parse_amount($self->{format}, $draft->{"amount_${row}"});
197
198       # $tax_id may be 0 as there's an entry in tax with id = 0.
199       # $chart_id must not be 0 as there's no entry in chart with id = 0.
200       next unless $chart_id && (($tax_id // '') ne '');
201
202       @values = (
203         # record_template_id,
204         $template_id,
205
206         # chart_id, tax_id, project_id,
207         $chart_id,
208         $tax_id,
209         $draft->{"project_id_${row}"} || undef,
210
211         # amount1, amount2, source, memo
212         $amount,
213         undef,
214         undef,
215         undef,
216       );
217
218       $self->{h_item}->execute(@values) || die $self->{h_item}->errstr;
219     }
220   }
221 }
222
223 sub migrate_gl_drafts {
224   my ($self) = @_;
225
226   $self->{h_draft}->execute('gl') || die $self->{h_draft}->errstr;
227
228   while (my $draft_record = $self->{h_draft}->fetchrow_hashref) {
229     my $draft       = SL::YAML::Load($draft_record->{form});
230     my $employee_id = $draft_record->{employee_id} || $draft->{employee_id} || (split m{--}, $draft->{employee})[1] || undef;
231
232     my @values = (
233       # template_name, template_type, customer_id, vendor_id,
234       $draft_record->{description} // $::locale->text('unnamed record template'),
235       'gl_transaction',
236       undef,
237       undef,
238
239       # currency_id, department_id, project_id, employee_id,
240       $self->{default_currency_id},
241       $draft->{department_id} || undef,
242       undef,
243       $employee_id,
244
245       # taxincluded,   direct_debit, ob_transaction, cb_transaction,
246       $draft->{taxincluded}    ? 1 : 0,
247       0,
248       $draft->{ob_transaction} ? 1 : 0,
249       $draft->{cb_transaction} ? 1 : 0,
250
251       # reference, description, ordnumber, notes,
252       $draft->{reference},
253       $draft->{description},
254       undef,
255       undef,
256
257       # ar_ap_chart_id
258       undef,
259     );
260
261     $self->{h_template}->execute(@values) || die $self->{h_template}->errstr;
262     my ($template_id) = $self->{h_template}->fetchrow_array;
263
264     foreach my $row (1..$draft->{rowcount}) {
265       my ($chart_accno) = split m{--}, $draft->{"accno_${row}"};
266       my ($tax_id)      = split m{--}, $draft->{"taxchart_${row}"};
267       my $chart_id      = $self->{chart_ids_by_accno}->{$chart_accno // ''};
268       my $debit         = $::form->parse_amount($self->{format}, $draft->{"debit_${row}"});
269       my $credit        = $::form->parse_amount($self->{format}, $draft->{"credit_${row}"});
270
271       # $tax_id may be 0 as there's an entry in tax with id = 0.
272       # $chart_id must not be 0 as there's no entry in chart with id = 0.
273       next unless $chart_id && (($tax_id // '') ne '');
274
275       @values = (
276         # record_template_id,
277         $template_id,
278
279         # chart_id, tax_id, project_id,
280         $chart_id,
281         $tax_id,
282         $draft->{"project_id_${row}"} || undef,
283
284         # amount1, amount2, source, memo
285         $debit,
286         $credit,
287         $draft->{"source_${row}"},
288         $draft->{"memo_${row}"},
289       );
290
291       $self->{h_item}->execute(@values) || die $self->{h_item}->errstr;
292     }
293   }
294 }
295
296 sub clean_drafts {
297   my ($self) = @_;
298
299   $self->db_query(qq|DELETE FROM drafts WHERE module IN ('ar', 'ap', 'gl')|);
300 }
301
302 sub run {
303   my ($self) = @_;
304
305   # A dummy for %::myconfig used for parsing numbers. The existing
306   # drafts have a fundamental flaw: they store numbers & dates in the
307   # database still formatted to the user's preferences. Determining
308   # the correct format is not possible. Therefore this script simply
309   # assumes that the installation is used by people with German
310   # preferences regarding both settings.
311   $self->{format} = {
312     numberformat => '1000,00',
313     dateformat   => 'dd.mm.yy',
314   };
315
316   $self->prepare_statements;
317   $self->fetch_auxilliary_data;
318   $self->migrate_ar_drafts;
319   $self->migrate_ap_drafts;
320   $self->migrate_gl_drafts;
321   $self->clean_drafts;
322   $self->finish_statements;
323
324   return 1;
325 }
326
327 1;