#!/usr/bin/perl
#
# bin/worker/shop-creditcard-charge
#
# This Gearman worker handles attempting to charge a user for their credit card
# transaction.  Goal is to be quick and useful.
#
# Authors:
#      Mark Smith <mark@dreamwidth.org>
#
# Copyright (c) 2010 by Dreamwidth Studios, LLC.
#
# This program is free software; you may redistribute it and/or modify it under
# the same terms as Perl itself. For a copy of the license, please reference
# 'perldoc perlartistic' or 'perldoc perlgpl'.
#

use strict;
BEGIN {
    require "$ENV{LJHOME}/cgi-bin/ljlib.pl";
}

use Gearman::Worker;
use Storable qw/ thaw /;

use LJ::Worker::Gearman;
use DW::Pay;
use DW::Shop;

gearman_decl( 'dw_creditcard_charge'  => \&worker );
gearman_work();

sub worker {
    my $job = $_[0];

    my %in = %{ thaw( $job->arg ) || {} };
    return
        unless exists $in{cctransid} && $in{cctransid} > 0 &&
               exists $in{cartid} && $in{cartid} > 0;

    my $dbh = DW::Pay::get_db_writer()
        or return undef;

    # at this point, we can save the error since we have a cctransid
    my $err = sub {
        $dbh->do( 'UPDATE cc_trans SET jobstate = ?, joberr = ?, gctaskref = NULL WHERE cctransid = ?',
                  undef, 'internal_failure', sprintf( shift(), @_ ), $in{cctransid} );
        return undef;
    };

    my $cart = DW::Shop::Cart->get_from_cartid( $in{cartid} )
        or return $err->( 'Failed to get cart %d.', $in{cartid} );
    return $err->( 'Cart is not in valid state PEND_PAID, is in state %d.', $cart->state )
        unless $cart->state == $DW::Shop::STATE_PEND_PAID;

    # now attempt to charge the user for this purchase
    my ( $res, $msg ) = $cart->engine->try_capture( %in );

    # update to say that this has been paid, if it has
    if ( $res ) {
        $cart->state( $DW::Shop::STATE_PAID );
        $msg = 'charged' . ( $msg ? " [$msg]" : '' );
        $dbh->do( 'UPDATE cc_trans SET jobstate = ?, joberr = ?, gctaskref = NULL WHERE cctransid = ?',
                  undef, 'paid', $msg, $in{cctransid} );

    } else {
        $cart->state( $DW::Shop::STATE_OPEN );
        $msg = 'declined' . ( $msg ? " [$msg]" : '' );
        $dbh->do( 'UPDATE cc_trans SET jobstate = ?, joberr = ?, gctaskref = NULL WHERE cctransid = ?',
                  undef, 'failed', $msg, $in{cctransid} );
    }

    return 1;
}

