Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision d4557a8b

Von Kivitendo Admin vor etwa 8 Jahren hinzugefügt

  • ID d4557a8bfab9f122ae19e91a8735e22a4b0c275b
  • Vorgänger 19c3be79
  • Nachfolger 032056b3

Neue Maske: Auftragsartikelsuche

um schnell Positionen aus (alten) Verkaufsaufträgen zu finden:

Verkauf -> Berichte -> Auftragsartikelsuche

Dies ist kein druckbarer Bericht, sondern soll helfen, schnell einen
bestimmten Auftrag oder eine Information zu einer bestimmten verkauften
Ware zu finden.

Wurde die Ware per Lieferschein verschickt und ausgelagert wird auch der
Lieferschein und die verschickte Menge angezeigt. Dies klappt aber nur
für Aufträge, wo die Einzelpositionen per RecordLinks verknüpft sind.

Unterschiede anzeigen:

SL/Controller/OrderItem.pm
1
package SL::Controller::OrderItem;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6
use SL::DB::Order;
7
use SL::DB::OrderItem;
8
use SL::DB::Customer;
9
use SL::DB::Part;
10
use SL::Controller::Helper::GetModels;
11
use SL::Controller::Helper::ParseFilter;
12
use SL::Locale::String qw(t8);
13

  
14
__PACKAGE__->run_before('check_auth');
15

  
16
use Rose::Object::MakeMethods::Generic (
17
  'scalar'                => [ qw(orderitems) ],
18
  'scalar --get_set_init' => [ qw(model) ],
19
);
20

  
21
my %sort_columns = (
22
  partnumber        => t8('Part Number'),
23
  ordnumber         => t8('Order'),
24
  customer          => t8('Customer'),
25
  transdate         => t8('Date'),
26
);
27

  
28
sub action_search {
29

  
30
  my ($self, %params) = @_;
31

  
32
  my $title = t8("Sold order items");
33

  
34
  $::request->layout->use_javascript('client_js.js');
35

  
36
  # The actual loading of orderitems happens in action_order_item_list_dynamic_table
37
  # which is processed inside this template and automatically called upon
38
  # loading. This causes all filtered orderitems to be displayed,
39
  # there is no paginate mechanism or export
40
  $self->render('order_items_search/order_items', { layout => 1, process => 1 },
41
                                                  title         => $title,
42
               );
43
}
44

  
45

  
46
sub action_order_item_list_dynamic_table {
47
  my ($self) = @_;
48

  
49
  $self->orderitems( $self->model->get );
50

  
51

  
52
  $self->add_linked_delivery_order_items;
53

  
54
  $self->render('order_items_search/_order_item_list', { layout  => 0 , process => 1 });
55
}
56

  
57
sub add_linked_delivery_order_items {
58
  my ($self) = @_;
59

  
60
  my $qty_round = 2;
61

  
62
  foreach my $orderitem ( @{ $self->orderitems } ) {
63
    my $dois = $orderitem->linked_delivery_order_items;
64
    $orderitem->{deliveryorders} = join('<br>', map { $_->displayable_delivery_order_info($qty_round) } @{$dois});
65
  };
66
};
67

  
68
sub init_model {
69
  my ($self) = @_;
70

  
71
  SL::Controller::Helper::GetModels->new(
72
    controller => $self,
73
    model      => 'OrderItem',
74
    query      => [ SL::DB::Manager::Order->type_filter('sales_order') ],
75
    sorted       => {
76
      _default     => {
77
        by           => 'transdate',
78
        dir          => 0,
79
      },
80
      %sort_columns,
81
    } ,
82
    with_objects    => [ 'order', 'order.customer', 'part' ],
83
  );
84
}
85

  
86
sub check_auth {
87
  $::auth->assert('sales_order_edit');
88
}
89

  
90
1;
91

  
92
__END__
93

  
94
=encoding utf-8
95

  
96
=head1 NAME
97

  
98
SL::Controller::OrderItem - Controller for OrderItems
99

  
100
=head2 OVERVIEW
101

  
102
Controller for quickly finding orderitems in sales orders. For example the
103
customer phones you, saying he would like to order another one of the green
104
thingies he ordered 2 years ago. You have no idea what he is referring to, but
105
you can quickly filter by customer (a customerpicker) and e.g. part description
106
or partnumber or order date, successively narrowing down the search. The
107
resulting list is updated dynamically after keypresses.
108

  
109
=head1 Usage
110

  
111
Certain fields can be preset by passing them as get parameters in the URL, so
112
you could create links to this report:
113

  
114
 controller.pl?action=OrderItem/search&ordnumber=24
115
 controller.pl?action=OrderItem/search&customer_id=3455
116

  
117
=head1 TODO AND CAVEATS
118

  
119
=over 4
120

  
121
=item * amount of results is limited
122

  
123
=back
124

  
125
=cut
css/common.css
72 72
#dunning_invoice_list .direct_debit a {
73 73
  color: #aaa;
74 74
}
75
/* orderitems */
76
.shipped     { color: green }
77
.not_shipped { color: red   }
doc/changelog
41 41
  - Neuer Controller für Preisgruppen, die nun sortiert und ungültig gesetzt
42 42
    werden können.
43 43

  
44
  - Neuer Berichte "Auftragsartikelsuche", um schnell Autragspositionen aus
45
    Verkaufsauträge finden zu können:
46
    Verkauf -> Berichte -> Auftragsartikelsuche
47

  
44 48
Administrative Änderungen
45 49

  
46 50
  - Diverse Textsuchen werden jetzt durch eine neue Klasse Indizes
locale/de/all
1942 1942
  'Order Number missing!'       => 'Auftragsnummer fehlt!',
1943 1943
  'Order amount'                => 'Auftragswert',
1944 1944
  'Order deleted!'              => 'Auftrag gelöscht!',
1945
  'Order item search'           => 'Auftragsartikelsuche',
1945 1946
  'Order probability'           => 'Auftragswahrscheinlichkeit',
1946 1947
  'Order probability & expected billing date' => 'Auftragswahrscheinlichkeit & vorrauss. Abrechnungsdatum',
1947 1948
  'Order value periodicity'     => 'Auftragswert basiert auf Periodizität',
......
2570 2571
  'Show follow ups...'          => 'Zeige Wiedervorlagen...',
2571 2572
  'Show help text'              => 'Hilfetext anzeigen',
2572 2573
  'Show history'                => 'Verlauf anzeigen',
2574
  'Show images'                 => 'Bilder zeigen',
2573 2575
  'Show items from invoices individually' => 'Artikel aus Rechnungen anzeigen',
2574 2576
  'Show mappings (csv_import)'  => 'Spaltenzuordnungen anzeigen',
2575 2577
  'Show old dunnings'           => 'Alte Mahnungen anzeigen',
......
2607 2609
  'Skonto information'          => 'Skonto Information',
2608 2610
  'So far you could use one partnumber for severel parts, for example a service and an article.' => 'Bisher war es möglich eine Artikelnummer für mehrere Artikel zu verwenden, zum Beispiel eine Artikelnummer für eine Dienstleistung, eine Ware und ein Erzeugnis.',
2609 2611
  'Sold'                        => 'Verkauft',
2612
  'Sold order items'            => 'Verkaufte Auftragsartikel',
2610 2613
  'Soldtotal does not make sense without any bsooqr options' => 'Option "Menge in gewählten Belegen" ohne gewählte Belege wird ignoriert.',
2611 2614
  'Solution'                    => 'Lösung',
2612 2615
  'Sort By'                     => 'Sortiert nach',
menus/user/00-erp.yaml
348 348
  module: dn.pl
349 349
  params:
350 350
    action: search
351
- parent: ar_reports
352
  id: ar_order_item_search
353
  name: Order item search
354
  order: 750
355
  access: sales_order_edit
356
  params:
357
    action: OrderItem/search
351 358
- parent: ar_reports
352 359
  id: ar_reports_delivery_plan
353 360
  name: Delivery Plan
templates/webpages/order_items_search/_order_item_list.html
1
[%- USE LxERP %]
2
[%- USE T8 %]
3
[%- USE L %]
4
[%- USE HTML %]
5
[%- USE P %]
6
[% SET qty_round = 2 %]
7
<table cellpadding="3px">
8
 <tr class="listheading">
9
  <th>[%- LxERP.t8("Part")           %]</th>
10
  <th>[%- LxERP.t8("Customer")       %]</th>
11
  <th>[%- LxERP.t8("Order")          %]</th>
12
  <th>[%- LxERP.t8("Transdate")      %]</th>
13
  <th>[%- LxERP.t8("Qty")            %]</th>
14
  <th>[%- LxERP.t8("Delivered")      %]</th>
15
  <th>[%- LxERP.t8("Price")          %]</th>
16
  <th>[%- LxERP.t8("Discount")       %] %</th>
17
  <th>[%- LxERP.t8("Delivery Order") %]</th>
18
  [% IF FORM.show_images %]
19
  <th>[%- LxERP.t8("Image")          %]</th>
20
  [% END %]
21
 </tr>
22
 [% FOREACH order_item = SELF.orderitems %]
23
 <tr id="tr_[% loop.count %]" class="listrow[% loop.count % 2 %]">
24
  <td>                 [% P.part(order_item.part, no_link => 0)               %]</td>
25
  <td>                 [% P.customer(order_item.order.customer, no_link => 0) %]</td>
26
  <td class="numeric"> [% P.sales_order(order_item.order, no_link => 0)       %]</td>
27
  <td>                 [% order_item.order.transdate.to_kivitendo             %]</td>
28
  <td class="numeric [% IF order_item.delivered_qty == order_item.qty %]shipped[% ELSE %]not_shipped[% END %]">
29
    [% LxERP.format_amount(order_item.qty, qty_round) %] [% order_item.unit | html %]
30
  </td>
31
  <td class="numeric"> [% LxERP.format_amount(order_item.delivered_qty, qty_round) %] [% order_item.unit | html %] </td>
32
  <td class="numeric"> [% order_item.sellprice_as_number                      %]</td>
33
  <td class="numeric"> [% order_item.discount_as_percent                      %]</td>
34
  <td>                 [% order_item.deliveryorders                           %]</td>
35
  [% IF FORM.show_images %]
36
  <td> [% IF order_item.part.image %]<a href="[% order_item.part.image | html %]" target="_blank"><img height="32" border="0" src="[% order_item.part.image | html %]"/></a>[% END %]</td>
37
  [% END %]
38
 </tr>
39
 [% END %]
40
</table>
templates/webpages/order_items_search/order_items.html
1
[% USE HTML %]
2
[%- USE LxERP %]
3
[%- USE T8 %]
4
[%- USE L %]
5

  
6
[% SET size=50 %]
7
[% SET show_images=0 %]
8

  
9
<h1>[% title %]</h1>
10
<div style="padding-bottom: 15px">
11
[% 'Filter' | $T8 %]:
12
<form id="filter" name="filter" method="post" action="controller.pl">
13
 <table>
14
  </tr>
15
    <td>[% 'Customer' | $T8 %]</td>
16
    <td>[% L.customer_vendor_picker('filter.order.customer.id', FORM.customer_id, type='customer', class="filter", size=size) %]</td>
17
  </tr>
18
  <tr>
19
    <td>[% 'Part' | $T8 %]</td>
20
    <td>[% L.input_tag('filter.part.all:substr:multi::ilike', FORM.part, size = size, class="filter") %]</td>
21
  </tr>
22
  <tr>
23
    <td>[% 'Order Number' | $T8 %]</td>
24
    <td>[% L.input_tag('filter.order.ordnumber:substr::ilike', FORM.ordnumber, size = 10, class="filter") %]</td>
25
  <tr>
26
  <tr>
27
    <td>[% 'Order Date' | $T8 %]</td>
28
    <td>[% 'From' | $T8 %] [% L.date_tag("filter.order.transdate:date::ge", filter.order.transdate_date___ge, class="filter") %] [% 'Until' | $T8 %] [% L.date_tag('filter.order.transdate:date::le', filter.order.transdate_date__le, class="filter") %]</td>
29
  <tr>
30
  <tr>
31
    <td>[% 'Description' | $T8 %]</td>
32
    <td>[% L.input_tag('filter.description:substr::ilike', filter.description_substr__ilike, size = size, class="filter") %]</td>
33
  </tr>
34
  <tr>
35
    <td>[% 'Long Description' | $T8 %]</td>
36
    <td>[% L.input_tag('filter.longdescription:substr::ilike', filter.longdescription_substr__ilike, size = size, class="filter") %]  </tr>
37
  <tr>
38
    <td>[% 'Show images' | $T8 %]</td>
39
    <td>[% L.checkbox_tag('show_images', checked=show_images) %]  </tr>
40
  </tr>
41
</table>
42
[% L.button_tag("this.form.reset(); refresh_plot();", LxERP.t8("Reset")) %]
43
</form>
44

  
45
<div id="orderitems" style="padding-top: 20px">
46
[% PROCESS 'order_items_search/_order_item_list.html' %]
47
</div>
48

  
49

  
50
<script type="text/javascript">
51
  $(function() {
52
    [% IF FORM.customer_id %]
53
      $( "#filter_part_all_substr_multi_ilike" ).focus();
54
    [% ELSE %]
55
      $( "#filter_order_customer_id_name" ).focus();
56
    [% END %]
57

  
58
    addInputCallback($(".filter"), refresh_plot , 300 );
59

  
60
    $('#show_images').change(function(){
61
      refresh_plot();
62
    });
63
  });
64

  
65

  
66
  function refresh_plot() {
67
    var filterdata = $('#filter').serialize()
68
    var url = './controller.pl?action=OrderItem/order_item_list_dynamic_table&' + filterdata;
69
    $.ajax({
70
        url : url,
71
        type: 'POST',
72
        success: function(data){
73
            $('#orderitems').html(data);
74
        }
75
    })
76

  
77
  };
78

  
79
function addInputCallback(inputfield, callback, delay) {
80
    var timer = null;
81
    inputfield.on('keyup', function() {
82
        if (timer) {
83
            window.clearTimeout(timer);
84
        }
85
        timer = window.setTimeout( function() {
86
            timer = null;
87
            callback();
88
        }, delay );
89
    });
90
    inputfield = null;
91
}
92
</script>

Auch abrufbar als: Unified diff