+
+ if ( $conf->exists('alert_expiration', $agentnum) ) {
+ my $msgnum = $conf->exists('alerter_msgnum', $agentnum);
+ my $template = FS::msg_template->by_key($msgnum) if $msgnum;
+ if (!$template) {
+ warn "template for alerter_msgnum $msgnum not found\n";
+ next;
+ }
+ # this is now a set of billing events
+ foreach my $days (30, 15, 5) {
+ my $event = FS::part_event->new({
+ 'agentnum' => $agentnum,
+ 'event' => "Card expiration warning - $days days",
+ 'eventtable' => 'cust_main',
+ 'check_freq' => '1d',
+ 'action' => 'notice',
+ 'disabled' => 'Y', #initialize first
+ });
+ my $error = $event->insert( 'msgnum' => $msgnum );
+ if ($error) {
+ warn "error creating expiration alert event:\n$error\n\n";
+ next;
+ }
+ # make it work like before:
+ # only send each warning once before the card expires,
+ # only warn active customers,
+ # only warn customers with CARD/DCRD,
+ # only warn customers who get email invoices
+ my %conds = (
+ 'once_every' => { 'run_delay' => '30d' },
+ 'cust_paydate_within' => { 'within' => $days.'d' },
+ 'cust_status' => { 'status' => { 'active' => 1 } },
+ 'payby' => { 'payby' => { 'CARD' => 1,
+ 'DCRD' => 1, }
+ },
+ 'message_email' => {},
+ );
+ foreach (keys %conds) {
+ my $condition = FS::part_event_condition->new({
+ 'conditionname' => $_,
+ 'eventpart' => $event->eventpart,
+ });
+ $error = $condition->insert( %{ $conds{$_} });
+ if ( $error ) {
+ warn "error creating expiration alert event:\n$error\n\n";
+ next;
+ }
+ }
+ $error = $event->initialize;
+ if ( $error ) {
+ warn "expiration alert event was created, but not initialized:\n$error\n\n";
+ }
+ } # foreach $days
+ $conf->delete('alerter_msgnum', $agentnum);
+ $conf->delete('alert_expiration', $agentnum);
+
+ } # if alerter_msgnum
+
+ }
+ foreach my $msg_template ( qsearch('msg_template', {}) ) {
+ if ( $msg_template->subject || $msg_template->body ) {
+ # create new default content
+ my %content;
+ $content{subject} = $msg_template->subject;
+ $msg_template->set('subject', '');
+
+ # work around obscure Pg/DBD bug
+ # https://rt.cpan.org/Public/Bug/Display.html?id=60200
+ # (though the right fix is to upgrade DBD)
+ my $body = $msg_template->body;
+ if ( $body =~ /^x([0-9a-f]+)$/ ) {
+ # there should be no real message templates that look like that
+ warn "converting template body to TEXT\n";
+ $body = pack('H*', $1);
+ }
+ $content{body} = $body;
+ $msg_template->set('body', '');
+
+ my $error = $msg_template->replace(%content);
+ die $error if $error;
+ }
+ }
+}
+
+sub eviscerate {
+ # Every bit as pleasant as it sounds.
+ #
+ # We do this because Text::Template::Preprocess doesn't
+ # actually work. It runs the entire template through
+ # the preprocessor, instead of the code segments. Which
+ # is a shame, because Text::Template already contains
+ # the code to do this operation.
+ my $body = shift;
+ my (@outside, @inside);
+ my $depth = 0;
+ my $chunk = '';
+ while($body || $chunk) {
+ my ($first, $delim, $rest);
+ # put all leading non-delimiters into $first
+ ($first, $rest) =
+ ($body =~ /^((?:\\[{}]|[^{}])*)(.*)$/s);
+ $chunk .= $first;
+ # put a leading delimiter into $delim if there is one
+ ($delim, $rest) =
+ ($rest =~ /^([{}]?)(.*)$/s);
+
+ if( $delim eq '{' ) {
+ $chunk .= '{';
+ if( $depth == 0 ) {
+ push @outside, $chunk;
+ $chunk = '';
+ }
+ $depth++;
+ }
+ elsif( $delim eq '}' ) {
+ $depth--;
+ if( $depth == 0 ) {
+ push @inside, $chunk;
+ $chunk = '';
+ }
+ $chunk .= '}';
+ }
+ else {
+ # no more delimiters
+ if( $depth == 0 ) {
+ push @outside, $chunk . $rest;
+ } # else ? something wrong
+ last;
+ }
+ $body = $rest;