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
72 my $null_escape = sub { @_ };
73 # 3.x only; 4.x quotation redesign uses actual sections for this
74 # and isn't a weird hack
76 map { $_->{'pkgnum'} = $_->{'preref_html'}; $_ }
77 $quotation->_items_pkg(escape_function => $null_escape,
78 preref_callback => sub { shift->quotationpkgnum });
79 push @items, $quotation->_items_total();
82 { 'description' => 'Estimated Charges',
83 'detail_items' => \@items
87 return { 'error' => '', 'sections' => $sections }
90 =item quotation_print { session, 'format' }
92 Renders the quotation. 'format' can be either 'html' or 'pdf'; the resulting
93 hashref will contain 'document' => the HTML or PDF contents.
100 my($context, $session, $custnum) = _custoragent_session_custnum($p);
101 return { 'error' => $session } if $context eq 'error';
103 my $quotation = _quotation($session);
104 return { 'error' => "No current quotation for this customer" } if !$quotation;
105 warn "quotation_print #".$quotation->quotationnum
108 my $format = $p->{'format'}
109 or return { 'error' => "No rendering format specified" };
112 if ($format eq 'html') {
113 $document = $quotation->print_html;
114 } elsif ($format eq 'pdf') {
115 $document = $quotation->print_pdf;
117 warn "$format, ".length($document)." bytes\n"
119 return { 'error' => '', 'document' => $document };
122 =item quotation_add_pkg { session, 'pkgpart', 'quantity', [ location opts ] }
124 Adds a package to the user's current quotation. Session info and 'pkgpart' are
125 required. 'quantity' defaults to 1.
127 Location can be specified as 'locationnum' to use an existing location, or
128 'address1', 'address2', 'city', 'state', 'zip', 'country' to create a new one,
129 or it will default to the customer's service location.
133 sub quotation_add_pkg {
136 my($context, $session, $custnum) = _custoragent_session_custnum($p);
137 return { 'error' => $session } if $context eq 'error';
139 my $quotation = _quotation($session);
140 my $cust_main = $quotation->cust_main;
142 my $pkgpart = $p->{'pkgpart'};
143 my $allowed_pkgpart = $cust_main->agent->pkgpart_hashref;
145 my $part_pkg = FS::part_pkg->by_key($pkgpart);
148 (!$allowed_pkgpart->{$pkgpart} and
149 $cust_main->agentnum != ($part_pkg->agentnum || 0))
151 warn "disallowed quotation_pkg pkgpart $pkgpart\n"
153 return { 'error' => "unknown package $pkgpart" };
156 warn "creating quotation_pkg with pkgpart $pkgpart\n"
158 my $quotation_pkg = FS::quotation_pkg->new({
159 'quotationnum' => $quotation->quotationnum,
160 'pkgpart' => $p->{'pkgpart'},
161 'quantity' => $p->{'quantity'} || 1,
163 if ( $p->{locationnum} > 0 ) {
164 $quotation_pkg->set('locationnum', $p->{locationnum});
165 } elsif ( $p->{address1} ) {
166 my $location = FS::cust_location->find_or_insert(
167 'custnum' => $cust_main->custnum,
168 map { $_ => $p->{$_} }
169 qw( address1 address2 city county state zip country )
171 $quotation_pkg->set('locationnum', $location->locationnum);
174 my $error = $quotation_pkg->insert
175 || $quotation->estimate;
178 'quotationnum' => $quotation->quotationnum };
181 =item quotation_remove_pkg { session, 'pkgnum' }
183 Removes the package from the user's current quotation. 'pkgnum' is required.
187 sub quotation_remove_pkg {
190 my($context, $session, $custnum) = _custoragent_session_custnum($p);
191 return { 'error' => $session } if $context eq 'error';
193 my $quotation = _quotation($session);
194 my $quotationpkgnum = $p->{pkgnum};
195 my $quotation_pkg = FS::quotation_pkg->by_key($quotationpkgnum);
197 or $quotation_pkg->quotationnum != $quotation->quotationnum) {
198 return { 'error' => "unknown quotation item $quotationpkgnum" };
200 warn "removing quotation_pkg with pkgpart ".$quotation_pkg->pkgpart."\n"
203 my $error = $quotation_pkg->delete
204 || $quotation->estimate;
207 'quotationnum' => $quotation->quotationnum };
210 =item quotation_order
212 Convert the current quotation to a package order.
216 sub quotation_order {
219 my($context, $session, $custnum) = _custoragent_session_custnum($p);
220 return { 'error' => $session } if $context eq 'error';
222 my $quotation = _quotation($session);
224 my $error = $quotation->order;
226 $quotation->set('disabled' => 'Y');
227 $error ||= $quotation->replace;
229 return { 'error' => $error };