d5419d21373e5c41dbe6855804b67820d2c2dc9f
[freeside.git] / rt / share / html / Elements / CustomerFields
1 <%doc>
2 All accessible Freeside customer fields fields go in here.  Those of 
3 them outside cust_main also need to go in RT::URI::freeside::Internal
4 (where they should be pulled into CustomerInfo).  Nothing should need 
5 to go in RT::Tickets_Overlay; it already resolves "Customer.foo" as 
6 "cust_main.foo", and "Customer.cust_bar.foo" as "JOIN cust_bar using 
7 (custnum) ... cust_bar.foo".
8
9 About the keys:
10 - 'Value' makes the field a search criterion.  This also requires 'Op'.
11   See Search/Elements/PickBasics.
12 - 'Display' makes it an output column, and is either the cust_main 
13   field, the CustomerInfo key, or a coderef that takes the RT::Ticket
14   as an argument.
15 - 'OrderBy' makes it a sort key, and must be set to an RT-SQL field
16   name to sort by.
17 </%doc>
18 <%once>
19
20 my @customer_fields = ( # ordered
21   {
22     # custnum
23     Name    => 'Customer',
24     Label   => 'Customer',
25     Display => sub {
26                 my $Ticket = shift;
27                 my @return = ();
28                 foreach my $c (ticket_cust_resolvers($Ticket)) {
29                     push @return, \'<A HREF="', $c->HREF, \'">',
30                                   $c->AsString,
31                                   \'</A>',
32                                   \'<BR>';
33                 }
34                 pop @return;
35                 @return;
36               },
37     OrderBy => 'Customer.Number',
38   },
39   {
40     #Column name (format string)
41     Name    => 'Agent',
42     # Column heading/query builder name
43     Label   => 'Agent',
44     # Column value (coderef, cust_main field, or CustomerInfo key)
45     Display => 'AgentName',
46     # Query builder options
47     # RT-SQL field, defaults to Name
48     QueryName => 'Customer.agentnum',
49     #QueryLabel => 'Agent' #defaults to Label
50     Op      => equals_notequals,
51     Value   => select_table('agent', 'agentnum', 'agent'),
52     # RT-SQL sort key (if any)
53     OrderBy => 'Customer.agentnum',
54   },
55   {
56     Name    => 'CustomerClass',
57     Label   => 'Customer Class',
58     Display => 'CustomerClass',
59     QueryName => 'Customer.classnum',
60     Op      => equals_notequals,
61     Value   => select_table('cust_class', 'classnum', 'classname'),
62     OrderBy => 'Customer.classnum',
63   },
64   {
65     Name    => 'AdvertisingSource',
66     Label   => 'Advertising Source',
67     Display => 'Referral',
68     QueryName => 'Customer.refnum',
69     Op      => equals_notequals,
70     Value   => select_table('part_referral', 'refnum', 'referral'),
71     OrderBy => 'Customer.refnum',
72   },
73   {
74     Name    => 'BillingType',
75     Label   => 'Billing Type',
76     Display => 'BillingType',
77     QueryName => 'Customer.payby',
78     Op      => equals_notequals,
79     Value   => {
80       Type => 'select',
81       Options => [ '' => '-',
82         map { $_, FS::payby->longname($_) } FS::payby->cust_payby 
83       ],
84     },
85   },
86   {
87     Name    => 'InvoiceEmail',
88     Label   => 'Invoice Email',
89     Display => 'InvoiceEmail',
90     # query/sort needed?
91   },
92   {
93     Name    => 'City',
94     Label   => 'City',
95     Display => 'city',
96     OrderBy => 'Customer.city',
97   },
98   {
99     Name    => 'State',
100     Label   => 'State',
101     Display => 'state',
102     OrderBy => 'Customer.state',
103   },
104   {
105     Name    => 'CustomerTags',
106     Label   => '',
107     Display => sub {
108                 my $Ticket = shift;
109                 my @return = ();
110                 foreach my $c (ticket_cust_resolvers($Ticket)) {
111                   foreach my $t (@{ $c->CustomerInfo->{CustomerTags} }) {
112                     push @return, \'<SPAN style="background-color:#',
113                     $t->{'color'},
114                     \';">&nbsp;',
115                     $t->{'name'},
116                     \'&nbsp;</SPAN>',
117                     \'&nbsp;'
118                     ;
119                   }
120                   pop @return;
121                   push @return, \'<BR>';
122                 }
123                 pop @return;
124                 @return;
125               },
126     QueryName => 'Customer.cust_tag.tagnum',
127     QueryLabel => 'Tag',
128     Op      => equals_notequals,
129     Value   => select_table('part_tag', 'tagnum', 'tagname'),
130     OrderBy => '',
131   },
132 );
133
134 #helper subs
135 #Op      
136 sub equals_notequals {
137   return {
138       Type => 'component',
139       Path => '/Elements/SelectBoolean',
140       Arguments => { TrueVal=> '=', FalseVal=> '!=' },
141   }
142 }
143
144 #Value
145 sub select_table {
146   my ($table, $value_col, $name_col, $hashref) = @_;
147   $hashref ||= { disabled => '' }; # common case
148   return {
149     Type => 'select',
150     Options => [ 
151       '' => '-',
152       map { $_->$value_col, $_->$name_col }
153       qsearch($table, $hashref)
154     ],
155   }
156 }
157
158 sub ticket_cust_resolvers {
159     my $Ticket = shift;
160     my @Customers = map { $_->TargetURI->Resolver->CustomerResolver }
161                       @{ $Ticket->Customers->ItemsArrayRef };
162     # this can contain cust_svc links, careful
163     # uniq
164     my %seen = map { $_->URI => $_ } @Customers;
165     values %seen;
166 }
167
168 sub cust_info_attribute { # the simple case of $resolver->CustomerInfo->{foo}
169     my $attribute = shift;
170     sub {
171         my $Ticket = shift;
172         my @return;
173         foreach my $c (ticket_cust_resolvers($Ticket)) {
174             push @return, $c->CustomerInfo->{$attribute}, '<BR>';
175         }
176         pop @return; #trailing <BR>
177         @return;
178     };
179 }
180
181 </%once>
182 <%init>
183
184 my $arg = shift;
185 if ( $arg eq 'Names' ) {
186   return map { $_->{Name} } @customer_fields;
187 }
188 elsif ( $arg eq 'ColumnMap' ) {
189   return map {
190     my $f = $_;
191
192     $f->{Name} => {
193         title     => $f->{Label},
194         attribute => $f->{OrderBy} || '',
195         value     => ref($f->{Display}) eq 'CODE' ? 
196                       $f->{Display} : 
197                       cust_info_attribute($f->{Display})
198       }
199   } #map
200   grep { exists $_->{Display} }
201   @customer_fields;
202 }
203 elsif ( $arg eq 'Criteria' ) {
204   return map {
205     my $f = $_;
206     # argument to Search/Elements/ConditionRow
207     $f->{Condition} ||
208     {
209       Name  => ($f->{QueryName} || $f->{Name}),
210       Field => ($f->{QueryLabel} || $f->{Label}),
211       Op    => $f->{Op},
212       Value => $f->{Value},
213     }
214   } #map
215   grep { exists $_->{Condition} || exists $_->{Value} }
216   @customer_fields;
217 }
218 else { die "unknown CustomerFields mode '$arg'\n"; }
219 </%init>