From 7f8599c0909affd56ad82fd842015bb51c6a3dbf Mon Sep 17 00:00:00 2001
From: Moritz Bunkus
Date: Thu, 24 Jan 2013 12:35:38 +0100
Subject: [PATCH] Projektverwaltung auf Rose- und Controller-Code umgestellt
---
SL/Controller/Project.pm | 290 ++++++++++++++++
SL/DB/Manager/Project.pm | 79 +++++
SL/DB/Project.pm | 59 +++-
SL/Projects.pm | 244 --------------
bin/mozilla/arap.pl | 51 ---
bin/mozilla/projects.pl | 316 ------------------
bin/mozilla/rp.pl | 35 +-
locale/de/all | 16 +-
menu.ini | 8 +-
projects.pl | 1 -
.../project_form.html => project/form.html} | 48 ++-
templates/webpages/project/report_bottom.html | 2 +
templates/webpages/project/search.html | 65 ++++
templates/webpages/projects/search.html | 91 -----
templates/webpages/rp/report.html | 6 +-
15 files changed, 532 insertions(+), 779 deletions(-)
create mode 100644 SL/Controller/Project.pm
create mode 100644 SL/DB/Manager/Project.pm
delete mode 100644 SL/Projects.pm
delete mode 100644 bin/mozilla/projects.pl
delete mode 120000 projects.pl
rename templates/webpages/{projects/project_form.html => project/form.html} (53%)
create mode 100644 templates/webpages/project/report_bottom.html
create mode 100644 templates/webpages/project/search.html
delete mode 100644 templates/webpages/projects/search.html
diff --git a/SL/Controller/Project.pm b/SL/Controller/Project.pm
new file mode 100644
index 000000000..fa42007bd
--- /dev/null
+++ b/SL/Controller/Project.pm
@@ -0,0 +1,290 @@
+package SL::Controller::Project;
+
+use strict;
+
+use parent qw(SL::Controller::Base);
+
+use Clone qw(clone);
+
+use SL::Controller::Helper::GetModels;
+use SL::Controller::Helper::Paginated;
+use SL::Controller::Helper::Sorted;
+use SL::Controller::Helper::ParseFilter;
+use SL::Controller::Helper::ReportGenerator;
+use SL::CVar;
+use SL::DB::Customer;
+use SL::DB::Project;
+use SL::Helper::Flash;
+use SL::Locale::String;
+
+use Rose::Object::MakeMethods::Generic
+(
+ scalar => [ qw(project db_args flat_filter) ],
+);
+
+__PACKAGE__->run_before('check_auth');
+__PACKAGE__->run_before('load_project', only => [ qw(edit update destroy) ]);
+
+__PACKAGE__->get_models_url_params('flat_filter');
+__PACKAGE__->make_paginated(
+ MODEL => 'Project',
+ PAGINATE_ARGS => 'db_args',
+ ONLY => [ qw(list) ],
+);
+
+__PACKAGE__->make_sorted(
+ MODEL => 'Project',
+ ONLY => [ qw(list) ],
+
+ DEFAULT_BY => 'projectnumber',
+ DEFAULT_DIR => 1,
+
+ customer => t8('Customer'),
+ description => t8('Description'),
+ projectnumber => t8('Project Number'),
+ type => t8('Type'),
+);
+
+
+#
+# actions
+#
+
+sub action_search {
+ my ($self) = @_;
+
+ my %params;
+
+ $params{CUSTOM_VARIABLES} = CVar->get_configs(module => 'Projects');
+ ($params{CUSTOM_VARIABLES_FILTER_CODE}, $params{CUSTOM_VARIABLES_INCLUSION_CODE})
+ = CVar->render_search_options(variables => $params{CUSTOM_VARIABLES},
+ include_prefix => 'l_',
+ include_value => 'Y');
+
+ $self->render('project/search', %params);
+}
+
+sub action_list {
+ my ($self) = @_;
+
+ $self->setup_db_args_from_filter;
+ $self->flat_filter({ map { $_->{key} => $_->{value} } $::form->flatten_variables('filter') });
+ # $self->make_filter_summary;
+
+ $self->prepare_report;
+
+ $self->{projects} = $self->get_models(%{ $self->db_args });
+
+ $self->list_objects;
+}
+
+sub action_new {
+ my ($self) = @_;
+
+ $self->project(SL::DB::Project->new);
+ $self->display_form(title => $::locale->text('Create a new project'),
+ callback => $::form->{callback} || $self->url_for(action => 'new'));
+}
+
+sub action_edit {
+ my ($self) = @_;
+ $self->display_form(title => $::locale->text('Edit project #1', $self->project->projectnumber),
+ callback => $::form->{callback} || $self->url_for(action => 'edit', id => $self->project->id));
+}
+
+sub action_create {
+ my ($self) = @_;
+
+ $self->project(SL::DB::Project->new);
+ $self->create_or_update;
+}
+
+sub action_update {
+ my ($self) = @_;
+ $self->create_or_update;
+}
+
+sub action_destroy {
+ my ($self) = @_;
+
+ if (eval { $self->project->delete; 1; }) {
+ flash_later('info', $::locale->text('The project has been deleted.'));
+ } else {
+ flash_later('error', $::locale->text('The project is in use and cannot be deleted.'));
+ }
+
+ $self->redirect_to(action => 'search');
+}
+
+#
+# filters
+#
+
+sub check_auth {
+ $::auth->assert('project_edit');
+}
+
+#
+# helpers
+#
+
+sub display_form {
+ my ($self, %params) = @_;
+
+ $params{ALL_CUSTOMERS} = SL::DB::Manager::Customer->get_all_sorted(where => [ or => [ obsolete => 0, obsolete => undef, id => $self->project->customer_id ]]);
+ $params{CUSTOM_VARIABLES} = CVar->get_custom_variables(module => 'Projects', trans_id => $self->project->id);
+ CVar->render_inputs(variables => $params{CUSTOM_VARIABLES}) if @{ $params{CUSTOM_VARIABLES} };
+
+ $::request->{layout}->focus('#projectnumber');
+
+ $self->render('project/form', %params);
+}
+
+sub create_or_update {
+ my $self = shift;
+ my $is_new = !$self->project->id;
+ my $params = delete($::form->{project}) || { };
+
+ delete $params->{id};
+ $self->project->assign_attributes(%{ $params });
+
+ my @errors = $self->project->validate;
+
+ if (@errors) {
+ flash('error', @errors);
+ $self->display_form(title => $is_new ? $::locale->text('Create a new project') : $::locale->text('Edit project'),
+ callback => $::form->{callback});
+ return;
+ }
+
+ $self->project->save;
+
+ CVar->save_custom_variables(
+ dbh => $self->project->db->dbh,
+ module => 'Projects',
+ trans_id => $self->project->id,
+ variables => $::form,
+ always_valid => 1,
+ );
+
+ flash_later('info', $is_new ? $::locale->text('The project has been created.') : $::locale->text('The project has been saved.'));
+
+ $self->redirect_to($::form->{callback} || (action => 'search'));
+}
+
+sub load_project {
+ my ($self) = @_;
+ $self->project(SL::DB::Project->new(id => $::form->{id})->load);
+}
+
+sub setup_db_args_from_filter {
+ my ($self) = @_;
+
+ $self->{filter} = {};
+ my %args = parse_filter(
+ $self->_pre_parse_filter($::form->{filter}, $self->{filter}),
+ with_objects => [ 'customer' ],
+ launder_to => $self->{filter},
+ );
+
+ $self->db_args(\%args);
+}
+
+# unfortunately ParseFilter can't handle compount filters.
+# so we clone the original filter (still need that for serializing)
+# rip out the options we know an replace them with the compound options.
+# ParseFilter will take care of the prefixing then.
+sub _pre_parse_filter {
+ my ($self, $orig_filter, $launder_to) = @_;
+
+ return undef unless $orig_filter;
+
+ my $filter = clone($orig_filter);
+
+ $launder_to->{active} = delete $filter->{active};
+ if ($orig_filter->{active} ne 'both') {
+ push @{ $filter->{and} }, $orig_filter->{active} eq 'active' ? (active => 1) : (or => [ active => 0, active => undef ]);
+ }
+
+ $launder_to->{valid} = delete $filter->{valid};
+ if ($orig_filter->{valid} ne 'both') {
+ push @{ $filter->{and} }, $orig_filter->{valid} eq 'valid' ? (valid => 1) : (or => [ valid => 0, valid => undef ]);
+ }
+
+ $launder_to->{status} = delete $filter->{status};
+ if ($orig_filter->{status} ne 'all') {
+ push @{ $filter->{and} }, SL::DB::Manager::Project->is_not_used_filter;
+ }
+
+ return $filter;
+}
+
+sub prepare_report {
+ my ($self) = @_;
+
+ my $callback = $self->get_callback;
+
+ my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
+ $self->{report} = $report;
+
+ my @columns = qw(projectnumber description customer active valid type);
+ my @sortable = qw(projectnumber description customer type);
+
+ my %column_defs = (
+ projectnumber => { obj_link => sub { $self->url_for(action => 'edit', id => $_[0]->id, callback => $callback) } },
+ description => { obj_link => sub { $self->url_for(action => 'edit', id => $_[0]->id, callback => $callback) } },
+ type => { },
+ customer => { sub => sub { $_[0]->customer ? $_[0]->customer->name : '' } },
+ active => { sub => sub { $_[0]->active ? $::locale->text('Active') : $::locale->text('Inactive') },
+ text => $::locale->text('Active') },
+ valid => { sub => sub { $_[0]->valid ? $::locale->text('Valid') : $::locale->text('Invalid') },
+ text => $::locale->text('Valid') },
+ );
+
+ map { $column_defs{$_}->{text} ||= $::locale->text( $self->get_sort_spec->{$_}->{title} ) } keys %column_defs;
+
+ $report->set_options(
+ std_column_visibility => 1,
+ controller_class => 'Project',
+ output_format => 'HTML',
+ top_info_text => $::locale->text('Projects'),
+ raw_bottom_info_text => $self->render('project/report_bottom', { no_output => 1, partial => 1 }),
+ title => $::locale->text('Projects'),
+ allow_pdf_export => 1,
+ allow_csv_export => 1,
+ );
+ $report->set_columns(%column_defs);
+ $report->set_column_order(@columns);
+ $report->set_export_options(qw(list filter));
+ $report->set_options_from_form;
+ $self->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
+
+ $self->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
+
+ $self->{report_data} = {
+ column_defs => \%column_defs,
+ columns => \@columns,
+ };
+}
+
+sub list_objects {
+ my ($self) = @_;
+ my $column_defs = $self->{report_data}->{column_defs};
+
+ for my $obj (@{ $self->{projects} || [] }) {
+ my %data = map {
+ $_ => {
+ data => $column_defs->{$_}{sub} ? $column_defs->{$_}{sub}->($obj)
+ : $obj->can($_) ? $obj->$_
+ : $obj->{$_},
+ link => $column_defs->{$_}{obj_link} ? $column_defs->{$_}{obj_link}->($obj) : '',
+ },
+ } @{ $self->{report_data}{columns} || {} };
+
+ $self->{report}->add_data(\%data);
+ }
+
+ return $self->{report}->generate_with_headers;
+}
+
+1;
diff --git a/SL/DB/Manager/Project.pm b/SL/DB/Manager/Project.pm
new file mode 100644
index 000000000..130e35ccd
--- /dev/null
+++ b/SL/DB/Manager/Project.pm
@@ -0,0 +1,79 @@
+package SL::DB::Manager::Project;
+
+use strict;
+
+use parent qw(SL::DB::Helper::Manager);
+
+use SL::DB::Helper::Paginated;
+use SL::DB::Helper::Sorted;
+
+sub object_class { 'SL::DB::Project' }
+
+__PACKAGE__->make_manager_methods;
+
+our %project_id_column_prefixes = (
+ ar => 'global',
+ ap => 'global',
+ oe => 'global',
+ delivery_orders => 'global',
+);
+
+our @tables_with_project_id_cols = qw(acc_trans ap ar delivery_order_items delivery_orders invoice oe orderitems rmaitems);
+
+sub _sort_spec {
+ return (
+ default => [ 'projectnumber', 1 ],
+ columns => {
+ SIMPLE => 'ALL',
+ customer => 'customer.name',
+ });
+}
+
+sub is_not_used_filter {
+ my ($class, $prefix) = @_;
+
+ my $query = join ' UNION ', map {
+ my $column = $project_id_column_prefixes{$_} . 'project_id';
+ qq|SELECT DISTINCT ${column} FROM ${_} WHERE ${column} IS NOT NULL|
+ } @tables_with_project_id_cols;
+
+ return ("!${prefix}id" => [ \"(${query})" ]);
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DB::Manager::Project - Manager for models for the 'project' table
+
+=head1 SYNOPSIS
+
+This is a standard Rose::DB::Manager based model manager and can be
+used as such.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C
+
+Returns an array containing a partial filter suitable for the C
+parameter that limits to projects that are not referenced from any
+other database table.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus Em.bunkus@linet-services.deE
+
+=cut
diff --git a/SL/DB/Project.pm b/SL/DB/Project.pm
index 1d1f1c4a8..ba6f12f0a 100644
--- a/SL/DB/Project.pm
+++ b/SL/DB/Project.pm
@@ -2,16 +2,52 @@ package SL::DB::Project;
use strict;
+use List::MoreUtils qw(any);
+
use SL::DB::MetaSetup::Project;
+use SL::DB::Manager::Project;
use SL::DB::Helper::CustomVariables(
module => 'Project',
cvars_alias => 1,
);
-__PACKAGE__->meta->make_manager_class;
__PACKAGE__->meta->initialize;
+sub validate {
+ my ($self) = @_;
+
+ my @errors;
+ push @errors, $::locale->text('The project number is missing.') if !$self->projectnumber;
+ push @errors, $::locale->text('The project number is already in use.') if !$self->is_projectnumber_unique;
+ push @errors, $::locale->text('The description is missing.') if !$self->description;
+
+ return @errors;
+}
+
+sub is_used {
+ my ($self) = @_;
+
+ # Unsaved projects are never referenced.
+ return 0 unless $self->id;
+
+ return any {
+ my $column = $SL::DB::Manager::Project::project_id_column_prefixes{$_} . 'project_id';
+ $self->db->dbh->selectrow_arrayref(qq|SELECT EXISTS(SELECT * FROM ${_} WHERE ${column} = ?)|, undef, $self->id)->[0]
+ } @SL::DB::Manager::Project::tables_with_project_id_cols;
+}
+
+sub is_projectnumber_unique {
+ my ($self) = @_;
+
+ return 1 unless $self->projectnumber;
+
+ my @filter = (projectnumber => $self->projectnumber);
+ @filter = (and => [ @filter, '!id' => $self->id ]) if $self->id;
+
+ return !SL::DB::Manager::Project->get_first(where => \@filter);
+}
+
1;
__END__
@@ -28,7 +64,26 @@ This is a standard Rose::DB::Object based model and can be used as one.
=head1 FUNCTIONS
-None so far.
+=over 4
+
+=item C
+
+Checks whether or not all fields are set to valid values so that the
+object can be saved. If valid returns an empty list. Returns an array
+of translated error message otherwise.
+
+=item C
+
+Checks whether or not the project is referenced from any other
+database table. Returns a boolean value.
+
+=item C
+
+Returns trueish if the project number is not used for any other
+project in the database. Also returns trueish if no project number has
+been set yet.
+
+=back
=head1 AUTHOR
diff --git a/SL/Projects.pm b/SL/Projects.pm
deleted file mode 100644
index 4c145bb57..000000000
--- a/SL/Projects.pm
+++ /dev/null
@@ -1,244 +0,0 @@
-#=====================================================================
-# LX-Office ERP
-# Copyright (C) 2004
-# Based on SQL-Ledger Version 2.1.9
-# Web http://www.lx-office.org
-#
-#=====================================================================
-# SQL-Ledger Accounting
-# Copyright (C) 1998-2002
-#
-# Author: Dieter Simader
-# Email: dsimader@sql-ledger.org
-# Web: http://www.sql-ledger.org
-#
-# Contributors:
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# 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.
-#======================================================================
-#
-# Project module
-#
-#======================================================================
-
-package Projects;
-
-use Data::Dumper;
-
-use SL::DBUtils;
-use SL::CVar;
-
-use strict;
-
-my %project_id_column_prefixes = ("ar" => "global",
- "ap" => "global",
- "oe" => "global",
- "delivery_orders" => "global");
-
-my @tables_with_project_id_cols = qw(acc_trans
- invoice
- orderitems
- rmaitems
- ar
- ap
- oe
- delivery_orders
- delivery_order_items);
-
-sub search_projects {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my %params = @_;
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
-
- my (@filters, @values);
-
- foreach my $column (qw(projectnumber description)) {
- if ($params{$column}) {
- push @filters, "p.$column ILIKE ?";
- push @values, '%' . $params{$column} . '%';
- }
- }
-
- if ($params{status} eq 'orphaned') {
- my @sub_filters;
-
- foreach my $table (@tables_with_project_id_cols) {
- push @sub_filters, qq|SELECT DISTINCT $project_id_column_prefixes{$table}project_id FROM $table
- WHERE NOT $project_id_column_prefixes{$table}project_id ISNULL|;
- }
-
- push @filters, "p.id NOT IN (" . join(" UNION ", @sub_filters) . ")";
- }
-
- if ($params{active} eq "active") {
- push @filters, 'p.active';
-
- } elsif ($params{active} eq "inactive") {
- push @filters, 'NOT COALESCE(p.active, FALSE)';
- }
-
- if ($params{valid} eq "valid") {
- push @filters, 'p.valid';
-
- } elsif ($params{valid} eq "invalid") {
- push @filters, 'NOT COALESCE(p.valid, FALSE)';
- }
-
- if ($params{customer}) {
- push @filters, 'c.name ILIKE ?';
- push @values, '%' . $params{customer} . '%';
- }
-
- if ($params{type}) {
- push @filters, 'p.type ILIKE ?';
- push @values, '%' . $params{type} . '%';
- }
-
- my ($cvar_where, @cvar_values) = CVar->build_filter_query('module' => 'Projects',
- 'trans_id_field' => 'p.id',
- 'filter' => $form);
-
- if ($cvar_where) {
- push @filters, $cvar_where;
- push @values, @cvar_values;
- }
-
-
- my $where = @filters ? 'WHERE ' . join(' AND ', map { "($_)" } @filters) : '';
-
- my $sortorder = $params{sort} ? $params{sort} : "projectnumber";
- $sortorder =~ s/[^a-z_]//g;
- my $query = qq|SELECT p.id, p.projectnumber, p.description, p.active, p.valid, p.type,
- c.name AS customer
- FROM project p
- LEFT JOIN customer c ON (p.customer_id = c.id)
- $where
- ORDER BY $sortorder|;
-
- $form->{project_list} = selectall_hashref_query($form, $dbh, $query, @values);
-
- $main::lxdebug->leave_sub();
-
- return scalar(@{ $form->{project_list} });
-}
-
-sub get_project {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my %params = @_;
-
- if (!$params{id}) {
- $main::lxdebug->leave_sub();
- return { };
- }
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
-
- my $project = selectfirst_hashref_query($form, $dbh, qq|SELECT * FROM project WHERE id = ?|, conv_i($params{id})) || { };
-
- if ($params{orphaned}) {
- # check if it is orphaned
- my (@values, $query);
-
- foreach my $table (@tables_with_project_id_cols) {
- $query .= " + " if ($query);
- $query .= qq|(SELECT COUNT(*) FROM $table
- WHERE $project_id_column_prefixes{$table}project_id = ?) |;
- push @values, conv_i($params{id});
- }
-
- $query = 'SELECT ' . $query;
-
- ($project->{orphaned}) = selectrow_query($form, $dbh, $query, @values);
- $project->{orphaned} = !$project->{orphaned};
- }
-
- $main::lxdebug->leave_sub();
-
- return $project;
-}
-
-sub save_project {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my %params = @_;
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
-
- my @values;
-
- if (!$params{id}) {
- ($params{id}) = selectfirst_array_query($form, $dbh, qq|SELECT nextval('id')|);
- do_query($form, $dbh, qq|INSERT INTO project (id) VALUES (?)|, conv_i($params{id}));
-
- $params{active} = 1;
- }
-
- my $query = <save_custom_variables('dbh' => $dbh,
- 'module' => 'Projects',
- 'trans_id' => $params{id},
- 'variables' => $form,
- 'always_valid' => 1);
-
- $dbh->commit();
-
- $main::lxdebug->leave_sub();
-
- return $params{id};
-}
-
-sub delete_project {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my %params = @_;
-
- Common::check_params(\%params, qw(id));
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
-
- do_query($form, $dbh, qq|DELETE FROM project WHERE id = ?|, conv_i($params{id}));
-
- $dbh->commit();
-
- $main::lxdebug->leave_sub();
-}
-
-1;
diff --git a/bin/mozilla/arap.pl b/bin/mozilla/arap.pl
index fe5fa2d27..347c152c7 100644
--- a/bin/mozilla/arap.pl
+++ b/bin/mozilla/arap.pl
@@ -30,8 +30,6 @@
# common routines for gl, ar, ap, is, ir, oe
#
-use SL::Projects;
-
use strict;
# any custom scripts for this one
@@ -298,54 +296,6 @@ sub _reset_salesman_id {
$::form->{salesman_id} = $current_employee->id if $current_employee && exists $::form->{salesman_id};
}
-sub check_project {
- $main::lxdebug->enter_sub();
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- $main::auth->assert('general_ledger | vendor_invoice_edit | sales_order_edit | invoice_edit |' .
- 'request_quotation_edit | sales_quotation_edit | purchase_order_edit | cash | report');
-
- my $nextsub = shift || 'update';
-
- for my $i (1 .. $form->{rowcount}) {
- my $suffix = $i ? "_$i" : "";
- my $prefix = $i ? "" : "global";
- $form->{"${prefix}project_id${suffix}"} = "" unless $form->{"${prefix}projectnumber$suffix"};
- if ($form->{"${prefix}projectnumber${suffix}"} ne $form->{"old${prefix}projectnumber${suffix}"}) {
- if ($form->{"${prefix}projectnumber${suffix}"}) {
-
- # get new project
- $form->{projectnumber} = $form->{"${prefix}projectnumber${suffix}"};
- my %params = map { $_ => $form->{$_} } qw(projectnumber description active);
- my $rows;
- if (($rows = Projects->search_projects(%params)) > 1) {
-
- # check form->{project_list} how many there are
- $form->{rownumber} = $i;
- &select_project($i ? undef : 1, $nextsub);
- ::end_of_request();
- }
-
- if ($rows == 1) {
- $form->{"${prefix}project_id${suffix}"} = $form->{project_list}->[0]->{id};
- $form->{"${prefix}projectnumber${suffix}"} = $form->{project_list}->[0]->{projectnumber};
- $form->{"old${prefix}projectnumber${suffix}"} = $form->{project_list}->[0]->{projectnumber};
- } else {
-
- # not on file
- $form->error($locale->text('Project not on file!'));
- }
- } else {
- $form->{"old${prefix}projectnumber${suffix}"} = "";
- }
- }
- }
-
- $main::lxdebug->leave_sub();
-}
-
sub select_project {
$::lxdebug->enter_sub;
@@ -420,7 +370,6 @@ arap.pl - helper functions or customer/vendor retrieval
=head1 SYNOPSIS
check_name('vendor')
- check_project();
=head1 DESCRIPTION
diff --git a/bin/mozilla/projects.pl b/bin/mozilla/projects.pl
deleted file mode 100644
index c1b8b7d6e..000000000
--- a/bin/mozilla/projects.pl
+++ /dev/null
@@ -1,316 +0,0 @@
-#=====================================================================
-# LX-Office ERP
-# Copyright (C) 2004
-# Based on SQL-Ledger Version 2.1.9
-# Web http://www.lx-office.org
-#
-#=====================================================================
-# SQL-Ledger Accounting
-# Copyright (c) 1998-2002
-#
-# Author: Dieter Simader
-# Email: dsimader@sql-ledger.org
-# Web: http://www.sql-ledger.org
-#
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# 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.
-#======================================================================
-#
-# project administration
-#======================================================================
-
-use POSIX qw(strftime);
-
-use SL::CVar;
-use SL::Projects;
-use SL::ReportGenerator;
-
-require "bin/mozilla/common.pl";
-require "bin/mozilla/reportgenerator.pl";
-
-use strict;
-
-sub add {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- # construct callback
- $form->{callback} = build_std_url('action') unless $form->{callback};
-
- display_project_form();
-
- $main::lxdebug->leave_sub();
-}
-
-sub edit {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- # show history button
- $form->{javascript} = qq||;
- #/show hhistory button
- $form->{title} = "Edit";
-
- $form->{project} = Projects->get_project('id' => $form->{id}, 'orphaned' => 1);
-
- display_project_form();
-
- $main::lxdebug->leave_sub();
-}
-
-sub search {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- $form->{title} = $locale->text('Projects');
-
- $form->{CUSTOM_VARIABLES} = CVar->get_configs('module' => 'Projects');
- ($form->{CUSTOM_VARIABLES_FILTER_CODE},
- $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables' => $form->{CUSTOM_VARIABLES},
- 'include_prefix' => 'l_',
- 'include_value' => 'Y');
- $::request->{layout}->focus('#projectnumber');
-
- $form->header();
- print $form->parse_html_template('projects/search');
-
- $main::lxdebug->leave_sub();
-}
-
-sub project_report {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
- my $locale = $main::locale;
-
- $form->{sort} ||= 'projectnumber';
- my $filter = $form->{filter} || { };
-
- Projects->search_projects(%{ $filter }, 'sort' => $form->{sort});
-
- my $cvar_configs = CVar->get_configs('module' => 'Projects');
-
- my $report = SL::ReportGenerator->new(\%myconfig, $form);
-
- my @columns = qw(projectnumber description customer type active valid);
-
- my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
- my @searchable_custom_variables = grep { $_->{searchable} } @{ $cvar_configs };
- my %column_defs_cvars = ();
- foreach (@includeable_custom_variables) {
- $column_defs_cvars{"cvar_$_->{name}"} = {
- 'text' => $_->{description},
- 'visible' => $form->{"l_cvar_$_->{name}"} eq 'Y',
- };
- }
-
- push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
-
-
- my @hidden_vars = (
- 'filter',
- map({ ('cvar_'. $_->{name} , 'l_cvar_'. $_->{name}) } @includeable_custom_variables),
- map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables)),
- );
- my $href = build_std_url('action=project_report', @hidden_vars);
-
-
- my %column_defs = (
- 'projectnumber' => { 'text' => $locale->text('Number'), },
- 'description' => { 'text' => $locale->text('Description'), },
- 'customer' => { 'text' => $locale->text('Customer'), },
- 'type' => { 'text' => $locale->text('Type'), },
- 'active' => { 'text' => $locale->text('Active'), 'visible' => 'both' eq $filter->{active}, },
- 'valid' => { 'text' => $locale->text('Valid'), 'visible' => 'both' eq $filter->{active}, },
- %column_defs_cvars,
- );
-
- foreach (qw(projectnumber description customer type)) {
- $column_defs{$_}->{link} = $href . "&sort=$_";
- $column_defs{$_}->{visible} = 1;
- }
-
- $report->set_columns(%column_defs);
- $report->set_column_order(@columns);
-
- $report->set_export_options('project_report', @hidden_vars, 'sort');
-
- CVar->add_custom_variables_to_report('module' => 'Project',
- 'trans_id_field' => 'id',
- 'configs' => $cvar_configs,
- 'column_defs' => \%column_defs,
- 'data' => $form->{project_list},
- );
-
- $report->set_sort_indicator($form->{sort}, 1);
-
- my @options;
- push @options, $locale->text('All') if ($filter->{all});
- push @options, $locale->text('Orphaned') if ($filter->{orphaned});
- push @options, $locale->text('Project Number') . " : $filter->{projectnumber}" if ($filter->{projectnumber});
- push @options, $locale->text('Description') . " : $filter->{description}" if ($filter->{description});
- push @options, $locale->text('Customer') . " : $filter->{customer}" if ($filter->{customer});
- push @options, $locale->text('Type') . " : $filter->{type}" if ($filter->{type});
- push @options, $locale->text('Active') if ($filter->{active} eq 'active');
- push @options, $locale->text('Inactive') if ($filter->{active} eq 'inactive');
- push @options, $locale->text('Orphaned') if ($filter->{status} eq 'orphaned');
-
- $form->{title} = $locale->text('Projects');
-
- $report->set_options('top_info_text' => join("\n", @options),
- 'output_format' => 'HTML',
- 'title' => $form->{title},
- 'attachment_basename' => $locale->text('project_list') . strftime('_%Y%m%d', localtime time),
- );
- $report->set_options_from_form();
- $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
-
- CVar->add_custom_variables_to_report('module' => 'Projects',
- 'trans_id_field' => 'id',
- 'configs' => $cvar_configs,
- 'column_defs' => \%column_defs,
- 'data' => $form->{project_list});
-
- my $edit_url = build_std_url('action=edit&type=project');
- my $callback = $form->escape($href) . '&sort=' . E($form->{sort});
-
- foreach my $project (@{ $form->{project_list} }) {
- $project->{active} = $project->{active} ? $locale->text('Yes') : $locale->text('No');
- $project->{valid} = $project->{valid} ? $locale->text('Yes') : $locale->text('No');
-
- my $row = { map { $_ => { 'data' => $project->{$_} } } keys %{ $project } };
-
- $row->{projectnumber}->{link} = $edit_url . "&id=" . E($project->{id}) . "&callback=${callback}";
-
- $report->add_data($row);
- }
-
- $report->generate_with_headers();
-
- $main::lxdebug->leave_sub();
-}
-
-sub display_project_form {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- $form->{project} ||= { };
-
- $form->{title} = $form->{project}->{id} ? $locale->text("Edit Project") : $locale->text("Add Project");
-
- $form->{ALL_CUSTOMERS} = SL::DB::Manager::Customer->get_all_sorted(where => [ or => [ obsolete => 0, obsolete => undef, id => $form->{project}->{customer_id} ]]);
- $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'Projects', 'trans_id' => $form->{project}->{id});
-# $main::lxdebug->dump(0, "cv", $form->{CUSTOM_VARIABLES});
- CVar->render_inputs('variables' => $form->{CUSTOM_VARIABLES}) if (scalar @{ $form->{CUSTOM_VARIABLES} });
-
- $form->header();
- print $form->parse_html_template('projects/project_form');
-
- $main::lxdebug->leave_sub();
-}
-
-sub save {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
- my $locale = $main::locale;
-
- $form->isblank("project.projectnumber", $locale->text('Project Number missing!'));
-
- my $project = $form->{project} || { };
- my $is_new = !$project->{id};
- $project->{id} = Projects->save_project(%{ $project });
-
- # saving the history
- if(!exists $form->{addition} && $project->{id} ne "") {
- $form->{id} = $project->{id};
- $form->{snumbers} = qq|projectnumber_| . $project->{projectnumber};
- $form->{addition} = "SAVED";
- $form->save_history;
- }
- # /saving the history
-
- if ($form->{callback}) {
- map { $form->{callback} .= "&new_${_}=" . $form->escape($project->{$_}); } qw(projectnumber description id);
- my $message = $is_new ? $locale->text('The project has been added.') : $locale->text('The project has been saved.');
- $form->{callback} .= "&message=" . E($message);
- }
-
- $form->redirect($locale->text('Project saved!'));
-
- $main::lxdebug->leave_sub();
-}
-
-sub save_as_new {
- $main::lxdebug->enter_sub();
-
- my $form = $main::form;
- my $locale = $main::locale;
-
- delete $form->{project}->{id} if ($form->{project});
- save();
-
- $main::lxdebug->leave_sub();
-}
-
-sub delete {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('project_edit');
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
- my $locale = $main::locale;
-
- my $project = $form->{project} || { };
- Projects->delete_project('id' => $project->{id});
-
- # saving the history
- if(!exists $form->{addition}) {
- $form->{snumbers} = qq|projectnumber_| . $project->{projectnumber};
- $form->{addition} = "DELETED";
- $form->save_history;
- }
- # /saving the history
-
- $form->redirect($locale->text('Project deleted!'));
-
- $main::lxdebug->leave_sub();
-}
-
-sub continue {
- call_sub($main::form->{nextsub});
-}
diff --git a/bin/mozilla/rp.pl b/bin/mozilla/rp.pl
index bc2eab6e2..9f6d848fd 100644
--- a/bin/mozilla/rp.pl
+++ b/bin/mozilla/rp.pl
@@ -37,11 +37,13 @@
use POSIX qw(strftime);
+use SL::DB::Project;
use SL::PE;
use SL::RP;
use SL::Iconv;
use SL::ReportGenerator;
use Data::Dumper;
+use List::MoreUtils qw(any);
require "bin/mozilla/arap.pl";
require "bin/mozilla/common.pl";
@@ -213,35 +215,6 @@ sub report {
sub continue { call_sub($main::form->{"nextsub"}); }
-sub get_project {
- $main::lxdebug->enter_sub();
-
- $main::auth->assert('report');
-
- my $form = $main::form;
- my %myconfig = %main::myconfig;
- my $locale = $main::locale;
-
- my $nextsub = shift;
-
- $form->{project_id} = $form->{project_id_1};
- if ($form->{projectnumber} && !$form->{project_id}) {
- $form->{rowcount} = 1;
-
- # call this instead of update
- $form->{update} = $nextsub;
- $form->{projectnumber_1} = $form->{projectnumber};
-
- delete $form->{sort};
- check_project('generate_projects');
-
- # if there is one only, assign id
- $form->{project_id} = $form->{project_id_1};
- }
-
- $main::lxdebug->leave_sub();
-}
-
sub generate_income_statement {
$main::lxdebug->enter_sub();
@@ -460,8 +433,8 @@ sub generate_projects {
my %myconfig = %main::myconfig;
my $locale = $main::locale;
- &get_project("generate_projects");
- $form->{projectnumber} = $form->{projectnumber_1};
+ my $project = $form->{project_id} ? SL::DB::Project->new(id => $form->{project_id})->load : undef;
+ $form->{projectnumber} = $project ? $project->projectnumber : '';
$form->{nextsub} = "generate_projects";
$form->{title} = $locale->text('Project Transactions');
diff --git a/locale/de/all b/locale/de/all
index ebafe70ef..61e797704 100644
--- a/locale/de/all
+++ b/locale/de/all
@@ -468,6 +468,7 @@ $self->{texts} = {
'Create a new business' => 'Einen neuen Kunden-/Lieferantentyp erfassen',
'Create a new department' => 'Eine neue Abteilung erfassen',
'Create a new payment term' => 'Neue Zahlungsbedingungen anlegen',
+ 'Create a new project' => 'Neues Projekt anlegen',
'Create a standard group' => 'Eine Standard-Benutzergruppe anlegen',
'Create and edit RFQs' => 'Lieferantenanfragen erfassen und bearbeiten',
'Create and edit dunnings' => 'Mahnungen erfassen und bearbeiten',
@@ -741,7 +742,6 @@ $self->{texts} = {
'Edit Price Factor' => 'Preisfaktor bearbeiten',
'Edit Pricegroup' => 'Preisgruppe bearbeiten',
'Edit Printer' => 'Drucker bearbeiten',
- 'Edit Project' => 'Projekt bearbeiten',
'Edit Purchase Delivery Order' => 'Lieferschein (Einkauf) bearbeiten',
'Edit Purchase Order' => 'Lieferantenaufrag bearbeiten',
'Edit Quotation' => 'Angebot bearbeiten',
@@ -772,6 +772,8 @@ $self->{texts} = {
'Edit note' => 'Notiz bearbeiten',
'Edit payment term' => 'Zahlungsbedingungen bearbeiten',
'Edit prices and discount (if not used, textfield is ONLY set readonly)' => 'Preise und Rabatt in Formularen frei anpassen (falls deaktiviert, wird allerdings NUR das textfield auf READONLY gesetzt / kann je nach Browserversion und technischen Fähigkeiten des Anwenders noch umgangen werden)',
+ 'Edit project' => 'Projekt bearbeiten',
+ 'Edit project #1' => 'Projekt #1 bearbeiten',
'Edit rights' => 'Rechte bearbeiten',
'Edit templates' => 'Vorlagen bearbeiten',
'Edit the Delivery Order' => 'Lieferschein bearbeiten',
@@ -1490,12 +1492,8 @@ $self->{texts} = {
'Project' => 'Projekt',
'Project Description' => 'Projektbeschreibung',
'Project Number' => 'Projektnummer',
- 'Project Number missing!' => 'Projektnummer fehlt!',
'Project Numbers' => 'Projektnummern',
'Project Transactions' => 'Projektbuchungen',
- 'Project deleted!' => 'Projekt gelöscht!',
- 'Project not on file!' => 'Dieses Projekt ist nicht in der Datenbank!',
- 'Project saved!' => 'Projekt gespeichert!',
'Projects' => 'Projekte',
'Projecttransactions' => 'Projektbuchungen',
'Prozentual/Absolut' => 'Prozentual/Absolut',
@@ -1655,6 +1653,7 @@ $self->{texts} = {
'Search AP Aging' => 'Offene Verbindlichkeiten',
'Search AR Aging' => 'Offene Forderungen',
'Search contacts' => 'Ansprechpersonensuche',
+ 'Search projects' => 'Projektsuche',
'Search term' => 'Suchbegriff',
'Searchable' => 'Durchsuchbar',
'Secondary sorting' => 'Untersortierung',
@@ -1990,8 +1989,12 @@ $self->{texts} = {
'The profile \'#1\' has been deleted.' => 'Das Profil \'#1\' wurde gelöscht.',
'The profile has been saved under the name \'#1\'.' => 'Das Profil wurde unter dem Namen \'#1\' gespeichert.',
'The program\'s exit code was #1 ("0" usually means that everything went OK).' => 'Der Exitcode des Programms war #1 ("0" bedeutet normalerweise, dass die Wiederherstellung erfolgreich war).',
- 'The project has been added.' => 'Das Projekt wurde erfasst.',
+ 'The project has been created.' => 'Das Projekt wurde angelegt.',
+ 'The project has been deleted.' => 'Das Projekt wurde gelöscht.',
'The project has been saved.' => 'Das Projekt wurde gespeichert.',
+ 'The project is in use and cannot be deleted.' => 'Das Projekt ist in Verwendung und kann nicht gelöscht werden.',
+ 'The project number is already in use.' => 'Die Projektnummer wird bereits verwendet.',
+ 'The project number is missing.' => 'Die Projektnummer fehlt.',
'The restoration process has started. Here\'s the output of the "pg_restore" command:' => 'Der Wiederherstellungsprozess wurde gestartet. Hier ist die Ausgabe des "pg_restore"-Programmes:',
'The restoration process is complete. Please review "pg_restore"\'s output to find out if the restoration was successful.' => 'Die Wiederherstellung ist abgeschlossen. Bitte sehen Sie sich die Ausgabe von "pg_restore" an, um festzustellen, ob die Wiederherstellung erfolgreich war.',
'The second reason is that kivitendo allowed the user to enter the tax amount manually regardless of the taxkey used.' => 'Der zweite Grund war, dass kivitendo zulieÃ, dass die Benutzer beliebige, von den tatsächlichen Steuerschlüsseln unabhängige Steuerbeträge eintrugen.',
@@ -2436,7 +2439,6 @@ $self->{texts} = {
'prev' => 'zurück',
'print' => 'drucken',
'proforma' => 'Proforma',
- 'project_list' => 'projektliste',
'purchase_delivery_order_list' => 'lieferscheinliste_einkauf',
'purchase_order' => 'Auftrag',
'purchase_order_list' => 'lieferantenauftragsliste',
diff --git a/menu.ini b/menu.ini
index 65a97c96c..5f85eed4c 100644
--- a/menu.ini
+++ b/menu.ini
@@ -32,8 +32,8 @@ item=assembly
[Master Data--Add Project]
ACCESS=project_edit
-module=projects.pl
-action=add
+module=controller.pl
+action=Project/new
[Master Data--Update Prices]
ACCESS=part_service_assembly_edit
@@ -84,8 +84,8 @@ searchitems=assembly
[Master Data--Reports--Projects]
ACCESS=project_edit
-module=projects.pl
-action=search
+module=controller.pl
+action=Project/search
[AR]
diff --git a/projects.pl b/projects.pl
deleted file mode 120000
index 385000d1b..000000000
--- a/projects.pl
+++ /dev/null
@@ -1 +0,0 @@
-am.pl
\ No newline at end of file
diff --git a/templates/webpages/projects/project_form.html b/templates/webpages/project/form.html
similarity index 53%
rename from templates/webpages/projects/project_form.html
rename to templates/webpages/project/form.html
index 3b6f7f45a..2ea52bc8f 100644
--- a/templates/webpages/projects/project_form.html
+++ b/templates/webpages/project/form.html
@@ -2,18 +2,13 @@
[%- USE L %]
[%- USE HTML %][%- USE LxERP %]
- [%- IF message %]
- [% message %]
+[%- INCLUDE 'common/flash.html' %]
-
- [%- END %]
+ [% title %]
- [% title %] [% HTML.escape(project.projectnumber) %]
-
-
diff --git a/templates/webpages/project/report_bottom.html b/templates/webpages/project/report_bottom.html
new file mode 100644
index 000000000..79e152304
--- /dev/null
+++ b/templates/webpages/project/report_bottom.html
@@ -0,0 +1,2 @@
+[% USE L %]
+[%- L.paginate_controls %]
diff --git a/templates/webpages/project/search.html b/templates/webpages/project/search.html
new file mode 100644
index 000000000..e5d4ff4ac
--- /dev/null
+++ b/templates/webpages/project/search.html
@@ -0,0 +1,65 @@
+[%- USE T8 %]
+[%- USE HTML %]
+[%- USE L %]
+[%- USE LxERP %]
+
+[%- INCLUDE 'common/flash.html' %]
+
+
diff --git a/templates/webpages/projects/search.html b/templates/webpages/projects/search.html
deleted file mode 100644
index 5eafb4024..000000000
--- a/templates/webpages/projects/search.html
+++ /dev/null
@@ -1,91 +0,0 @@
-[%- USE T8 %]
-[%- USE HTML %]
-
diff --git a/templates/webpages/rp/report.html b/templates/webpages/rp/report.html
index c4e8692c3..afffd5c0c 100644
--- a/templates/webpages/rp/report.html
+++ b/templates/webpages/rp/report.html
@@ -89,10 +89,7 @@
[%- END %]
[%- IF is_projects %]
-
- [% 'Project' | $T8 %] |
-
- |
+ [% INCLUDE projectnumber %]
[% 'as at' | $T8 %] |
@@ -364,4 +361,3 @@
-
--
2.20.1