%doc>
All accessible Freeside customer fields fields go in here. Those of
them outside cust_main also need to go in RT::URI::freeside::Internal
(where they should be pulled into CustomerInfo). Nothing should need
to go in RT::Tickets_Overlay; it already resolves "Customer.foo" as
"cust_main.foo", and "Customer.cust_bar.foo" as "JOIN cust_bar using
(custnum) ... cust_bar.foo".
About the keys:
- 'Value' makes the field a search criterion. This also requires 'Op'.
See Search/Elements/PickBasics.
- 'Display' makes it an output column, and is either the cust_main
field, the CustomerInfo key, or a coderef that takes the RT::Ticket
as an argument.
- 'OrderBy' makes it a sort key, and must be set to an RT-SQL field
name to sort by.
%doc>
<%once>
my @customer_fields = ( # ordered
{
# custnum
Name => 'Customer',
Label => 'Customer',
Display => sub {
my $Ticket = shift;
my @return = ();
foreach my $c (ticket_cust_resolvers($Ticket)) {
push @return, \'',
$c->AsString,
\'',
\'
';
}
pop @return;
@return;
},
OrderBy => 'Customer.Number',
},
{
#Column name (format string)
Name => 'Agent',
# Column heading/query builder name
Label => 'Agent',
# Column value (coderef, cust_main field, or CustomerInfo key)
Display => 'AgentName',
# Query builder options
# RT-SQL field, defaults to Name
QueryName => 'Customer.agentnum',
#QueryLabel => 'Agent' #defaults to Label
Op => equals_notequals,
Value => select_table('agent', 'agentnum', 'agent'),
# RT-SQL sort key (if any)
OrderBy => 'Customer.agentnum',
},
{
Name => 'CustomerClass',
Label => 'Customer Class',
Display => 'CustomerClass',
QueryName => 'Customer.classnum',
Op => equals_notequals,
Value => select_table('cust_class', 'classnum', 'classname'),
OrderBy => 'Customer.classnum',
},
{
Name => 'AdvertisingSource',
Label => 'Advertising Source',
Display => 'Referral',
QueryName => 'Customer.refnum',
Op => equals_notequals,
Value => select_table('part_referral', 'refnum', 'referral'),
OrderBy => 'Customer.refnum',
},
{
Name => 'BillingType',
Label => 'Billing Type',
Display => 'BillingType',
QueryName => 'Customer.payby',
Op => equals_notequals,
Value => {
Type => 'select',
Options => [ '' => '-',
map { $_, FS::payby->longname($_) } FS::payby->cust_payby
],
},
},
{
Name => 'InvoiceEmail',
Label => 'Invoice Email',
Display => 'InvoiceEmail',
# query/sort needed?
},
{
Name => 'BillingAddress',
Label => 'Billing Address',
Display => 'bill_location',
},
{
Name => 'StreetAddress1',
Label => 'Street Address',
Display => 'bill_address1',
},
{
Name => 'StreetAddress2',
Label => '',
Display => 'bill_address2',
},
{
Name => 'City',
Label => 'City',
Display => 'bill_city',
},
{
Name => 'State',
Label => 'State',
Display => 'bill_state',
},
{
Name => 'CustomerTags',
Label => '',
Display => sub {
my $Ticket = shift;
my @return = ();
foreach my $c (ticket_cust_resolvers($Ticket)) {
foreach my $t (@{ $c->CustomerInfo->{CustomerTags} }) {
push @return, \' ',
$t->{'name'},
\' ',
\' '
;
}
pop @return;
push @return, \'
';
}
pop @return;
@return;
},
QueryName => 'Customer.cust_tag.tagnum',
QueryLabel => 'Tag',
Op => equals_notequals,
Value => select_table('part_tag', 'tagnum', 'tagname'),
OrderBy => '',
},
);
#helper subs
#Op
sub equals_notequals {
return {
Type => 'component',
Path => '/Elements/SelectBoolean',
Arguments => { TrueVal=> '=', FalseVal=> '!=' },
}
}
#Value
sub select_table {
my ($table, $value_col, $name_col, $hashref) = @_;
$hashref ||= { disabled => '' }; # common case
return {
Type => 'select',
Options => [
'' => '-',
map { $_->$value_col, $_->$name_col }
qsearch($table, $hashref)
],
}
}
sub ticket_cust_resolvers {
my $Ticket = shift;
my @Customers = map { $_->TargetURI->Resolver->CustomerResolver }
@{ $Ticket->Customers->ItemsArrayRef };
# this can contain cust_svc links, careful
# uniq
my %seen = map { $_->URI => $_ } @Customers;
values %seen;
}
sub cust_info_attribute { # the simple case of $resolver->CustomerInfo->{foo}
my $attribute = shift;
sub {
my $Ticket = shift;
my @return;
foreach my $c (ticket_cust_resolvers($Ticket)) {
push @return, $c->CustomerInfo->{$attribute}, '
';
}
pop @return; #trailing
@return;
};
}
%once>
<%init>
my $arg = shift;
if ( $arg eq 'Names' ) {
return map { $_->{Name} } @customer_fields;
}
elsif ( $arg eq 'ColumnMap' ) {
return map {
my $f = $_;
$f->{Name} => {
title => $f->{Label},
attribute => $f->{OrderBy} || '',
value => ref($f->{Display}) eq 'CODE' ?
$f->{Display} :
cust_info_attribute($f->{Display})
}
} #map
grep { exists $_->{Display} }
@customer_fields;
}
elsif ( $arg eq 'Criteria' ) {
return map {
my $f = $_;
# argument to Search/Elements/ConditionRow
$f->{Condition} ||
{
Name => ($f->{QueryName} || $f->{Name}),
Field => ($f->{QueryLabel} || $f->{Label}),
Op => $f->{Op},
Value => $f->{Value},
}
} #map
grep { exists $_->{Condition} || exists $_->{Value} }
@customer_fields;
}
else { die "unknown CustomerFields mode '$arg'\n"; }
%init>