use FS::contact_class;
use FS::part_svc_class;
use FS::ftp_target;
+ use FS::quotation;
+ use FS::quotation_pkg;
+ use FS::quotation_pkg_discount;
# Sammath Naur
if ( $FS::Mason::addl_handler_use ) {
--- /dev/null
+package FS::Quotable_Mixin;
+
+use strict;
+use FS::Record qw( qsearch ); #qsearchs );
+use FS::quotation;
+
+sub quotation {
+ my $self = shift;
+ my $pk = $self->primary_key;
+ qsearch('quotation', { $pk => $self->$pk() } );
+}
+
+1;
--- /dev/null
+package FS::quotation;
+
+use strict;
+use base qw( FS::otaker_Mixin FS::Record );
+use FS::Record; # qw( qsearch qsearchs );
+use FS::cust_main;
+use FS::prospect_main;
+
+=head1 NAME
+
+FS::quotation - Object methods for quotation records
+
+=head1 SYNOPSIS
+
+ use FS::quotation;
+
+ $record = new FS::quotation \%hash;
+ $record = new FS::quotation { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::quotation object represents a quotation. FS::quotation inherits from
+FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item quotationnum
+
+primary key
+
+=item prospectnum
+
+prospectnum
+
+=item custnum
+
+custnum
+
+=item _date
+
+_date
+
+=item disabled
+
+disabled
+
+=item usernum
+
+usernum
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new quotation. To add the quotation to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'quotation'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid quotation. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('quotationnum')
+ || $self->ut_foreign_keyn('prospectnum', 'prospect_main', 'prospectnum' )
+ || $self->ut_foreign_keyn('custnum', 'cust_main', 'custnum' )
+ || $self->ut_numbern('_date')
+ || $self->ut_enum('disabled', [ '', 'Y' ])
+ || $self->ut_numbern('usernum')
+ ;
+ return $error if $error;
+
+ $self->_date(time) unless $self->_date;
+
+ #XXX set usernum
+
+ $self->SUPER::check;
+}
+
+=item prospect_main
+
+=cut
+
+sub prospect_main {
+ my $self = shift;
+ qsearchs('prospect_main', { 'prospectnum' => $self->prospectnum } );
+}
+
+=item cust_main
+
+=cut
+
+sub cust_main {
+ my $self = shift;
+ qsearchs('cust_main', { 'custnum' => $self->custnum } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
--- /dev/null
+package FS::quotation_pkg;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record; # qw( qsearch qsearchs );
+use FS::part_pkg;
+use FS::cust_location;
+
+=head1 NAME
+
+FS::quotation_pkg - Object methods for quotation_pkg records
+
+=head1 SYNOPSIS
+
+ use FS::quotation_pkg;
+
+ $record = new FS::quotation_pkg \%hash;
+ $record = new FS::quotation_pkg { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::quotation_pkg object represents a quotation package.
+FS::quotation_pkg inherits from FS::Record. The following fields are currently
+supported:
+
+=over 4
+
+=item quotationpkgnum
+
+primary key
+
+=item pkgpart
+
+pkgpart
+
+=item locationnum
+
+locationnum
+
+=item start_date
+
+start_date
+
+=item contract_end
+
+contract_end
+
+=item quantity
+
+quantity
+
+=item waive_setup
+
+waive_setup
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new quotation package. To add the quotation package to the database,
+see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'quotation_pkg'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid quotation package. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('quotationpkgnum')
+ || $self->ut_foreign_key('pkgpart', 'part_pkg', 'pkgpart' )
+ || $self->ut_foreign_keyn('locationnum', 'cust_location', 'locationnum' )
+ || $self->ut_numbern('start_date')
+ || $self->ut_numbern('contract_end')
+ || $self->ut_numbern('quantity')
+ || $self->ut_enum('waive_setup', [ '', 'Y'] )
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
--- /dev/null
+package FS::quotation_pkg_discount;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::quotation_pkg_discount - Object methods for quotation_pkg_discount records
+
+=head1 SYNOPSIS
+
+ use FS::quotation_pkg_discount;
+
+ $record = new FS::quotation_pkg_discount \%hash;
+ $record = new FS::quotation_pkg_discount { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::quotation_pkg_discount object represents a quotation package discount.
+FS::quotation_pkg_discount inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item quotationpkgdiscountnum
+
+primary key
+
+=item quotationpkgnum
+
+quotationpkgnum
+
+=item discountnum
+
+discountnum
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new quotation package discount. To add the quotation package
+discount to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'quotation_pkg_discount'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid quotation package discount.
+If there is an error, returns the error, otherwise returns false.
+Called by the insert and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('quotationpkgdiscountnum')
+ || $self->ut_foreign_key('quotationpkgnum', 'quotation_pkg', 'quotationpkgnum' )
+ || $self->ut_foreign_key('discountnum', 'discount', 'discountnum' )
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::Quotable_Mixin;
+$loaded=1;
+print "ok 1\n";
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::quotation;
+$loaded=1;
+print "ok 1\n";
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::quotation_pkg;
+$loaded=1;
+print "ok 1\n";
--- /dev/null
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::quotation_pkg_discount;
+$loaded=1;
+print "ok 1\n";
--- /dev/null
+<% include( 'elements/process.html',
+ 'table' => 'quotation',
+ 'redirect' => $p.'view/quotation.html?',
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Generate quotation');
+
+</%init>
--- /dev/null
+<% include( 'elements/edit.html',
+ 'name' => 'Quotation',
+ 'table' => 'quotation',
+ 'labels' => {
+ 'quotationnum' => 'Quotation number',
+ },
+ #XXX some way to disable the "view all"
+ )
+%>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Generate quotation');
+
+</%init>
--- /dev/null
+<& /elements/header.html, mt('Quotation View'), $menubar &>
+
+%#XXX link to order...
+
+<%doc>
+
+XXX resending quotations
+
+% if ( $curuser->access_right('Resend invoices') ) {
+
+ <A HREF="<% $p %>misc/send-invoice.cgi?method=print;<% $link %>"><% mt('Re-print this invoice') |h %></A>
+
+% if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) {
+ | <A HREF="<% $p %>misc/send-invoice.cgi?method=email;<% $link %>"><% mt('Re-email this invoice') |h %></A>
+% }
+
+% if ( $conf->exists('hylafax') && length($cust_bill->cust_main->fax) ) {
+ | <A HREF="<% $p %>misc/send-invoice.cgi?method=fax;<% $link %>"><% mt('Re-fax this invoice') |h %></A>
+% }
+
+ <BR><BR>
+
+% }
+
+XXX view typset quotation
+
+% if ( $conf->exists('invoice_latex') ) {
+
+ <A HREF="<% $p %>view/cust_bill-pdf.cgi?<% $link %>"><% mt('View typeset invoice PDF') |h %></A>
+ <BR><BR>
+% }
+
+XXX actually show the quotation
+
+% if ( $conf->exists('invoice_html') ) {
+ <% join('', $cust_bill->print_html(\%opt) ) %>
+% } else {
+ <PRE><% join('', $cust_bill->print_text(\%opt) ) %></PRE>
+% }
+
+</%doc>
+
+<& /elements/footer.html &>
+<%init>
+
+my $curuser = $FS::CurrentUser::CurrentUser;
+
+#die "access denied"
+# unless $curuser->access_right('View quotations');
+
+my $quotationnum;
+my($query) = $cgi->keywords;
+if ( $query =~ /^(\d+)$/ ) {
+ $quotationnum = $1;
+} else {
+ $quotationnum = $cgi->param('quotationnum');
+}
+
+#my $conf = new FS::Conf;
+
+my $quotation = qsearchs({
+ 'select' => 'quotation.*',
+ 'table' => 'quotation',
+ #'addl_from' => 'LEFT JOIN cust_main USING ( custnum )',
+ 'hashref' => { 'quotationnum' => $quotationnum },
+ #'extra_sql' => ' AND '. $curuser->agentnums_sql,
+});
+die "Quotation #$quotationnum not found!" unless $quotation;
+
+if ( my $custnum = $quotation->custnum ) {
+ my $display_custnum = $quotation->cust_main->display_custnum;
+ $menubar = menubar(
+ emt("View this customer (#[_1])",$display_custnum) => "${p}view/cust_main.cgi?$custnum",
+ );
+} elsif ( my $prospectnum = $quotation->prospectnum ) {
+ $menubar = menubar(
+ emt("View this prospect (#[_1])",$prospectnum) => "${p}view/prospect_main.html?$prospectnum",
+ );
+}
+
+</%init>