Revision db7a2e79
Von Sven Schöling vor mehr als 8 Jahren hinzugefügt
SL/Controller/Letter.pm | ||
---|---|---|
use SL::Webdav::File;
|
||
|
||
use Rose::Object::MakeMethods::Generic (
|
||
'scalar --get_set_init' => [ qw(letter all_employees models webdav_objects) ],
|
||
'scalar --get_set_init' => [ qw(letter all_employees models webdav_objects is_sales) ],
|
||
);
|
||
|
||
__PACKAGE__->run_before('check_auth_edit');
|
||
... | ... | |
subject => t8('Subject'),
|
||
letternumber => t8('Letternumber'),
|
||
customer_id => t8('Customer'),
|
||
vendor_id => t8('Vendor'),
|
||
contact => t8('Contact'),
|
||
);
|
||
|
||
### actions
|
||
|
||
sub action_add {
|
||
my ($self, %params) = @_;
|
||
|
||
... | ... | |
return $self->action_add
|
||
unless $::form->{letter} || $::form->{draft};
|
||
|
||
$self->letter(SL::DB::Letter->new_from_draft($::form->{draft}{id}))
|
||
if $::form->{draft};
|
||
if ($::form->{draft}) {
|
||
$self->letter(SL::DB::Letter->new_from_draft($::form->{draft}{id}));
|
||
$self->is_sales($self->letter->is_sales);
|
||
}
|
||
|
||
$self->_display(
|
||
title => t8('Edit Letter'),
|
||
... | ... | |
|
||
my $letter = $self->letter;
|
||
|
||
if (!$self->letter->customer_id || !$self->letter->customer) {
|
||
if (!$self->letter->has_customer_vendor) {
|
||
return $self->js
|
||
->replaceWith(
|
||
'#letter_cp_id',
|
||
... | ... | |
->render;
|
||
}
|
||
|
||
my $contacts = $letter->customer->contacts;
|
||
my $contacts = $letter->customer_vendor->contacts;
|
||
|
||
my $default;
|
||
if ( $letter->contact
|
||
&& $letter->contact->cp_cv_id
|
||
&& $letter->contact->cp_cv_id == $letter->customer_id) {
|
||
&& $letter->contact->cp_cv_id == $letter->customer_vendor_id) {
|
||
$default = $letter->contact->cp_id;
|
||
} else {
|
||
$default = '';
|
||
... | ... | |
);
|
||
}
|
||
|
||
### internal methods
|
||
|
||
sub _display {
|
||
my ($self, %params) = @_;
|
||
|
||
... | ... | |
$params{title} ||= t8('Edit Letter');
|
||
|
||
$::form->{type} = 'letter'; # needed for print_options
|
||
$::form->{vc} = 'customer'; # needs to be for _get_contacts...
|
||
$::form->{vc} = $letter->is_sales ? 'customer' : 'vendor'; # needs to be for _get_contacts...
|
||
|
||
$::request->layout->add_javascripts('customer_or_vendor_selection.js');
|
||
$::request->layout->add_javascripts('edit_part_window.js');
|
||
... | ... | |
my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
|
||
$self->{report} = $report;
|
||
|
||
my @columns = qw(date subject letternumber customer_id contact date);
|
||
my @sortable = qw(date subject letternumber customer_id contact date);
|
||
my @columns = qw(date subject letternumber customer_id vendor_id contact date);
|
||
my @sortable = qw(date subject letternumber customer_id vendor_id contact date);
|
||
|
||
my %column_defs = (
|
||
date => { text => t8('Date'), sub => sub { $_[0]->date_as_date } },
|
||
... | ... | |
obj_link => sub { $self->url_for(action => 'edit', 'letter.id' => $_[0]->id, callback => $self->models->get_callback) } },
|
||
letternumber => { text => t8('Letternumber'), sub => sub { $_[0]->letternumber },
|
||
obj_link => sub { $self->url_for(action => 'edit', 'letter.id' => $_[0]->id, callback => $self->models->get_callback) } },
|
||
customer_id => { text => t8('Customer'), sub => sub { SL::DB::Manager::Customer->find_by_or_create(id => $_[0]->customer_id)->displayable_name } },
|
||
customer_id => { text => t8('Customer'), sub => sub { SL::DB::Manager::Customer->find_by_or_create(id => $_[0]->customer_id)->displayable_name }, visible => $self->is_sales },
|
||
vendor_id => { text => t8('Vendor'), sub => sub { SL::DB::Manager::Vendor->find_by_or_create(id => $_[0]->vendor_id)->displayable_name }, visible => !$self->is_sales},
|
||
contact => { text => t8('Contact'), sub => sub { $_[0]->contact ? $_[0]->contact->full_name : '' } },
|
||
);
|
||
|
||
... | ... | |
|
||
$report->set_columns(%column_defs);
|
||
$report->set_column_order(@columns);
|
||
$report->set_export_options(qw(list filter));
|
||
$report->set_export_options(qw(list filter is_sales));
|
||
$report->set_options_from_form;
|
||
|
||
$self->models->disable_plugin('paginated') if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
|
||
$self->models->add_additional_url_params(is_sales => $self->is_sales);
|
||
$self->models->finalize;
|
||
$self->models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
|
||
|
||
... | ... | |
|
||
return 0 if $params{skip_drafts};
|
||
|
||
my $letter_drafts = SL::DB::Manager::LetterDraft->get_all;
|
||
my $letter_drafts = SL::DB::Manager::LetterDraft->get_all(
|
||
query => [
|
||
SL::DB::Manager::Letter->is_sales_filter($self->is_sales),
|
||
]
|
||
);
|
||
|
||
return unless @$letter_drafts;
|
||
|
||
... | ... | |
->assign_attributes(%{ $::form->{letter} });
|
||
|
||
if ($letter->cp_id) {
|
||
# $letter->customer_id($letter->contact->cp_cv_id);
|
||
# $letter->customer_vendor_id($letter->contact->cp_cv_id);
|
||
# contacts don't have language_id yet
|
||
# $letter->greeting(GenericTranslations->get(
|
||
# translation_type => 'greetings::' . ($letter->contact->cp_gender eq 'f' ? 'female' : 'male'),
|
||
... | ... | |
# ));
|
||
}
|
||
|
||
$self->is_sales($letter->is_sales);
|
||
|
||
$letter;
|
||
}
|
||
|
||
... | ... | |
SL::Controller::Helper::GetModels->new(
|
||
controller => $self,
|
||
model => 'Letter',
|
||
query => [
|
||
SL::DB::Manager::Letter->is_sales_filter($self->is_sales),
|
||
],
|
||
sorted => \%sort_columns,
|
||
with_objects => [ 'contact', 'salesman', 'employee' ],
|
||
);
|
||
... | ... | |
} @all_objects ];
|
||
}
|
||
|
||
sub init_is_sales {
|
||
die 'is_sales must be set' unless defined $::form->{is_sales};
|
||
$::form->{is_sales};
|
||
}
|
||
|
||
sub check_auth_edit {
|
||
$::auth->assert('sales_letter_edit');
|
||
}
|
||
... | ... | |
|
||
Simple letter CRUD controller with drafting capabilities.
|
||
|
||
=head1 TODO
|
||
|
||
Customer/Vendor switch for dealing with vendor letters
|
||
|
||
copy to webdav is crap
|
||
|
||
customer/vendor stuff
|
||
|
||
=head1 AUTHOR
|
||
|
||
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
|
SL/DB/Letter.pm | ||
---|---|---|
$self;
|
||
}
|
||
|
||
sub is_sales {
|
||
die 'not an accessor' if @_ > 1;
|
||
$_[0]{customer_id} * 1;
|
||
}
|
||
|
||
sub has_customer_vendor {
|
||
my ($self) = @_;
|
||
die 'not an accessor' if @_ > 1;
|
||
|
||
return $self->is_sales
|
||
? ($self->customer_id && $self->customer)
|
||
: ($self->vendor_id && $self->vendor);
|
||
}
|
||
|
||
sub customer_vendor {
|
||
die 'not an accessor' if @_ > 1;
|
||
$_[0]->is_sales ? $_[0]->customer : $_[0]->vendor;
|
||
}
|
||
|
||
sub customer_vendor_id {
|
||
die 'not an accessor' if @_ > 1;
|
||
$_[0]->customer_id || $_[0]->vendor_id;
|
||
}
|
||
|
||
1;
|
SL/DB/Manager/Letter.pm | ||
---|---|---|
sub object_class { 'SL::DB::Letter' }
|
||
|
||
__PACKAGE__->make_manager_methods;
|
||
__PACKAGE__->add_filter_specs(
|
||
is_sales => sub {
|
||
my ($key, $value, $prefix) = @_;
|
||
__PACKAGE__->is_sales_filter($value, $prefix);
|
||
},
|
||
);
|
||
|
||
sub is_sales_filter {
|
||
my ($class, $value, $prefix) = @_;
|
||
|
||
return () if !defined $value;
|
||
return ($prefix . 'customer_id' => { gt => 0 }) if $value;
|
||
return ($prefix . 'vendor_id' => { gt => 0 }) if !$value;
|
||
}
|
||
|
||
sub _sort_spec {
|
||
return ( columns => { SIMPLE => 'ALL',
|
SL/DB/MetaSetup/Letter.pm | ||
---|---|---|
__PACKAGE__->meta->columns(
|
||
body => { type => 'text' },
|
||
cp_id => { type => 'integer' },
|
||
customer_id => { type => 'integer', not_null => 1 },
|
||
customer_id => { type => 'integer' },
|
||
date => { type => 'date' },
|
||
employee_id => { type => 'integer' },
|
||
greeting => { type => 'text' },
|
||
... | ... | |
reference => { type => 'text' },
|
||
salesman_id => { type => 'integer' },
|
||
subject => { type => 'text' },
|
||
vendor_id => { type => 'integer' },
|
||
);
|
||
|
||
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
|
||
... | ... | |
class => 'SL::DB::Employee',
|
||
key_columns => { salesman_id => 'id' },
|
||
},
|
||
|
||
vendor => {
|
||
class => 'SL::DB::Vendor',
|
||
key_columns => { vendor_id => 'id' },
|
||
},
|
||
);
|
||
|
||
1;
|
SL/DB/MetaSetup/LetterDraft.pm | ||
---|---|---|
__PACKAGE__->meta->columns(
|
||
body => { type => 'text' },
|
||
cp_id => { type => 'integer' },
|
||
customer_id => { type => 'integer', not_null => 1 },
|
||
customer_id => { type => 'integer' },
|
||
date => { type => 'date' },
|
||
employee_id => { type => 'integer' },
|
||
greeting => { type => 'text' },
|
||
... | ... | |
reference => { type => 'text' },
|
||
salesman_id => { type => 'integer' },
|
||
subject => { type => 'text' },
|
||
vendor_id => { type => 'integer' },
|
||
);
|
||
|
||
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
|
||
... | ... | |
class => 'SL::DB::Employee',
|
||
key_columns => { salesman_id => 'id' },
|
||
},
|
||
|
||
vendor => {
|
||
class => 'SL::DB::Vendor',
|
||
key_columns => { vendor_id => 'id' },
|
||
},
|
||
);
|
||
|
||
1;
|
doc/UPGRADE | ||
---|---|---|
das auf dem Zielsystem absolut nicht möglich ist, muss das Upgradescript
|
||
sql/Pg-Upgrade2/trigram_indices.sql deaktiviert oder entfernt werden.
|
||
|
||
* Für das neue Feature Lieferantenbriefe ist die Standardvorlage für Briefe
|
||
(letter.tex) angepasst worden. Statt letter.customer muss der Adressat jetzt
|
||
aus letter.custoemr_vendor erzeugt werden.
|
||
|
||
|
||
Upgrade auf v3.4.1
|
||
==================
|
doc/changelog | ||
---|---|---|
- Neues Recht "Verknüpfte Belege", standardmäßig erlaubt. Betrifft alle
|
||
Belege und die Projektstammdaten
|
||
|
||
- Briefe sind jetzt auch für Lieferanten verfügbar. Die neuen Rechte dafür
|
||
sind für Gruppen vergeben, die auch Einkaufsbelege bearbeiten dürfen.
|
||
|
||
Administrative Änderungen
|
||
|
||
- Diverse Textsuchen werden jetzt durch eine neue Klasse Indizes
|
locale/de/all | ||
---|---|---|
'Edit project link' => 'Projektverknüpfung bearbeiten',
|
||
'Edit project status' => 'Projektstatus bearbeiten',
|
||
'Edit project type' => 'Projekttypen bearbeiten',
|
||
'Edit purchase letters' => 'Einkaufsbrief erstellen',
|
||
'Edit purchase price rule' => 'Einkaufspreisregel bearbeiten',
|
||
'Edit requirement spec' => 'Pflichtenheft bearbeiten',
|
||
'Edit requirement spec status' => 'Pflichtenheftstatus bearbeiten',
|
||
... | ... | |
'Show overdue sales quotations and requests for quotations...' => 'Überfällige Angebote und Preisanfragen anzeigen...',
|
||
'Show parts' => 'Artikel anzeigen',
|
||
'Show parts longdescription (notes) in select list' => 'Langtext in Auswahlliste bei mehreren Treffern im Stammdaten-Bestand anzeigen',
|
||
'Show purchase letters report' => 'Einkaufsbriefe zeigen',
|
||
'Show requirement spec' => 'Pflichtenheft anzeigen',
|
||
'Show requirement spec template' => 'Pflichtenheftvorlage anzeigen',
|
||
'Show sales letters report' => 'Verkaufsbrief anzeigen',
|
menus/user/00-erp.yaml | ||
---|---|---|
access: sales_letter_edit
|
||
params:
|
||
action: Letter/add
|
||
is_sales: 1
|
||
- parent: ar
|
||
id: ar_invoices
|
||
name: Invoices
|
||
... | ... | |
access: sales_letter_report
|
||
params:
|
||
action: Letter/list
|
||
is_sales: 1
|
||
- id: ap
|
||
name: AP
|
||
icon: ap
|
||
... | ... | |
params:
|
||
action: add
|
||
type: invoice
|
||
- parent: ap
|
||
id: ap_add_letter
|
||
name: Add Letter
|
||
order: 450
|
||
access: purchase_letter_edit
|
||
params:
|
||
action: Letter/add
|
||
is_sales: 0
|
||
- parent: ap
|
||
id: ap_reports
|
||
name: Reports
|
||
... | ... | |
params:
|
||
action: DeliveryValueReport/list
|
||
vc: vendor
|
||
- parent: ap_reports
|
||
id: ap_reports_letters
|
||
name: Letters
|
||
order: 1100
|
||
access: purchase_letter_report
|
||
params:
|
||
action: Letter/list
|
||
is_sales: 0
|
||
- id: warehouse
|
||
name: Warehouse
|
||
icon: warehouse
|
sql/Pg-upgrade2-auth/purchase_letter_rights.pl | ||
---|---|---|
# @tag: purchase_letter_rights
|
||
# @description: Neue Rechte für Lieferantenbriefe
|
||
# @depends: release_3_2_0 sales_letter_rights
|
||
# @locales: Edit purchase letters
|
||
# @locales: Show purchase letters report
|
||
package SL::DBUpgrade2::purchase_letter_rights;
|
||
|
||
use strict;
|
||
use utf8;
|
||
|
||
use parent qw(SL::DBUpgrade2::Base);
|
||
|
||
use SL::DBUtils;
|
||
|
||
sub run {
|
||
my ($self) = @_;
|
||
|
||
$self->db_query("INSERT INTO auth.master_rights (position, name, description) VALUES (?, ?, ?)", bind => $_) for
|
||
[ 2550, 'purchase_letter_edit', 'Edit purchase letters' ],
|
||
[ 2650, 'purchase_letter_report', 'Show purchase letters report' ];
|
||
|
||
my $groups = $main::auth->read_groups();
|
||
|
||
foreach my $group (values %{$groups}) {
|
||
$group->{rights}->{purchase_letter_edit} = $group->{rights}->{purchase_order_edit};
|
||
$group->{rights}->{purchase_letter_report} = $group->{rights}->{purchase_order_edit};
|
||
$main::auth->save_group($group);
|
||
}
|
||
|
||
return 1;
|
||
} # end run
|
||
|
||
1;
|
sql/Pg-upgrade2/letter_vendorletter.sql | ||
---|---|---|
-- @tag: letter_vendorletter
|
||
-- @description: Briefe jetzt auch für Lieferanten
|
||
-- @depends: release_3_4_1
|
||
-- @encoding: utf-8
|
||
|
||
ALTER TABLE letter ALTER COLUMN customer_id DROP NOT NULL;
|
||
ALTER TABLE letter ADD COLUMN vendor_id INTEGER REFERENCES vendor(id);
|
||
|
||
ALTER TABLE letter_draft ALTER COLUMN customer_id DROP NOT NULL;
|
||
ALTER TABLE letter_draft ADD COLUMN vendor_id INTEGER REFERENCES vendor(id);
|
templates/print/RB/letter.tex | ||
---|---|---|
% config: tag-style=$( )$
|
||
$( USE KiviLatex )$
|
||
$( USE P )$
|
||
$( SET customer = letter.customer )$
|
||
$( SET customer = letter.customer_vendor )$
|
||
\input{inheaders.tex}
|
||
$( KiviLatex.required_packages_for_html )$
|
||
|
templates/webpages/letter/edit.html | ||
---|---|---|
<input type="hidden" name="letter.id" value="[% letter.id | html %]">
|
||
<input type="hidden" name="draft.id" value="[% draft.id | html %]">
|
||
<input type="hidden" name="type" value="[% type | html %]">
|
||
[% L.hidden_tag('is_sales', SELF.is_sales) %]
|
||
|
||
[%- INCLUDE 'common/flash.html' %]
|
||
|
||
... | ... | |
<td width=50%>
|
||
<!-- upper left block -->
|
||
<table width=90%>
|
||
[%- IF SELF.is_sales %]
|
||
<tr>
|
||
<th align='right'>[% 'Customer' | $T8 %]:</th>
|
||
<td>[% P.customer_vendor_picker('letter.customer_id', letter.customer_id, type='customer') %]
|
||
... | ... | |
[%- END %]
|
||
</td>
|
||
</tr>
|
||
[%- ELSE %]
|
||
<tr>
|
||
<th align='right'>[% 'Vendor' | $T8 %]:</th>
|
||
<td>[% P.customer_vendor_picker('letter.vendor_id', letter.vendor_id, type='vendor') %]
|
||
[%- IF letter.vendor_id %]
|
||
<input type="button" value="[% 'Details (one letter abbreviation)' | $T8 %]" onclick="show_vc_details('vendor')">
|
||
[%- END %]
|
||
</td>
|
||
</tr>
|
||
[%- END %]
|
||
<tr>
|
||
<th align='right'>[% 'Contact Person' | $T8 %]</th>
|
||
<td>[% L.select_tag('letter.cp_id', letter.customer_id ? letter.customer.contacts : [], value_key='cp_id', title_key='full_name', default=letter.cp_id) %]</td>
|
||
<td>[% L.select_tag('letter.cp_id', letter.customer_vendor_id ? letter.customer_vendor.contacts : [], value_key='cp_id', title_key='full_name', default=letter.cp_id) %]</td>
|
||
</tr>
|
||
<tr>
|
||
<th align='right'>[% 'Your Reference' | $T8 %]:</th>
|
||
... | ... | |
var data = $('form').serializeArray();
|
||
data.push({ name: 'action_update_contacts', value: 1 });
|
||
$.post('controller.pl', data, kivi.eval_json_result);
|
||
});
|
||
$('#letter_vendor_id').change(function(){
|
||
var data = $('form').serializeArray();
|
||
data.push({ name: 'action_update_contacts', value: 1 });
|
||
$.post('controller.pl', data, kivi.eval_json_result);
|
||
})
|
||
})
|
||
</script>
|
templates/webpages/letter/load_drafts.html | ||
---|---|---|
<th class="listheading"> </th>
|
||
<th class="listheading">[% 'Date' | $T8 %]</th>
|
||
<th class="listheading">[% 'Subject' | $T8 %]</th>
|
||
[%- IF SELF.is_sales %]
|
||
<th class="listheading">[% 'Customer' | $T8 %]</th>
|
||
[%- ELSE %]
|
||
<th class="listheading">[% 'Vendor' | $T8 %]</th>
|
||
[%- END %]
|
||
</tr>
|
||
|
||
[% FOREACH row = LETTER_DRAFTS %]
|
||
... | ... | |
<td>[% L.checkbox_tag("ids[+]", value=row.id) %]</td>
|
||
<td>[% row.date.to_kivitendo | html %]</td>
|
||
<td><a href="[% SELF.url_for(action='edit', 'draft.id'=row.id) %]">[% row.subject | html %]</a></td>
|
||
[%- IF SELF.is_sales %]
|
||
<td>[% row.customer.displayable_name | html %]</td>
|
||
[%- ELSE %]
|
||
<td>[% row.vendor.displayable_name | html %]</td>
|
||
[%- END %]
|
||
</tr>
|
||
[% END %]
|
||
</table>
|
||
... | ... | |
<tr>
|
||
<td>
|
||
<input type="hidden" name="action" value="Letter/dispatch">
|
||
[% L.hidden_tag('is_sales', SELF.is_sales) %]
|
||
<input type="submit" class="submit" name="action_skip_draft" value="[% 'Skip' | $T8 %]">
|
||
<input type="submit" class="submit" name="action_delete_drafts" value="[% 'Delete drafts' | $T8 %]">
|
||
</td>
|
templates/webpages/letter/search.html | ||
---|---|---|
<th align='right'>[% 'Letternumber' | $T8 %]</th>
|
||
<td>[% L.input_tag('filter.letternumber:substr::ilike', filter.letternumber_substr__ilike, style='width:250px') %]</th>
|
||
</tr>
|
||
[%- IF SELF.is_sales %]
|
||
<tr>
|
||
<td align="right">[% 'Customer' | $T8 %]</td>
|
||
<td>[% L.customer_vendor_picker('filter.customer_id', filter.customer_id, type='customer', style='width:250px') %]</td>
|
||
</tr>
|
||
|
||
[%- ELSE %]
|
||
<tr>
|
||
<td align="right">[% 'Vendor' | $T8 %]</td>
|
||
<td>[% L.customer_vendor_picker('filter.vendor_id', filter.vendor_id, type='vendor', style='width:250px') %]</td>
|
||
</tr>
|
||
[%- END %]
|
||
<tr>
|
||
<td align="right">[% 'Contact' | $T8 %]</td>
|
||
<td>[% L.input_tag('filter.contact.cp_name:substr::ilike', filter.contact.cp_name_substr__ilike, style='width:250px') %]</th>
|
||
... | ... | |
</tr>
|
||
</table>
|
||
|
||
[% L.hidden_tag('is_sales', SELF.is_sales) %]
|
||
[% L.hidden_tag('sort_by', FORM.sort_by) %]
|
||
[% L.hidden_tag('sort_dir', FORM.sort_dir) %]
|
||
[% L.hidden_tag('page', FORM.page) %]
|
Auch abrufbar als: Unified diff
Briefe: Lieferantenbriefe