2 use Test::More tests => 7;
5 use Support::TestSetup;
11 use SL::DATEV qw(:CONSTANTS);
12 use SL::Dev::CustomerVendor qw(new_customer);
15 my ($customer, $employee, $ar_tax_19, $ar_tax_7, $ar_tax_0);
16 my ($ar_chart, $bank, $ar_amount_chart);
18 $config->{numberformat} = '1.000,00';
23 $params{$_} ||= {} for qw(buchungsgruppe customer);
27 $employee = SL::DB::Manager::Employee->current || croak "No employee";
28 $ar_tax_19 = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19) || croak "No 19% tax";
29 $ar_tax_7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No 7% tax";
30 $ar_tax_0 = SL::DB::Manager::Tax->find_by(taxkey => 0, rate => 0.00) || croak "No 0% tax";
32 $customer = new_customer()->save; # new customer with default name "Testkunde"
34 $ar_chart = SL::DB::Manager::Chart->find_by(accno => '1400') || croak "Can't find Forderungen";
35 $bank = SL::DB::Manager::Chart->find_by(accno => '1200') || croak "Can't find Bank";
36 $ar_amount_chart = SL::DB::Manager::Chart->find_by(accno => '8590') || croak "Can't find verrechn., eigentlich Anzahlungen";
40 Support::TestSetup::login();
44 # check ar without tax
45 my $invoice = _ar(customer => $customer,
48 notes => 'ar without tax',
51 # for testing load a fresh instance of the invoice from the database
52 my $inv = SL::DB::Invoice->new(id => $invoice->id)->load;
54 my $number_of_acc_trans = scalar @{ $inv->transactions };
55 is($::form->round_amount($inv->amount) , 100 , "invoice_amount = 100");
56 is($number_of_acc_trans , 5 , "number of transactions");
57 is($inv->datepaid->to_kivitendo , DateTime->today->to_kivitendo , "datepaid");
58 is($inv->amount - $inv->paid , 0 , "paid = amount ");
59 is($inv->gldate->to_kivitendo, $inv->transactions->[0]->gldate->to_kivitendo, "gldate matches in ar and acc_trans");
61 ok 0, "couldn't find first invoice";
65 my $invoice2 = _ar_with_tax(customer => $customer,
68 notes => 'ar with taxincluded',
70 my $inv_with_tax = SL::DB::Invoice->new(id => $invoice2->id)->load;
71 if ( $inv_with_tax ) {
72 is(scalar @{ $inv_with_tax->transactions }, 7, "number of transactions for inv_with_tax");
74 ok 0, "couldn't find second invoice";
78 is(SL::DB::Manager::Invoice->get_all_count(), 2, "total number of invoices created is 2");
86 SL::DB::Manager::AccTransaction->delete_all(all => 1);
87 SL::DB::Manager::Invoice->delete_all( all => 1);
88 SL::DB::Manager::Customer->delete_all( all => 1);
94 my $amount = $params{amount} || croak "ar needs param amount";
95 my $customer = $params{customer} || croak "ar needs param customer";
96 my $transdate = $params{transdate} || DateTime->today;
97 my $gldate = $params{gldate} || DateTime->today->add(days => 1);
98 my $with_payment = $params{with_payment} || 0;
100 # SL::DB::Invoice has a _before_save_set_invnumber hook, so we don't need to pass invnumber
101 my $invoice = SL::DB::Invoice->new(
104 netamount => $amount,
105 transdate => $transdate,
108 customer_id => $customer->id,
109 taxzone_id => $customer->taxzone_id,
110 currency_id => $customer->currency_id,
111 globalproject_id => $params{project},
112 notes => $params{notes},
116 my $db = $invoice->db;
118 $db->with_transaction( sub {
120 $invoice->add_ar_amount_row(
121 amount => $amount / 2,
122 chart => $ar_amount_chart,
123 tax_id => $ar_tax_0->id,
125 $invoice->add_ar_amount_row(
126 amount => $amount / 2,
127 chart => $ar_amount_chart,
128 tax_id => $ar_tax_0->id,
131 $invoice->create_ar_row( chart => $ar_chart );
133 _save_and_pay_and_check(invoice => $invoice,
135 pay => $with_payment,
141 }) || die "something went wrong: " . $db->error;
148 my $amount = $params{amount} || croak "ar needs param amount";
149 my $customer = $params{customer} || croak "ar needs param customer";
150 my $transdate = $params{transdate} || DateTime->today;
151 my $gldate = $params{gldate} || DateTime->today->add(days => 1);
152 my $with_payment = $params{with_payment} || 0;
154 my $invoice = SL::DB::Invoice->new(
157 netamount => $amount,
158 transdate => $transdate,
161 customer_id => $customer->id,
162 taxzone_id => $customer->taxzone_id,
163 currency_id => $customer->currency_id,
164 globalproject_id => $params{project},
165 notes => $params{notes},
169 my $db = $invoice->db;
171 $db->with_transaction( sub {
173 # TODO: check for currency and exchange rate
175 $invoice->add_ar_amount_row(
176 amount => $amount / 2,
177 chart => $ar_amount_chart,
178 tax_id => $ar_tax_19->id,
180 $invoice->add_ar_amount_row(
181 amount => $amount / 2,
182 chart => $ar_amount_chart,
183 tax_id => $ar_tax_19->id,
186 $invoice->create_ar_row( chart => $ar_chart );
187 _save_and_pay_and_check(invoice => $invoice,
189 pay => $with_payment,
194 }) || die "something went wrong: " . $db->error;
198 sub _save_and_pay_and_check {
200 my $invoice = $params{invoice} // croak "invoice missing";
201 my $datev_check = $params{datev_check} // 1; # do datev check by default
202 croak "no bank" unless ref $params{bank} eq 'SL::DB::Chart';
204 # make sure invoice is saved before making payments
205 my $return = $invoice->save;
207 $invoice->pay_invoice(chart_id => $params{bank}->id,
208 amount => $invoice->amount,
209 transdate => $invoice->transdate->to_kivitendo,
210 payment_type => 'without_skonto', # default if not specified
214 my $datev = SL::DATEV->new(
215 dbh => $invoice->db->dbh,
216 trans_id => $invoice->id,
219 $datev->generate_datev_data;
221 # _save_and_pay_and_check should always be called inside a with_transaction block
222 if ($datev->errors) {
223 $invoice->db->dbh->rollback;
224 die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;