1 package FS::ClientAPI::MyAccount::quotation;
4 use FS::Record qw(qsearch qsearchs);
10 sub _custoragent_session_custnum {
11 FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
15 # the currently active quotation
18 if ( my $quotationnum = $session->{'quotationnum'} ) {
19 $quotation = FS::quotation->by_key($quotationnum);
22 # find the last quotation created through selfservice
23 $quotation = qsearchs( 'quotation', {
24 'custnum' => $session->{'custnum'},
25 'usernum' => $FS::CurrentUser::CurrentUser->usernum,
28 warn "found selfservice quotation #". $quotation->quotationnum."\n"
29 if $quotation and $DEBUG;
32 $quotation = FS::quotation->new({
33 'custnum' => $session->{'custnum'},
34 'usernum' => $FS::CurrentUser::CurrentUser->usernum,
37 $quotation->insert; # what to do on error? call the police?
38 warn "started new selfservice quotation #". $quotation->quotationnum."\n"
39 if $quotation and $DEBUG;
41 $session->{'quotationnum'} = $quotation->quotationnum;
45 =item quotation_info { session }
47 Returns a hashref describing the current quotation, containing:
49 - "sections", an arrayref containing one section for each billing frequency.
53 - "detail_items", an arrayref of detail items, each with:
54 - "pkgnum", the reference number (actually the quotationpkgnum field)
55 - "description", the package name (or tax name)
64 my($context, $session, $custnum) = _custoragent_session_custnum($p);
65 return { 'error' => $session } if $context eq 'error';
67 my $quotation = _quotation($session);
68 return { 'error' => "No current quotation for this customer" } if !$quotation;
69 warn "quotation_info #".$quotation->quotationnum
73 my $null_escape = sub { @_ };
74 my ($sections) = $quotation->_items_sections(escape => $null_escape);
75 foreach my $section (@$sections) {
76 $section->{'detail_items'} =
77 [ $quotation->_items_pkg('section' => $section, escape_function => $null_escape) ];
79 return { 'error' => '', 'sections' => $sections }
82 =item quotation_print { session, 'format' }
84 Renders the quotation. 'format' can be either 'html' or 'pdf'; the resulting
85 hashref will contain 'document' => the HTML or PDF contents.
92 my($context, $session, $custnum) = _custoragent_session_custnum($p);
93 return { 'error' => $session } if $context eq 'error';
95 my $quotation = _quotation($session);
96 return { 'error' => "No current quotation for this customer" } if !$quotation;
97 warn "quotation_print #".$quotation->quotationnum
100 my $format = $p->{'format'}
101 or return { 'error' => "No rendering format specified" };
104 if ($format eq 'html') {
105 $document = $quotation->print_html;
106 } elsif ($format eq 'pdf') {
107 $document = $quotation->print_pdf;
109 warn "$format, ".length($document)." bytes\n"
111 return { 'error' => '', 'document' => $document };
114 =item quotation_add_pkg { session, 'pkgpart', 'quantity', [ location opts ] }
116 Adds a package to the user's current quotation. Session info and 'pkgpart' are
117 required. 'quantity' defaults to 1.
119 Location can be specified as 'locationnum' to use an existing location, or
120 'address1', 'address2', 'city', 'state', 'zip', 'country' to create a new one,
121 or it will default to the customer's service location.
125 sub quotation_add_pkg {
128 my($context, $session, $custnum) = _custoragent_session_custnum($p);
129 return { 'error' => $session } if $context eq 'error';
131 my $quotation = _quotation($session);
132 my $cust_main = $quotation->cust_main;
134 my $pkgpart = $p->{'pkgpart'};
135 my $allowed_pkgpart = $cust_main->agent->pkgpart_hashref;
137 my $part_pkg = FS::part_pkg->by_key($pkgpart);
139 if (!$part_pkg or !$allowed_pkgpart->{$pkgpart}) {
140 warn "disallowed quotation_pkg pkgpart $pkgpart\n"
142 return { 'error' => "unknown package $pkgpart" };
145 warn "creating quotation_pkg with pkgpart $pkgpart\n"
147 my $quotation_pkg = FS::quotation_pkg->new({
148 'quotationnum' => $quotation->quotationnum,
149 'pkgpart' => $p->{'pkgpart'},
150 'quantity' => $p->{'quantity'} || 1,
152 if ( $p->{locationnum} > 0 ) {
153 $quotation_pkg->set('locationnum', $p->{locationnum});
154 } elsif ( $p->{address1} ) {
155 my $location = FS::cust_location->find_or_insert(
156 'custnum' => $cust_main->custnum,
157 map { $_ => $p->{$_} }
158 qw( address1 address2 city county state zip country )
160 $quotation_pkg->set('locationnum', $location->locationnum);
163 my $error = $quotation_pkg->insert
164 || $quotation->estimate;
167 'quotationnum' => $quotation->quotationnum };
170 =item quotation_remove_pkg { session, 'pkgnum' }
172 Removes the package from the user's current quotation. 'pkgnum' is required.
176 sub quotation_remove_pkg {
179 my($context, $session, $custnum) = _custoragent_session_custnum($p);
180 return { 'error' => $session } if $context eq 'error';
182 my $quotation = _quotation($session);
183 my $quotationpkgnum = $p->{pkgnum};
184 my $quotation_pkg = FS::quotation_pkg->by_key($quotationpkgnum);
186 or $quotation_pkg->quotationnum != $quotation->quotationnum) {
187 return { 'error' => "unknown quotation item $quotationpkgnum" };
189 warn "removing quotation_pkg with pkgpart ".$quotation_pkg->pkgpart."\n"
192 my $error = $quotation_pkg->delete
193 || $quotation->estimate;
196 'quotationnum' => $quotation->quotationnum };
199 =item quotation_order
201 Convert the current quotation to a package order.
205 sub quotation_order {
208 my($context, $session, $custnum) = _custoragent_session_custnum($p);
209 return { 'error' => $session } if $context eq 'error';
211 my $quotation = _quotation($session);
213 my $error = $quotation->order;
214 $quotation->set('disabled' => 'Y');
215 $error ||= $quotation->replace;
217 return { 'error' => $error };