diff options
| -rw-r--r-- | FS/FS/part_event/Condition/inactive_age.pm | 38 | ||||
| -rw-r--r-- | rt/lib/RT/Interface/Web_Vendor.pm | 27 | ||||
| -rw-r--r-- | rt/share/html/Elements/ColumnMap | 40 | ||||
| -rw-r--r-- | rt/share/html/Elements/RT__Ticket/ColumnMap | 15 | ||||
| -rw-r--r-- | rt/share/html/Search/Elements/ResultsStructuredView | 10 | 
5 files changed, 96 insertions, 34 deletions
| diff --git a/FS/FS/part_event/Condition/inactive_age.pm b/FS/FS/part_event/Condition/inactive_age.pm index 8918a1a3c..cbf4b9e0a 100644 --- a/FS/FS/part_event/Condition/inactive_age.pm +++ b/FS/FS/part_event/Condition/inactive_age.pm @@ -11,6 +11,10 @@ sub option_fields {      'age'  =>  { 'label'   => 'No activity within',                   'type'    => 'freq',                 }, +    'ignore_pkgclass' => +               { 'label' => 'Except charges of class', +                 'type'  => 'select-pkg_class', +               },      # flags to select kinds of activity,       # like if you just want "no payments since"?      # not relevant yet @@ -22,23 +26,51 @@ sub condition {    my $custnum = $obj->custnum;    my $age = $self->option_age_from('age', $opt{'time'} ); -  foreach my $t (qw(cust_bill cust_pay cust_credit cust_refund)) { +  my $ignore_pkgclass = $self->option('ignore_pkgclass'); + +  my $where = "custnum = $custnum AND _date >= $age"; + +  foreach my $t (qw(cust_pay cust_credit cust_refund)) {      my $class = "FS::$t"; -    return 0 if $class->count("custnum = $custnum AND _date >= $age"); +    return 0 if $class->count($where);    } + +  # cust_bill: handle the ignore_pkgclass option +  if ( $ignore_pkgclass =~ /^\d+$/ ) { +    $where .= " AND EXISTS( ". +      "SELECT 1 FROM cust_bill_pkg JOIN cust_pkg USING (pkgnum) " . +      "JOIN part_pkg USING (pkgpart) " . +      "WHERE cust_bill_pkg.invnum = cust_bill.invnum " . +      "AND COALESCE(part_pkg.classnum, -1) != $ignore_pkgclass" . +      " )"; +  } +  #warn "$where\n"; +  return 0 if FS::cust_bill->count($where); +    1;  }  sub condition_sql {    my( $class, $table, %opt ) = @_;    my $age   = $class->condition_sql_option_age_from('age', $opt{'time'}); +  my $ignore_pkgclass = $class->condition_sql_option_integer('ignore_pkgclass'); +  # will evaluate to zero if there isn't one    my @sql; -  for my $t (qw(cust_bill cust_pay cust_credit cust_refund)) { +  for my $t (qw(cust_pay cust_credit cust_refund)) {      push @sql,        "NOT EXISTS( SELECT 1 FROM $t ".        "WHERE $t.custnum = cust_main.custnum AND $t._date >= $age".        ")";    } +  #cust_bill +  push @sql, +    "NOT EXISTS( ". +    "SELECT 1 FROM cust_bill JOIN cust_bill_pkg USING (invnum) ". +    "JOIN cust_pkg USING (pkgnum) JOIN part_pkg USING (pkgpart) ". +    "WHERE cust_bill.custnum = cust_main.custnum ". +    "AND cust_bill._date >= $age ". +    "AND COALESCE(part_pkg.classnum, -1) != $ignore_pkgclass ". +    ")";    join(' AND ', @sql);  } diff --git a/rt/lib/RT/Interface/Web_Vendor.pm b/rt/lib/RT/Interface/Web_Vendor.pm index ee8c34b55..6218641a7 100644 --- a/rt/lib/RT/Interface/Web_Vendor.pm +++ b/rt/lib/RT/Interface/Web_Vendor.pm @@ -533,5 +533,32 @@ sub ProcessUpdateMessage {      return @results;  } +sub default_FormatDate { $_[0]->AsString } + +sub ProcessColumnMapValue { +    my $value = shift; +    my %args = ( Arguments => [], +                 Escape => 1, +                 FormatDate => \&default_FormatDate, +                 @_ ); + +    if ( ref $value ) { +        if ( ref $value eq 'RT::Date' ) { +            return $args{FormatDate}->($value); +        } elsif ( UNIVERSAL::isa( $value, 'CODE' ) ) { +            my @tmp = $value->( @{ $args{'Arguments'} } ); +            return ProcessColumnMapValue( ( @tmp > 1 ? \@tmp : $tmp[0] ), %args ); +        } elsif ( UNIVERSAL::isa( $value, 'ARRAY' ) ) { +            return join '', map ProcessColumnMapValue( $_, %args ), @$value; +        } elsif ( UNIVERSAL::isa( $value, 'SCALAR' ) ) { +            return $$value; +        } +    } + +    return $m->interp->apply_escapes( $value, 'h' ) if $args{'Escape'}; +    return $value; +} + +  1; diff --git a/rt/share/html/Elements/ColumnMap b/rt/share/html/Elements/ColumnMap index 2d226dafc..c81dbb8a5 100644 --- a/rt/share/html/Elements/ColumnMap +++ b/rt/share/html/Elements/ColumnMap @@ -64,8 +64,7 @@ my $COLUMN_MAP = {      Created => {          attribute => 'Created',          title     => 'Created', # loc -        date      => sub { return $_[0]->CreatedObj }, -        value     => sub { return $_[0]->CreatedObj->AsString } +        value     => sub { return $_[0]->CreatedObj },      },      CreatedRelative => {          attribute => 'Created', @@ -80,8 +79,7 @@ my $COLUMN_MAP = {      LastUpdated => {          attribute => 'LastUpdated',          title     => 'Last Updated', # loc -        date      => sub { return $_[0]->LastUpdatedObj }, -        value     => sub { return $_[0]->LastUpdatedObj->AsString } +        value     => sub { return $_[0]->LastUpdatedObj },      },      LastUpdatedRelative => {          attribute => 'LastUpdated', @@ -101,15 +99,31 @@ my $COLUMN_MAP = {              # Display custom field contents, separated by newlines.              # For Image custom fields we also show a thumbnail here. -            my $values = $_[0]->CustomFieldValues( $_[-1] ); -            my @values = map { -                ( -                    ($_->CustomFieldObj->Type eq 'Image') -                        ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ )) -                        : $_->Content -                ), -                \'<br />', -            } @{ $values->ItemsArrayRef }; +            my $object = shift; +            my $cfname = pop; +            my $values = $object->CustomFieldValues( $cfname ); +            return if $values->Count == 0; +            my @values; +            # it is guaranteed to be the same type for all fields, right? +            my $v = $values->First; +            my $cftype = $v->CustomFieldObj->Type; + +            do { +                if ($cftype eq 'Image') { +                    push @values,  +                        \($m->scomp( '/Elements/ShowCustomFieldImage', +                                      Object => $v )); +                } elsif ( $cftype eq 'Date' or $cftype eq 'DateTime' ) { +                    # then actually return the date object; +                    # ProcessColumnMapValue will stringify it +                    my $DateObj = RT::Date->new( $session{'CurrentUser'} ); +                    $DateObj->Set(Format => 'unknown', Value => $v->Content); +                    push @values, $DateObj; +                } else { +                    push @values, $v->Content; +                } +                push @values, \'<br />'; # this is deeply silly +            } while ($v = $values->Next);              pop @values; # Remove that last <br />              return @values;          }, diff --git a/rt/share/html/Elements/RT__Ticket/ColumnMap b/rt/share/html/Elements/RT__Ticket/ColumnMap index 9e6466cdd..9cceaf6ca 100644 --- a/rt/share/html/Elements/RT__Ticket/ColumnMap +++ b/rt/share/html/Elements/RT__Ticket/ColumnMap @@ -220,32 +220,27 @@ $COLUMN_MAP = {      Starts => {          title     => 'Starts', # loc          attribute => 'Starts', -        date      => sub { return $_[0]->StartsObj }, -        value     => sub { return $_[0]->StartsObj->AsString } +        value     => sub { return $_[0]->StartsObj }      },      Started => {          title     => 'Started', # loc          attribute => 'Started', -        date      => sub { return $_[0]->StartedObj }, -        value     => sub { return $_[0]->StartedObj->AsString } +        value     => sub { return $_[0]->StartedObj },      },      Told => {          title     => 'Told', # loc          attribute => 'Told', -        date      => sub { return $_[0]->ToldObj }, -        value     => sub { return $_[0]->ToldObj->AsString } +        value     => sub { return $_[0]->ToldObj },      },      Due => {          title     => 'Due', # loc          attribute => 'Due', -        date      => sub { return $_[0]->DueObj }, -        value     => sub { return $_[0]->DueObj->AsString } +        value     => sub { return $_[0]->DueObj },      },      Resolved => {          title     => 'Resolved', # loc          attribute => 'Resolved', -        date      => sub { return $_[0]->ResolvedObj }, -        value     => sub { return $_[0]->ResolvedObj->AsString } +        value     => sub { return $_[0]->ResolvedObj }      },      UpdateStatus => {          title => 'New messages', # loc diff --git a/rt/share/html/Search/Elements/ResultsStructuredView b/rt/share/html/Search/Elements/ResultsStructuredView index 495f0d0c8..0e9457c45 100644 --- a/rt/share/html/Search/Elements/ResultsStructuredView +++ b/rt/share/html/Search/Elements/ResultsStructuredView @@ -132,7 +132,7 @@ while ( my $Ticket = $Tickets->Next()) {              if ( !exists $ColumnMap->{$col}{'value'} ) {                  my $map = {}; -                foreach ('attribute', 'value', 'date') { +                foreach ('attribute', 'value') {                      $map->{$_} = $m->comp(                          '/Elements/ColumnMap',                          Class => 'RT__Ticket', @@ -140,19 +140,13 @@ while ( my $Ticket = $Tickets->Next()) {                          Attr  => $_,                      );                  } -                # Canonicalize dates -                if ( defined $map->{'date'} ) { -                    $map->{value} = sub {  -                        my $DateObj = $map->{'date'}->(@_) or return undef; -                        $FormatDate->($DateObj); -                    }; -                }                  $ColumnMap->{$col} = $map;              }              push @out, ProcessColumnMapValue(                  $ColumnMap->{$col}{'value'},                  Arguments => [ $Ticket, $row ], +                FormatDate => $FormatDate,              );          } #foreach $subcol          $value = join('', '<span>', @out, '</span>'); | 
