Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision f82c6163

Von Bernd Bleßmann vor mehr als 3 Jahren hinzugefügt

  • ID f82c616366833bcef7b1298a550528e5226e0a1c
  • Vorgänger ffd6f21b
  • Nachfolger 5f810b4b

Zeiterfassung: Konvertierung: angegebenen Auftrag als Vorgänger verwenden können

Unterschiede anzeigen:

SL/BackgroundJob/ConvertTimeRecordings.pm
20 20
}
21 21
use Rose::Object::MakeMethods::Generic (
22 22
 'scalar'                => [ qw(data) ],
23
 'scalar --get_set_init' => [ qw(rounding link_project) ],
23
 'scalar --get_set_init' => [ qw(rounding link_order) ],
24 24
);
25 25

  
26 26
# valid parameters -> better as class members with rose generic set/get
......
30 30
              customernumbers => '',
31 31
              part_id => '',
32 32
              rounding => 1,
33
              link_project => 0,
33
              link_order => 0,
34 34
              project_id => '',
35 35
             );
36 36

  
......
56 56
  # TODO check user input param values - (defaults are assigned later)
57 57
  # 1- If there are any customer numbers check if they refer to valid customers
58 58
  #    otherwise croak and do nothing
59
  # 2 .. n Same applies for other params if used at all (rounding -> 0|1  link_project -> 0|1)
59
  # 2 .. n Same applies for other params if used at all (rounding -> 0|1  link_order -> 0|1)
60 60

  
61 61
  # from/to date from data. Defaults to begining and end of last month.
62 62
  # TODO get/set see above
......
89 89

  
90 90
  my @donumbers;
91 91

  
92
  if ($self->data->{link_project}) {
92
  if ($self->data->{link_order}) {
93 93
    my %time_recordings_by_order_id;
94 94
    my %orders_by_order_id;
95 95
    foreach my $tr (@$time_recordings) {
......
126 126
  1
127 127
}
128 128

  
129
sub init_link_project {
129
sub init_link_order {
130 130
  0
131 131
}
132 132

  
......
137 137
  my %time_recordings_by_customer_id;
138 138
  push @{ $time_recordings_by_customer_id{$_->customer_id} }, $_ for @$time_recordings;
139 139

  
140
  my %convert_params = map { $_ => $self->data->{$_} } qw(rounding link_project project_id);
140
  my %convert_params = map { $_ => $self->data->{$_} } qw(rounding link_order project_id);
141 141
  $convert_params{default_part_id} = $self->data->{part_id};
142 142

  
143 143
  my @donumbers;
......
174 174
sub convert_with_linking {
175 175
  my ($self, $time_recordings_by_order_id, $orders_by_order_id) = @_;
176 176

  
177
  my %convert_params = map { $_ => $self->data->{$_} } qw(rounding link_project project_id);
177
  my %convert_params = map { $_ => $self->data->{$_} } qw(rounding link_order project_id);
178 178
  $convert_params{default_part_id} = $self->data->{part_id};
179 179

  
180 180
  my @donumbers;
......
236 236
sub get_order_for_time_recording {
237 237
  my ($self, $tr) = @_;
238 238

  
239
  # check project
240
  my $project_id;
241
  #$project_id   = $self->overide_project_id;
242
  $project_id   = $self->data->{project_id};
243
  $project_id ||= $tr->project_id;
244
  #$project_id ||= $self->default_project_id;
239
  my $orders;
240

  
241
  if (!$tr->order_id) {
242
    # check project
243
    my $project_id;
244
    #$project_id   = $self->overide_project_id;
245
    $project_id   = $self->data->{project_id};
246
    $project_id ||= $tr->project_id;
247
    #$project_id ||= $self->default_project_id;
248

  
249
    if (!$project_id) {
250
      my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : no project id';
251
      $::lxdebug->message(LXDebug->WARN(), $err_msg);
252
      push @{ $self->{job_errors} }, $err_msg;
253
      return;
254
    }
245 255

  
246
  if (!$project_id) {
247
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : no project id';
248
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
249
    push @{ $self->{job_errors} }, $err_msg;
250
    return;
251
  }
256
    my $project = SL::DB::Project->load_cached($project_id);
252 257

  
253
  my $project = SL::DB::Project->load_cached($project_id);
258
    if (!$project) {
259
      my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project not found';
260
      $::lxdebug->message(LXDebug->WARN(), $err_msg);
261
      push @{ $self->{job_errors} }, $err_msg;
262
      return;
263
    }
264
    if (!$project->active || !$project->valid) {
265
      my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project not active or not valid';
266
      $::lxdebug->message(LXDebug->WARN(), $err_msg);
267
      push @{ $self->{job_errors} }, $err_msg;
268
      return;
269
    }
270
    if ($project->customer_id && $project->customer_id != $tr->customer_id) {
271
      my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project customer does not match customer of time recording';
272
      $::lxdebug->message(LXDebug->WARN(), $err_msg);
273
      push @{ $self->{job_errors} }, $err_msg;
274
      return;
275
    }
254 276

  
255
  if (!$project) {
256
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project not found';
257
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
258
    push @{ $self->{job_errors} }, $err_msg;
259
    return;
260
  }
261
  if (!$project->active || !$project->valid) {
262
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project not active or not valid';
263
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
264
    push @{ $self->{job_errors} }, $err_msg;
265
    return;
277
    $orders = SL::DB::Manager::Order->get_all(where        => [customer_id      => $tr->customer_id,
278
                                                               or               => [quotation => undef, quotation => 0],
279
                                                               globalproject_id => $project_id, ],
280
                                              with_objects => ['orderitems']);
281

  
282
  } else {
283
    # order_id given
284
    my $order = SL::DB::Manager::Order->find_by(id => $tr->order_id);
285
    push @$orders, $order if $order;
266 286
  }
267
  if ($project->customer_id && $project->customer_id != $tr->customer_id) {
268
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project customer does not match customer of time recording';
287

  
288
  if (!scalar @$orders) {
289
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : no order found';
269 290
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
270 291
    push @{ $self->{job_errors} }, $err_msg;
271 292
    return;
......
292 313
    return;
293 314
  }
294 315

  
295
  my $orders = SL::DB::Manager::Order->get_all(where        => [customer_id      => $tr->customer_id,
296
                                                                or               => [quotation => undef, quotation => 0],
297
                                                                globalproject_id => $project_id, ],
298
                                               with_objects => ['orderitems']);
299 316
  my @matching_orders;
300 317
  foreach my $order (@$orders) {
301 318
    if (any { $_->parts_id == $part_id } @{ $order->items_sorted }) {
......
310 327
    return;
311 328
  }
312 329

  
313
  return $matching_orders[0];
330
  my $matching_order = $matching_orders[0];
331

  
332
  if (!$matching_order->is_sales) {
333
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : found order is not a sales order';
334
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
335
    push @{ $self->{job_errors} }, $err_msg;
336
    return;
337
  }
338

  
339
  if ($matching_order->customer_id != $tr->customer_id) {
340
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : customer of order does not match customer of time recording';
341
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
342
    push @{ $self->{job_errors} }, $err_msg;
343
    return;
344
  }
345

  
346
  if ($tr->project_id && $tr->project_id != ($matching_order->globalproject_id || 0)) {
347
    my $err_msg = 'ConvertTimeRecordings: searching related order failed for time recording id ' . $tr->id . ' : project of order does not match project of time recording';
348
    $::lxdebug->message(LXDebug->WARN(), $err_msg);
349
    push @{ $self->{job_errors} }, $err_msg;
350
    return;
351
  }
352

  
353
  return $matching_order;
314 354
}
315 355

  
316 356
1;
......
382 422
ie. 0.25h 0.5h 0.75h 1.25h ...
383 423
Defaults to rounding true (1).
384 424

  
385
=item C<link_project>
425
=item C<link_order>
386 426

  
387
If set the job tries to find a previous Order with the current
388
customer and project number and tries to do as much automatic
389
workflow processing as the UI.
427
If set the job links the created delivery order with with the order
428
given in the time recording entry. If there is no order given, then
429
it tries to find an order with with the current customer and project
430
number and tries to do as much automatic workflow processing as the
431
UI.
390 432
Defaults to off. If set to true (1) the job will fail if there
391
is no Sales Orders which qualifies as a predecessor.
433
is no sales order which qualifies as a predecessor.
392 434
Conditions for a predeccesor:
393 435

  
436
 * Order given in time recording entry OR
394 437
 * Global project_id must match time_recording.project_id OR data.project_id
395
 * Customer name must match time_recording.customer_id OR data.customernumbers
438
 * Customer must match customer in time recording entry
396 439
 * The sales order must have at least one or more time related services
397 440
 * The Project needs to be valid and active
398 441

  
399
The job doesn't care if the Sales Order is already delivered or closed.
442
The job doesn't care if the sales order is already delivered or closed.
400 443
If the sales order is overdelivered some organisational stuff needs to be done.
401 444
The sales order may also already be closed, ie the amount is fully billed, but
402 445
the services are not yet fully delivered (simple case: 'Payment in advance').
t/background_job/convert_time_recordings.t
1
use Test::More tests => 20;
1
use Test::More tests => 27;
2 2

  
3 3
use strict;
4 4

  
......
20 20
Support::TestSetup::login();
21 21

  
22 22
sub clear_up {
23
  foreach (qw(OrderItem Order DeliveryOrder TimeRecording Project Part Customer RecordLink)) {
23
  foreach (qw(TimeRecording OrderItem Order DeliveryOrder Project Part Customer RecordLink)) {
24 24
    "SL::DB::Manager::${_}"->delete_all(all => 1);
25 25
  }
26 26
  SL::DB::Manager::Employee->delete_all(where => [ '!login' => 'unittests' ]);
......
69 69
)->save;
70 70

  
71 71
my %data   = (
72
  link_project => 1,
73
  project_id   => $project->id,
74
  from_date    => '01.04.2021',
75
  to_date      => '30.04.2021',
72
  link_order => 1,
73
  project_id => $project->id,
74
  from_date  => '01.04.2021',
75
  to_date    => '30.04.2021',
76 76
);
77 77
my $db_obj = SL::DB::BackgroundJob->new();
78 78
$db_obj->set_data(%data);
......
135 135

  
136 136
# two time recordings, one order linked with project_id
137 137
%data = (
138
  link_project => 1,
139
  project_id   => $project->id,
140
  from_date    => '01.04.2021',
141
  to_date      => '30.04.2021',
138
  link_order => 1,
139
  project_id => $project->id,
140
  from_date  => '01.04.2021',
141
  to_date    => '30.04.2021',
142 142
);
143 143
$db_obj = SL::DB::BackgroundJob->new();
144 144
$db_obj->set_data(%data);
......
194 194

  
195 195
# two time recordings, one order linked with project_id
196 196
%data = (
197
  link_project => 1,
198
  project_id   => $project->id,
199
  from_date    => '01.04.2021',
200
  to_date      => '30.04.2021',
197
  link_order => 1,
198
  project_id => $project->id,
199
  from_date  => '01.04.2021',
200
  to_date    => '30.04.2021',
201 201
);
202 202
$db_obj = SL::DB::BackgroundJob->new();
203 203
$db_obj->set_data(%data);
......
243 243
)->save;
244 244

  
245 245
%data = (
246
  link_project => 0,
247
  from_date    => '01.04.2021',
248
  to_date      => '30.04.2021',
246
  link_order => 0,
247
  from_date  => '01.04.2021',
248
  to_date    => '30.04.2021',
249 249
);
250 250
$db_obj = SL::DB::BackgroundJob->new();
251 251
$db_obj->set_data(%data);
......
259 259
clear_up();
260 260

  
261 261

  
262
########################################
263
# time recording, linked with order_id
264
########################################
265
$part     = new_service(partnumber => 'Serv1', unit => 'Std')->save;
266
$customer = new_customer()->save;
267

  
268
# sales order with globalproject_id
269
$sales_order = create_sales_order(
270
  save             => 1,
271
  customer         => $customer,
272
  taxincluded      => 0,
273
  orderitems       => [ create_order_item(part => $part, qty => 3, sellprice => 70), ]
274
);
275

  
276
@time_recordings = ();
277
push @time_recordings, new_time_recording(
278
  start_time => DateTime->new(year => 2021, month =>  4, day => 19, hour => 10, minute =>  5),
279
  end_time   => DateTime->new(year => 2021, month =>  4, day => 19, hour => 11, minute =>  5),
280
  customer   => $customer,
281
  order      => $sales_order,
282
  part       => $part,
283
)->save;
284

  
285
%data = (
286
  link_order => 1,
287
  from_date  => '01.04.2021',
288
  to_date    => '30.04.2021',
289
);
290
$db_obj = SL::DB::BackgroundJob->new();
291
$db_obj->set_data(%data);
292
$job    = SL::BackgroundJob::ConvertTimeRecordings->new;
293
$ret    = $job->run($db_obj);
294

  
295
is_deeply($job->{job_errors}, [], 'no errros');
296
like($ret, qr{^Number of delivery orders created: 1}, 'linked by order_id: one delivery order created');
297

  
298
$linked_dos = $sales_order->linked_records(to => 'DeliveryOrder');
299
is(scalar @$linked_dos, 1, 'linked by order_id: one delivery order linked to order');
300

  
301
$linked_items = $sales_order->items->[0]->linked_records(to => 'DeliveryOrderItem');
302
is(scalar @$linked_items, 1, 'linked by order_id: one delivery order item linked to order item');
303
is($linked_items->[0]->qty*1, 1, 'linked by order_id: qty in delivery order');
304
is($linked_items->[0]->base_qty*1, 1, 'linked by order_id: base_qty in delivery order');
305

  
306
# reload order and orderitems to get changes to deliverd and ship
307
Rose::DB::Object::Helpers::forget_related($sales_order, 'orderitems');
308
$sales_order->load;
309

  
310
is($sales_order->items->[0]->ship*1, 1, 'linked by order_id: ship in related order');
311

  
312
clear_up();
313

  
314

  
262 315
########################################
263 316

  
264 317
$::locale = $old_locale;

Auch abrufbar als: Unified diff