Created
September 9, 2014 14:05
-
-
Save SysPete/719cb0156d1cdc532c11 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
any [ 'get', 'post' ] => '/checkout' => require_login sub { | |
return forward 404 if config->{shop_disabled}; | |
return redirect '/cart' if cart->count == 0; | |
my ( $data, $form, $form_last, $forms_ref, $params ); | |
my $posted = 1; | |
$form_last = 'personal_details'; | |
$forms_ref = session 'form'; | |
foreach my $name (qw/personal_details confirm_order payment_details/) { | |
$form = $forms_ref->{$name}; | |
unless ( defined $form && $form->{valid} ) { | |
$form_last = $name; | |
last; | |
} | |
} | |
debug "form $form_last"; | |
$params = params; | |
if ( $form_last eq 'personal_details' ) { | |
if ( scalar keys %$params == 0 ) { | |
debug "pristine form"; | |
undef $posted; | |
my $ship_adr = shop_address->search( | |
{ | |
users_id => session('logged_in_user_id'), | |
type => 'shipping', | |
}, | |
{ | |
order_by => 'last_modified DESC', | |
rows => 1, | |
}, | |
)->single; | |
if ($ship_adr) { | |
$data->{result} = { | |
address => $ship_adr->address, | |
address2 => $ship_adr->address_2, | |
postal_code => $ship_adr->postal_code, | |
city => $ship_adr->city, | |
country => $ship_adr->country_iso_code, | |
telephone => $ship_adr->phone, | |
}; | |
$data->{result}->{state} = $ship_adr->State->state_iso_code | |
if $ship_adr->states_id; | |
} | |
} | |
else { | |
$data = validator( $params, $form_last ); | |
if ( $data->{valid} ) { | |
my $result = $data->{result}; | |
$result->{valid} = 1; | |
# create shipping address and push data into session | |
my $user = shop_user->search( | |
{ users_id => session('logged_in_user_id') }, | |
{ rows => 1 } )->single; | |
error "Failed to find user in DB" unless $user; | |
my $data = { | |
type => 'shipping', | |
users_id => $user->users_id, | |
first_name => $user->first_name, | |
last_name => $user->last_name, | |
address => $result->{address}, | |
address_2 => $result->{address2}, | |
postal_code => $result->{postal_code}, | |
city => $result->{city}, | |
phone => $result->{telephone}, | |
country_iso_code => $result->{country}, | |
}; | |
if ( defined $result->{state} ) { | |
$data->{State}->{state_iso_code} = $result->{state}; | |
} | |
my $ship_address = shop_address->find_or_create($data); | |
error "Failed to create shipping address" unless $ship_address; | |
$result->{ship_address_id} = $ship_address->id; | |
# update session | |
my $forms_ref = session 'form'; | |
$forms_ref->{$form_last} = $result; | |
session 'form' => $forms_ref; | |
return redirect '/checkout'; | |
} | |
} | |
my $countries = | |
shop_country->search( { active => 1 }, { order_by => 'name' } ); | |
my $country = var('geo_country_code') || 'MT'; | |
$country = $data->{result}->{country} if $data->{result}->{country}; | |
my $states = | |
shop_schema->resultset('State') | |
->search( { active => 1, country_iso_code => $country }, | |
{ order_by => 'name' } ); | |
my $state = var('geo_state_code') || ''; | |
$state = $data->{result}->{state} if $data->{result}->{state}; | |
# jquery to handle add/remove state list on country change + datepicker | |
my $script = q| | |
$(document).ready(function () { | |
$("#country").change(function(){ | |
var countryName = $('#country').val(); | |
$.get('/component/select_states/' + countryName, function(data) { | |
$('#states').replaceWith(data); | |
}); | |
}); | |
$('input.date').datepicker({ | |
startDate: "| . DateTime->now->add( days => 7 )->dmy . q|", | |
format: "dd-mm-yyyy", | |
autoclose: true | |
}); | |
}); | |
|; | |
return template '/checkout_personal_details' => { | |
country => $country, | |
countries => $countries, | |
data => $data->{result}, | |
posted => $posted, | |
script => $script, | |
state => $state, | |
states => $states, | |
state_label => $country eq 'CA' ? 'Province' : 'State', | |
title => 'Checkout', | |
}; | |
} | |
elsif ( $form_last eq 'confirm_order' ) { | |
if ( scalar keys %$params == 0 ) { | |
debug "pristine form"; | |
} | |
else { | |
$data = validator( $params, $form_last ); | |
if ( $data->{valid} ) { | |
# stash things in session and redirect back to /checkout | |
$form = $data->{result}; | |
$form->{valid} = 1; | |
$forms_ref->{$form_last} = $form; | |
session 'form' => $forms_ref; | |
redirect '/checkout'; | |
} | |
} | |
return template '/checkout_confirm_order' => { | |
cart => cart, | |
data => $data->{result}, | |
title => 'Checkout', | |
}; | |
} | |
elsif ( $form_last eq 'payment_details' ) { | |
my $cart = cart; | |
if ( scalar keys %$params == 0 ) { | |
debug "pristine form"; | |
undef $posted; | |
my $user = | |
shop_user->search( { users_id => session('logged_in_user_id') }, | |
{ rows => 1 } )->single; | |
my $billing_adr = shop_address->search( | |
{ | |
users_id => $user->users_id, | |
type => 'billing', | |
}, | |
{ | |
order_by => 'last_modified DESC', | |
rows => 1, | |
}, | |
)->single; | |
if ($billing_adr) { | |
$data->{result} = { | |
address => $billing_adr->address, | |
address2 => $billing_adr->address_2, | |
postal_code => $billing_adr->postal_code, | |
city => $billing_adr->city, | |
country => $billing_adr->country_iso_code, | |
}; | |
$data->{result}->{state} = $billing_adr->State->state_iso_code | |
if $billing_adr->states_id; | |
} | |
else { | |
# use address from personal_details in the session | |
my $form = $forms_ref->{personal_details}; | |
$data->{result} = { | |
address => $form->{address}, | |
address2 => $form->{address2}, | |
postal_code => $form->{postal_code}, | |
city => $form->{city}, | |
country => $form->{country}, | |
state => $form->{state}, | |
}; | |
} | |
} | |
else { | |
$data = validator( $params, $form_last ); | |
if ( $data->{valid} ) { | |
# all seems OK so create order | |
my $result = $data->{result}; | |
my $users_id = session('logged_in_user_id'); | |
my ( $form, $ship_address, $bill_address, $addr_values ); | |
my $user = shop_user->find( | |
{ users_id => session('logged_in_user_id') } ); | |
$form = $forms_ref->{personal_details}; | |
$ship_address = shop_address->search( | |
{ addresses_id => $form->{ship_address_id} }, | |
{ rows => 1 } )->single; | |
my $bill_data = { | |
users_id => $user->users_id, | |
type => 'billing', | |
first_name => $user->first_name, | |
last_name => $user->last_name, | |
address => $result->{address}, | |
address_2 => $result->{address2}, | |
postal_code => $result->{postal_code}, | |
city => $result->{city}, | |
phone => '', | |
country_iso_code => $result->{country}, | |
}; | |
if ( defined $result->{state} ) { | |
my $state = shop_schema->resultset('State')->search( | |
{ | |
country_iso_code => $result->{country}, | |
state_iso_code => $result->{state} | |
}, | |
{ rows => 1 } | |
)->single; | |
if ($state) { | |
} | |
$bill_data->{states_id} = $state->states_id; | |
} | |
$bill_address = | |
shop_address->search( $bill_data, { rows => 1 } )->single; | |
$bill_address = shop_address->create($bill_data) | |
unless $bill_address; | |
# attempt to collect payment | |
my $amount = $result->{amount}; | |
$amount = cart->total if ($amount > cart->total); | |
$amount = sprintf( "%.2f", $amount ); | |
my $expiration = sprintf( "%02d/%02d", | |
$result->{cc_month}, $result->{cc_year} ); | |
my %payment_data = ( | |
action => 'Normal Authorization', | |
amount => $amount, | |
card_number => $result->{cc_number}, | |
cvv => $result->{cvv_number}, | |
expiration => $expiration, | |
address => $result->{address}, | |
city => $result->{city}, | |
region => $result->{region}, | |
zip => $result->{postal_code}, | |
country => $result->{country}, | |
); | |
my $braintree_config = | |
config->{plugins}->{Interchange6}->{Payment}->{providers} | |
->{Braintree}; | |
my $tx = Business::OnlinePayment->new( | |
'Braintree', | |
merchant_id => $braintree_config->{merchant_id}, | |
public_key => $braintree_config->{public_key}, | |
private_key => $braintree_config->{private_key}, | |
); | |
if ( $braintree_config->{test_transaction} ) { | |
$tx->test_transaction(1); | |
} | |
$tx->content(%payment_data); | |
$tx->submit(); | |
if ( $tx->is_success() ) { | |
info "Payment success: " . Dumper($tx); | |
if ( $tx->can('popup_url') ) { | |
debug( "Payment redirect: ", $tx->popup_url() ); | |
return redirect $tx->popup_url(); | |
} | |
debug "Payment successful: ", $tx->authorization; | |
# order date | |
my $order_date = DateTime->now->iso8601; | |
# create orderlines | |
my @orderlines; | |
my $position = 1; | |
my @cart_products = cart->products_array; | |
for my $product (@cart_products) { | |
my $ol_prod = shop_product( $product->sku ); | |
my %orderline_product = ( | |
sku => $ol_prod->sku, | |
order_position => $position++, | |
name => $ol_prod->name, | |
short_description => $ol_prod->short_description, | |
description => $ol_prod->description, | |
weight => $ol_prod->weight, | |
quantity => $product->quantity, | |
price => $ol_prod->price, | |
subtotal => $ol_prod->price * $product->quantity, | |
); | |
push @orderlines, \%orderline_product; | |
} | |
# create Order | |
my $parser = | |
DateTime::Format::Natural->new( format => 'dd/mm/yyy' ); | |
my %order_info = ( | |
users_id => $users_id, | |
billing_addresses_id => $bill_address->id, | |
shipping_addresses_id => $ship_address->id, | |
subtotal => cart->subtotal, | |
total_cost => cart->total, | |
order_date => $order_date, | |
order_number => $tx->order_number, | |
start_date => $parser->parse_datetime( $form->{start} ), | |
end_date => $parser->parse_datetime( $form->{end} ), | |
status => 'success', | |
site => var('site'), | |
Orderline => \@orderlines, | |
); | |
my $order = shop_order->create( \%order_info ); | |
# create PaymentOrder | |
shop_schema->resultset('PaymentOrder')->create( | |
{ | |
payment_mode => 'Braintree', | |
payment_action => $payment_data{action}, | |
payment_id => $tx->order_number, | |
auth_code => $tx->authorization, | |
users_id => $user->id, | |
sessions_id => session->id, | |
orders_id => $order->id, | |
amount => $payment_data{amount}, | |
status => 'success', | |
} | |
); | |
# email to customer | |
$form = $forms_ref->{personal_details}; | |
my $name = var 'name'; | |
my $site = var 'site'; | |
my $from = "info\@dive${site}.com"; | |
my $to = join( '', | |
$user->first_name, " ", $user->last_name, | |
" <", $user->email, ">" ); | |
my $params = { | |
first_name => $user->first_name, | |
last_name => $user->last_name, | |
email => $user->email, | |
phone => $form->{telephone}, | |
name => $name, | |
site => $site, | |
from => $from, | |
order => $order, | |
orderlines => \@orderlines, | |
paid => $payment_data{amount}, | |
}; | |
# email to customer | |
send_email( | |
template => 'email/order_confirmation', | |
from => var('short_name') . " <$from>", | |
to => $to, | |
subject => "Thank you for your order/booking with " | |
. var('short_name'), | |
params => $params, | |
); | |
# email to diveshack | |
send_email( | |
template => 'email/order_confirmation', | |
from => var('short_name') . " <$from>", | |
to => config->{email_to}, | |
subject => "website booking: for " . var('short_name'), | |
params => $params, | |
); | |
# email to Peter Mottram | |
send_email( | |
template => 'email/order_confirmation', | |
from => var('short_name') . " <$from>", | |
to => '[email protected]', | |
subject => "website booking: for " . var('short_name'), | |
params => $params, | |
); | |
# clear up | |
session form => undef; | |
cart->clear; | |
return template 'order' => { | |
title => "Thankyou for your order", | |
message => "You should soon receive a confirmation " | |
. "email from us. Please get in touch if you do not " | |
. "receive this within the next few hours.", | |
order => $order, | |
}; | |
} | |
else { | |
error "Payment failed: " . Dumper($tx); | |
$data->{result}->{err_cc_number} = "Payment failed. " | |
. "Check card details or try a different card."; | |
delete $data->{result}->{cc_number}; | |
delete $data->{result}->{cvv_number}; | |
} | |
} | |
else { | |
# scrub useless cc_number and cvv_number | |
delete $form->{result}->{cc_number}; | |
delete $form->{result}->{cvv_number}; | |
} | |
} | |
my $countries = | |
shop_country->search( { active => 1 }, { order_by => 'name' } ); | |
my $country = var('geo_country_code') || 'MT'; | |
$country = $data->{result}->{country} if $data->{result}->{country}; | |
my $states = | |
shop_schema->resultset('State') | |
->search( { active => 1, country_iso_code => $country }, | |
{ order_by => 'name' } ); | |
my $state = var('geo_state_code') || ''; | |
$state = $data->{result}->{state} if $data->{result}->{state}; | |
# jquery to handle add/remove state list on country change | |
# and to change voucher amount field visibility | |
# + braintree ajax | |
my $cse_key = config->{plugins}->{Interchange6}->{Payment}->{providers} | |
->{Braintree}->{cse_key}; | |
my $script = q( | |
$(document).ready(function () { | |
$("#country").change(function(){ | |
var countryName = $('#country').val(); | |
$.get('/component/select_states/' + countryName, function(data) { | |
$('#states').replaceWith(data); | |
}); | |
}); | |
$("#amount").change(function(){ | |
$("#voucher_full, #voucher_deposit").hide(); | |
$('#voucher_' + $(this).find('option:selected').attr('id')).show(); | |
}) | |
}); | |
) . qq( | |
var braintree = Braintree.create("$cse_key"); | |
braintree.onSubmitEncryptForm('payment-form'); | |
); | |
# dummy card details in development environment | |
my $braintree_config = | |
config->{plugins}->{Interchange6}->{Payment}->{providers} | |
->{Braintree}; | |
if ( config->{environment} eq 'development' || $braintree_config->{test_transaction} ) { | |
$data->{result}->{cc_number} = '4111 1111 1111 1111' | |
unless $data->{result}->{cc_number}; | |
$data->{result}->{cvv_number} = '111' | |
unless $data->{result}->{cvv_number}; | |
$data->{result}->{cc_month} = '12' | |
unless $data->{result}->{cc_month}; | |
$data->{result}->{cc_year} = '2018' | |
unless $data->{result}->{cc_year}; | |
$data->{result}->{cc_holder} = 'John Smith' | |
unless $data->{result}->{cc_holder}; | |
} | |
# month/years for CC checkout | |
my ( @months, @years ); | |
my $dtl = DateTime::Locale->load( config->{locale} ); | |
my $cur_date = DateTime->now( locale => $dtl ); | |
my $i = 1; | |
for my $name ( @{ $dtl->month_stand_alone_abbreviated } ) { | |
push( @months, { value => $i++, label => ucfirst($name) } ); | |
} | |
for my $year ( | |
$cur_date->year .. $cur_date->clone->add( years => 10 )->year ) | |
{ | |
push( @years, { value => $year, label => $year } ); | |
} | |
# calculate voucher_amount | |
my @rec_course_skus = @{ var('rec_course_skus') }; | |
my $rec_courses_total = 0; | |
my $voucher_amount = 0; | |
foreach my $product ( $cart->products_array ) { | |
if ( grep { $_ eq $product->sku } @rec_course_skus ) { | |
$rec_courses_total += $product->price * $product->quantity; | |
} | |
} | |
if ( $rec_courses_total >= 400 ) { | |
$voucher_amount = int( $rec_courses_total / 100 ) * 10; | |
} | |
# display template | |
if ($posted) { | |
delete $data->{result}->{cc_number}; | |
delete $data->{result}->{cvv_number}; | |
} | |
return template '/checkout_payment_details' => { | |
cart => $cart, | |
country => $country, | |
countries => $countries, | |
data => $data->{result}, | |
months => \@months, | |
posted => $posted, | |
script => $script, | |
state => $state, | |
states => $states, | |
state_label => $country eq 'CA' ? 'Province' : 'State', | |
title => 'Checkout', | |
voucher_amount => $voucher_amount, | |
years => \@years, | |
}; | |
} | |
# we should never get here | |
forward 404; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment