tasks/ccbill-check-access
#!/usr/bin/env perl
# ===================================================================
# File: ccbill-check-access
# Project: ShinyCMS
# Purpose: Check if CCBill subscription customers have renewed their access
#
# Author: Denny de la Haye <2019@denny.me>
# Copyright (c) 2009-2019 Denny de la Haye
#
# ShinyCMS is free software; you can redistribute it and/or modify it
# under the terms of either the GPL 2.0 or the Artistic License 2.0
# ===================================================================
use strict;
use warnings;
# Load local modules
use FindBin qw( $Bin );
use lib "$Bin/../lib";
use ShinyCMS;
use ShinyCMS::Schema;
# Exit if already running
use File::Pid;
my $pidfile = File::Pid->new({
file => '/tmp/shinycms-ccbill-check-access.'. ShinyCMS->config->{ domain } .'.pid',
});
if ( my $num = $pidfile->running ) {
die "Already running: $num\n";
}
$pidfile->write;
# Load CPAN modules
use DateTime;
use DateTime::Format::ISO8601;
use LWP::UserAgent;
use Text::CSV;
use Data::Dumper;
# Configure debug output level
my $debug = 1;
# Configure whether to make test mode requests or not
my $testmode = 1; # 0 for normal/live mode, 1 for test mode
# Get the current date and time
my $now = DateTime->now;
# Get a database connection
my $schema = ShinyCMS::Schema->connect(
ShinyCMS->config->{ 'Model::DB' }->{ connect_info }
);
# Fetch the active members list from CCBill (or use on-disk copy if one exists for today)
my $csv_data;
my $date = $now->ymd;
if ( -f $Bin.'/'.$date.'.csv' ) {
print "Using backup file...\n" if $debug;
{
local $/ = undef;
open my $backup, '<', $Bin.'/'.$date.'.csv' or die "Failed to open backup CSV file: $!";
$csv_data = <$backup>;
close $backup;
}
}
else {
print "Fetching subscription data from CCBill...\n" if $debug;
my $account = ShinyCMS->config->{'ccbill-check-access'}->{ account };
my $subacc = ShinyCMS->config->{'ccbill-check-access'}->{ subacc };
my $username = ShinyCMS->config->{'ccbill-check-access'}->{ username };
my $password = ShinyCMS->config->{'ccbill-check-access'}->{ password };
die 'CCBill details missing from config!' unless
$account && $subacc && $username && $password;
my $url = 'https://datalink.ccbill.com/data/main.cgi'.
'?transactionTypes=ACTIVEMEMBERS'.
'&clientAccnum='.$account.
'&clientSubacc='.$subacc.
'&username='.$username.
'&password='.$password;
$url .= '&testMode=1' if $testmode == 1;
my $ua = LWP::UserAgent->new;
my $response = $ua->get( $url );
if ( $response->is_success ) {
$csv_data = $response->decoded_content;
open my $backup, '>', $Bin.'/'.$date.'.csv' or die "Failed to write backup CSV file: $!";
print $backup $csv_data;
close $backup or die "Failed to close backup CSV file: $!";
}
else {
die $response->status_line;
}
}
my @csv_lines = split "\n", $csv_data;
die $csv_lines[0] if $csv_lines[0] =~ m/Error: /;
# Loop through the CSV file building up a hash
my $csv = Text::CSV->new
or die 'Failed to create CSV parser: ' . Text::CSV->error_diag;
my $active = {};
foreach my $csv_line ( @csv_lines ) {
$csv->parse( $csv_line );
my @line = $csv->fields;
my $subscription_id = $line[3];
my $renews_on = $line[22];
my $duration = $line[20];
if ( $renews_on ) {
my $new_dt = DateTime::Format::ISO8601->parse_datetime( $renews_on . 'T23:59:59' );
$active->{ $subscription_id }->{ renews_on } = $new_dt;
$active->{ $subscription_id }->{ duration } = $duration;
}
}
# Fetch the active user access list from the database
my $users = $schema->resultset('UserAccess')->search({
# expires => { '<=' => $now->add( days => 1 )->ymd },
recurring => { '!=' => undef },
});
# Loop through active access list checking against CCBill active member list
my $e = 0;
my $a = 0;
my $r = 0;
while ( my $access = $users->next ) {
my $subscription_id = $access->get_column('subscription_id') || '';
if ( $subscription_id and not $active->{ $subscription_id } ) {
print 'Access for ', $access->user->username, ' expired on ',
$access->expires, "\n" if $debug;
$access->update({ recurring => undef });
$e++;
}
else {
my $new_expiry = $active->{ $subscription_id }->{ renews_on };
if ( $new_expiry->epoch == $access->expires->epoch ) {
print 'Access for ', $access->user->username, ' unchanged; ',
'access expires on ', $access->expires, "\n" if $debug;
$a++
}
else {
my $duration = $active->{ $subscription_id }->{ duration };
print 'Access for ', $access->user->username, ' updated; ',
' old expiry date: ', $access->expires,
', new expiry date: ', $new_expiry, "\n" if $debug;
$access->update({
expires => $new_expiry,
recurring => $duration,
});
$r++;
}
}
}
print "RENEWED: $r ACTIVE: $a EXPIRED: $e\n" if $debug;
# Remove the PID file
$pidfile->remove;