@@ -289,6 +289,216 @@ sub perform_request {
289
289
return $response ;
290
290
}
291
291
292
+ sub perform_request_graphql {
293
+ my ($self , %args ) = @_ ;
294
+
295
+ my $uri = URI-> new( $self -> config-> {graphql_url } );
296
+ my $request = HTTP::Request-> new(
297
+ ' POST' ,
298
+ $uri ,
299
+ );
300
+ $request -> header(
301
+ Authorization => ' Basic '
302
+ . $self -> config-> {graphql_key }
303
+ );
304
+ $request -> content_type(' application/json; charset=UTF-8' );
305
+
306
+ my $query ;
307
+ if ( $args {type } eq ' job_types' ) {
308
+ $query = $self -> job_types_graphql_query();
309
+ } elsif ( $args {type } eq ' jobs' ) {
310
+ $query = $self -> jobs_graphql_query(%args );
311
+ } elsif ( $args {type } eq ' job_status_logs' ) {
312
+ $query = $self -> job_status_logs_graphql_query(%args );
313
+ }
314
+
315
+ my $body = {
316
+ query => $query ,
317
+ };
318
+
319
+ $request -> content(encode_json($body ));
320
+
321
+ my $response = $self -> ua-> request($request );
322
+
323
+ my $content = decode_json($response -> content);
324
+
325
+ return $content ;
326
+ }
327
+
328
+ # GraphQL queries.
329
+ # Confirm docs: https://help.dudesolutions.com/Content/PDF/Confirm/v21.10/confirm-v21-10-web-api-specification.pdf
330
+ #
331
+ # We use GraphQL to fetch 'job' objects from Confirm.
332
+ # You can read about GraphQL at https://graphql.org/learn/
333
+ # BUT
334
+ # it appears that Confirm's implementation lacks some features, notably
335
+ # variable support (hence the use of string interpolation below). It also
336
+ # tends to ignore faulty filter definitions in favour of fetching everything.
337
+
338
+ sub job_status_logs_graphql_query {
339
+ my ( $self , %args ) = @_ ;
340
+
341
+ my @job_type_codes
342
+ = keys %{ $self -> config-> {job_service_whitelist } // () };
343
+
344
+ my @status_codes
345
+ = keys %{ $self -> config-> {job_reverse_status_mapping } // () };
346
+
347
+ my (
348
+ $start_date ,
349
+ $end_date ,
350
+ $job_type_codes_str ,
351
+ $status_codes_str ,
352
+ ) = (
353
+ $args {start_date },
354
+ $args {end_date },
355
+ join ( ' ,' , @job_type_codes ),
356
+ join ( ' ,' , @status_codes ),
357
+ );
358
+
359
+ return <<GRAPHQL ;
360
+ {
361
+ jobStatusLogs(
362
+ filter: {
363
+ loggedDate: {
364
+ greaterThanEquals: "$start_date "
365
+ lessThanEquals: "$end_date "
366
+ }
367
+ statusCode: {
368
+ inList: [ $status_codes_str ]
369
+ }
370
+ }
371
+ ) {
372
+ jobNumber
373
+ key
374
+ loggedDate
375
+ statusCode
376
+
377
+ job {
378
+ jobType(
379
+ filter: {
380
+ code: {
381
+ inList: [ $job_type_codes_str ]
382
+ }
383
+ }
384
+ ){
385
+ code
386
+ }
387
+ }
388
+ }
389
+ }
390
+ GRAPHQL
391
+ }
392
+
393
+ sub jobs_graphql_query {
394
+ my ( $self , %args ) = @_ ;
395
+
396
+ my $job_numbers_str = join ' ,' , @{ $args {job_numbers } };
397
+
398
+ my @status_codes
399
+ = keys %{ $self -> config-> {job_reverse_status_mapping } // () };
400
+ my $status_codes_str = join ( ' ,' , @status_codes );
401
+
402
+ return <<"GRAPHQL"
403
+ {
404
+ jobs (
405
+ filter: {
406
+ jobNumber: {
407
+ inList: [ $job_numbers_str ]
408
+ }
409
+ }
410
+ ){
411
+ description
412
+ entryDate
413
+ geometry
414
+ jobNumber
415
+
416
+ jobType {
417
+ code
418
+ name
419
+ }
420
+ priority {
421
+ code
422
+ name
423
+ }
424
+
425
+ statusLogs (
426
+ filter: {
427
+ statusCode: {
428
+ inList: [ $status_codes_str ]
429
+ }
430
+ }
431
+ ) {
432
+ loggedDate
433
+ statusCode
434
+ }
435
+ }
436
+ }
437
+ GRAPHQL
438
+ }
439
+
440
+ sub job_types_graphql_query {
441
+ return <<'GRAPHQL'
442
+ {
443
+ jobTypes{
444
+ code
445
+ name
446
+ }
447
+ }
448
+ GRAPHQL
449
+ }
450
+
451
+ sub GetJobStatusLogs {
452
+ my ( $self , %args ) = @_ ;
453
+
454
+ my $content
455
+ = $self -> perform_request_graphql( type => ' job_status_logs' , %args );
456
+
457
+ return $content -> {data }{jobStatusLogs } // [];
458
+ }
459
+
460
+ sub GetJobs {
461
+ my ($self , %args ) = @_ ;
462
+
463
+ return []
464
+ unless $args {job_numbers }
465
+ && ref $args {job_numbers } eq ' ARRAY'
466
+ && @{ $args {job_numbers } };
467
+
468
+ my $content = $self -> perform_request_graphql( type => ' jobs' , %args );
469
+
470
+ return [] unless $content -> {data }{jobs };
471
+
472
+ my @jobs ;
473
+
474
+ # Extra filtering.
475
+ # I don't know how to filter out jobs with certain priorities in the
476
+ # graphql (possibly a limitation of Confirm's implementation), so let's
477
+ # do it here.
478
+ for my $job ( @{$content -> {data }{jobs }} ) {
479
+ next
480
+ if $self -> config-> {job_priority_blacklist }
481
+ && $self -> config-> {job_priority_blacklist }{ $job -> {priority }{code } };
482
+
483
+ push @jobs , $job ;
484
+ }
485
+
486
+ return \@jobs ;
487
+ }
488
+
489
+ sub GetJobLookups {
490
+ my $self = shift ;
491
+
492
+ my $lookups = $self -> memcache-> get(' GetJobLookups' );
493
+ unless ($lookups ) {
494
+ $lookups = $self -> perform_request_graphql(type => ' job_types' );
495
+
496
+ $self -> memcache-> set(' GetJobLookups' , $lookups , 1800);
497
+ }
498
+
499
+ return $lookups -> {data }{jobTypes } // [];
500
+ }
501
+
292
502
sub GetEnquiries {
293
503
my $self = shift ;
294
504
0 commit comments