Projekt

Allgemein

Profil

Herunterladen (25,9 KB) Statistiken
| Zweig: | Markierung: | Revision:
package SL::Controller::EmailJournal;

use strict;

use parent qw(SL::Controller::Base);

use SL::ZUGFeRD;
use SL::Controller::ZUGFeRD;
use SL::Controller::Helper::GetModels;
use SL::DB::Employee;
use SL::DB::EmailJournal;
use SL::DB::EmailJournalAttachment;
use SL::Presenter::EmailJournal;
use SL::Presenter::Record qw(grouped_record_list);
use SL::Presenter::Tag qw(html_tag div_tag button_tag);
use SL::Helper::Flash;
use SL::Locale::String qw(t8);

use SL::DB::Order;
use SL::DB::Order::TypeData;
use SL::DB::DeliveryOrder;
use SL::DB::DeliveryOrder::TypeData;
use SL::DB::Reclamation;
use SL::DB::Reclamation::TypeData;
use SL::DB::Invoice;
use SL::DB::Invoice::TypeData;
use SL::DB::PurchaseInvoice;
use SL::DB::PurchaseInvoice::TypeData;

use SL::DB::Manager::Customer;
use SL::DB::Manager::Vendor;

use List::Util qw(first);
use List::MoreUtils qw(any);

use Rose::Object::MakeMethods::Generic
(
scalar => [ qw(entry) ],
'scalar --get_set_init' => [ qw(models can_view_all filter_summary) ],
);

__PACKAGE__->run_before('add_stylesheet');
__PACKAGE__->run_before('add_js');

my %RECORD_TYPES_INFO = (
Order => {
controller => 'Order',
class => 'Order',
types => SL::DB::Order::TypeData->valid_types(),
},
DeliveryOrder => {
controller => 'DeliveryOrder',
class => 'DeliveryOrder',
types => SL::DB::DeliveryOrder::TypeData->valid_types(),
},
Reclamation => {
controller => 'Reclamation',
class => 'Reclamation',
types => SL::DB::Reclamation::TypeData->valid_types(),
},
GlTransaction => {
controller => 'gl.pl',
class => 'GLTransaction',
types => [
'gl_transaction',
],
},
ArTransaction => {
controller => 'ar.pl',
class => 'Invoice',
types => [
'ar_transaction',
],
},
Invoice => {
controller => 'is.pl',
class => 'Invoice',
types => SL::DB::Invoice::TypeData->valid_types(),
},
ApTransaction => {
controller => 'ap.pl',
class => 'PurchaseInvoice',
types => [
'ap_transaction',
],
},
PurchaseInvoice => {
controller => 'ir.pl',
class => 'PurchaseInvoice',
types => SL::DB::PurchaseInvoice::TypeData->valid_types(),
},
GlRecordTemplate => {
controller => 'gl.pl',
class => 'RecordTemplate',
types => [
'gl_transaction_template',
],
},
ArRecordTemplate => {
controller => 'ar.pl',
class => 'RecordTemplate',
types => [
'ar_transaction_template',
],
},
ApRecordTemplate => {
controller => 'ap.pl',
class => 'RecordTemplate',
types => [
'ap_transaction_template',
],
},
);
my %RECORD_TYPE_TO_CONTROLLER =
map {
my $controller = $RECORD_TYPES_INFO{$_}->{controller};
map { $_ => $controller } @{ $RECORD_TYPES_INFO{$_}->{types} }
} keys %RECORD_TYPES_INFO;
my %RECORD_TYPE_TO_MODEL =
map {
my $class = $RECORD_TYPES_INFO{$_}->{class};
map { $_ => "SL::DB::$class" } @{ $RECORD_TYPES_INFO{$_}->{types} }
} keys %RECORD_TYPES_INFO;
my %RECORD_TYPE_TO_MANAGER =
map {
my $class = $RECORD_TYPES_INFO{$_}->{class};
map { $_ => "SL::DB::Manager::$class" } @{ $RECORD_TYPES_INFO{$_}->{types} }
} keys %RECORD_TYPES_INFO;
my @ALL_RECORD_TYPES =
map { @{ $RECORD_TYPES_INFO{$_}->{types} } } keys %RECORD_TYPES_INFO;
my %RECORD_TYPE_TO_NR_KEY =
map {
my $model = $RECORD_TYPE_TO_MODEL{$_};
if (any {$model eq $_} qw(SL::DB::Invoice SL::DB::PurchaseInvoice)) {
$_ => 'invnumber';
} elsif (any {$model eq $_} qw(SL::DB::RecordTemplate)) {
$_ => 'template_name';
} elsif (any {$model eq $_} qw(SL::DB::GLTransaction)) {
$_ => 'reference';
} else {
my $type_data = SL::DB::Helper::TypeDataProxy->new($model, $_);
$_ => $type_data->properties('nr_key');
}
} @ALL_RECORD_TYPES;

# has do be done at runtime for translation to work
sub get_record_types_with_info {
my @record_types_with_info = ();
for my $record_class (
'SL::DB::Order', 'SL::DB::DeliveryOrder', 'SL::DB::Reclamation',
'SL::DB::Invoice', 'SL::DB::PurchaseInvoice',
) {
my $type_data = "${record_class}::TypeData";
my $valid_types = $type_data->valid_types();
for my $type (@$valid_types) {
push @record_types_with_info, {
record_type => $type,
text => $type_data->can('get3')->($type, 'text', 'type'),
customervendor => $type_data->can('get3')->($type, 'properties', 'customervendor'),
workflow_needed => $type_data->can('get3')->($type, 'properties', 'worflow_needed'),
can_workflow => (
any {
$_ ne 'delete' && $type_data->can('get3')->($type, 'show_menu', $_)
} keys %{$type_data->can('get')->($type, 'show_menu')}
),
};
}
}
push @record_types_with_info, (
# transactions
# gl_transaction can be for vendor and customer
{ record_type => 'gl_transaction', customervendor => 'customer', workflow_needed => 0, can_workflow => 1, text => t8('GL Transaction')},
{ record_type => 'gl_transaction', customervendor => 'vendor', workflow_needed => 0, can_workflow => 1, text => t8('GL Transaction')},
{ record_type => 'ar_transaction', customervendor => 'customer', workflow_needed => 0, can_workflow => 1, text => t8('AR Transaction')},
{ record_type => 'ap_transaction', customervendor => 'vendor', workflow_needed => 0, can_workflow => 1, text => t8('AP Transaction')},
# templates
{ record_type => 'gl_transaction_template', is_template => 1, customervendor => 'customer', workflow_needed => 0, can_workflow => 0, text => t8('GL Transaction')},
{ record_type => 'gl_transaction_template', is_template => 1, customervendor => 'vendor', workflow_needed => 0, can_workflow => 0, text => t8('GL Transaction')},
{ record_type => 'ar_transaction_template', is_template => 1, customervendor => 'customer', workflow_needed => 0, can_workflow => 0, text => t8('AR Transaction')},
{ record_type => 'ap_transaction_template', is_template => 1, customervendor => 'vendor', workflow_needed => 0, can_workflow => 0, text => t8('AP Transaction')},
);
return @record_types_with_info;
}

# has do be done at runtime for translation to work
sub get_record_types_to_text {
my @record_types_with_info = get_record_types_with_info();

my %record_types_to_text = ();
$record_types_to_text{$_->{record_type}} = $_->{text} for @record_types_with_info;
$record_types_to_text{'catch_all'} = t8("Catch-all");

return %record_types_to_text;
}

sub record_types_for_customer_vendor_type_and_action {
my ($self, $customer_vendor_type, $action) = @_;
return [
map { $_->{record_type} }
grep {
# No gl_transaction in standard workflows
# They can't be filtered by customer/vendor or open/closed and polute the list
($_->{record_type} ne 'gl_transaction')
}
grep {
($_->{customervendor} eq $customer_vendor_type)
&& ($action eq 'workflow_record' ? $_->{can_workflow} : 1)
&& ($action eq 'create_new' ? $_->{workflow_needed} : 1)
&& ($action eq 'linking_record' ? !$_->{is_template} : 1)
&& ($action eq 'template_record' ? $_->{is_template} : 1)
}
$self->get_record_types_with_info()
];
}

#
# actions
#

sub action_list {
my ($self) = @_;

$::auth->assert('email_journal');
# default filter
$::form->{filter} ||= {"obsolete:eq_ignore_empty" => 0};

if ( $::instance_conf->get_email_journal == 0 ) {
flash('info', $::locale->text('Storing the emails in the journal is currently disabled in the client configuration.'));
}
$self->setup_list_action_bar;
my @record_types_with_info = $self->get_record_types_with_info();
my %record_types_to_text = $self->get_record_types_to_text();
$self->render('email_journal/list',
title => $::locale->text('Email journal'),
ENTRIES => $self->models->get,
MODELS => $self->models,
RECORD_TYPES_WITH_INFO => \@record_types_with_info,
RECORD_TYPES_TO_TEXT => \%record_types_to_text,
);
}

sub action_show {
my ($self) = @_;

$::auth->assert('email_journal');

my $back_to = $::form->{back_to} || $self->url_for(action => 'list');

$self->entry(SL::DB::EmailJournal->new(id => $::form->{id})->load);

if (!$self->can_view_all && ($self->entry->sender_id != SL::DB::Manager::Employee->current->id)) {
$::form->error(t8('You do not have permission to access this entry.'));
}

my @record_types_with_info = $self->get_record_types_with_info();
my %record_types_to_text = $self->get_record_types_to_text();

my $customer = $self->find_customer_vendor_from_email('customer', $self->entry);
my $vendor = $self->find_customer_vendor_from_email('vendor' , $self->entry);
my ($cv_type_found) =
map {$_->{customervendor}}
first {$_->{record_type} eq $self->entry->record_type}
@record_types_with_info;
$cv_type_found ||= 'vendor' if defined $vendor;
$cv_type_found ||= 'customer';

my $record_types = $self->record_types_for_customer_vendor_type_and_action(
$cv_type_found, 'workflow_record'
);

$self->setup_show_action_bar;
$self->render(
'email_journal/show',
title => $::locale->text('View email'),
CUSTOMER => $customer,
VENDOR => $vendor,
CV_TYPE_FOUND => $cv_type_found,
RECORD_TYPES_WITH_INFO => \@record_types_with_info,
RECORD_TYPES_TO_TEXT => \%record_types_to_text,
back_to => $back_to,
);
}

sub action_attachment_preview {
my ($self) = @_;

eval {
$::auth->assert('email_journal');

my $attachment_id = $::form->{attachment_id};
die "no 'attachment_id' was given" unless $attachment_id;

my $attachment;
$attachment = SL::DB::EmailJournalAttachment->new(
id => $attachment_id,
)->load;


if (!$self->can_view_all
&& $attachment->email_journal->sender_id
&& ($attachment->email_journal->sender_id != SL::DB::Manager::Employee->current->id)) {
$::form->error(t8('You do not have permission to access this entry.'));
}

my $output = SL::Presenter::EmailJournal::attachment_preview(
$attachment,
style => "height: 1800px"
);

$self->render( \$output, { layout => 0, process => 0,});
} or do {
$self->render('generic/error', { layout => 0 }, label_error => $@);
};
}

sub action_show_attachment {
my ($self) = @_;

$::auth->assert('email_journal');

my $attachment_id = $::form->{attachment_id};
my $attachment = SL::DB::EmailJournalAttachment->new(id => $attachment_id)->load;

if (!$self->can_view_all && ($attachment->email_journal->sender_id != SL::DB::Manager::Employee->current->id)) {
$::form->error(t8('You do not have permission to access this entry.'));
}

return $self->send_file(
\$attachment->content,
name => $attachment->name,
type => $attachment->mime_type,
content_disposition => 'inline',
);
}

sub action_download_attachment {
my ($self) = @_;

$::auth->assert('email_journal');

my $attachment = SL::DB::EmailJournalAttachment->new(id => $::form->{id})->load;

if (!$self->can_view_all && ($attachment->email_journal->sender_id != SL::DB::Manager::Employee->current->id)) {
$::form->error(t8('You do not have permission to access this entry.'));
}
my $ref = \$attachment->content;
if ( $attachment->file_id > 0 ) {
my $file = SL::File->get(id => $attachment->file_id );
$ref = $file->get_content if $file;
}
$self->send_file($ref, name => $attachment->name, type => $attachment->mime_type);
}

sub action_apply_record_action {
my ($self) = @_;
my $email_journal_id = $::form->{email_journal_id};
my $attachment_id = $::form->{attachment_id};
my $customer_vendor = $::form->{customer_vendor_selection};
my $customer_vendor_id = $::form->{"${customer_vendor}_id"};
my $action = $::form->{action_selection};
my $record_id = $::form->{"record_id"};
my $record_type = $::form->{"record_type"};
$record_type ||= $::form->{"${customer_vendor}_${action}_type_selection"};

die t8("No record is selected.") unless $record_id || $action eq 'new_record';
die t8("No record type is selected.") unless $record_type;
die "no 'email_journal_id' was given" unless $email_journal_id;
die "no 'customer_vendor_selection' was given" unless $customer_vendor;
die "no 'action_selection' was given" unless $action;

if (scalar @domain_hits) {
my $first_customer_vendor = $domain_hits[0];
unless (any {$_->id != $first_customer_vendor->id} @domain_hits) {
$customer_vendor = $first_customer_vendor;
}
}
}

return $customer_vendor;
}

sub add_js {
$::request->{layout}->use_javascript("${_}.js") for qw(
kivi.EmailJournal
);
}

sub init_can_view_all { $::auth->assert('email_employee_readall', 1) }

sub init_models {
my ($self) = @_;

my @where;
push @where, (sender_id => SL::DB::Manager::Employee->current->id) if !$self->can_view_all;

SL::Controller::Helper::GetModels->new(
controller => $self,
query => \@where,
with_objects => [ 'sender' ],
sorted => {
sender => t8('Sender'),
from => t8('From'),
recipients => t8('Recipients'),
subject => t8('Subject'),
sent_on => t8('Sent on'),
status => t8('Status'),
extended_status => t8('Extended status'),
record_type => t8('Record Type'),
obsolete => t8('Obsolete'),
linked_to => t8('Linked to'),
},
);
}

sub init_filter_summary {
my ($self) = @_;

my $filter = $::form->{filter} || {};
my @filters = (
[ "from:substr::ilike", $::locale->text('From') ],
[ "recipients:substr::ilike", $::locale->text('Recipients') ],
[ "sent_on:date::ge", $::locale->text('Sent on') . " " . $::locale->text('From Date') ],
[ "sent_on:date::le", $::locale->text('Sent on') . " " . $::locale->text('To Date') ],
);

my @filter_strings = grep { $_ }
map { $filter->{ $_->[0] } ? $_->[1] . ' ' . $filter->{ $_->[0] } : undef }
@filters;

my %status = (
send_failed => $::locale->text('send failed'),
sent => $::locale->text('sent'),
imported => $::locale->text('imported'),
);
push @filter_strings, $status{ $filter->{'status:eq_ignore_empty'} } if $filter->{'status:eq_ignore_empty'};


my %record_type_to_text = $self->get_record_types_to_text();
push @filter_strings, $record_type_to_text{ $filter->{'record_type:eq_ignore_empty'} } if $filter->{'record_type:eq_ignore_empty'};

push @filter_strings, $::locale->text('Obsolete') if $filter->{'obsolete:eq_ignore_empty'} eq '1';
push @filter_strings, $::locale->text('Not obsolete') if $filter->{'obsolete:eq_ignore_empty'} eq '0';

push @filter_strings, $::locale->text('Linked') if $filter->{'linked_to:eq_ignore_empty'} eq '1';
push @filter_strings, $::locale->text('Not linked') if $filter->{'linked_to:eq_ignore_empty'} eq '0';

return join ', ', @filter_strings;
}

sub setup_list_action_bar {
my ($self) = @_;

for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
action => [
t8('Filter'),
submit => [ '#filter_form', { action => 'EmailJournal/list' } ],
accesskey => 'enter',
],
);
}
}

sub setup_show_action_bar {
my ($self) = @_;

for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
action => [
t8('Back'),
call => [ 'kivi.history_back' ],
],
);
}
}

1;
(27-27/84)