summaryrefslogtreecommitdiff
path: root/FS/FS/part_pkg
diff options
context:
space:
mode:
authorJonathan Prykop <jonathan@freeside.biz>2016-07-16 15:43:42 -0500
committerJonathan Prykop <jonathan@freeside.biz>2016-08-14 19:16:38 -0500
commit0edd5b9d5c03f02341b1004888f0f712c8defb47 (patch)
tree6b0de01c7062d45ff852a88966e5764efb762ced /FS/FS/part_pkg
parent630a48c51cc20dd2e2c2a09a61999e5a0ae3e5ba (diff)
RT#38973: Bill for time worked on ticket resolution [checkpoint, not ready for backport]
Diffstat (limited to 'FS/FS/part_pkg')
-rw-r--r--FS/FS/part_pkg/rt_field.pm177
1 files changed, 177 insertions, 0 deletions
diff --git a/FS/FS/part_pkg/rt_field.pm b/FS/FS/part_pkg/rt_field.pm
new file mode 100644
index 0000000..1b18720
--- /dev/null
+++ b/FS/FS/part_pkg/rt_field.pm
@@ -0,0 +1,177 @@
+package FS::part_pkg::rt_field;
+
+use strict;
+use FS::Conf;
+use FS::TicketSystem;
+use FS::Record qw(qsearchs qsearch);
+use FS::part_pkg::recur_Common;
+use FS::part_pkg::global_Mixin;
+use FS::rt_field_charge;
+
+our @ISA = qw(FS::part_pkg::recur_Common);
+
+our $DEBUG = 0;
+
+use vars qw( $conf $money_char );
+
+FS::UID->install_callback( sub {
+ $conf = new FS::Conf;
+ $money_char = $conf->config('money_char') || '$';
+});
+
+my %custom_field = (
+ 'type' => 'select-rt-customfield',
+ 'lookuptype' => 'RT::Queue-RT::Ticket',
+);
+
+our %info = (
+ 'name' => 'Bill from custom fields in resolved RT tickets',
+ 'shortname' => 'RT custom rate',
+ 'weight' => 65,
+ 'inherit_fields' => [ 'global_Mixin' ],
+ 'fields' => {
+ 'unit_field' => { 'name' => 'Units field',
+ %custom_field,
+ 'validate' => sub { return ${$_[1]} ? '' : 'Units field must be specified' },
+ },
+ 'rate_field' => { 'name' => 'Charge per unit (from RT field)',
+ %custom_field,
+ 'empty_label' => '',
+ },
+ 'rate_flat' => { 'name' => 'Charge per unit (flat)',
+ 'validate' => \&FS::part_pkg::global_Mixin::validate_moneyn },
+ 'display_fields' => { 'name' => 'Display fields',
+ %custom_field,
+ 'multiple' => 1,
+ 'parse' => sub { @_ }, # because /edit/process/part_pkg.pm doesn't grok select multiple
+ },
+ # from global_Mixin, but don't get used by this at all
+ 'unused_credit_cancel' => {'disabled' => 1},
+ 'unused_credit_suspend' => {'disabled' => 1},
+ 'unused_credit_change' => {'disabled' => 1},
+ },
+ 'validate' => sub {
+ my $options = shift;
+ return 'Rate must be specified'
+ unless $options->{'rate_field'} or $options->{'rate_flat'};
+ return 'Cannot specify both flat rate and rate field'
+ if $options->{'rate_field'} and $options->{'rate_flat'};
+ return '';
+ },
+ 'fieldorder' => [ 'unit_field', 'rate_field', 'rate_flat', 'display_fields' ]
+);
+
+sub price_info {
+ my $self = shift;
+ my $str = $self->SUPER::price_info;
+ $str .= ' plus ' if $str;
+ FS::TicketSystem->init();
+ my %custom_fields = FS::TicketSystem->custom_fields();
+ my $rate = $self->option('rate_flat',1);
+ my $rate_field = $self->option('rate_field',1);
+ my $unit_field = $self->option('unit_field');
+ $str .= $rate
+ ? $money_char . sprintf("%.2",$rate)
+ : $custom_fields{$rate_field};
+ $str .= ' x ' . $custom_fields{$unit_field};
+ return $str;
+}
+
+sub calc_setup {
+ my($self, $cust_pkg ) = @_;
+ $self->option('setup_fee');
+}
+
+sub calc_recur {
+ my $self = shift;
+ my($cust_pkg, $sdate, $details, $param ) = @_;
+
+ my $charges = 0;
+
+ $charges += $self->calc_usage(@_);
+ $charges += ($cust_pkg->quantity || 1) * $self->calc_recur_Common(@_);
+
+ $charges;
+
+}
+
+sub can_discount { 0; }
+
+sub calc_usage {
+ my $self = shift;
+ my($cust_pkg, $sdate, $details, $param ) = @_;
+
+ FS::TicketSystem->init();
+
+ # not date delimited--load all resolved tickets
+ # will subtract previous charges below
+ # only way to be sure we've caught everything
+ # limit set to be arbitrarily large (10000)
+ my $tickets = FS::TicketSystem->customer_tickets( $cust_pkg->custnum, 10000, undef, 'resolved');
+
+ my $rate = $self->option('rate_flat',1);
+ my $rate_field = $self->option('rate_field',1);
+ my $unit_field = $self->option('unit_field');
+ my @display_fields = split(', ',$self->option('display_fields',1) || '');
+
+ my %custom_fields = FS::TicketSystem->custom_fields();
+ my $rate_label = $rate
+ ? ''
+ : ' ' . $custom_fields{$rate_field};
+ my $unit_label = $custom_fields{$unit_field};
+
+ $rate_field = 'CF.{' . $rate_field . '}' if $rate_field;
+ $unit_field = 'CF.{' . $unit_field . '}';
+
+ my $charges = 0;
+ foreach my $ticket ( @$tickets ) {
+ next unless $ticket->{$unit_field};
+ next unless $rate || $ticket->{$rate_field};
+ my $trate = $rate || $ticket->{$rate_field};
+ my $tunit = $ticket->{$unit_field};
+ my $subcharge = sprintf('%.2f', $trate * $tunit);
+ my $precharge = _previous_charges( $cust_pkg->pkgnum, $ticket->{'id'} );
+ $subcharge -= $precharge;
+
+ # if field values for previous charges increased,
+ # we can make additional charges here and now,
+ # but if field values were decreased, we just ignore--
+ # credits will have to be applied manually later, if that's what's intended
+ next if $subcharge <= 0;
+
+ my $rt_field_charge = new FS::rt_field_charge {
+ 'pkgnum' => $cust_pkg->pkgnum,
+ 'ticketid' => $ticket->{'id'},
+ 'rate' => $trate,
+ 'units' => $tunit,
+ 'charge' => $subcharge,
+ '_date' => $$sdate,
+ };
+ my $error = $rt_field_charge->insert;
+ die "Error inserting rt_field_charge: $error" if $error;
+ push @$details, $money_char . sprintf('%.2f',$trate) . $rate_label . ' x ' . $tunit . ' ' . $unit_label;
+ push @$details, ' - ' . $money_char . sprintf('%.2f',$precharge) . ' previously charged' if $precharge;
+ foreach my $field (
+ sort { $ticket->{'_cf_sort_order'}{$a} <=> $ticket->{'_cf_sort_order'}{$b} } @display_fields
+ ) {
+ my $label = $custom_fields{$field};
+ my $value = $ticket->{'CF.{' . $field . '}'};
+ push @$details, $label . ': ' . $value if $value;
+ }
+ $charges += $subcharge;
+ }
+ return $charges;
+}
+
+sub _previous_charges {
+ my ($pkgnum, $ticketid) = @_;
+ my $prev = 0;
+ foreach my $rt_field_charge (
+ qsearch('rt_field_charge', { pkgnum => $pkgnum, ticketid => $ticketid })
+ ) {
+ $prev += $rt_field_charge->charge;
+ }
+ return $prev;
+}
+
+1;