1 package SL::Presenter::Record;
 
   6 use SL::Presenter::EscapedText qw(escape is_escaped);
 
   8 use Exporter qw(import);
 
   9 our @EXPORT_OK = qw(grouped_record_list empty_record_list record_list record);
 
  14 use List::Util qw(first);
 
  18   return []     if !defined $array;
 
  19   return $array if ref $array;
 
  24   my ($record, %params) = @_;
 
  26   my %grouped = _group_records( [ $record ] ); # pass $record as arrayref
 
  27   my $type    = (keys %grouped)[0];
 
  29   $record->presenter->sales_invoice(   $record, %params) if $type eq 'sales_invoices';
 
  30   $record->presenter->purchase_invoice($record, %params) if $type eq 'purchase_invoices';
 
  31   $record->presenter->ar_transaction(  $record, %params) if $type eq 'ar_transactions';
 
  32   $record->presenter->ap_transaction(  $record, %params) if $type eq 'ap_transactions';
 
  33   $record->presenter->gl_transaction(  $record, %params) if $type eq 'gl_transactions';
 
  38 sub grouped_record_list {
 
  39   my ($list, %params) = @_;
 
  41   %params    = map { exists $params{$_} ? ($_ => $params{$_}) : () } qw(edit_record_links with_columns object_id object_model);
 
  43   my %groups = _sort_grouped_lists(_group_records($list));
 
  46   $output .= _requirement_spec_list(       $groups{requirement_specs},        %params) if $groups{requirement_specs};
 
  47   $output .= _shop_order_list(             $groups{shop_orders},              %params) if $groups{shop_orders};
 
  48   $output .= _sales_quotation_list(        $groups{sales_quotations},         %params) if $groups{sales_quotations};
 
  49   $output .= _sales_order_list(            $groups{sales_orders},             %params) if $groups{sales_orders};
 
  50   $output .= _sales_delivery_order_list(   $groups{sales_delivery_orders},    %params) if $groups{sales_delivery_orders};
 
  51   $output .= _rma_delivery_order_list(     $groups{rma_delivery_orders},      %params) if $groups{rma_delivery_orders};
 
  52   $output .= _sales_invoice_list(          $groups{sales_invoices},           %params) if $groups{sales_invoices};
 
  53   $output .= _ar_transaction_list(         $groups{ar_transactions},          %params) if $groups{ar_transactions};
 
  55   $output .= _request_quotation_list(      $groups{purchase_quotations},      %params) if $groups{purchase_quotations};
 
  56   $output .= _purchase_order_list(         $groups{purchase_orders},          %params) if $groups{purchase_orders};
 
  57   $output .= _purchase_delivery_order_list($groups{purchase_delivery_orders}, %params) if $groups{purchase_delivery_orders};
 
  58   $output .= _supplier_delivery_order_list($groups{supplier_delivery_orders}, %params) if $groups{supplier_delivery_orders};
 
  59   $output .= _purchase_invoice_list(       $groups{purchase_invoices},        %params) if $groups{purchase_invoices};
 
  60   $output .= _ap_transaction_list(         $groups{ap_transactions},          %params) if $groups{ap_transactions};
 
  62   $output .= _gl_transaction_list(         $groups{gl_transactions},          %params) if $groups{gl_transactions};
 
  64   $output .= _bank_transactions(           $groups{bank_transactions},        %params) if $groups{bank_transactions};
 
  66   $output .= _sepa_collection_list(        $groups{sepa_collections},         %params) if $groups{sepa_collections};
 
  67   $output .= _sepa_transfer_list(          $groups{sepa_transfers},           %params) if $groups{sepa_transfers};
 
  69   $output .= _letter_list(                 $groups{letters},                  %params) if $groups{letters};
 
  70   $output .= _email_journal_list(          $groups{email_journals},           %params) if $groups{email_journals};
 
  72   $output .= _dunning_list(                $groups{dunnings},                 %params) if $groups{dunnings};
 
  74   $output  = SL::Presenter->get->render('presenter/record/grouped_record_list', %params, output => $output);
 
  79 sub grouped_list { goto &grouped_record_list }
 
  81 sub empty_record_list {
 
  83   return grouped_record_list([], %params);
 
  86 sub empty_list { goto &empty_record_list }
 
  89   my ($list, %params) = @_;
 
  93   if (ref($params{columns}) eq 'ARRAY') {
 
  95       if (ref($_) eq 'ARRAY') {
 
  96         { title => $_->[0], data => $_->[1], link => $_->[2] }
 
 100     } @{ delete $params{columns} };
 
 103     croak "Wrong type for 'columns' argument: not an array reference";
 
 106   my %with_columns = map { ($_ => 1) } @{ _arrayify($params{with_columns}) };
 
 107   if ($with_columns{record_link_direction}) {
 
 109       title => $::locale->text('Link direction'),
 
 111           $_[0]->{_record_link_depth} > 1
 
 112         ? $::locale->text('Row was linked to another record')
 
 113         : $_[0]->{_record_link_direction} eq 'from'
 
 114         ? $::locale->text('Row was source for current record')
 
 115         : $::locale->text('Row was created from current record') },
 
 119   my %column_meta   = map { $_->name => $_ } @{ $list->[0]->meta->columns       };
 
 120   my %relationships = map { $_->name => $_ } @{ $list->[0]->meta->relationships };
 
 123     my ($obj, $method, @args) = @_;
 
 124     $obj->$method(@args);
 
 128   foreach my $obj (@{ $list }) {
 
 131     foreach my $spec (@columns) {
 
 134       my $method       =  $spec->{column} || $spec->{data};
 
 135       my $meta         =  $column_meta{ $spec->{data} };
 
 136       my $type         =  ref $meta;
 
 137       my $relationship =  $relationships{ $spec->{data} };
 
 138       my $rel_type     =  !$relationship ? '' : $relationship->class;
 
 139       $rel_type        =~ s/^SL::DB:://;
 
 140       $rel_type        =  SL::Util::snakify($rel_type);
 
 142       if (ref($spec->{data}) eq 'CODE') {
 
 143         $cell{value} = $spec->{data}->($obj);
 
 146         $cell{value} = ref $obj->$method && $obj->$method->isa('SL::DB::Object') && $obj->$method->presenter->can($rel_type) ? $obj->$method->presenter->$rel_type(display => 'table-cell')
 
 147                      : $type eq 'Rose::DB::Object::Metadata::Column::Date'                      ? $call->($obj, $method . '_as_date')
 
 148                      : $type =~ m/^Rose::DB::Object::Metadata::Column::(?:Float|Numeric|Real)$/ ? $::form->format_amount(\%::myconfig, $call->($obj, $method), 2)
 
 149                      : $type eq 'Rose::DB::Object::Metadata::Column::Boolean'                   ? $call->($obj, $method . '_as_bool_yn')
 
 150                      : $type =~ m/^Rose::DB::Object::Metadata::Column::(?:Integer|Serial)$/     ? $spec->{data} * 1
 
 151                      :                                                                            $call->($obj, $method);
 
 154       $cell{alignment} = 'right' if $type =~ m/int|serial|float|real|numeric/;
 
 159     push @data, { columns => \@row, record_link => $obj->{_record_link} };
 
 163     map +{ value     => $columns[$_]->{title},
 
 164            alignment => $data[0]->{columns}->[$_]->{alignment},
 
 165          }, (0..scalar(@columns) - 1);
 
 167   return SL::Presenter->get->render(
 
 168     'presenter/record/record_list',
 
 170     TABLE_HEADER => \@header,
 
 171     TABLE_ROWS   => \@data,
 
 175 sub list { goto &record_list }
 
 184     requirement_specs        => sub { (ref($_[0]) eq 'SL::DB::RequirementSpec')                                         },
 
 185     shop_orders              => sub { (ref($_[0]) eq 'SL::DB::ShopOrder')       &&  $_[0]->id                           },
 
 186     sales_quotations         => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('sales_quotation')   },
 
 187     sales_orders             => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('sales_order')       },
 
 188     sales_delivery_orders    => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('sales_delivery_order') },
 
 189     rma_delivery_orders      => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('rma_delivery_order')   },
 
 190     sales_invoices           => sub { (ref($_[0]) eq 'SL::DB::Invoice')         &&  $_[0]->invoice                      },
 
 191     ar_transactions          => sub { (ref($_[0]) eq 'SL::DB::Invoice')         && !$_[0]->invoice                      },
 
 192     purchase_quotations      => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('request_quotation') },
 
 193     purchase_orders          => sub { (ref($_[0]) eq 'SL::DB::Order')           &&  $_[0]->is_type('purchase_order')    },
 
 194     purchase_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('purchase_delivery_order') },
 
 195     supplier_delivery_orders => sub { (ref($_[0]) eq 'SL::DB::DeliveryOrder')   &&  $_[0]->is_type('supplier_delivery_order') },
 
 196     purchase_invoices        => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') &&  $_[0]->invoice                      },
 
 197     ap_transactions          => sub { (ref($_[0]) eq 'SL::DB::PurchaseInvoice') && !$_[0]->invoice                      },
 
 198     sepa_collections         => sub { (ref($_[0]) eq 'SL::DB::SepaExportItem')  &&  $_[0]->ar_id                        },
 
 199     sepa_transfers           => sub { (ref($_[0]) eq 'SL::DB::SepaExportItem')  &&  $_[0]->ap_id                        },
 
 200     gl_transactions          => sub { (ref($_[0]) eq 'SL::DB::GLTransaction')                                           },
 
 201     bank_transactions        => sub { (ref($_[0]) eq 'SL::DB::BankTransaction') &&  $_[0]->id                           },
 
 202     letters                  => sub { (ref($_[0]) eq 'SL::DB::Letter')          &&  $_[0]->id                           },
 
 203     email_journals           => sub { (ref($_[0]) eq 'SL::DB::EmailJournal')    &&  $_[0]->id                           },
 
 204     dunnings                 => sub { (ref($_[0]) eq 'SL::DB::Dunning')                                                 },
 
 209   foreach my $record (@{ $list || [] }) {
 
 210     my $type         = (first { $matchers{$_}->($record) } keys %matchers) || 'other';
 
 211     $groups{$type} ||= [];
 
 212     push @{ $groups{$type} }, $record;
 
 218 sub _sort_grouped_lists {
 
 221   foreach my $group (keys %groups) {
 
 222     next unless @{ $groups{$group} };
 
 223     if ($groups{$group}->[0]->can('compare_to')) {
 
 224       $groups{$group} = [ sort { $a->compare_to($b)    } @{ $groups{$group} } ];
 
 226       $groups{$group} = [ sort { $a->date <=> $b->date } @{ $groups{$group} } ];
 
 233 sub _requirement_spec_list {
 
 234   my ($list, %params) = @_;
 
 238     title   => $::locale->text('Requirement specs'),
 
 239     type    => 'requirement_spec',
 
 241       [ $::locale->text('Requirement spec number'), sub { $_[0]->presenter->requirement_spec(display => 'table-cell') } ],
 
 242       [ $::locale->text('Customer'),                'customer'                                                      ],
 
 243       [ $::locale->text('Title'),                   'title'                                                         ],
 
 244       [ $::locale->text('Project'),                 'project',                                                      ],
 
 245       [ $::locale->text('Status'),                  sub { $_[0]->status->description }                              ],
 
 251 sub _shop_order_list {
 
 252   my ($list, %params) = @_;
 
 256     title   => $::locale->text('Shop Orders'),
 
 257     type    => 'shop_order',
 
 259       [ $::locale->text('Shop Order Date'),         sub { $_[0]->order_date->to_kivitendo }                         ],
 
 260       [ $::locale->text('Shop Order Number'),       sub { $_[0]->presenter->shop_order(display => 'table-cell') }   ],
 
 261       [ $::locale->text('Transfer Date'),           'transfer_date'                                                 ],
 
 262       [ $::locale->text('Amount'),                  'amount'                                                        ],
 
 268 sub _sales_quotation_list {
 
 269   my ($list, %params) = @_;
 
 273     title   => $::locale->text('Sales Quotations'),
 
 274     type    => 'sales_quotation',
 
 276       [ $::locale->text('Quotation Date'),          'transdate'                                                                ],
 
 277       [ $::locale->text('Quotation Number'),        sub { $_[0]->presenter->sales_quotation(display => 'table-cell') }         ],
 
 278       [ $::locale->text('Customer'),                'customer'                                                                 ],
 
 279       [ $::locale->text('Net amount'),              'netamount'                                                                ],
 
 280       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 281       [ $::locale->text('Project'),                 'globalproject', ],
 
 282       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 288 sub _request_quotation_list {
 
 289   my ($list, %params) = @_;
 
 293     title   => $::locale->text('Request Quotations'),
 
 294     type    => 'request_quotation',
 
 296       [ $::locale->text('Quotation Date'),          'transdate'                                                                ],
 
 297       [ $::locale->text('Quotation Number'),        sub { $_[0]->presenter->request_quotation(display => 'table-cell') }       ],
 
 298       [ $::locale->text('Vendor'),                  'vendor'                                                                   ],
 
 299       [ $::locale->text('Net amount'),              'netamount'                                                                ],
 
 300       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 301       [ $::locale->text('Project'),                 'globalproject', ],
 
 302       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 308 sub _sales_order_list {
 
 309   my ($list, %params) = @_;
 
 313     title   => $::locale->text('Sales Orders'),
 
 314     type    => 'sales_order',
 
 316       [ $::locale->text('Order Date'),              'transdate'                                                                ],
 
 317       [ $::locale->text('Order Number'),            sub { $_[0]->presenter->sales_order(display => 'table-cell') }             ],
 
 318       [ $::locale->text('Quotation'),               'quonumber' ],
 
 319       [ $::locale->text('Customer'),                'customer'                                                                 ],
 
 320       [ $::locale->text('Net amount'),              'netamount'                                                                ],
 
 321       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 322       [ $::locale->text('Project'),                 'globalproject', ],
 
 323       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 329 sub _purchase_order_list {
 
 330   my ($list, %params) = @_;
 
 334     title   => $::locale->text('Purchase Orders'),
 
 335     type    => 'purchase_order',
 
 337       [ $::locale->text('Order Date'),              'transdate'                                                                ],
 
 338       [ $::locale->text('Order Number'),            sub { $_[0]->presenter->purchase_order(display => 'table-cell') }          ],
 
 339       [ $::locale->text('Request for Quotation'),   'quonumber' ],
 
 340       [ $::locale->text('Vendor'),                  'vendor'                                                                 ],
 
 341       [ $::locale->text('Net amount'),              'netamount'                                                                ],
 
 342       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 343       [ $::locale->text('Project'),                 'globalproject', ],
 
 344       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 350 sub _sales_delivery_order_list {
 
 351   my ($list, %params) = @_;
 
 355     title   => $::locale->text('Sales Delivery Orders'),
 
 356     type    => 'sales_delivery_order',
 
 358       [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
 
 359       [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->sales_delivery_order(display => 'table-cell') }    ],
 
 360       [ $::locale->text('Order Number'),            'ordnumber' ],
 
 361       [ $::locale->text('Customer'),                'customer'                                                                 ],
 
 362       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 363       [ $::locale->text('Project'),                 'globalproject', ],
 
 364       [ $::locale->text('Delivered'),               'delivered'                                                                ],
 
 365       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 371 sub _rma_delivery_order_list {
 
 372   my ($list, %params) = @_;
 
 376     title   => $::locale->text('RMA Delivery Orders'),
 
 377     type    => 'rma_delivery_order',
 
 379       [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
 
 380       [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->rma_delivery_order(display => 'table-cell') }    ],
 
 381       [ $::locale->text('Order Number'),            'ordnumber' ],
 
 382       [ $::locale->text('Customer'),                'customer'                                                                 ],
 
 383       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 384       [ $::locale->text('Project'),                 'globalproject', ],
 
 385       [ $::locale->text('Delivered'),               'delivered'                                                                ],
 
 386       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 392 sub _purchase_delivery_order_list {
 
 393   my ($list, %params) = @_;
 
 397     title   => $::locale->text('Purchase Delivery Orders'),
 
 398     type    => 'purchase_delivery_order',
 
 400       [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
 
 401       [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->purchase_delivery_order(display => 'table-cell') } ],
 
 402       [ $::locale->text('Order Number'),            'ordnumber' ],
 
 403       [ $::locale->text('Vendor'),                  'vendor'                                                                 ],
 
 404       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 405       [ $::locale->text('Project'),                 'globalproject', ],
 
 406       [ $::locale->text('Delivered'),               'delivered'                                                                ],
 
 407       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 413 sub _supplier_delivery_order_list {
 
 414   my ($list, %params) = @_;
 
 418     title   => $::locale->text('Supplier Delivery Orders'),
 
 419     type    => 'supplier_delivery_order',
 
 421       [ $::locale->text('Delivery Order Date'),     'transdate'                                                                ],
 
 422       [ $::locale->text('Delivery Order Number'),   sub { $_[0]->presenter->supplier_delivery_order(display => 'table-cell') } ],
 
 423       [ $::locale->text('Order Number'),            'ordnumber' ],
 
 424       [ $::locale->text('Vendor'),                  'vendor'                                                                 ],
 
 425       [ $::locale->text('Transaction description'), 'transaction_description'                                                  ],
 
 426       [ $::locale->text('Project'),                 'globalproject', ],
 
 427       [ $::locale->text('Delivered'),               'delivered'                                                                ],
 
 428       [ $::locale->text('Closed'),                  'closed'                                                                   ],
 
 434 sub _sales_invoice_list {
 
 435   my ($list, %params) = @_;
 
 439     title   => $::locale->text('Sales Invoices'),
 
 440     type    => 'sales_invoice',
 
 442       [ $::locale->text('Invoice Date'),            'transdate'               ],
 
 443       [ $::locale->text('Type'),                    sub { $_[0]->displayable_type } ],
 
 444       [ $::locale->text('Invoice Number'),          sub { $_[0]->presenter->sales_invoice(display => 'table-cell') } ],
 
 445       [ $::locale->text('Quotation Number'),        'quonumber' ],
 
 446       [ $::locale->text('Order Number'),            'ordnumber' ],
 
 447       [ $::locale->text('Customer'),                'customer'                ],
 
 448       [ $::locale->text('Net amount'),              'netamount'               ],
 
 449       [ $::locale->text('Paid'),                    'paid'                    ],
 
 450       [ $::locale->text('Transaction description'), 'transaction_description' ],
 
 456 sub _purchase_invoice_list {
 
 457   my ($list, %params) = @_;
 
 461     title   => $::locale->text('Purchase Invoices'),
 
 462     type    => 'purchase_invoice',
 
 464       [ $::locale->text('Invoice Date'),                 'transdate'               ],
 
 465       [ $::locale->text('Invoice Number'),               sub { $_[0]->presenter->purchase_invoice(display => 'table-cell') } ],
 
 466       [ $::locale->text('Request for Quotation Number'), 'quonumber' ],
 
 467       [ $::locale->text('Order Number'),                 'ordnumber' ],
 
 468       [ $::locale->text('Vendor'),                       'vendor'                 ],
 
 469       [ $::locale->text('Net amount'),                   'netamount'               ],
 
 470       [ $::locale->text('Paid'),                         'paid'                    ],
 
 471       [ $::locale->text('Transaction description'),      'transaction_description' ],
 
 477 sub _ar_transaction_list {
 
 478   my ($list, %params) = @_;
 
 482     title   => $::locale->text('AR Transactions'),
 
 483     type    => 'ar_transaction',
 
 485       [ $::locale->text('Invoice Date'),            'transdate'               ],
 
 486       [ $::locale->text('Type'),                    sub { $_[0]->displayable_type } ],
 
 487       [ $::locale->text('Invoice Number'),          sub { $_[0]->presenter->ar_transaction(display => 'table-cell') } ],
 
 488       [ $::locale->text('Customer'),                'customer'                ],
 
 489       [ $::locale->text('Net amount'),              'netamount'               ],
 
 490       [ $::locale->text('Paid'),                    'paid'                    ],
 
 491       [ $::locale->text('Transaction description'), 'transaction_description' ],
 
 497 sub _ap_transaction_list {
 
 498   my ($list, %params) = @_;
 
 502     title   => $::locale->text('AP Transactions'),
 
 503     type    => 'ap_transaction',
 
 505       [ $::locale->text('Invoice Date'),            'transdate'                      ],
 
 506       [ $::locale->text('Invoice Number'),          sub { $_[0]->presenter->ap_transaction(display => 'table-cell') } ],
 
 507       [ $::locale->text('Vendor'),                  'vendor'                         ],
 
 508       [ $::locale->text('Net amount'),              'netamount'                      ],
 
 509       [ $::locale->text('Paid'),                    'paid'                           ],
 
 510       [ $::locale->text('Transaction description'), 'transaction_description'        ],
 
 516 sub _gl_transaction_list {
 
 517   my ($list, %params) = @_;
 
 521     title   => $::locale->text('GL Transactions'),
 
 522     type    => 'gl_transaction',
 
 524       [ $::locale->text('Transdate'),        'transdate'                                                    ],
 
 525       [ $::locale->text('Reference'),   'reference'                                                    ],
 
 526       [ $::locale->text('Description'), sub { $_[0]->presenter->gl_transaction(display => 'table-cell') } ],
 
 532 sub _bank_transactions {
 
 533   my ($list, %params) = @_;
 
 537     title   => $::locale->text('Bank transactions'),
 
 538     type    => 'bank_transactions',
 
 540       [ $::locale->text('Transdate'),            'transdate'                      ],
 
 541       [ $::locale->text('Local Bank Code'),      sub { $_[0]->local_bank_account->presenter->bank_code }  ],
 
 542       [ $::locale->text('Local account number'), sub { $_[0]->local_bank_account->presenter->account_number }  ],
 
 543       [ $::locale->text('Remote Bank Code'),     'remote_bank_code' ],
 
 544       [ $::locale->text('Remote account number'),'remote_account_number' ],
 
 545       [ $::locale->text('Valutadate'),           'valutadate' ],
 
 546       [ $::locale->text('Amount'),               'amount' ],
 
 547       [ $::locale->text('Currency'),             sub { $_[0]->currency->name } ],
 
 548       [ $::locale->text('Remote name'),          'remote_name' ],
 
 549       [ $::locale->text('Purpose'),              'purpose' ],
 
 555 sub _sepa_export_list {
 
 556   my ($list, %params) = @_;
 
 558   my ($source, $destination) = $params{type} eq 'sepa_transfer' ? qw(our vc)                                 : qw(vc our);
 
 559   $params{title}             = $params{type} eq 'sepa_transfer' ? $::locale->text('Bank transfers via SEPA') : $::locale->text('Bank collections via SEPA');
 
 560   $params{with_columns}      = [ grep { $_ ne 'record_link_direction' } @{ $params{with_columns} || [] } ];
 
 562   delete $params{edit_record_links};
 
 567       [ $::locale->text('Export Number'),    'sepa_export',                                  ],
 
 568       [ $::locale->text('Execution date'),   'execution_date'                                ],
 
 569       [ $::locale->text('Export date'),      sub { $_[0]->sepa_export->itime->to_kivitendo } ],
 
 570       [ $::locale->text('Source BIC'),       "${source}_bic"                                 ],
 
 571       [ $::locale->text('Source IBAN'),      "${source}_iban"                                ],
 
 572       [ $::locale->text('Destination BIC'),  "${destination}_bic"                            ],
 
 573       [ $::locale->text('Destination IBAN'), "${destination}_iban"                           ],
 
 574       [ $::locale->text('Amount'),           'amount'                                        ],
 
 580 sub _sepa_transfer_list {
 
 581   my ($list, %params) = @_;
 
 582   _sepa_export_list($list, %params, type => 'sepa_transfer');
 
 585 sub _sepa_collection_list {
 
 586   my ($list, %params) = @_;
 
 587   _sepa_export_list($list, %params, type => 'sepa_collection');
 
 591   my ($list, %params) = @_;
 
 595     title   => $::locale->text('Letters'),
 
 598       [ $::locale->text('Date'),         'date'                                                ],
 
 599       [ $::locale->text('Letternumber'), sub { $_[0]->presenter->letter(display => 'table-cell') } ],
 
 600       [ $::locale->text('Customer'),     'customer'                                            ],
 
 601       [ $::locale->text('Reference'),    'reference'                                           ],
 
 602       [ $::locale->text('Subject'),      'subject'                                             ],
 
 608 sub _email_journal_list {
 
 609   my ($list, %params) = @_;
 
 613     title   => $::locale->text('Email'),
 
 614     type    => 'email_journal',
 
 616       [ $::locale->text('Sent on'), sub { $_[0]->sent_on->to_kivitendo(precision => 'seconds') } ],
 
 617       [ $::locale->text('Subject'), sub { $_[0]->presenter->email_journal(display => 'table-cell') } ],
 
 618       [ $::locale->text('Status'),  'status'                                                     ],
 
 619       [ $::locale->text('From'),    'from'                                                       ],
 
 620       [ $::locale->text('To'),      'recipients'                                                 ],
 
 626   my ($list, %params) = @_;
 
 630     title   => $::locale->text('Dunnings'),
 
 633       [ $::locale->text('Dunning Level'),   sub { $_[0]->presenter->dunning(display => 'table-cell') } ],
 
 634       [ $::locale->text('Dunning Date'),    'transdate'                                                ],
 
 635       [ $::locale->text('Dunning Duedate'), 'duedate'                                                  ],
 
 636       [ $::locale->text('Total Fees'),      'fee'                                                      ],
 
 637       [ $::locale->text('Interest'),        'interest'                                                 ],
 
 653 SL::Presenter::Record - Presenter module for lists of
 
 654 sales/purchase/general ledger record Rose::DB objects
 
 658   # Retrieve a number of documents from somewhere, e.g.
 
 659   my $order   = SL::DB::Manager::Order->get_first(where => [ SL::DB::Manager::Order->type_filter('sales_order') ]);
 
 660   my $records = $order->linked_records(destination => 'to');
 
 662   # Give HTML representation:
 
 663   my $html = SL::Presenter->get->grouped_record_list($records);
 
 675 Returns a rendered version (actually an instance of
 
 676 L<SL::Presenter::EscapedText>) of a single ar, ap or gl object.
 
 679   # fetch the record from a random acc_trans object and print its link (could be ar, ap or gl)
 
 680   my $record = SL::DB::Manager::AccTransaction->get_first()->record;
 
 681   my $html   = SL::Presenter->get->record($record, display => 'inline');
 
 683 =item C<grouped_record_list $list, %params>
 
 685 =item C<empty_record_list>
 
 687 Returns a rendered version (actually an instance of
 
 688 L<SL::Presenter::EscapedText>) of an empty list of records. Is usually
 
 689 only called by L<grouped_record_list> if its list is empty.
 
 691 =item C<grouped_record_list $list, %params>
 
 693 Given a number of Rose::DB objects in the array reference C<$list>
 
 694 this function first groups them by type. Then it calls L<record_list>
 
 695 with each non-empty type-specific sub-list and the appropriate
 
 696 parameters for outputting a list of those records.
 
 698 Returns a rendered version (actually an instance of
 
 699 L<SL::Presenter::EscapedText>) of all the lists.
 
 701 The order in which the records are grouped is:
 
 705 =item * sales quotations
 
 709 =item * sales delivery orders
 
 711 =item * rma delivery orders
 
 713 =item * sales invoices
 
 715 =item * AR transactions
 
 717 =item * requests for quotations
 
 719 =item * purchase orders
 
 721 =item * purchase delivery orders
 
 723 =item * supplier delivery orders
 
 725 =item * purchase invoices
 
 727 =item * AP transactions
 
 729 =item * GL transactions
 
 731 =item * SEPA collections
 
 733 =item * SEPA transfers
 
 737 Objects of unknown types are skipped.
 
 739 Parameters are passed to C<record_list> include C<with_objects> and
 
 740 C<edit_record_links>.
 
 742 =item C<record_list $list, %params>
 
 744 Returns a rendered version (actually an instance of
 
 745 L<SL::Presenter::EscapedText>) of a list of records. This list
 
 746 consists of a heading and a tabular representation of the list.
 
 748 The parameters include:
 
 754 Mandatory. The title to use in the heading. Must already be
 
 759 Mandatory. An array reference of column specs to output. Each column
 
 760 spec can be either an array reference or a hash reference.
 
 762 If a column spec is an array reference then the first element is the
 
 763 column's name shown in the table header. It must already be translated.
 
 765 The second element can be either a string or a code reference. A
 
 766 string is taken as the name of a function to call on the Rose::DB
 
 767 object for the current row. Its return value is formatted depending on
 
 768 the column's type (e.g. dates are output as the user expects them,
 
 769 floating point numbers are rounded to two decimal places and
 
 770 right-aligned etc). If it is a code reference then that code is called
 
 771 with the object as the first argument. Its return value should be an
 
 772 instance of L<SL::Presenter::EscapedText> and contain the rendered
 
 773 representation of the content to output.
 
 775 The third element, if present, can be a link to which the column will
 
 778 If the column spec is a hash reference then the same arguments are
 
 779 expected. The corresponding hash keys are C<title>, C<data> and
 
 782 =item C<with_columns>
 
 784 Can be set by the caller to indicate additional columns to
 
 785 be listed. Currently supported:
 
 789 =item C<record_link_destination>
 
 791 The record link destination. Requires that the records to be listed have
 
 792 been retrieved via the L<SL::DB::Helper::LinkedRecords> helper.
 
 796 =item C<edit_record_links>
 
 798 If trueish additional controls will be rendered that allow the user to
 
 799 remove and add record links. Requires that the records to be listed have
 
 800 been retrieved via the L<SL::DB::Helper::LinkedRecords> helper.
 
 812 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>