2 Accessible Freeside svc_x fields go in here. RT::URI::freeside::Internal
3 pulls all fields from cust_svc and the svc_x tables into ServiceInfo().
4 RT::Tickets_Overlay resolves "Service.foo" as "cust_svc.foo", and
5 "Service.svc_acct.bar" as "JOIN svc_acct USING (svcnum) ... svc_acct.bar".
7 See /Elements/CustomerFields for notes on this data structure.
11 my @service_fields = ( # ordered
19 foreach my $s (ticket_svc_resolvers($Ticket)) {
20 push @return, \'<A HREF="', $s->HREF, \'">',
28 OrderBy => 'Service.Number',
31 #Column name (format string)
32 Name => 'ServiceType',
33 # Column heading/query builder name
34 Label => 'Service Type',
35 # Column value (coderef, cust_svc/svc_x field, or ServiceInfo key)
36 Display => 'ServiceType',
37 # Query builder options
38 # RT-SQL field, defaults to Name
39 QueryName => 'Service.svcpart',
40 Op => equals_notequals,
41 Value => select_table('part_svc', 'svcpart', 'svc'),
42 # RT-SQL sort key (if any)
43 OrderBy => 'Service.svcpart',
46 Name => 'ServiceLocation',
47 Label => 'Service Location',
48 Display => svc_location_attribute('location'),
51 Name => 'ServiceKey', # loosely corresponds to smartsearch/label field
57 'Service.svc_acct.username' => loc('Username'),
58 'Service.svc_phone.phonenum' => loc('Phone Number'),
59 'Service.svc_broadband.ip_addr' => loc('IP Address'),
60 'Service.svc_broadband.mac_addr' => loc('MAC Address'),
63 Op => matches_notmatches,
64 Value => { Type => 'text', Size => 20 },
69 QueryName => 'Service.svc_broadband.routernum',
71 Op => equals_notequals,
72 Value => select_table('router', 'routernum', 'routername'),
73 OrderBy => 'Service.svc_broadband.routernum',
79 sub equals_notequals {
82 Path => '/Elements/SelectBoolean',
83 Arguments => { TrueVal=> '=', FalseVal=> '!=' },
86 sub matches_notmatches {
89 Path => '/Elements/SelectMatch',
95 my ($table, $value_col, $name_col, $hashref) = @_;
96 $hashref ||= { disabled => '' }; # common case
101 map { $_->$value_col, $_->$name_col }
102 qsearch($table, $hashref)
107 sub ticket_svc_resolvers {
109 my @Services = @{ $Ticket->Services->ItemsArrayRef };
110 return map $_->TargetURI->Resolver, @Services;
113 sub svc_info_attribute {
114 my $attribute = shift;
118 foreach my $s (ticket_svc_resolvers($Ticket)) {
119 push @return, $s->ServiceInfo->{$attribute}, '<BR>';
121 pop @return; #trailing <BR>
126 sub svc_location_attribute {
127 # Tricky: if the ticket is linked to a service, we want to return the
128 # service's location, but if it's not, we want to return the customer's
129 # default service location.
130 # If it's linked to Customer A and also to Service A, it should return
131 # Service A's location (and not Customer A's default service location).
132 # But if it's linked to Service A and also to Customer B, then what? We
133 # can't satisfy all the constraints here.
134 my $attribute = shift;
138 my @svc_resolvers = ticket_svc_resolvers($Ticket);
139 if (@svc_resolvers) {
140 warn '#' . $Ticket->id . ", service attribute $attribute\n";
141 foreach my $s (@svc_resolvers) {
142 push @return, $s->ServiceInfo->{$attribute}, '<BR>';
145 warn '#' . $Ticket->id . ", customer attribute ship_$attribute\n";
146 my @cust_resolvers = map $_->TargetURI->Resolver,
147 @{ $Ticket->Customers->ItemsArrayRef };
148 foreach my $c (@cust_resolvers) {
149 push @return, $c->CustomerInfo->{"ship_$attribute"}, '<BR>';
152 pop @return; #trailing <BR>
160 #warn Dumper(\@service_fields);
163 if ( $arg eq 'Names' ) {
164 return map { $_->{Name} }
165 grep { exists $_->{Display} }
168 elsif ( $arg eq 'ColumnMap' ) {
172 title => $f->{Label},
173 attribute => $f->{OrderBy} || '',
174 value => ref($f->{Display}) eq 'CODE' ?
176 svc_info_attribute($f->{Display})
179 grep { exists $_->{Display} }
182 elsif ( $arg eq 'Criteria' ) {
185 # argument to Search/Elements/ConditionRow
187 Name => ($f->{QueryName} || $f->{Name}),
188 Field => ($f->{QueryLabel} || $f->{Label}),
190 Value => $f->{Value},
193 grep { exists($_->{Value}) }
196 else { die "unknown ServiceFields mode '$arg'\n"; }