buster dev
[freeside.git] / rt / t / customfields / transaction_searching.t
1 use strict;
2 use warnings;
3
4 use RT::Test tests => 'no_declare';
5
6 my $initialdata = RT::Test::get_relocatable_file("transaction-cfs" => "..", "data", "initialdata");
7 my ($rv, $msg) = RT->DatabaseHandle->InsertData( $initialdata, undef, disconnect_after => 0 );
8 ok($rv, "Inserted test data from $initialdata")
9     or diag "Error: $msg";
10
11 create_tickets(
12     Spam        => {  },
13     Coffee      => { Billable   => "No", },
14     Phone       => { Billable   => "Yes", Who => ["Telecom", "Information Technology"], When => "2013-06-25", Location => "Geology" },
15     Stacks      => { Billable   => "Yes", Who => "Library", When => "2013-06-01" },
16     Benches     => { Billable   => "Yes", Location => "Outdoors" },
17 );
18
19 # Sanity check
20 results_are("CF.Location IS NOT NULL", [qw( Phone Benches )]);
21 results_are("CF.Location IS NULL",     [qw( Spam Coffee Stacks )]);
22
23 # TODO: Ideal behaviour of TxnCF IS NULL not yet determined
24 #results_are("TxnCF.Billable IS NULL", [qw( Spam )]);
25
26 results_are("TxnCF.Billable IS NOT NULL", [qw( Coffee Phone Stacks Benches )]);
27 results_are("TxnCF.Billable = 'No'", [qw( Coffee )]);
28 results_are("TxnCF.Billable = 'Yes'", [qw( Phone Stacks Benches )]);
29 results_are("TxnCF.Billable = 'Yes' AND CF.Location IS NOT NULL", [qw( Phone Benches )]);
30 results_are("TxnCF.Billable = 'Yes' AND CF.Location = 'Outdoors'", [qw( Benches )]);
31 results_are("TxnCF.Billable = 'Yes' AND CF.Location LIKE 'o'", [qw( Phone Benches )]);
32
33 results_are("TxnCF.Who = 'Telecom' OR TxnCF.Who = 'Library'", [qw( Phone Stacks )]);
34
35 # TODO: Negative searching finds tickets with at least one txn doesn't have the value
36 #results_are("TxnCF.Who != 'Library'", [qw( Spam Coffee Phone Benches )]);
37
38 results_are("TxnCF.When > '2013-06-24'", [qw( Phone )]);
39 results_are("TxnCF.When < '2013-06-24'", [qw( Stacks )]);
40 results_are("TxnCF.When >= '2013-06-01' and TxnCF.When <= '2013-06-30'", [qw( Phone Stacks )]);
41
42 results_are("TxnCF.Who LIKE 'e'", [qw( Phone )]);
43
44 # TODO: Negative searching finds tickets with at least one txn doesn't have the value
45 #results_are("TxnCF.Who NOT LIKE 'e'", [qw( Spam Coffee Stacks Benches )]);
46
47 results_are("TxnCF.Who NOT LIKE 'e' and TxnCF.Who IS NOT NULL", [qw( Stacks )]);
48
49
50 # Multiple CFs with same name applied to different queues
51 clear_tickets();
52 create_tickets(
53     BlueNone    => { Queue => "Blues" },
54     PurpleNone  => { Queue => "Purples" },
55
56     Blue        => { Queue => "Blues",   Color => "Blue" },
57     Purple      => { Queue => "Purples", Color => "Purple" },
58 );
59
60 # Queue-specific txn CFs
61 results_are("TxnCF.Blues.{Color} = 'Blue'", [qw( Blue )]);
62 results_are("TxnCF.Blues.{Color} = 'Purple'", []);
63
64 # Multiple transaction CFs by name
65 results_are("TxnCF.{Color} IS NOT NULL", [qw( Blue Purple )]);
66 results_are("TxnCF.{Color} = 'Blue'", [qw( Blue )]);
67 results_are("TxnCF.{Color} = 'Purple'", [qw( Purple )]);
68 results_are("TxnCF.{Color} LIKE 'e'", [qw( Blue Purple )]);
69
70 done_testing;
71
72 sub results_are {
73     local $Test::Builder::Level = $Test::Builder::Level + 1;
74
75     my $query    = shift;
76     my $expected = shift;
77     my %expected = map { $_ => 1 } @$expected;
78     my @unexpected;
79
80     my $tickets = RT::Tickets->new(RT->SystemUser);
81     my ($ok, $msg) = $tickets->FromSQL($query);
82     ok($ok, "Searched: $query")
83         or return diag $msg;
84     for my $t (@{$tickets->ItemsArrayRef || []}) {
85         if (delete $expected{$t->Subject}) {
86             ok(1, "Found expected ticket ".$t->Subject);
87         } else {
88             push @unexpected, $t->Subject;
89         }
90     }
91     ok(0, "Didn't find expected ticket $_")
92         for grep $expected{$_}, @$expected;
93     ok(0, "Found unexpected tickets: ".join ", ", @unexpected)
94         if @unexpected;
95 }
96
97 sub create_tickets {
98     my %ticket = @_;
99     for my $subject (sort keys %ticket) {
100         my %data = %{$ticket{$subject}};
101         my $location = delete $data{Location};
102         my $queue    = delete $data{Queue} || "General";
103
104         my $ticket = RT::Ticket->new( RT->SystemUser );
105         my ($ok, $msg) = $ticket->Create(
106             Queue   => $queue,
107             Subject => $subject,
108         );
109         ok($ticket->id, "Created ticket: $msg") or next;
110
111         if ($location) {
112             ($ok, $msg) = $ticket->AddCustomFieldValue( Field => "Location", Value => $location );
113             ok($ok, "Added Location: $msg") or next;
114         }
115
116         my ($txnid, $txnmsg, $txn) = $ticket->Correspond( Content => "test transaction" );
117         unless ($txnid) {
118             RT->Logger->error("Unable to correspond on ticket $ok: $txnmsg");
119             next;
120         }
121         for my $name (sort keys %data) {
122             my $values = ref $data{$name} ? $data{$name} : [$data{$name}];
123             for my $v (@$values) {
124                 ($ok, $msg) = $txn->_AddCustomFieldValue(
125                     Field => $name,
126                     Value => $v,
127                     RecordTransaction => 0
128                 );
129                 ok($ok, "Added txn CF $name value '$v'")
130                     or diag $msg;
131             }
132         }
133     }
134 }
135
136 sub clear_tickets {
137     my $tickets = RT::Tickets->new( RT->SystemUser );
138     $tickets->FromSQL("id > 0");
139     $_->SetStatus("deleted") for @{$tickets->ItemsArrayRef};
140 }