Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 51072516

Von Bernd Bleßmann vor etwa 7 Jahren hinzugefügt

  • ID 51072516787d639c5f8df4d487155b4a66b16d6f
  • Vorgänger 1bbcb32c
  • Nachfolger d3c230bf

Inventur: Eingabemaske und Journal im Inventory-Controller

Unterschiede anzeigen:

SL/Controller/Inventory.pm
7 7
use parent qw(SL::Controller::Base);
8 8

  
9 9
use SL::DB::Inventory;
10
use SL::DB::Stocktaking;
10 11
use SL::DB::Part;
11 12
use SL::DB::Warehouse;
12 13
use SL::DB::Unit;
14
use SL::DB::Default;
13 15
use SL::WH;
14 16
use SL::ReportGenerator;
15 17
use SL::Locale::String qw(t8);
......
17 19
use SL::DBUtils;
18 20
use SL::Helper::Flash;
19 21
use SL::Controller::Helper::ReportGenerator;
22
use SL::Controller::Helper::GetModels;
20 23

  
21 24
use English qw(-no_match_vars);
22 25

  
23 26
use Rose::Object::MakeMethods::Generic (
24
  'scalar --get_set_init' => [ qw(warehouses units) ],
27
  'scalar --get_set_init' => [ qw(warehouses units is_stocktaking stocktaking_models stocktaking_cutoff_date) ],
25 28
  'scalar'                => [ qw(warehouse bin unit part) ],
26 29
);
27 30

  
28 31
__PACKAGE__->run_before('_check_auth');
29 32
__PACKAGE__->run_before('_check_warehouses');
30
__PACKAGE__->run_before('load_part_from_form',   only => [ qw(stock_in part_changed mini_stock stock) ]);
31
__PACKAGE__->run_before('load_unit_from_form',   only => [ qw(stock_in part_changed mini_stock stock) ]);
32
__PACKAGE__->run_before('load_wh_from_form',     only => [ qw(stock_in warehouse_changed stock) ]);
33
__PACKAGE__->run_before('load_bin_from_form',    only => [ qw(stock_in stock) ]);
33
__PACKAGE__->run_before('load_part_from_form',   only => [ qw(stock_in part_changed mini_stock stock stocktaking_part_changed save_stocktaking) ]);
34
__PACKAGE__->run_before('load_unit_from_form',   only => [ qw(stock_in part_changed mini_stock stock stocktaking_part_changed save_stocktaking) ]);
35
__PACKAGE__->run_before('load_wh_from_form',     only => [ qw(stock_in warehouse_changed stock stocktaking save_stocktaking) ]);
36
__PACKAGE__->run_before('load_bin_from_form',    only => [ qw(stock_in stock stocktaking save_stocktaking) ]);
34 37
__PACKAGE__->run_before('set_target_from_part',  only => [ qw(part_changed) ]);
35 38
__PACKAGE__->run_before('mini_stock',            only => [ qw(stock_in mini_stock) ]);
36
__PACKAGE__->run_before('sanitize_target',       only => [ qw(stock_usage stock_in warehouse_changed part_changed) ]);
39
__PACKAGE__->run_before('sanitize_target',       only => [ qw(stock_usage stock_in warehouse_changed part_changed stocktaking stocktaking_part_changed save_stocktaking) ]);
37 40
__PACKAGE__->run_before('set_layout');
38 41

  
39 42
sub action_stock_in {
......
483 486
    ->render;
484 487
}
485 488

  
489
sub action_stocktaking {
490
  my ($self) = @_;
491

  
492
  $::request->{layout}->use_javascript("${_}.js") for qw(kivi.Inventory);
493
  $::request->layout->focus('#part_id_name');
494
  $self->setup_stock_stocktaking_action_bar;
495
  $self->render('inventory/stocktaking/form', title => t8('Stocktaking'));
496
}
497

  
498
sub action_save_stocktaking {
499
  my ($self) = @_;
500

  
501
  return $self->js->flash('error', t8('A target quantitiy has to be given'))->render()
502
    if $::form->{target_qty} eq '';
503

  
504
  my $target_qty = $::form->parse_amount(\%::myconfig, $::form->{target_qty});
505

  
506
  return $self->js->flash('error', t8('Error: A negative target quantity is not allowed.'))->render()
507
    if $target_qty < 0;
508

  
509
  my $stocked_qty  = _get_stocked_qty($self->part,
510
                                      warehouse_id => $self->warehouse->id,
511
                                      bin_id       => $self->bin->id,
512
                                      chargenumber => $::form->{chargenumber},
513
                                      bestbefore   => $::form->{bestbefore},);
514

  
515
  my $stocked_qty_in_form_units = $self->part->unit_obj->convert_to($stocked_qty, $self->unit);
516

  
517
  if (!$::form->{dont_check_already_counted}) {
518
    my $already_counted = _already_counted($self->part,
519
                                           warehouse_id => $self->warehouse->id,
520
                                           bin_id       => $self->bin->id,
521
                                           cutoff_date  => $::form->{cutoff_date_as_date},
522
                                           chargenumber => $::form->{chargenumber},
523
                                           bestbefore   => $::form->{bestbefore});
524
    if (scalar @$already_counted) {
525
      my $reply = $self->js->dialog->open({
526
        html   => $self->render('inventory/stocktaking/_already_counted_dialog',
527
                                { output => 0 },
528
                                already_counted           => $already_counted,
529
                                stocked_qty               => $stocked_qty,
530
                                stocked_qty_in_form_units => $stocked_qty_in_form_units),
531
        id     => 'already_counted_dialog',
532
        dialog => {
533
          title => t8('Already counted'),
534
        },
535
      })->render;
536

  
537
      return $reply;
538
    }
539
  }
540

  
541
  # - target_qty is in units given in form ($self->unit)
542
  # - WH->transfer expects qtys in given unit (here: unit from form (unit -> $self->unit))
543
  # Therefore use stocked_qty in form units for calculation.
544
  my $qty        = $target_qty - $stocked_qty_in_form_units;
545
  my $src_or_dst = $qty < 0? 'src' : 'dst';
546
  $qty           = abs($qty);
547

  
548
  my $transfer_error;
549
  # do stock
550
  $::form->throw_on_error(sub {
551
    eval {
552
      WH->transfer({
553
        parts                   => $self->part,
554
        $src_or_dst.'_bin'      => $self->bin,
555
        $src_or_dst.'_wh'       => $self->warehouse,
556
        qty                     => $qty,
557
        unit                    => $self->unit,
558
        transfer_type           => 'stocktaking',
559
        chargenumber            => $::form->{chargenumber},
560
        bestbefore              => $::form->{bestbefore},
561
        ean                     => $::form->{ean},
562
        comment                 => $::form->{comment},
563
        record_stocktaking      => 1,
564
        stocktaking_qty         => $target_qty,
565
        stocktaking_cutoff_date => $::form->{cutoff_date_as_date},
566
      });
567
      1;
568
    } or do { $transfer_error = $EVAL_ERROR->getMessage; }
569
  });
570

  
571
  return $self->js->flash('error', $transfer_error)->render()
572
    if $transfer_error;
573

  
574
  flash_later('info', $::locale->text('Part successful counted'));
575
  $self->redirect_to(action              => 'stocktaking',
576
                     warehouse_id        => $self->warehouse->id,
577
                     bin_id              => $self->bin->id,
578
                     cutoff_date_as_date => $self->stocktaking_cutoff_date->to_kivitendo);
579
}
580

  
581
sub action_reload_stocktaking_history {
582
  my ($self) = @_;
583

  
584
  $::form->{filter}{'cutoff_date:date'} = $self->stocktaking_cutoff_date->to_kivitendo;
585
  $::form->{filter}{'employee_id'}      = SL::DB::Manager::Employee->current->id;
586

  
587
  $self->prepare_stocktaking_report;
588
  $self->report_generator_list_objects(report => $self->{report}, objects => $self->stocktaking_models->get, layout => 0, header => 0);
589
}
590

  
591
sub action_stocktaking_part_changed {
592
  my ($self) = @_;
593

  
594
  $self->js
595
    ->replaceWith('#unit_id', $self->build_unit_select)
596
    ->focus('#target_qty')
597
    ->render;
598
}
599

  
600
sub action_stocktaking_journal {
601
  my ($self) = @_;
602

  
603
  $self->prepare_stocktaking_report(full => 1);
604
  $self->report_generator_list_objects(report => $self->{report}, objects => $self->stocktaking_models->get);
605
}
486 606
#================================================================
487 607

  
488 608
sub _check_auth {
......
505 625
  SL::DB::Manager::Unit->get_all;
506 626
}
507 627

  
628
sub init_is_stocktaking {
629
  return $_[0]->action_name =~ m{stocktaking};
630
}
631

  
632
sub init_stocktaking_models {
633
  my ($self) = @_;
634

  
635
  SL::Controller::Helper::GetModels->new(
636
    controller   => $self,
637
    model        => 'Stocktaking',
638
    sorted       => {
639
      _default => {
640
        by    => 'itime',
641
        dir   => 0,
642
      },
643
      itime        => t8('Insert Date'),
644
      qty          => t8('Target Qty'),
645
      chargenumber => t8('Charge Number'),
646
      comment      => t8('Comment'),
647
      employee     => t8('Employee'),
648
      ean          => t8('EAN'),
649
      partnumber   => t8('Part Number'),
650
      part         => t8('Part Description'),
651
      bin          => t8('Bin'),
652
      cutoff_date  => t8('Cutoff Date'),
653
    },
654
    with_objects => ['employee', 'parts', 'warehouse', 'bin'],
655
  );
656
}
657

  
658
sub init_stocktaking_cutoff_date {
659
  my ($self) = @_;
660

  
661
  return DateTime->from_kivitendo($::form->{cutoff_date_as_date}) if $::form->{cutoff_date_as_date};
662
  return SL::DB::Default->get->stocktaking_cutoff_date if SL::DB::Default->get->stocktaking_cutoff_date;
663

  
664
  # Default cutoff date is last day of current year, but if current month
665
  # is janurary, it is the last day of the last year.
666
  my $now    = DateTime->now_local;
667
  my $cutoff = DateTime->new(year => $now->year, month => 12, day => 31);
668
  if ($now->month < 1) {
669
    $cutoff->substract(years => 1);
670
  }
671
  return $cutoff;
672
}
673

  
508 674
sub set_target_from_part {
509 675
  my ($self) = @_;
510 676

  
......
538 704
}
539 705

  
540 706
sub load_wh_from_form {
541
  $_[0]->warehouse(SL::DB::Manager::Warehouse->find_by_or_create(id => $::form->{warehouse_id}));
707
  my $preselected;
708
  $preselected = SL::DB::Default->get->stocktaking_warehouse_id if $_[0]->is_stocktaking;
709

  
710
  $_[0]->warehouse(SL::DB::Manager::Warehouse->find_by_or_create(id => ($::form->{warehouse_id} || $preselected)));
542 711
}
543 712

  
544 713
sub load_bin_from_form {
545
  $_[0]->bin(SL::DB::Manager::Bin->find_by_or_create(id => $::form->{bin_id}));
714
  my $preselected;
715
  $preselected = SL::DB::Default->get->stocktaking_bin_id if $_[0]->is_stocktaking;
716

  
717
  $_[0]->bin(SL::DB::Manager::Bin->find_by_or_create(id => ($::form->{bin_id} || $preselected)));
546 718
}
547 719

  
548 720
sub set_layout {
......
619 791
  $::form->show_generic_error($msg);
620 792
}
621 793

  
794
sub prepare_stocktaking_report {
795
  my ($self, %params) = @_;
796

  
797
  my $callback    = $self->stocktaking_models->get_callback;
798

  
799
  my $report      = SL::ReportGenerator->new(\%::myconfig, $::form);
800
  $self->{report} = $report;
801

  
802
  my @columns     = qw(itime employee ean partnumber part qty unit bin chargenumber comment cutoff_date);
803
  my @sortable    = qw(itime employee ean partnumber part qty bin chargenumber comment cutoff_date);
804

  
805
  my %column_defs = (
806
    itime           => { sub   => sub { $_[0]->itime_as_timestamp },
807
                         text  => t8('Insert Date'), },
808
    employee        => { sub   => sub { $_[0]->employee->safe_name },
809
                         text  => t8('Employee'), },
810
    ean             => { sub   => sub { $_[0]->part->ean },
811
                         text  => t8('EAN'), },
812
    partnumber      => { sub   => sub { $_[0]->part->partnumber },
813
                         text  => t8('Part Number'), },
814
    part            => { sub   => sub { $_[0]->part->description },
815
                         text  => t8('Part Description'), },
816
    qty             => { sub   => sub { $_[0]->qty_as_number },
817
                         text  => t8('Target Qty'),
818
                         align => 'right', },
819
    unit            => { sub   => sub { $_[0]->part->unit },
820
                         text  => t8('Unit'), },
821
    bin             => { sub   => sub { $_[0]->bin->full_description },
822
                         text  => t8('Bin'), },
823
    chargenumber    => { text  => t8('Charge Number'), },
824
    comment         => { text  => t8('Comment'), },
825
    cutoff_date     => { sub   => sub { $_[0]->cutoff_date_as_date },
826
                         text  => t8('Cutoff Date'), },
827
  );
828

  
829
  $report->set_options(
830
    std_column_visibility => 1,
831
    controller_class      => 'Inventory',
832
    output_format         => 'HTML',
833
    title                 => (!!$params{full})? $::locale->text('Stocktaking Journal') : $::locale->text('Stocktaking History'),
834
    allow_pdf_export      => !!$params{full},
835
    allow_csv_export      => !!$params{full},
836
  );
837
  $report->set_columns(%column_defs);
838
  $report->set_column_order(@columns);
839
  $report->set_export_options(qw(stocktaking_journal filter));
840
  $report->set_options_from_form;
841
  $self->stocktaking_models->disable_plugin('paginated') if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
842
  $self->stocktaking_models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable) if !!$params{full};
843
  if (!!$params{full}) {
844
    $report->set_options(
845
      raw_top_info_text    => $self->render('inventory/stocktaking/full_report_top', { output => 0 }),
846
    );
847
  }
848
  $report->set_options(
849
    raw_bottom_info_text => $self->render('inventory/stocktaking/report_bottom',   { output => 0 }),
850
  );
851
}
852

  
853
sub _get_stocked_qty {
854
  my ($part, %params) = @_;
855

  
856
  my $bestbefore_filter  = '';
857
  my $bestbefore_val_cnt = 0;
858
  if ($::instance_conf->get_show_bestbefore) {
859
    $bestbefore_filter  = ($params{bestbefore}) ? 'AND bestbefore = ?' : 'AND bestbefore IS NULL';
860
    $bestbefore_val_cnt = ($params{bestbefore}) ? 1                    : 0;
861
  }
862

  
863
  my $query = <<SQL;
864
    SELECT sum(qty) FROM inventory
865
      WHERE parts_id = ? AND warehouse_id = ? AND bin_id = ? AND chargenumber = ? $bestbefore_filter
866
      GROUP BY warehouse_id, bin_id, chargenumber
867
SQL
868

  
869
  my @values = ($part->id,
870
                $params{warehouse_id},
871
                $params{bin_id},
872
                $params{chargenumber});
873
  push @values, $params{bestbefore} if $bestbefore_val_cnt;
874

  
875
  my ($stocked_qty) = selectrow_query($::form, $::form->get_standard_dbh, $query, @values);
876

  
877
  return 1*($stocked_qty || 0);
878
}
879

  
880
sub _already_counted {
881
  my ($part, %params) = @_;
882

  
883
  my %bestbefore_filter;
884
  if ($::instance_conf->get_show_bestbefore) {
885
    %bestbefore_filter = (bestbefore => $params{bestbefore});
886
  }
887

  
888
  SL::DB::Manager::Stocktaking->get_all(query => [and => [parts_id     => $part->id,
889
                                                          warehouse_id => $params{warehouse_id},
890
                                                          bin_id       => $params{bin_id},
891
                                                          cutoff_date  => $params{cutoff_date},
892
                                                          chargenumber => $params{chargenumber},
893
                                                          %bestbefore_filter]],
894
                                        sort_by => ['itime DESC']);
895
}
896

  
622 897
sub setup_stock_in_action_bar {
623 898
  my ($self, %params) = @_;
624 899

  
......
648 923
  }
649 924
}
650 925

  
926
sub setup_stock_stocktaking_action_bar {
927
  my ($self, %params) = @_;
928

  
929
  for my $bar ($::request->layout->get('actionbar')) {
930
    $bar->add(
931
      action => [
932
        t8('Save'),
933
        call      => [ 'kivi.Inventory.save_stocktaking' ],
934
        accesskey => 'enter',
935
      ],
936
    );
937
  }
938
}
939

  
651 940
1;
652 941
__END__
653 942

  
......
655 944

  
656 945
=head1 NAME
657 946

  
658
SL::Controller::Inventory - Report Controller for inventory
947
SL::Controller::Inventory - Controller for inventory
659 948

  
660 949
=head1 DESCRIPTION
661 950

  
662
This controller makes three reports about inventory in warehouses/stocks
951
This controller handles stock in, stocktaking and reports about inventory
952
in warehouses/stocks
663 953

  
664 954
- warehouse content
665 955

  
......
667 957

  
668 958
- warehouse withdrawal
669 959

  
960
- stocktaking
961

  
962
=head2 Stocktaking
963

  
964
Stocktaking allows to document the counted quantities of parts during
965
stocktaking for a certain cutoff date. Differences between counted and stocked
966
quantities are corrected in the stock. The transfer type 'stocktacking' is set
967
here.
968

  
969
After picking a part, the mini stock for this part is displayed. At the bottom
970
of the form a history of already counted parts for the current employee and the
971
choosen cutoff date is shown.
972

  
973
Warehouse, bin and cutoff date canbe preselected in the client configuration.
974

  
975
If a part was already counted for this cutoff date, warehouse and bin, a warning
976
is displayed, allowing the user to choose to add the counted quantity to the
977
stocked one or to take his counted quantity as the new stocked quantity.
978

  
979
There is also a journal of stocktakings.
980

  
981
Templates are located under C<templates/webpages/inventory/stocktaking>.
982
JavaScript functions can be found in C<js/kivi.Inventory.js>.
983

  
670 984
=head1 FUNCTIONS
671 985

  
672 986
=over 4
......
682 996

  
683 997
The manual pagination is implemented like the pagination in SL::Controller::CsvImport.
684 998

  
999
=item C<action_stocktaking>
1000

  
1001
This action renders the input form for stocktaking.
1002

  
1003
=item C<action_save_stocktaking>
1004

  
1005
This action saves the stocktaking values and corrects the stock after checking
1006
if the part is already counted for this warehouse, bin and cutoff date.
1007
For saving SL::WH->transfer is called.
1008

  
1009
=item C<action_reload_stocktaking_history>
1010

  
1011
This action is responsible for displaying the stocktaking history at the bottom
1012
of the form. It uses the stocktaking journal with fixed filters for cutoff date
1013
and the current employee. The history is displayed via javascript.
1014

  
1015
=item C<action_stocktaking_part_changed>
1016

  
1017
This action is called after the user selected or changed the part.
1018

  
1019
=item C<is_stocktaking>
1020

  
1021
This is a method to check if actions are called from stocktaking form.
1022

  
685 1023
=back
686 1024

  
687 1025
=head1 SPECIAL CASES
......
698 1036

  
699 1037
=head1 AUTHOR
700 1038

  
701
only for C<action_stock_usage> and C<action_usage>:
1039
=over 4
1040

  
1041
=item only for C<action_stock_usage> and C<action_usage>:
702 1042

  
703 1043
Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
704 1044

  
1045
=item for stocktaking:
1046

  
1047
Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
1048

  
1049
=back
705 1050

  
706 1051
=cut
SL/DB/Manager/Stocktaking.pm
1
# This file has been auto-generated only because it didn't exist.
2
# Feel free to modify it at will; it will not be overwritten automatically.
3

  
4 1
package SL::DB::Manager::Stocktaking;
5 2

  
6 3
use strict;
7 4

  
8 5
use parent qw(SL::DB::Helper::Manager);
9 6

  
7
use SL::DB::Helper::Filtered;
8
use SL::DB::Helper::Paginated;
9
use SL::DB::Helper::Sorted;
10

  
10 11
sub object_class { 'SL::DB::Stocktaking' }
11 12

  
12 13
__PACKAGE__->make_manager_methods;
13 14

  
15
sub _sort_spec {
16
  return (
17
    default        => [ 'itime', 1 ],
18
    columns        => {
19
      SIMPLE       => 'ALL',
20
      comment      => 'lower(comment)',
21
      chargenumber => 'lower(chargenumber)',
22
      employee     => 'lower(employee.name)',
23
      ean          => 'lower(parts.ean)',
24
      partnumber   => 'lower(parts.partnumber)',
25
      part         => 'lower(parts.description)',
26
      bin          => ['lower(warehouse.description)', 'lower(bin.description)'],
27
    });
28
}
29

  
30
sub default_objects_per_page {
31
  20;
32
}
33

  
14 34
1;
SL/DB/Stocktaking.pm
10 10

  
11 11
__PACKAGE__->meta->initialize;
12 12

  
13
# part accessor is badly named
14
sub part {
15
  goto &parts;
16
}
17

  
13 18
1;
js/kivi.Inventory.js
1
namespace('kivi.Inventory', function(ns) {
2
  ns.reload_bin_selection = function() {
3
    $.post("controller.pl", { action: 'Inventory/warehouse_changed',
4
                              warehouse_id: function(){ return $('#warehouse_id').val() } },
5
           kivi.eval_json_result);
6
  };
7

  
8
  ns.save_stocktaking = function(dont_check_already_counted) {
9
    var data = $('#stocktaking_form').serializeArray();
10
    data.push({ name: 'action', value: 'Inventory/save_stocktaking' });
11
    data.push({ name: 'dont_check_already_counted', value: dont_check_already_counted });
12

  
13
    $.post("controller.pl", data, kivi.eval_json_result);
14
  };
15

  
16
  ns.stocktaking_part_changed = function() {
17
    var data = $('#stocktaking_form').serializeArray();
18
    data.push({ name: 'action', value: 'Inventory/stocktaking_part_changed' });
19
    $.post("controller.pl", data, kivi.eval_json_result);
20
    $.post("controller.pl", { action: 'Inventory/mini_stock',
21
                              part_id: function(){ return $('#part_id').val() } },
22
           kivi.eval_json_result);
23
  };
24

  
25
  ns.reload_stocktaking_history = function(target, source) {
26
    var data = $('#stocktaking_form').serializeArray();
27
    $.ajax({
28
      url:        source,
29
      data:       data,
30
      success:    function (rsp) {
31
        $(target).html(rsp);
32
        $(target).find('a.paginate-link').click(function(event){
33
          event.preventDefault();
34
          kivi.Inventory.reload_stocktaking_history(target, event.target + '')});
35
      }
36
    });
37
  };
38

  
39
  ns.stocktaking_correct_counted = function() {
40
    kivi.Inventory.close_already_counted_dialog();
41
    kivi.Inventory.save_stocktaking(1);
42
  };
43

  
44
  ns.stocktaking_add_counted = function(qty_to_add_to) {
45
    resulting_qty = kivi.parse_amount($('#target_qty').val()) + 1.0*qty_to_add_to;
46
    $('#target_qty').val(kivi.format_amount(resulting_qty, -2));
47
    kivi.Inventory.close_already_counted_dialog();
48
    kivi.Inventory.save_stocktaking(1);
49
  };
50

  
51
  ns.close_already_counted_dialog = function() {
52
    $('#already_counted_dialog').dialog("close");
53
  };
54

  
55
});
56

  
57
$(function(){
58
  $('#part_id').change(kivi.Inventory.stocktaking_part_changed);
59
  $('#warehouse_id').change(kivi.Inventory.reload_bin_selection);
60
  $('#cutoff_date_as_date').change(function() {kivi.Inventory.reload_stocktaking_history('#stocktaking_history', 'controller.pl?action=Inventory/reload_stocktaking_history');});
61

  
62
  kivi.Inventory.reload_stocktaking_history('#stocktaking_history', 'controller.pl?action=Inventory/reload_stocktaking_history');
63
});
menus/user/00-erp.yaml
543 543
  params:
544 544
    action: transfer_warehouse_selection
545 545
    trans_type: removal
546
- parent: warehouse
547
  id: warehouse_stocktaking
548
  name: Stocktaking
549
  order: 450
550
  access: warehouse_management
551
  params:
552
    action: Inventory/stocktaking
546 553
- parent: warehouse
547 554
  id: warehouse_reports
548 555
  name: Reports
......
571 578
  access: warehouse_contents | warehouse_management
572 579
  params:
573 580
    action: Inventory/stock_usage
581
- parent: warehouse_reports
582
  id: warehouse_stocktaking_journal
583
  name: Stocktaking Journal
584
  order: 400
585
  access: warehouse_contents | warehouse_management
586
  params:
587
    action: Inventory/stocktaking_journal
574 588
- id: general_ledger
575 589
  name: General Ledger
576 590
  icon: gl
templates/webpages/inventory/stocktaking/_already_counted_dialog.html
1
[%- USE T8 %][%- USE HTML %][%- USE L %][%- USE LxERP %]
2

  
3
<form method="post" id="already_counted_form" method="POST">
4

  
5
  [% 'This part was already counted for this bin:' | $T8 %]<br>
6
  [% SELF.part.displayable_name %] / [% SELF.part.ean %]<br>
7
  [% already_counted.first.bin.full_description %], [% 'Stocked Qty' | $T8 %]: [%- LxERP.format_amount(stocked_qty, -2) -%]&nbsp;[%- SELF.part.unit -%]
8
  [%- IF SELF.part.unit != SELF.unit.name -%]
9
    ([%- LxERP.format_amount(stocked_qty_in_form_units, -2) -%]&nbsp;[%- SELF.unit.name -%])<br>
10
  [%- END -%]
11
  <br>
12
  <br>
13
  <table>
14
    <tr class='listheading'>
15
      <th>[% 'Insert Date' | $T8 %]</th>
16
      <th>[% 'Employee' | $T8 %]</th>
17
      <th>[% 'Bin' | $T8 %]</th>
18
      <th>[% 'Target Qty' | $T8 %]</th>
19
    </tr>
20
    [% FOREACH ac = already_counted %]
21
    <tr class='listrow'>
22
      <td>[%- ac.itime_as_timestamp -%]</td>
23
      <td>[%- ac.employee.safe_name -%]</td>
24
      <td>[%- ac.bin.full_description -%]</td>
25
      <td class="numeric">[%- ac.qty_as_number -%]&nbsp;[%- ac.part.unit -%]</td>
26
    </tr>
27
    [% END %]
28
  </table>
29

  
30
  <p>
31
    [% 'Please choose the action to be processed for your target quantity:' | $T8 %]<br>
32
    [% 'Correct counted' | $T8 %]: [% 'The stock will be changed to your target quantity.' | $T8 %]<br>
33
    [% 'Add counted' | $T8 %]: [% 'Your target quantity will be added to the stocked quantity.' | $T8 %]<br>
34
  </p>
35

  
36
  <br>
37
  [% L.hidden_tag('action', 'Inventory/dispatch') %]
38
  [% L.button_tag('kivi.Inventory.stocktaking_correct_counted()', LxERP.t8("Correct counted")) %]
39
  [% L.button_tag('kivi.Inventory.stocktaking_add_counted(' _ stocked_qty_in_form_units _ ')', LxERP.t8("Add counted")) %]
40
  <a href="#" onclick="kivi.Inventory.close_already_counted_dialog();">[%- LxERP.t8("Cancel") %]</a>
41

  
42
</form>
templates/webpages/inventory/stocktaking/_filter.html
1
[%- USE T8 %]
2
[%- USE HTML %]
3
[%- USE L %]
4
[%- USE LxERP %]
5

  
6
<table id="filter_table">
7
 <tr>
8
  <th align="right">[% 'Cutoff Date' | $T8 %]</th>
9
  <td>[% L.date_tag('filter.cutoff_date:date', filter.cutoff_date_date) %]</td>
10
 </tr>
11
 <tr>
12
  <th align="right">[% 'Comment' | $T8 %]</th>
13
  <td>[% L.input_tag('filter.comment:substr::ilike', filter.comment_substr__ilike, size=60) %]</td>
14
 </tr>
15
</table>
templates/webpages/inventory/stocktaking/form.html
1
[%- USE T8 %]
2
[%- USE L %]
3
[%- USE P %]
4
[%- USE HTML %]
5
[%- USE LxERP %]
6

  
7
<h1>[% title | html %]</h1>
8

  
9
[%- INCLUDE 'common/flash.html' %]
10

  
11
<form method="post" action="controller.pl" id="stocktaking_form">
12

  
13
 <p>
14
  <label for="part_id">[% "Article" | $T8 %]</label>
15
  [% P.part.picker("part_id", "") %]
16
 </p>
17

  
18
 <p>
19
   <div id="stock"></div>
20
 </p>
21

  
22
 <table id="stocktaking_settings_table">
23
   <tr>
24
     <th align="right" nowrap>[% 'Destination warehouse' | $T8 %]</th>
25
     <td>[% L.select_tag('warehouse_id', SELF.warehouses, default=SELF.warehouse.id, title_key='description') %]
26
       [% IF SELF.warehouse.id %]
27
         [% L.select_tag('bin_id', SELF.warehouse.bins, default=SELF.bin.id, title_key='description') %]
28
       [%- ELSE %]
29
         <span id='bin_id'></span>
30
       [% END %]
31
     </td>
32
   </tr>
33

  
34
   <tr>
35
     <th align="right" nowrap>[% 'Charge number' | $T8 %]</th>
36
     <td>[% L.input_tag('chargenumber', "", size=30) %]</td>
37
   </tr>
38

  
39
   [% IF INSTANCE_CONF.get_show_bestbefore %]
40
     <tr>
41
       <th align="right" nowrap>[% 'Best Before' | $T8 %]</th>
42
       <td>[% L.date_tag('bestbefore', "") %]</td>
43
     </tr>
44
   [%- END %]
45

  
46
   <tr>
47
     <th align="right" nowrap>[% 'Target Qty' | $T8 %]</th>
48
     <td>
49
       [% L.input_tag('target_qty', '', size=10, class='numeric') %]
50
       [%- IF SELF.part.unit %]
51
         [% L.select_tag('unit_id', SELF.part.available_units, title_key='name', default=SELF.unit.id) %]
52
       [%- ELSE %]
53
         [% L.select_tag('unit_id', SELF.units, title_key='name') %]
54
       [%- END %]
55
     </td>
56
   </tr>
57

  
58
   <tr>
59
     <th align="right" nowrap>[% 'Cutoff Date' | $T8 %]</th>
60
     <td>
61
       [% L.date_tag('cutoff_date_as_date', SELF.stocktaking_cutoff_date) %]
62
     </td>
63
   </tr>
64

  
65
   <tr>
66
     <th align="right" nowrap>[% 'Optional comment' | $T8 %]</th>
67
     <td>
68
       [% L.input_tag('comment', SELF.stocktaking_comment, size=40) %]
69
     </td>
70
   </tr>
71
 </table>
72

  
73
</form>
74

  
75
<p>
76
  <div id="stocktaking_history">
77
    [%- LxERP.t8("Loading...") %]
78
  </div>
79
</p>
templates/webpages/inventory/stocktaking/full_report_top.html
1
[%- USE L %]
2
[%- USE T8 %]
3
[%- USE LxERP %]
4
[%- USE HTML %]
5
<form action='controller.pl' method='post'>
6
<div class='filter_toggle'>
7
<a href='#' onClick='javascript:$(".filter_toggle").toggle()'>[% 'Show Filter' | $T8 %]</a>
8
  [% SELF.filter_summary | html %]
9
</div>
10
<div class='filter_toggle' style='display:none'>
11
<a href='#' onClick='javascript:$(".filter_toggle").toggle()'>[% 'Hide Filter' | $T8 %]</a>
12
[%- PROCESS 'inventory/stocktaking/_filter.html' filter=SELF.stocktaking_models.filtered.laundered %]
13

  
14
[% L.hidden_tag('action', 'Inventory/dispatch') %]
15
[% L.hidden_tag('sort_by', FORM.sort_by) %]
16
[% L.hidden_tag('sort_dir', FORM.sort_dir) %]
17
[% L.hidden_tag('page', FORM.page) %]
18
[% L.input_tag('action_stocktaking_journal', LxERP.t8('Continue'), type = 'submit', class='submit')%]
19

  
20

  
21
<a href='#' onClick='javascript:$("#filter_table input").val("");$("#filter_table input[type=checkbox]").prop("checked", 0);'>[% 'Reset' | $T8 %]</a>
22

  
23
</div>
24

  
25
</form>
26
 <hr>
templates/webpages/inventory/stocktaking/report_bottom.html
1
[% USE L %]
2
[%- L.paginate_controls(models=SELF.stocktaking_models) %]

Auch abrufbar als: Unified diff