2 use base qw( FS::Template_Mixin FS::cust_main_Mixin FS::otaker_Mixin FS::Record
14 FS::quotation - Object methods for quotation records
20 $record = new FS::quotation \%hash;
21 $record = new FS::quotation { 'column' => 'value' };
23 $error = $record->insert;
25 $error = $new_record->replace($old_record);
27 $error = $record->delete;
29 $error = $record->check;
33 An FS::quotation object represents a quotation. FS::quotation inherits from
34 FS::Record. The following fields are currently supported:
71 Creates a new quotation. To add the quotation to the database, see L<"insert">.
73 Note that this stores the hash reference, not a distinct copy of the hash it
74 points to. You can ask the object for a copy with the I<hash> method.
78 sub table { 'quotation'; }
79 sub notice_name { 'Quotation'; }
80 sub template_conf { 'quotation_'; }
84 Adds this record to the database. If there is an error, returns the error,
85 otherwise returns false.
89 Delete this record from the database.
91 =item replace OLD_RECORD
93 Replaces the OLD_RECORD with this one in the database. If there is an error,
94 returns the error, otherwise returns false.
98 Checks all fields to make sure this is a valid quotation. If there is
99 an error, returns the error, otherwise returns false. Called by the insert
108 $self->ut_numbern('quotationnum')
109 || $self->ut_foreign_keyn('prospectnum', 'prospect_main', 'prospectnum' )
110 || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum' )
111 || $self->ut_numbern('_date')
112 || $self->ut_enum('disabled', [ '', 'Y' ])
113 || $self->ut_numbern('usernum')
115 return $error if $error;
117 $self->_date(time) unless $self->_date;
119 $self->usernum($FS::CurrentUser::CurrentUser->usernum) unless $self->usernum;
132 sub cust_bill_pkg { #actually quotation_pkg objects
133 shift->quotation_pkg(@_);
142 $self->_total('setup');
145 =item total_recur [ FREQ ]
151 #=item total_recur [ FREQ ]
152 #my $freq = @_ ? shift : '';
153 $self->_total('recur');
157 my( $self, $method ) = @_;
160 $total += $_->$method() for $self->cust_bill_pkg;
161 sprintf('%.2f', $total);
165 #prevent things from falsely showing up as taxes, at least until we support
166 # quoting tax amounts..
171 shift->cust_bill_pkg;
175 my( $self, $total_items ) = @_;
177 if ( $self->total_setup > 0 ) {
178 push @$total_items, {
179 'total_item' => $self->mt( $self->total_recur > 0 ? 'Total Setup' : 'Total' ),
180 'total_amount' => $self->total_setup,
184 #could/should add up the different recurring frequencies on lines of their own
185 # but this will cover the 95% cases for now
186 if ( $self->total_recur > 0 ) {
187 push @$total_items, {
188 'total_item' => $self->mt('Total Recurring'),
189 'total_amount' => $self->total_recur,
195 =item enable_previous
199 sub enable_previous { 0 }
201 =item convert_cust_main
203 If this quotation already belongs to a customer, then returns that customer, as
204 an FS::cust_main object.
206 Otherwise, creates a new customer (FS::cust_main object and record, and
207 associated) based on this quotation's prospect, then orders this quotation's
208 packages as real packages for the customer.
210 If there is an error, returns an error message, otherwise, returns the
211 newly-created FS::cust_main object.
215 sub convert_cust_main {
218 my $cust_main = $self->cust_main;
219 return $cust_main if $cust_main; #already converted, don't again
221 my $oldAutoCommit = $FS::UID::AutoCommit;
222 local $FS::UID::AutoCommit = 0;
225 $cust_main = $self->prospect_main->convert_cust_main;
226 unless ( ref($cust_main) ) { # eq 'FS::cust_main' ) {
227 $dbh->rollback if $oldAutoCommit;
231 $self->prospectnum('');
232 $self->custnum( $cust_main->custnum );
233 my $error = $self->replace || $self->order;
235 $dbh->rollback if $oldAutoCommit;
239 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
247 This method is for use with quotations which are already associated with a customer.
249 Orders this quotation's packages as real packages for the customer.
251 If there is an error, returns an error message, otherwise returns false.
258 tie my %cust_pkg, 'Tie::RefHash',
259 map { FS::cust_pkg->new({ pkgpart => $_->pkgpart,
260 quantity => $_->quantity,
264 $self->quotation_pkg ;
266 $self->cust_main->order_pkgs( \%cust_pkg );
277 =item search_sql_where HASHREF
279 Class method which returns an SQL WHERE fragment to search for parameters
280 specified in HASHREF. Valid parameters are
286 List reference of start date, end date, as UNIX timestamps.
296 List reference of charged limits (exclusive).
300 List reference of charged limits (exclusive).
304 flag, return open invoices only
308 flag, return net invoices only
316 Note: validates all passed-in data; i.e. safe to use with unchecked CGI params.
320 sub search_sql_where {
321 my($class, $param) = @_;
323 # warn "$me search_sql_where called with params: \n".
324 # join("\n", map { " $_: ". $param->{$_} } keys %$param ). "\n";
330 if ( $param->{'agentnum'} =~ /^(\d+)$/ ) {
331 push @search, "( prospect_main.agentnum = $1 OR cust_main.agentnum = $1 )";
335 # if ( $param->{'refnum'} =~ /^(\d+)$/ ) {
336 # push @search, "cust_main.refnum = $1";
340 if ( $param->{'prospectnum'} =~ /^(\d+)$/ ) {
341 push @search, "quotation.prospectnum = $1";
345 if ( $param->{'custnum'} =~ /^(\d+)$/ ) {
346 push @search, "cust_bill.custnum = $1";
350 if ( $param->{_date} ) {
351 my($beginning, $ending) = @{$param->{_date}};
353 push @search, "quotation._date >= $beginning",
354 "quotation._date < $ending";
358 if ( $param->{'quotationnum_min'} =~ /^(\d+)$/ ) {
359 push @search, "quotation.quotationnum >= $1";
361 if ( $param->{'quotationnum_max'} =~ /^(\d+)$/ ) {
362 push @search, "quotation.quotationnum <= $1";
366 # if ( $param->{charged} ) {
367 # my @charged = ref($param->{charged})
368 # ? @{ $param->{charged} }
369 # : ($param->{charged});
371 # push @search, map { s/^charged/cust_bill.charged/; $_; }
375 my $owed_sql = FS::cust_bill->owed_sql;
378 push @search, "quotation._date < ". (time-86400*$param->{'days'})
381 #agent virtualization
382 my $curuser = $FS::CurrentUser::CurrentUser;
383 #false laziness w/search/quotation.html
384 push @search,' ( '. $curuser->agentnums_sql( table=>'prospect_main' ).
385 ' OR '. $curuser->agentnums_sql( table=>'cust_main' ).
388 join(' AND ', @search );
398 L<FS::Record>, schema.html from the base documentation.