Revision 19e2bb1a
Von Tamino Steinert vor etwa 1 Jahr hinzugefügt
SL/Controller/EmailJournal.pm | ||
---|---|---|
use SL::DB::Employee;
|
||
use SL::DB::EmailJournal;
|
||
use SL::DB::EmailJournalAttachment;
|
||
use SL::Presenter::EmailJournal;
|
||
use SL::Presenter::Tag qw(html_tag div_tag radio_button_tag);
|
||
use SL::Helper::Flash;
|
||
use SL::Locale::String qw(t8);
|
||
use SL::System::TaskServer;
|
||
use SL::Presenter::EmailJournal;
|
||
|
||
use SL::DB::Order;
|
||
use SL::DB::Order::TypeData;
|
||
... | ... | |
use SL::DB::Manager::Customer;
|
||
use SL::DB::Manager::Vendor;
|
||
|
||
use List::MoreUtils qw(any);
|
||
|
||
use Rose::Object::MakeMethods::Generic
|
||
(
|
||
scalar => [ qw(entry) ],
|
||
... | ... | |
my %RECORD_TYPES_INFO = (
|
||
Order => {
|
||
controller => 'Order',
|
||
model => 'SL::DB::Order',
|
||
class => 'Order',
|
||
types => SL::DB::Order::TypeData->valid_types(),
|
||
},
|
||
DeliveryOrder => {
|
||
controller => 'DeliveryOrder',
|
||
model => 'SL::DB::DeliveryOrder',
|
||
class => 'DeliveryOrder',
|
||
types => SL::DB::DeliveryOrder::TypeData->valid_types(),
|
||
},
|
||
Reclamation => {
|
||
controller => 'Reclamation',
|
||
model => 'SL::DB::Reclamation',
|
||
class => 'Reclamation',
|
||
types => SL::DB::Reclamation::TypeData->valid_types(),
|
||
},
|
||
ArTransaction => {
|
||
controller => 'ar.pl',
|
||
model => 'SL::DB::Invoice',
|
||
class => 'Invoice',
|
||
types => [
|
||
'ar_transaction',
|
||
],
|
||
},
|
||
Invoice => {
|
||
controller => 'is.pl',
|
||
model => 'SL::DB::Invoice',
|
||
class => 'Invoice',
|
||
types => [
|
||
'invoice',
|
||
'invoice_for_advance_payment',
|
||
... | ... | |
},
|
||
ApTransaction => {
|
||
controller => 'ap.pl',
|
||
model => 'SL::DB::PurchaseInvoice',
|
||
class => 'PurchaseInvoice',
|
||
types => [
|
||
'ap_transaction',
|
||
],
|
||
},
|
||
PurchaseInvoice => {
|
||
controller => 'ir.pl',
|
||
model => 'SL::DB::PurchaseInvoice',
|
||
class => 'PurchaseInvoice',
|
||
types => [
|
||
'purchase_invoice',
|
||
'purchase_credit_note',
|
||
... | ... | |
} keys %RECORD_TYPES_INFO;
|
||
my %RECORD_TYPE_TO_MODEL =
|
||
map {
|
||
my $model = $RECORD_TYPES_INFO{$_}->{model};
|
||
map { $_ => $model } @{ $RECORD_TYPES_INFO{$_}->{types} }
|
||
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;
|
||
|
||
# has do be done at runtime for translation to work
|
||
sub get_record_types_with_info {
|
||
# TODO: what record types can be created, which are only available in workflows?
|
||
my @record_types_with_info = ();
|
||
for my $record_class ('SL::DB::Order', 'SL::DB::DeliveryOrder', 'SL::DB::Reclamation') {
|
||
my $valid_types = "${record_class}::TypeData"->valid_types();
|
||
for my $type (@$valid_types) {
|
||
|
||
my $type_data = SL::DB::Helper::TypeDataProxy->new($record_class, $type);
|
||
push @record_types_with_info, {
|
||
record_type => $type,
|
||
customervendor => $type_data->properties('customervendor'),
|
||
text => $type_data->text('type'),
|
||
};
|
||
}
|
||
}
|
||
push @record_types_with_info, (
|
||
# invoice
|
||
{ record_type => 'invoice', customervendor => 'customer', text => t8('Invoice') },
|
||
{ record_type => 'invoice_for_advance_payment', customervendor => 'customer', text => t8('Invoice for Advance Payment')},
|
||
{ record_type => 'invoice_for_advance_payment_storno', customervendor => 'customer', text => t8('Storno Invoice for Advance Payment')},
|
||
{ record_type => 'final_invoice', customervendor => 'customer', text => t8('Final Invoice')},
|
||
{ record_type => 'invoice_storno', customervendor => 'customer', text => t8('Storno Invoice')},
|
||
{ record_type => 'credit_note', customervendor => 'customer', text => t8('Credit Note')},
|
||
{ record_type => 'credit_note_storno', customervendor => 'customer', text => t8('Storno Credit Note')},
|
||
{ record_type => 'ar_transaction', customervendor => 'customer', text => t8('AR Transaction')},
|
||
# purchase invoice
|
||
{ record_type => 'purchase_invoice', customervendor => 'vendor', text => t8('Purchase Invoice')},
|
||
{ record_type => 'purchase_credit_note', customervendor => 'vendor', text => t8('Purchase Credit Note')},
|
||
{ record_type => 'ap_transaction', customervendor => 'vendor', text => t8('AP Transaction')},
|
||
);
|
||
return @record_types_with_info;
|
||
}
|
||
|
||
sub record_types_for_customer_vendor_type {
|
||
my ($self, $customer_vendor_type) = @_;
|
||
return [ map { $_->{record_type} } grep { $_->{customervendor} eq $customer_vendor_type } $self->get_record_types_with_info ];
|
||
}
|
||
|
||
#
|
||
# actions
|
||
... | ... | |
$::form->error(t8('You do not have permission to access this entry.'));
|
||
}
|
||
|
||
# TODO: what record types can be created, which are only available in workflows?
|
||
my @record_types_with_info = ();
|
||
for my $record_class ('SL::DB::Order', 'SL::DB::DeliveryOrder', 'SL::DB::Reclamation') {
|
||
my $valid_types = "${record_class}::TypeData"->valid_types();
|
||
for my $type (@$valid_types) {
|
||
|
||
my $type_data = SL::DB::Helper::TypeDataProxy->new($record_class, $type);
|
||
push @record_types_with_info, {
|
||
record_type => $type,
|
||
customervendor => $type_data->properties('customervendor'),
|
||
text => $type_data->text('type'),
|
||
};
|
||
}
|
||
}
|
||
push @record_types_with_info, (
|
||
# invoice
|
||
{ record_type => 'ar_transaction' , customervendor => 'customer', text => t8('AR Transaction')},
|
||
{ record_type => 'invoice' , customervendor => 'customer', text => t8('Invoice') },
|
||
{ record_type => 'invoice_for_advance_payment' , customervendor => 'customer', text => t8('Invoice for Advance Payment')},
|
||
{ record_type => 'invoice_for_advance_payment_storno', customervendor => 'customer', text => t8('Storno Invoice for Advance Payment')},
|
||
{ record_type => 'final_invoice' , customervendor => 'customer', text => t8('Final Invoice')},
|
||
{ record_type => 'invoice_storno' , customervendor => 'customer', text => t8('Storno Invoice')},
|
||
{ record_type => 'credit_note' , customervendor => 'customer', text => t8('Credit Note')},
|
||
{ record_type => 'credit_note_storno' , customervendor => 'customer', text => t8('Storno Credit Note')},
|
||
# purchase invoice
|
||
{ record_type => 'ap_transaction' , customervendor => 'vendor', text => t8('AP Transaction')},
|
||
{ record_type => 'purchase_invoice' , customervendor => 'vendor', text => t8('Purchase Invoice')},
|
||
{ record_type => 'purchase_credit_note', customervendor => 'vendor', text => t8('Purchase Credit Note')},
|
||
);
|
||
my @record_types_with_info = $self->get_record_types_with_info();
|
||
|
||
my $customer_vendor = $self->find_customer_vendor_from_email($self->entry);
|
||
my $cv_type = $customer_vendor && $customer_vendor->is_vendor ? 'vendor' : 'customer';
|
||
|
||
my $record_types = $self->record_types_for_customer_vendor_type($cv_type);
|
||
my @records = $self->get_records_for_types(
|
||
$record_types,
|
||
customer_vendor_type => $cv_type,
|
||
customer_vendor_id => $customer_vendor && $customer_vendor->id,
|
||
with_closed => 0,
|
||
);
|
||
|
||
$self->setup_show_action_bar;
|
||
$self->render(
|
||
... | ... | |
CUSTOMER_VENDOR => , $customer_vendor,
|
||
CV_TYPE_FOUND => $customer_vendor && $customer_vendor->is_vendor ? 'vendor' : 'customer',
|
||
RECORD_TYPES_WITH_INFO => \@record_types_with_info,
|
||
RECORDS => \@records,
|
||
back_to => $back_to
|
||
);
|
||
}
|
||
|
||
sub get_records_for_types {
|
||
my ($self, $record_types, %params) = @_;
|
||
$record_types = [ $record_types ] unless ref $record_types eq 'ARRAY';
|
||
|
||
my $cv_type = $params{customer_vendor_type};
|
||
my $cv_id = $params{customer_vendor_id};
|
||
my $with_closed = $params{with_closed};
|
||
|
||
my @records = ();
|
||
foreach my $record_type (@$record_types) {
|
||
my $manager = $RECORD_TYPE_TO_MANAGER{$record_type};
|
||
my $model = $RECORD_TYPE_TO_MODEL{$record_type};
|
||
my %additional_where = ();
|
||
if ($cv_type && $cv_id) {
|
||
$additional_where{"${cv_type}_id"} = $cv_id;
|
||
}
|
||
unless ($with_closed) {
|
||
if (any {$_ eq 'closed' } $model->meta->columns) {
|
||
$additional_where{closed} = 0;
|
||
} elsif (any {$_ eq 'paid' } $model->meta->columns) {
|
||
$additional_where{amount} = { gt => \'paid' };
|
||
}
|
||
}
|
||
my $records_of_type = $manager->get_all(
|
||
where => [
|
||
$manager->type_filter($record_type),
|
||
%additional_where,
|
||
],
|
||
);
|
||
push @records, @$records_of_type;
|
||
}
|
||
|
||
return @records;
|
||
}
|
||
|
||
sub action_attachment_preview {
|
||
my ($self) = @_;
|
||
|
||
... | ... | |
my $customer_vendor = $::form->{customer_vendor_selection};
|
||
my $customer_vendor_id = $::form->{"${customer_vendor}_id"};
|
||
my $action = $::form->{action_selection};
|
||
my $record_type = $::form->{"${customer_vendor}_record_type_selection"};
|
||
my $record_id = $::form->{"${record_type}_id"};
|
||
my $record_type_id = $::form->{"record_type_id"};
|
||
die t8("No record is selected.") unless $record_type_id || $action eq 'create_new';
|
||
|
||
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;
|
||
|
||
my ($record_type, $record_id) = split(/-/, $record_type_id);
|
||
|
||
if ($action eq 'linking') {
|
||
return $self->link_and_add_attachment_to_record({
|
||
... | ... | |
->render();
|
||
}
|
||
|
||
sub action_update_record_list {
|
||
my ($self) = @_;
|
||
$::auth->assert('email_journal');
|
||
my $customer_vendor_type = $::form->{customer_vendor_selection};
|
||
my $customer_vendor_id = $::form->{"${customer_vendor_type}_id"};
|
||
my $record_type = $::form->{"${customer_vendor_type}_record_type_selection"};
|
||
my $with_closed = $::form->{with_closed};
|
||
|
||
$record_type ||= $self->record_types_for_customer_vendor_type($customer_vendor_type);
|
||
|
||
my @records = $self->get_records_for_types(
|
||
$record_type,
|
||
customer_vendor_type => $customer_vendor_type,
|
||
customer_vendor_id => $customer_vendor_id,
|
||
with_closed => $with_closed,
|
||
);
|
||
|
||
unless (@records) {
|
||
$self->js->replaceWith('#record_list', div_tag(
|
||
html_tag('h3', t8('No records found.')),
|
||
id => 'record_list',
|
||
))->render();
|
||
return;
|
||
}
|
||
|
||
my $new_div = div_tag(
|
||
join('', map {
|
||
div_tag(
|
||
radio_button_tag('record_type_id',
|
||
value => $_->record_type . "-" . $_->id, label => $_->displayable_name,
|
||
class => "record_radio", label_class => "record_radio",
|
||
),
|
||
id => "record_$_->{id}",
|
||
)
|
||
} @records),
|
||
id => 'record_list',
|
||
);
|
||
|
||
$self->js->replaceWith('#record_list', $new_div)->render();
|
||
}
|
||
|
||
#
|
||
# filters
|
||
#
|
css/design40/email_journal.css | ||
---|---|---|
/* E-Mail-Journal */
|
||
.email_journal_details tbody pre {
|
||
margin: 0px;
|
||
input.record_radio {
|
||
visibility:hidden;
|
||
position:absolute;
|
||
float: left;
|
||
}
|
||
|
||
.email_journal_details tbody th {
|
||
text-align: right;
|
||
vertical-align: top;
|
||
label.record_radio {
|
||
cursor: pointer;
|
||
float: left;
|
||
overflow: hidden;
|
||
width: 200px;
|
||
padding: 5px;
|
||
margin: 5px;
|
||
border-radius: 5px;
|
||
border: 1px solid;
|
||
text-align: center;
|
||
}
|
||
|
||
.email_journal_details tbody td {
|
||
vertical-align: top;
|
||
input.record_radio:checked + label {
|
||
background-color: var(--color-lighter);
|
||
}
|
js/kivi.EmailJournal.js | ||
---|---|---|
$('#vendor_div').show();
|
||
$('#vendor_record_types_div').show();
|
||
}
|
||
kivi.EmailJournal.update_record_type_selection(customer_vendor);
|
||
kivi.EmailJournal.update_record_list();
|
||
}
|
||
|
||
ns.update_action_selection = function() {
|
||
let record_action = $('#action_selection').val();
|
||
|
||
$('#record_type_div').hide();
|
||
$('#no_record_type_div').hide();
|
||
$('#record_div').hide();
|
||
$('#no_record_div').hide();
|
||
|
||
if (record_action == 'create_new') {
|
||
$('#no_record_type_div').show();
|
||
$('#no_record_div').show();
|
||
} else {
|
||
$('#record_type_div').show();
|
||
$('#record_div').show();
|
||
}
|
||
}
|
||
|
||
ns.update_record_type_selection = function(customer_vendor) {
|
||
let record_type = $('#' + customer_vendor + '_record_type_selection').val();
|
||
ns.update_record_list = function() {
|
||
let $form = $('#record_action_form');
|
||
|
||
$('.record_type').hide();
|
||
if (record_type != '') {
|
||
$('#' + record_type + '_div').show();
|
||
} else {
|
||
$('#record_type_placeholder_div').show();
|
||
}
|
||
let data = $form.serializeArray();
|
||
data.push({ name: 'action', value: 'EmailJournal/update_record_list' });
|
||
|
||
$.post("controller.pl", data, kivi.eval_json_result);
|
||
}
|
||
|
||
ns.apply_action_with_attachment = function() {
|
templates/design40_webpages/email_journal/show.html | ||
---|---|---|
cv_type _ "_id",
|
||
CUSTOMER_VENDOR.is_customer == cv_is_cusotmer ? CUSTOMER_VENDOR : undef,
|
||
type=cv_type, class="wi-normal", placeholder=LxERP.t8(cv_name)
|
||
onchange='kivi.EmailJournal.update_record_list();'
|
||
) %]
|
||
</div>
|
||
[% END %]
|
||
... | ... | |
value_key='value', title_key='name',
|
||
with_empty=1, empty_value='', empty_title=LxERP.t8("Select record type"),
|
||
class="wi-normal",
|
||
onchange='kivi.EmailJournal.update_record_type_selection("' _ customer_vendor _ '");'
|
||
onchange='kivi.EmailJournal.update_record_list();'
|
||
) %]
|
||
</div>
|
||
[% END %]
|
||
|
||
<div id="record_type_div" class="col" style="display:block">
|
||
[% FOREACH record_info = RECORD_TYPES_WITH_INFO %]
|
||
<div id="[% record_info.record_type _ "_div" %]" class="col record_type" style="display:none">
|
||
[% L.input_tag(record_info.record_type _ "_id", '',
|
||
style="color:black", class="wi-normal",
|
||
placeholder=record_info.record_type _ " id") %]
|
||
</div>
|
||
[% END %]
|
||
<div id="record_type_placeholder_div" class="col record_type" style="display:block">
|
||
[% L.input_tag('cv_placeholder', '',
|
||
style="color:black", class="wi-normal", disabled=1,
|
||
placeholder=LxERP.t8("Select record type first"),
|
||
) %]
|
||
</div>
|
||
</div>
|
||
<div id="no_record_type_div" class="col" style="display:none">
|
||
[% L.input_tag('cv_placeholder', '',
|
||
style="color:black", class="wi-normal", disabled=1,
|
||
placeholder=LxERP.t8("No record needed"),
|
||
) %]
|
||
<div id="with_closed_div" class="col">
|
||
[% L.select_tag('with_closed',
|
||
[
|
||
{value => "1", name => LxERP.t8("With closed")},
|
||
{value => "0", name => LxERP.t8("Only open")},
|
||
],
|
||
default = 0, value_key='value', title_key='name',
|
||
class="wi-small",
|
||
onchange='kivi.EmailJournal.update_record_list();'
|
||
) %]
|
||
</div>
|
||
|
||
|
||
<div class="col">
|
||
[% L.button_tag('kivi.EmailJournal.apply_action_with_attachment();', LxERP.t8('Apply with Attachment')) %]
|
||
</div>
|
||
</div> <!-- action_div -->
|
||
|
||
[% BLOCK panel_1 %]
|
||
<div id="record_div">
|
||
<div id="record_list">
|
||
[% FOREACH record = RECORDS %]
|
||
<div id="record_[% record.id %]">
|
||
[% L.radio_button_tag('record_type_id', class="record_radio",
|
||
value=record.record_type _ '-' _ record.id,
|
||
label_class="record_radio", label=record.displayable_name) %]
|
||
</div>
|
||
[% END %]
|
||
[% IF RECORDS.size == 0 %]
|
||
<div id="no_record_div">
|
||
<h3> [% LxERP.t8("No records found.") %] </h3>
|
||
</div>
|
||
[% END %]
|
||
</div>
|
||
</div>
|
||
<div id="no_record_div" class="col" style="display:none">
|
||
<h3> [% LxERP.t8("No record needed.") %] </h3>
|
||
</div>
|
||
[% END %]
|
||
[% SET display_status = (RECORDS.size > 20 ? 'closed' : 'open');
|
||
INCLUDE 'common/toggle_panel.html'
|
||
block_name='panel_1'
|
||
button_closed = LxERP.t8('Show Records')
|
||
button_open = LxERP.t8('Hide Records')
|
||
;
|
||
%]
|
||
</form>
|
||
|
||
<!-- kivi.EmailJournal.update_attachment_preview -->
|
Auch abrufbar als: Unified diff
EmailJournal: Workflow: Vorschlag der passenden Belege