X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;ds=inline;f=bin%2Fmozilla%2Fir.pl;h=48ff6c3b085059e61ff59bbcc17fd7f882652988;hb=a910619e4c9c90063f5d6a17e51a8da9eadc1ac0;hp=e08c4355dbeb52420c9001e104074b03f0781290;hpb=60fd91996b9b38f11519f467e8b0664448db2755;p=kivitendo-erp.git
diff --git a/bin/mozilla/ir.pl b/bin/mozilla/ir.pl
index e08c4355d..48ff6c3b0 100644
--- a/bin/mozilla/ir.pl
+++ b/bin/mozilla/ir.pl
@@ -24,7 +24,8 @@
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1335, USA.
#======================================================================
#
# Inventory received module
@@ -34,14 +35,17 @@
use SL::FU;
use SL::IR;
use SL::IS;
-use SL::PE;
+use SL::DB::BankTransactionAccTrans;
use SL::DB::Default;
+use SL::DB::Department;
+use SL::DB::Project;
use SL::DB::PurchaseInvoice;
+use SL::DB::Vendor;
+use List::MoreUtils qw(uniq);
use List::Util qw(max sum);
use List::UtilsBy qw(sort_by);
require "bin/mozilla/io.pl";
-require "bin/mozilla/arap.pl";
require "bin/mozilla/common.pl";
use strict;
@@ -50,6 +54,20 @@ use strict;
# end of main
+sub _may_view_or_edit_this_invoice {
+ return 1 if $::auth->assert('ap_transactions', 1); # may edit all invoices
+ return 0 if !$::form->{id}; # creating new invoices isn't allowed without invoice_edit
+ return 0 if !$::form->{globalproject_id}; # existing records without a project ID are not allowed
+ return SL::DB::Project->new(id => $::form->{globalproject_id})->load->may_employee_view_project_invoices(SL::DB::Manager::Employee->current);
+}
+
+sub _assert_access {
+ my $cache = $::request->cache('ap.pl::_assert_access');
+
+ $cache->{_may_view_or_edit_this_invoice} = _may_view_or_edit_this_invoice() if !exists $cache->{_may_view_or_edit_this_invoice};
+ $::form->show_generic_error($::locale->text("You do not have the permissions to access this function.")) if ! $cache->{_may_view_or_edit_this_invoice};
+}
+
sub add {
$main::lxdebug->enter_sub();
@@ -76,11 +94,13 @@ sub add {
sub edit {
$main::lxdebug->enter_sub();
+ # Delay access check to after the invoice's been loaded in
+ # "create_links" so that project-specific invoice rights can be
+ # evaluated.
+
my $form = $main::form;
my $locale = $main::locale;
- $main::auth->assert('vendor_invoice_edit');
-
$form->{show_details} = $::myconfig{show_form_details};
# show history button
@@ -99,26 +119,18 @@ sub edit {
sub invoice_links {
$main::lxdebug->enter_sub();
+ # Delay access check to after the invoice's been loaded so that
+ # project-specific invoice rights can be evaluated.
+
my $form = $main::form;
my %myconfig = %main::myconfig;
- $main::auth->assert('vendor_invoice_edit');
-
$form->{vc} = 'vendor';
# create links
$form->create_links("AP", \%myconfig, "vendor");
- #quote all_vendor Bug 133
- foreach my $ref (@{ $form->{all_vendor} }) {
- $ref->{name} = $form->quote($ref->{name});
- }
-
- if ($form->{all_vendor}) {
- unless ($form->{vendor_id}) {
- $form->{vendor_id} = $form->{all_vendor}->[0]->{id};
- }
- }
+ _assert_access();
$form->backup_vars(qw(payment_id language_id taxzone_id
currency delivery_term_id intnotes cp_id));
@@ -132,25 +144,6 @@ sub invoice_links {
my @curr = $form->get_all_currencies();
map { $form->{selectcurrency} .= "$_\n" } @curr;
- $form->{oldvendor} = "$form->{vendor}--$form->{vendor_id}";
-
- # build vendor/customer drop down comatibility... don't ask
- if (@{ $form->{"all_vendor"} || [] }) {
- $form->{"selectvendor"} = 1;
- $form->{vendor} = qq|$form->{vendor}--$form->{vendor_id}|;
- }
-
- # departments
- if ($form->{all_departments}) {
- $form->{selectdepartment} = " \n";
- $form->{department} = "$form->{department}--$form->{department_id}";
-
- map {
- $form->{selectdepartment} .=
- " $_->{description}--$_->{id}\n"
- } (@{ $form->{all_departments} || [] });
- }
-
# forex
$form->{forex} = $form->{exchangerate};
my $exchangerate = ($form->{exchangerate}) ? $form->{exchangerate} : 1;
@@ -202,11 +195,11 @@ sub invoice_links {
sub prepare_invoice {
$main::lxdebug->enter_sub();
+ _assert_access();
+
my $form = $main::form;
my %myconfig = %main::myconfig;
- $main::auth->assert('vendor_invoice_edit');
-
$form->{type} = "purchase_invoice";
if ($form->{id}) {
@@ -245,37 +238,173 @@ sub prepare_invoice {
$main::lxdebug->leave_sub();
}
+sub setup_ir_action_bar {
+ my $form = $::form;
+ my $change_never = $::instance_conf->get_ir_changeable == 0;
+ my $change_on_same_day_only = $::instance_conf->get_ir_changeable == 2 && ($form->current_date(\%::myconfig) ne $form->{gldate});
+ my $has_storno = ($::form->{storno} && !$::form->{storno_id});
+ my $payments_balanced = ($::form->{oldtotalpaid} == 0);
+ my $may_edit_create = $::auth->assert('vendor_invoice_edit', 1);
+
+ my $has_sepa_exports;
+ if ($form->{id}) {
+ my $invoice = SL::DB::Manager::PurchaseInvoice->find_by(id => $form->{id});
+ $has_sepa_exports = 1 if ($invoice->find_sepa_export_items()->[0]);
+ }
+
+ my $is_linked_bank_transaction;
+ if ($::form->{id}
+ && SL::DB::Default->get->payments_changeable != 0
+ && SL::DB::Manager::BankTransactionAccTrans->find_by(ap_id => $::form->{id})) {
+
+ $is_linked_bank_transaction = 1;
+ }
+ for my $bar ($::request->layout->get('actionbar')) {
+ $bar->add(
+ action => [
+ t8('Update'),
+ submit => [ '#form', { action => "update" } ],
+ id => 'update_button',
+ accesskey => 'enter',
+ disabled => !$may_edit_create ? t8('You must not change this invoice.') : undef,
+ ],
+
+ combobox => [
+ action => [
+ t8('Post'),
+ submit => [ '#form', { action => "post" } ],
+ checks => [ 'kivi.validate_form' ],
+ checks => [ 'kivi.validate_form', 'kivi.AP.check_fields_before_posting', 'kivi.AP.check_duplicate_invnumber' ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : $form->{locked} ? t8('The billing period has already been locked.')
+ : $form->{storno} ? t8('A canceled invoice cannot be posted.')
+ : ($form->{id} && $change_never) ? t8('Changing invoices has been disabled in the configuration.')
+ : ($form->{id} && $change_on_same_day_only) ? t8('Invoices can only be changed on the day they are posted.')
+ : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+ : undef,
+ ],
+ action => [
+ t8('Post Payment'),
+ submit => [ '#form', { action => "post_payment" } ],
+ checks => [ 'kivi.validate_form' ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+ : undef,
+ ],
+ action => [
+ t8('Mark as paid'),
+ submit => [ '#form', { action => "mark_as_paid" } ],
+ checks => [ 'kivi.validate_form' ],
+ confirm => t8('This will remove the invoice from showing as unpaid even if the unpaid amount does not match the amount. Proceed?'),
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : undef,
+ only_if => $::instance_conf->get_ir_show_mark_as_paid,
+ ],
+ ], # end of combobox "Post"
+
+ combobox => [
+ action => [ t8('Storno'),
+ submit => [ '#form', { action => "storno" } ],
+ checks => [ 'kivi.validate_form' ],
+ confirm => t8('Do you really want to cancel this invoice?'),
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : $has_sepa_exports ? t8('This invoice has been linked with a sepa export, undo this first.')
+ : !$payments_balanced ? t8('Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount')
+ : undef,
+ ],
+ action => [ t8('Delete'),
+ submit => [ '#form', { action => "delete" } ],
+ checks => [ 'kivi.validate_form' ],
+ confirm => t8('Do you really want to delete this object?'),
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : $form->{locked} ? t8('The billing period has already been locked.')
+ : $change_never ? t8('Changing invoices has been disabled in the configuration.')
+ : $change_on_same_day_only ? t8('Invoices can only be changed on the day they are posted.')
+ : $has_sepa_exports ? t8('This invoice has been linked with a sepa export, undo this first.')
+ : $has_storno ? t8('Can only delete the "Storno zu" part of the cancellation pair.')
+ : $is_linked_bank_transaction ? t8('This transaction is linked with a bank transaction. Please undo and redo the bank transaction booking if needed.')
+ : undef,
+ ],
+ ], # end of combobox "Storno"
+
+ 'separator',
+
+ combobox => [
+ action => [ t8('Workflow') ],
+ action => [
+ t8('Use As New'),
+ submit => [ '#form', { action => "use_as_new" } ],
+ checks => [ 'kivi.validate_form' ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : !$form->{id} ? t8('This invoice has not been posted yet.')
+ : undef,
+ ],
+ ], # end of combobox "Workflow"
+
+ combobox => [
+ action => [ t8('more') ],
+ action => [
+ t8('History'),
+ call => [ 'set_history_window', $::form->{id} * 1, 'id', 'glid' ],
+ disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
+ ],
+ action => [
+ t8('Follow-Up'),
+ call => [ 'follow_up_window' ],
+ disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
+ ],
+ action => [
+ t8('Drafts'),
+ call => [ 'kivi.Draft.popup', 'ir', 'invoice', $::form->{draft_id}, $::form->{draft_description} ],
+ disabled => !$may_edit_create ? t8('You must not change this invoice.')
+ : $form->{id} ? t8('This invoice has already been posted.')
+ : $form->{locked} ? t8('The billing period has already been locked.')
+ : undef,
+ ],
+ ], # end of combobox "more"
+ );
+ }
+ $::request->layout->add_javascripts('kivi.Validator.js', 'kivi.AP.js');
+
+}
+
sub form_header {
$main::lxdebug->enter_sub();
+ _assert_access();
+
my $form = $main::form;
my %myconfig = %main::myconfig;
my $locale = $main::locale;
my $cgi = $::request->{cgi};
- $main::auth->assert('vendor_invoice_edit');
-
my %TMPL_VAR = ();
my @custom_hiddens;
- $TMPL_VAR{invoice_obj} = SL::DB::PurchaseInvoice->new(id => $form->{id})->load if $form->{id};
- $form->{employee_id} = $form->{old_employee_id} if $form->{old_employee_id};
- $form->{salesman_id} = $form->{old_salesman_id} if $form->{old_salesman_id};
+ $TMPL_VAR{invoice_obj} = SL::DB::PurchaseInvoice->load_cached($form->{id}) if $form->{id};
+ $TMPL_VAR{vendor_obj} = SL::DB::Vendor->load_cached($form->{vendor_id}) if $form->{vendor_id};
+ my $current_employee = SL::DB::Manager::Employee->current;
+ $form->{employee_id} = $form->{old_employee_id} if $form->{old_employee_id};
+ $form->{salesman_id} = $form->{old_salesman_id} if $form->{old_salesman_id};
+ $form->{employee_id} ||= $current_employee->id;
+ $form->{salesman_id} ||= $current_employee->id;
$form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
- my @old_project_ids = ($form->{"globalproject_id"});
- map { push @old_project_ids, $form->{"project_id_$_"} if $form->{"project_id_$_"}; } 1..$form->{"rowcount"};
+ my @old_project_ids = uniq grep { $_ } map { $_ * 1 } ($form->{"globalproject_id"}, map { $form->{"project_id_$_"} } 1..$form->{"rowcount"});
+ my @conditions = @old_project_ids ? (id => \@old_project_ids) : ();
+ $TMPL_VAR{ALL_PROJECTS} = SL::DB::Manager::Project->get_all_sorted(query => [ or => [ active => 1, @conditions ]]);
+ $form->{ALL_PROJECTS} = $TMPL_VAR{ALL_PROJECTS}; # make projects available for second row drop-down in io.pl
- $form->get_lists("projects" => { "key" => "ALL_PROJECTS",
- "all" => 0,
- "old_id" => \@old_project_ids },
- "taxzones" => "ALL_TAXZONES",
+ $form->get_lists("taxzones" => ($form->{id} ? "ALL_TAXZONES" : "ALL_ACTIVE_TAXZONES"),
"currencies" => "ALL_CURRENCIES",
- "vendors" => "ALL_VENDORS",
- "departments" => "all_departments",
"price_factors" => "ALL_PRICE_FACTORS");
+ $TMPL_VAR{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all_sorted;
$TMPL_VAR{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ or => [ id => $::form->{employee_id}, deleted => 0 ] ]);
$TMPL_VAR{ALL_CONTACTS} = SL::DB::Manager::Contact->get_all_sorted(query => [
or => [
@@ -286,15 +415,6 @@ sub form_header {
]
]
]);
- $TMPL_VAR{department_labels} = sub { "$_[0]->{description}--$_[0]->{id}" };
-
- # customer
- $TMPL_VAR{vc_keys} = sub { "$_[0]->{name}--$_[0]->{id}" };
- $TMPL_VAR{vclimit} = $myconfig{vclimit};
- $TMPL_VAR{vc_select} = "customer_or_vendor_selection_window('vendor', '', 1, 0)";
- push @custom_hiddens, "vendor_id";
- push @custom_hiddens, "oldvendor";
- push @custom_hiddens, "selectvendor";
# currencies and exchangerate
my @values = map { $_ } @{ $form->{ALL_CURRENCIES} };
@@ -312,36 +432,33 @@ sub form_header {
$TMPL_VAR{creditwarning} = ($form->{creditlimit} != 0) && ($form->{creditremaining} < 0) && !$form->{update};
$TMPL_VAR{is_credit_remaining_negativ} = $form->{creditremaining} =~ /-/;
- my $follow_up_vc = $form->{vendor};
- $follow_up_vc =~ s/--\d*\s*$//;
- $TMPL_VAR{vendor_name} = $follow_up_vc;
-
# set option selected
foreach my $item (qw(AP)) {
$form->{"select$item"} =~ s/ selected//;
$form->{"select$item"} =~ s/option>\Q$form->{$item}\E/option selected>$form->{$item}/;
}
- $TMPL_VAR{is_type_credit_note} = $form->{type} eq "credit_note";
$TMPL_VAR{is_format_html} = $form->{format} eq 'html';
$TMPL_VAR{dateformat} = $myconfig{dateformat};
$TMPL_VAR{numberformat} = $myconfig{numberformat};
# hiddens
$TMPL_VAR{HIDDENS} = [qw(
- id action type media format queued printed emailed title vc discount
+ id type queued printed emailed title vc discount
title creditlimit creditremaining tradediscount business closedto locked shipped storno storno_id
max_dunning_level dunning_amount
shiptoname shiptostreet shiptozipcode shiptocity shiptocountry shiptogln shiptocontact shiptophone shiptofax
shiptoemail shiptodepartment_1 shiptodepartment_2 message email subject cc bcc taxaccounts cursor_fokus
- convert_from_do_ids convert_from_oe_ids show_details gldate useasnew
+ convert_from_do_ids convert_from_oe_ids convert_from_ap_ids show_details gldate useasnew
), @custom_hiddens,
- map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts}];
+ map { $_.'_rate', $_.'_description', $_.'_taxnumber', $_.'_tax_id' } split / /, $form->{taxaccounts}];
$TMPL_VAR{payment_terms_obj} = get_payment_terms_for_invoice();
- $form->{duedate} = $TMPL_VAR{payment_terms_obj}->calc_date(reference_date => $form->{invdate}, due_date => $form->{due_due})->to_kivitendo if $TMPL_VAR{payment_terms_obj};
+ $form->{duedate} = $TMPL_VAR{payment_terms_obj}->calc_date(reference_date => $form->{invdate}, due_date => $form->{duedate})->to_kivitendo if $TMPL_VAR{payment_terms_obj};
- $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.Draft kivi.SalesPurchase ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_customer autocomplete_part client_js));
+ $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.Draft kivi.File kivi.SalesPurchase kivi.Part kivi.CustomerVendor kivi.Validator ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_project client_js));
+
+ setup_ir_action_bar();
$form->header();
@@ -372,21 +489,15 @@ sub _sort_payments {
sub form_footer {
$main::lxdebug->enter_sub();
+ _assert_access();
+
my $form = $main::form;
my %myconfig = %main::myconfig;
my $locale = $main::locale;
- $main::auth->assert('vendor_invoice_edit');
-
$form->{invtotal} = $form->{invsubtotal};
$form->{oldinvtotal} = $form->{invtotal};
- # note rows
- $form->{rows} = max 2,
- $form->numtextrows($form->{notes}, 26, 8),
- $form->numtextrows($form->{intnotes}, 35, 8);
-
-
# tax, total and subtotal calculations
my ($tax, $subtotal);
$form->{taxaccounts_array} = [ split / /, $form->{taxaccounts} ];
@@ -406,7 +517,7 @@ sub form_footer {
# follow ups
if ($form->{id}) {
- $form->{follow_ups} = FU->follow_ups('trans_id' => $form->{id}) || [];
+ $form->{follow_ups} = FU->follow_ups('trans_id' => $form->{id}, 'not_done' => 1) || [];
$form->{follow_ups_unfinished} = ( sum map { $_->{due} * 1 } @{ $form->{follow_ups} } ) || 0;
}
@@ -452,7 +563,6 @@ sub form_footer {
$form->{ALL_DELIVERY_TERMS} = SL::DB::Manager::DeliveryTerm->get_all_sorted();
print $form->parse_html_template('ir/form_footer', {
- is_type_credit_note => ($form->{type} eq "credit_note"),
totalpaid => $totalpaid,
paid_missing => $form->{invtotal} - $totalpaid,
show_storno => $form->{id} && !$form->{storno} && !IS->has_storno(\%myconfig, $form, "ap") && !$totalpaid,
@@ -468,16 +578,15 @@ sub form_footer {
}
sub mark_as_paid {
- $main::lxdebug->enter_sub();
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
+ $::auth->assert('vendor_invoice_edit');
- $main::auth->assert('vendor_invoice_edit');
+ SL::DB::PurchaseInvoice->new(id => $::form->{id})->load->mark_as_paid;
- &mark_as_paid_common(\%myconfig,"ap");
+ $::form->redirect($::locale->text("Marked as paid"));
+}
- $main::lxdebug->leave_sub();
+sub show_draft {
+ update();
}
sub update {
@@ -488,7 +597,9 @@ sub update {
$main::auth->assert('vendor_invoice_edit');
- &check_name('vendor');
+ if (($form->{previous_vendor_id} || $form->{vendor_id}) != $form->{vendor_id}) {
+ IR->get_vendor(\%myconfig, $form);
+ }
if (!$form->{forex}) { # read exchangerate from input field (not hidden)
$form->{exchangerate} = $form->parse_amount(\%myconfig, $form->{exchangerate});
@@ -626,7 +737,8 @@ sub storno {
$form->{paidaccounts} = 0;
map { my $key = $_; delete $form->{$key} if grep { $key =~ /^$_/ } qw(datepaid_ gldate_ acc_trans_id_ source_ memo_ paid_ exchangerate_ AR_paid_) } keys %{ $form };
# set new ids for storno invoice
- delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+ # set new persistent ids for storno invoice items
+ $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
# saving the history
if(!exists $form->{addition} && $form->{id} ne "") {
@@ -637,6 +749,8 @@ sub storno {
}
# /saving the history
+ # record link invoice to storno
+ $form->{convert_from_ap_ids} = $form->{id};
$form->{storno_id} = $form->{id};
$form->{storno} = 1;
$form->{id} = "";
@@ -747,14 +861,14 @@ sub post {
$form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
$form->isblank("invdate", $locale->text('Invoice Date missing!'));
- $form->isblank("vendor", $locale->text('Vendor missing!'));
+ $form->isblank("vendor_id", $locale->text('Vendor missing!'));
$form->isblank("invnumber", $locale->text('Invnumber missing!'));
$form->{invnumber} =~ s/^\s*//g;
$form->{invnumber} =~ s/\s*$//g;
# if the vendor changed get new values
- if (&check_name('vendor')) {
+ if (($form->{previous_vendor_id} || $form->{vendor_id}) != $form->{vendor_id}) {
&update;
$::dispatcher->end_request;
}
@@ -821,8 +935,11 @@ sub post {
$form->save_history;
}
# /saving the history
+ $form->{callback} = 'ir.pl?action=edit&id=' . $form->{id};
$form->redirect( $locale->text('Invoice')
. " $form->{invnumber} "
+ . ", " . $locale->text('ID')
+ . ': ' . $form->{id} . ' '
. $locale->text('posted!'));
}
$form->error($locale->text('Cannot post invoice!'));
@@ -870,7 +987,7 @@ sub delete {
sub display_form {
$::lxdebug->enter_sub;
- $::auth->assert('vendor_invoice_edit');
+ _assert_access();
relink_accounts();