},
{
+ 'key' => 'refund_receipt_msgnum',
+ 'section' => 'notification',
+ 'description' => 'Template to use for manual refund receipts.',
+ %msg_template_options,
+ },
+
+ {
'key' => 'trigger_export_insert_on_payment',
'section' => 'billing',
'description' => 'Enable exports on payment application.',
LEFT JOIN ($sales_credit) AS sales_credit USING (billpkgnum)
LEFT JOIN ($exempt_credit) AS exempt_credit USING (billpkgnum, taxnum)
$join_cust_pkg $where AND $nottax
- $group
+ $group_all
";
# also include the exempt-sales credit amount, for the credit report
LEFT JOIN ($exempt_credit) AS exempt_credit USING (taxnum)
JOIN cust_bill_pkg USING (billpkgnum)
$join_cust_pkg $where AND $nottax
- $group
+ $group_all
";
# taxable sales
sprintf("%.2f", $amount );
}
+=item send_receipt HASHREF | OPTION => VALUE ...
+
+Sends a payment receipt for this payment.
+
+refund_receipt_msgnum must be configured.
+
+Available options:
+
+=over 4
+
+=item cust_main
+
+Customer (FS::cust_main) object (for efficiency).
+
+=cut
+
+=back
+
+=cut
+
+sub send_receipt {
+ my $self = shift;
+ my $opt = ref($_[0]) ? shift : { @_ };
+
+ my $cust_main = $opt->{'cust_main'} || $self->cust_main;
+
+ my $conf = new FS::Conf;
+
+ my $msgnum = $conf->config('refund_receipt_msgnum', $cust_main->agentnum);
+ return "No refund_receipt_msgnum configured" unless $msgnum;
+
+ my $msg_template = qsearchs('msg_template',{ msgnum => $msgnum});
+ return "Could not load template"
+ unless $msg_template;
+
+ my $cust_msg = $msg_template->prepare(
+ 'cust_main' => $cust_main,
+ 'object' => $self,
+ 'msgtype' => 'receipt',
+ );
+ return 'Error preparing message' unless $cust_msg;
+ my $error = $cust_msg->insert;
+ return $error if $error;
+
+ my $queue = new FS::queue {
+ 'job' => 'FS::cust_msg::process_send',
+ 'custnum' => $cust_main->custnum,
+ };
+ $error = $queue->insert( $cust_msg->custmsgnum );
+
+ return $error;
+}
+
=back
=head1 CLASS METHODS
$cust_pay->paymask : $cust_pay->decrypt($cust_pay->payinfo)
} ],
],
+ # for refund receipts
+ 'cust_refund' => [
+ 'refundnum',
+ [ refund => sub { sprintf("%.2f", shift->refund) } ],
+ [ payby => sub { FS::payby->shortname(shift->payby) } ],
+ [ date => sub { time2str("%a %B %o, %Y", shift->_date) } ],
+ [ payinfo => sub {
+ my $cust_refund = shift;
+ ($cust_refund->payby eq 'CARD' || $cust_refund->payby eq 'CHEK') ?
+ $cust_refund->paymask : $cust_refund->decrypt($cust_refund->payinfo)
+ } ],
+ ],
# for payment decline messages
# try to support all cust_pay fields
# 'error' is a special case, it contains the raw error from the gateway
'body_etc' => $body_etc,
'name_singular' => 'template',
'table' => 'msg_template',
- 'viewall_dir' => 'browse',
+ 'viewall_url' => $fsurl.'browse/msg_template/email.html',
'agent_virt' => 1,
'agent_null' => 1,
'agent_null_right' => [ 'View global templates', 'Edit global templates' ],
'$payinfo' => 'Card/account# (masked)',
'$error' => 'Decline reason',
],
+ 'cust_refund' => [
+ '$refundnum' => 'Refund#',
+ '$refund' => 'Refund Amount',
+ '$payby' => 'Refund method',
+ '$date' => 'Refund date',
+ '$payinfo' => 'Card/account# (masked)',
+ ],
'system_log' => [
'$logmessage' => 'Log entry message',
'$loglevel' => 'Log entry level',
'service' => 'Service address',
'cust_main' => 'Customer status and payment info',
'cust_pkg' => 'Package fields',
+'cust_refund' => 'Refund fields',
'cust_bill' => 'Invoice fields',
'cust_pay' => 'Payment fields',
'svc_acct' => 'Login service fields',
#required
'action' => 'content.html', # uri for content of popup
- #alternately, use instead of action
- 'js_action' => 'url', # javascript variable or expression
-
#strongly recommended
'actionlabel => 'You clicked', # popup title
+ #alternately, use instead of action, values will be passed unquoted to overlib
+ 'js_action' => 'url', # javascript variable or expression
+ 'js_actionlabel' => 'actionlabel', # javascript variable or expression
+
#opt
'width' => 540,
'height' => 336,
$params = { @_ };
}
-$action = q(') . $params->{'action'} . q(') if exists $params->{'action'};
+$action = q(') . $params->{'action'} . q(');
$action = $params->{'js_action'} if exists $params->{'js_action'};
-$actionlabel = $params->{'actionlabel'} if exists $params->{'actionlabel'};
+$actionlabel = q(') . $params->{'actionlabel'} . q(');
+$actionlabel = $params->{'js_actionlabel'} if exists $params->{'js_actionlabel'};
$width = $params->{'width'} if exists $params->{'width'};
$height = $params->{'height'} if exists $params->{'height'};
$color = $params->{'color'} if exists $params->{'color'};
my $onclick =
"overlib( OLiframeContent($action, $width, $height, '$popup_name', 0, '$scrolling' ), ".
- "CAPTION, '$actionlabel', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, ".
+ "CAPTION, $actionlabel, STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, ".
"DRAGGABLE, CLOSECLICK, ".
"BGCOLOR, '$color', CGCOLOR, '$color', FGCOLOR, '#f8f8f8', ".
"CLOSETEXT, '$closetext'".
-% if ( $error ) {
+% if ($cgi->param('popup')) {
+% my $title = $error ? 'Error sending invoice email' : 'Invoice email sent';
+<% include('/elements/header-popup.html', $title ) %>
+<DIV STYLE="text-align: center;">
+<SPAN STYLE="color: red; font-weight: bold;"><% $error %></SPAN><BR>
+<BUTTON TYPE="button" onClick="parent.cClick();">Close</BUTTON>
+</DIV>
+<% include('/elements/footer.html') %>
+% } elsif ( $error ) {
% errorpage($error);
% } else {
<% $cgi->redirect("${p}view/cust_main.cgi?$custnum") %>
if (confirm(message) == true)
window.location.href = href;
}
+function areyousure_popup(message, action, actionlabel) {
+ if (confirm(message) == true) {
+<% include('/elements/popup_link_onclick.html',
+ 'js_action' => 'action',
+ 'js_actionlabel' => 'actionlabel',
+ ) %>
+ }
+}
</SCRIPT>
<br>
#rights
( map { $_ => $curuser->access_right($_) }
(
- 'View invoices', 'Void invoices', 'Unvoid invoices',
+ 'View invoices', 'Void invoices', 'Unvoid invoices', 'Resend invoices',
'Apply payment', 'Refund credit card payment', 'Refund Echeck payment',
'Post refund', 'Post check refund', 'Post cash refund ', 'Refund payment',
'Credit card void', 'Echeck void', 'Void payments', 'Unvoid payments',
#customer information
'total_owed' => $cust_main->total_owed,
'total_unapplied_refunds' => $cust_main->total_unapplied_refunds,
+ 'has_email_address' => scalar($cust_main->invoicing_list_emailonly),
);
$opt{'date_format'} ||= '%m/%d/%Y';
-<% $link %><% $invoice %><% $link ? '</A>' : '' %><% "$void$under" %>
+<% $link %><% $invoice %><% $link ? '</A>' : '' %><% "$email$void$under" %>
<%init>
my( $cust_bill, %opt ) = @_;
')';
}
+my $email = ($opt{'has_email_address'} && $opt{'Resend invoices'}) ?
+ q! (<A HREF="javascript:void(0)" ONCLICK="areyousure_popup('Send email receipt for invoice #!.
+ $cust_bill->invnum.
+ q! to customer?','!.
+ "${p}misc/send-invoice.cgi?method=email;notice_name=Invoice;popup=1;invnum=".
+ $cust_bill->invnum.
+ q!','Email Invoice Receipt')" TITLE="Send email receipt">email receipt</A>)!
+ : '';
+
my $events = '';
if ( $cust_bill->num_cust_event
&& ($opt{'Billing event reports'} || $opt{'View customer billing events'})
<% $payment. ' '. $info. $desc.
- $view. $change_pkg. $apply. $refund. $void. $unapply
+ $view. $email. $change_pkg. $apply. $refund. $void. $unapply
%>
<%init>
).
')';
+my $email = $opt{'has_email_address'} ?
+ q! (<A HREF="javascript:void(0)" ONCLICK="areyousure_popup('Send email receipt for payment to customer?','!.
+ "${p}view/cust_pay.html?link=email;paynum=".
+ $cust_pay->paynum.
+ q!','Email Payment Receipt')" TITLE="Send email receipt">email receipt</A>)!
+ : '';
+
my $change_pkg = '';
if ( $apply && $opt{'pkg-balances'} && $cust_pay->pkgnum ) {
$change_pkg =
<% $refund %>
(<% "$payby$payinfo" %>)
-<% "$view$delete" %>
+<% "$view$email$delete" %>
<%init>
my( $cust_refund, %opt ) = @_;
).
')';
+my $email = $opt{'has_email_address'} ?
+ q! (<A HREF="javascript:void(0)" ONCLICK="areyousure_popup('Send email receipt for refund to customer?','!.
+ "${p}view/cust_refund.html?link=email;refundnum=".
+ $cust_refund->refundnum.
+ q!','Email Refund Receipt')" TITLE="Send email receipt">email receipt</A>)!
+ : '';
+
my $delete = '';
$delete = areyousure_link("${p}misc/delete-cust_refund.cgi?".$cust_refund->refundnum,
emt('Are you sure you want to delete this refund?'),
<& /elements/header-popup.html, mt("$thing Receipt") &>
<div align="center">
- <A HREF="javascript:self.parent.location = '<% $pr_link %>'"><% mt('Print') |h %></A> |
- <A HREF="javascript:self.location = '<% $email_link %>'"><% mt('Re-email') |h %></A>
+ <A HREF="javascript:self.parent.location = '<% $pr_link %>'"><% mt('Print') |h %></A>
+% if ( $cust_main->invoicing_list_emailonly ) {
+ | <A HREF="javascript:self.location = '<% $email_link %>'"><% mt('Re-email') |h %></A>
+% }
</div><BR>
% } elsif ( $link eq 'print' ) {
});
die "$thing #$paynum not found!" unless $cust_pay;
+my $cust_main = $cust_pay->cust_main;
+
my $pr_link = "${p}view/cust_pay.html?link=print;paynum=$paynum;void=$void";
my $email_link = "${p}view/cust_pay.html?link=email;paynum=$paynum;void=$void";
my $custnum = $cust_pay->custnum;
-my $display_custnum = $cust_pay->cust_main->display_custnum;
+my $display_custnum = $cust_main->display_custnum;
my $conf = new FS::Conf;
my $email_error;
if ( $link eq 'email' ) {
- my $email_error = $cust_pay->send_receipt(
- 'manual' => 1,
+ $email_error = $cust_pay->send_receipt(
+ 'manual' => 1,
+ 'cust_main' => $cust_main,
);
warn "can't send payment receipt/statement: $email_error" if $email_error;
<& /elements/header-popup.html, mt('Refund Receipt') &>
- <CENTER><A HREF="javascript:self.parent.location = '<% $pr_link %>'"><% mt('Print') |h %></A></CENTER><BR>
+ <DIV ALIGN="center">
+ <A HREF="javascript:self.parent.location = '<% $pr_link %>'"><% mt('Print') |h %></A>
+% if ( $cust_main->invoicing_list_emailonly ) {
+ | <A HREF="javascript:self.location = '<% $email_link %>'"><% mt('Email') |h %></A>
+% }
+ </DIV>
% } elsif ( $link eq 'print' ) {
%>
<BR><BR>
+% } elsif ( $link eq 'email' ) {
+% if ( $email_error ) {
+ <& /elements/header-popup.html, mt("Error re-emailing receipt: [_1]", $email_error) &>
+% } else {
+ <& /elements/header-popup.html, mt("Re-emailed receipt") &>
+% }
% } else {
<& /elements/header.html, mt('Refund Receipt'), menubar(
% }
-% unless ($link eq 'popup' ) {
+% unless ($link =~ /^(popup|email)$/ ) {
<& /elements/small_custview.html,
$custnum,
scalar($conf->config('countrydefault')),
window.print();
</SCRIPT>
-% }
+% } elsif ( $link eq 'email' ) {
-% if ( $link =~ /^(popup|print)$/ ) {
+ <SCRIPT TYPE="text/javascript">
+ window.top.location.reload();
+ </SCRIPT>
+
+% }
+% if ( $link =~ /^(popup|print|email)$/ ) {
</BODY>
</HTML>
% } else {
});
die "Refund #$refundnum not found!" unless $cust_refund;
+my $cust_main = $cust_refund->cust_main;
+
my $pr_link = "${p}view/cust_refund.html?link=print;refundnum=$refundnum";
+my $email_link = "${p}view/cust_refund.html?link=email;refundnum=$refundnum";
my $custnum = $cust_refund->custnum;
-my $display_custnum = $cust_refund->cust_main->display_custnum;
+my $display_custnum = $cust_main->display_custnum;
my $conf = new FS::Conf;
tie my %payby, 'Tie::IxHash', FS::payby->payby2longname;
+my $email_error;
+
+if ( $link eq 'email' ) {
+ $email_error = $cust_refund->send_receipt( 'cust_main' => $cust_main );
+ warn "can't send refund receipt: $email_error" if $email_error;
+}
+
</%init>