X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fquotation.pm;h=a3f061291b4330dc404bc9cbc36255ffdce399ad;hp=f3bfc27f161a4a99d2083a3fe3e8286bf3935329;hb=046409735189fe40a1d349c4f1902da2bc1d71b2;hpb=9fe9b2f47608e1ea7387539a77a95023f9872bdf diff --git a/FS/FS/quotation.pm b/FS/FS/quotation.pm index f3bfc27f1..a3f061291 100644 --- a/FS/FS/quotation.pm +++ b/FS/FS/quotation.pm @@ -138,8 +138,9 @@ sub check { $self->usernum($FS::CurrentUser::CurrentUser->usernum) unless $self->usernum; - return 'confidence must be an integer between 1 and 100' - if length($self->confidence) && (($self->confidence < 1) || ($self->confidence > 100)); + return 'confidence percentage must be an integer between 1 and 100' + if length($self->confidence) + && ( ($self->confidence < 1) || ($self->confidence > 100) ); return 'prospectnum or custnum must be specified' if ! $self->prospectnum @@ -226,6 +227,11 @@ sub email_subject { eval qq("$subject"); } +sub pdf_filename { + my $self = shift; + 'Quotation-'. $self->quotationnum. '.pdf'; +} + =item cust_or_prosect =cut @@ -272,23 +278,24 @@ sub _items_sections { my %opt = @_; my $escape = $opt{escape}; # the only one we care about + my %show; # package frequency => 1 if there's anything to display my %subtotals = (); # package frequency => subtotal - my $disable_total = 0; + my $prorate_total = 0; foreach my $pkg ($self->quotation_pkg) { my $part_pkg = $pkg->part_pkg; my $recur_freq = $part_pkg->freq; - $show{$recur_freq} = 1 if $pkg->unitrecur > 0 or $part_pkg->recur_show_zero; - $show{0} = 1 if $pkg->unitsetup > 0 or $part_pkg->setup_show_zero; + $show{$recur_freq} = 1 if $pkg->unitrecur > 0 or $pkg->recur_show_zero; + $show{0} = 1 if $pkg->unitsetup > 0 or $pkg->setup_show_zero; ($subtotals{0} ||= 0) += $pkg->setup + $pkg->setup_tax; ($subtotals{$recur_freq} ||= 0) += $pkg->recur + $pkg->recur_tax; #this is a shitty hack based on what's in part_pkg/ at the moment # but its good enough for the 99% common case of preventing totals from # displaying for prorate packages - $disable_total = 1 + $prorate_total = 1 if $part_pkg->plan =~ /^(prorate|torrus|agent$)/ || $part_pkg->option('recur_method') eq 'prorate' || ( $part_pkg->option('sync_bill_date') @@ -296,6 +303,9 @@ sub _items_sections { && $self->cust_main->billing_pkgs #num_billing_pkgs when we have it ); + #possible improvement: keep track of flat vs. prorate totals to make the + # bottom range more accurate when mixing flat and prorate packages + } my @pkg_freq_order = keys %{ FS::Misc->pkg_freqs }; @@ -330,15 +340,31 @@ sub _items_sections { }; } - unless ( $disable_total || $no_recurring ) { + unless ( $no_recurring ) { my $total = 0; $total += $_ for values %subtotals; - push @sections, { - 'description' => 'First payment', + my %total = ( 'sort_weight' => 0, - 'category' => 'Total category', #required but what's it used for? - 'subtotal' => sprintf('%.2f',$total) - }; + 'category' => 'Total category', #required but what's it used for? + ); + + if ( $prorate_total ) { + + push @sections, { + %total, + 'description' => 'First payment (depending on day of month)', + 'subtotal' => [ $subtotals{0}, $total ], + }; + + } else { + + push @sections, { + %total, + 'description' => 'First payment', + 'subtotal' => $total, + }; + } + } return \@sections, []; @@ -350,7 +376,7 @@ sub _items_sections { sub enable_previous { 0 } -=item convert_cust_main +=item convert_cust_main [ PARAMS ] If this quotation already belongs to a customer, then returns that customer, as an FS::cust_main object. @@ -362,10 +388,13 @@ packages as real packages for the customer. If there is an error, returns an error message, otherwise, returns the newly-created FS::cust_main object. +Accepts the same params as L. + =cut sub convert_cust_main { my $self = shift; + my $params = shift || {}; my $cust_main = $self->cust_main; return $cust_main if $cust_main; #already converted, don't again @@ -382,7 +411,7 @@ sub convert_cust_main { $self->prospectnum(''); $self->custnum( $cust_main->custnum ); - my $error = $self->replace || $self->order; + my $error = $self->replace || $self->order(undef,$params); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -394,7 +423,7 @@ sub convert_cust_main { } -=item order [ HASHREF ] +=item order [ HASHREF ] [ PARAMS ] This method is for use with quotations which are already associated with a customer. @@ -406,11 +435,16 @@ If HASHREF is passed, it will be filled with a hash mapping the C of each quoted package to the C of the package as ordered. +If PARAMS hashref is passed, the following params are accepted: + +onhold - if true, suspends newly ordered packages + =cut sub order { my $self = shift; my $pkgnum_map = shift || {}; + my $params = shift || {}; my $details_map = {}; tie my %all_cust_pkg, 'Tie::RefHash'; @@ -461,10 +495,11 @@ sub order { } } - foreach my $quotationpkgnum (keys %$pkgnum_map) { - # convert the objects to just pkgnums - my $cust_pkg = $pkgnum_map->{$quotationpkgnum}; - $pkgnum_map->{$quotationpkgnum} = $cust_pkg->pkgnum; + if ($$params{'onhold'}) { + foreach my $quotationpkgnum (keys %$pkgnum_map) { + last if $error; + $error = $pkgnum_map->{$quotationpkgnum}->suspend(); + } } if ($error) { @@ -473,6 +508,13 @@ sub order { } $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + foreach my $quotationpkgnum (keys %$pkgnum_map) { + # convert the objects to just pkgnums + my $cust_pkg = $pkgnum_map->{$quotationpkgnum}; + $pkgnum_map->{$quotationpkgnum} = $cust_pkg->pkgnum; + } + ''; #no error } @@ -494,6 +536,7 @@ sub charge { my $cust_pkg_ref = ''; my ( $bill_now, $invoice_terms ) = ( 0, '' ); my $locationnum; + my ( $discountnum, $discountnum_amount, $discountnum_percent ) = ( '','','' ); if ( ref( $_[0] ) ) { $amount = $_[0]->{amount}; $setup_cost = $_[0]->{setup_cost}; @@ -513,6 +556,9 @@ sub charge { $bill_now = exists($_[0]->{bill_now}) ? $_[0]->{bill_now} : ''; $invoice_terms = exists($_[0]->{invoice_terms}) ? $_[0]->{invoice_terms} : ''; $locationnum = $_[0]->{locationnum}; + $discountnum = $_->{setup_discountnum}; + $discountnum_amount = $_->{setup_discountnum_amount}; + $discountnum_percent = $_->{setup_discountnum_percent}; } else { $amount = shift; $setup_cost = ''; @@ -583,12 +629,15 @@ sub charge { # of ordering a customer package, no "bill now") my $quotation_pkg = new FS::quotation_pkg ( { - 'quotationnum' => $self->quotationnum, - 'pkgpart' => $pkgpart, - 'quantity' => $quantity, - #'start_date' => $start_date, - #'no_auto' => $no_auto, - 'locationnum'=> $locationnum, + 'quotationnum' => $self->quotationnum, + 'pkgpart' => $pkgpart, + 'quantity' => $quantity, + #'start_date' => $start_date, + #'no_auto' => $no_auto, + 'locationnum' => $locationnum, + 'setup_discountnum' => $discountnum, + 'setup_discountnum_amount' => $discountnum_amount, + 'setup_discountnum_percent' => $discountnum_percent, } ); $error = $quotation_pkg->insert; @@ -667,7 +716,10 @@ sub estimate { my $cust_main; if ( $cust_or_prospect->isa('FS::prospect_main') ) { $cust_main = $cust_or_prospect->convert_cust_main; - die "$cust_main (simulating customer signup)\n" unless ref $cust_main; + unless ( ref($cust_main) ) { + $temp_dbh->rollback; + die "$cust_main (simulating customer signup)\n"; + } $fake_self->set('prospectnum', ''); $fake_self->set('custnum', $cust_main->custnum); } else { @@ -675,8 +727,12 @@ sub estimate { } # order packages + local($FS::cust_pkg::disable_start_on_hold) = 1; $error = $fake_self->order(\%pkgnum_of); - die "$error (simulating package order)\n" if $error; + if ( $error ) { + $temp_dbh->rollback; + die "$error (simulating package order)\n"; + } my @new_pkgs = map { FS::cust_pkg->by_key($_) } values(%pkgnum_of); @@ -689,7 +745,10 @@ sub estimate { 'no_usage_reset' => 1, ); $error = $cust_main->bill(%bill_opt); - die "$error (simulating initial billing)\n" if $error; + if ( $error ) { + $temp_dbh->rollback; + die "$error (simulating initial billing)\n" if $error; + } # pick dates for future bills my %next_bill_pkgs; @@ -705,7 +764,10 @@ sub estimate { $bill_opt{'return_bill'} = $return_bill[$i] = []; $bill_opt{'pkg_list'} = $next_bill_pkgs{$next_bill}; $error = $cust_main->bill(%bill_opt); - die "$error (simulating recurring billing cycle $i)\n" if $error; + if ( $error ) { + $temp_dbh->rollback; + die "$error (simulating recurring billing cycle $i)\n"; + } $i++; } @@ -1055,8 +1117,8 @@ sub _items_pkg { * $quotation_pkg->quantity); next if $this_item->{'amount'} == 0 and !( $setuprecur eq 'setup' - ? $part_pkg->setup_show_zero - : $part_pkg->recur_show_zero + ? $quotation_pkg->setup_show_zero + : $quotation_pkg->recur_show_zero ); if ( $preref ) {