site/cgi-bin/modules/BSE/Session.pm
site/cgi-bin/modules/BSE/SessionSign.pm
site/cgi-bin/modules/BSE/Shipping.pm
+site/cgi-bin/modules/BSE/Shop/PaymentTypes.pm
site/cgi-bin/modules/BSE/Shop/Util.pm
site/cgi-bin/modules/BSE/Sort.pm
site/cgi-bin/modules/BSE/Storage/AmazonS3.pm
site/templates/menu/menu5.tmpl
site/templates/meta/flv_flowplaylist.tmpl
site/templates/noartbase.tmpl
+site/templates/preload.tmpl
site/templates/printable/printable.tmpl
site/templates/printable/wap.tmpl
site/templates/search_base.tmpl
-- truncated credit card number
ccPAN varchar(4) not null default '',
+ -- true if the order was paid manually
+ paid_manually integer not null default 0,
+
primary key (id),
index order_cchash(ccNumberHash),
index order_userId(userId, orderDate)
randomdata = /dev/urandom
access_control=0
file_handlers=flv
+preload_template=preload.tmpl
[paths]
; the following needs to be set to a path writable by the BSE processes
--- /dev/null
+package BSE::Shop::PaymentTypes;
+use strict;
+
+our $VERSION = "1.000";
+
+use Exporter qw(import);
+
+our @EXPORT_OK = qw(PAYMENT_CC PAYMENT_CHEQUE PAYMENT_CALLME PAYMENT_MANUAL PAYMENT_PAYPAL payment_types);
+
+our @EXPORT = grep /^PAYMENT_/, @EXPORT_OK;
+
+our %EXPORT_TAGS =
+ (
+ default => \@EXPORT,
+ );
+
+use constant PAYMENT_CC => 0;
+use constant PAYMENT_CHEQUE => 1;
+use constant PAYMENT_CALLME => 2;
+use constant PAYMENT_MANUAL => 3;
+use constant PAYMENT_PAYPAL => 4;
+
+my @types =
+ (
+ {
+ id => PAYMENT_CC,
+ name => 'CC',
+ desc => 'Credit Card',
+ require => [ qw/cardNumber cardExpiry ccName/ ],
+ },
+ {
+ id => PAYMENT_CHEQUE,
+ name => 'Cheque',
+ desc => 'Cheque',
+ require => [],
+ },
+ {
+ id => PAYMENT_CALLME,
+ name => 'CallMe',
+ desc => 'Call customer for payment',
+ require => [],
+ },
+ {
+ id => PAYMENT_MANUAL,
+ name => 'Manual',
+ desc => 'Manual',
+ require => [],
+ },
+ {
+ id => PAYMENT_PAYPAL,
+ name => "PayPal",
+ desc => "PayPal",
+ require => [],
+ },
+ );
+
+=item payment_types($cfg)
+
+Returns payment type ids, and hashes describing each of the configured
+payment types.
+
+These are used to generate the tags used for testing whether payment
+types are available. Also used for validating payment type
+information.
+
+=cut
+
+sub payment_types {
+ my ($cfg) = @_;
+
+ $cfg ||= BSE::Cfg->single;
+
+ my %types = map { $_->{id} => $_ } @types;
+
+ my @payment_types = split /,/, $cfg->entry('shop', 'payment_types', '0');
+
+ my %all_types = map { $_ => 1 } keys %types, @payment_types;
+
+ for my $type (keys %all_types) {
+ my $hash = $types{$type}; # avoid autovivification
+ my $name = $cfg->entry('payment type names', $type, $hash->{name} || "Type 0 has no name");
+ my $desc = $cfg->entry('payment type descs', $type,
+ $hash->{desc} || $name);
+ my $enabled = !$cfg->entry('payment type disable', $hash->{name}, 0);
+ my @require = $hash->{require} ? @{$hash->{require}} : ();
+ @require = split /,/, $cfg->entry('payment type required', $type,
+ join ",", @require);
+ $types{$type} =
+ {
+ id => $type,
+ name => $name,
+ desc => $desc,
+ require => \@require,
+ sort => scalar $cfg->entry("payment type sort", $hash->{name}, $type),
+ };
+ }
+
+ for my $type (@payment_types) {
+ unless ($types{$type}) {
+ print STDERR "** payment type $type doesn't have a name defined\n";
+ next;
+ }
+ $types{$type}{enabled} = 1;
+ }
+
+ # credit card payments require either encrypted emails enabled or
+ # an online CC processing module
+ if ($types{+PAYMENT_CC}) {
+ my $noencrypt = $cfg->entryBool('shop', 'noencrypt', 0);
+ my $ccprocessor = $cfg->entry('shop', 'cardprocessor');
+
+ if ($noencrypt && !$ccprocessor) {
+ $types{+PAYMENT_CC}{enabled} = 0;
+ $types{+PAYMENT_CC}{message} =
+ "No card processor configured and encryption disabled";
+ }
+ }
+
+ # paypal requires api confguration
+ if ($types{+PAYMENT_PAYPAL} && $types{+PAYMENT_PAYPAL}{enabled}) {
+ require BSE::PayPal;
+
+ unless (BSE::PayPal->configured) {
+ $types{+PAYMENT_PAYPAL}{enabled} = 0;
+ $types{+PAYMENT_PAYPAL}{message} = "No API configuration";
+ }
+ }
+
+ return sort { $a->{sort} <=> $b->{sort} } values %types;
+}
+
+1;
+
+=head1 NAME
+
+BSE::Shop::PaymentTypes - defines payment type constants.
+
+=head1 SYNOPSIS
+
+ use BSE::Shop::PaymentTypes;
+
+ $order->set_paymentType(PAYMENT_CC);
+
+ use BSE::Shop::PaymentTypes 'payment_types';
+
+ my @types = payment_types();
+
+=cut
payment_types order_item_opts
PAYMENT_CC PAYMENT_CHEQUE PAYMENT_CALLME PAYMENT_MANUAL PAYMENT_PAYPAL/;
-our $VERSION = "1.006";
+our $VERSION = "1.007";
our %EXPORT_TAGS =
(
use BSE::CfgInfo qw(custom_class);
use Carp 'confess';
use BSE::Util::HTML qw(escape_html);
-
-use constant PAYMENT_CC => 0;
-use constant PAYMENT_CHEQUE => 1;
-use constant PAYMENT_CALLME => 2;
-use constant PAYMENT_MANUAL => 3;
-use constant PAYMENT_PAYPAL => 4;
+use BSE::Shop::PaymentTypes qw(:default payment_types);
=item shop_cart_tags($acts, $cart, $cart_prods, $req, $stage)
return;
}
-=item payment_types($cfg)
-
-Returns payment type ids, and hashes describing each of the configured
-payment types.
-
-These are used to generate the tags used for testing whether payment
-types are available. Also used for validating payment type
-information.
-
-=cut
-
-sub payment_types {
- my ($cfg) = @_;
-
- my @types =
- (
- {
- id => PAYMENT_CC,
- name => 'CC',
- desc => 'Credit Card',
- require => [ qw/cardNumber cardExpiry ccName/ ],
- },
- {
- id => PAYMENT_CHEQUE,
- name => 'Cheque',
- desc => 'Cheque',
- require => [],
- },
- {
- id => PAYMENT_CALLME,
- name => 'CallMe',
- desc => 'Call customer for payment',
- require => [],
- },
- {
- id => PAYMENT_PAYPAL,
- name => "PayPal",
- desc => "PayPal",
- require => [],
- },
- );
- my %types = map { $_->{id} => $_ } @types;
-
- my @payment_types = split /,/, $cfg->entry('shop', 'payment_types', '0');
-
- for my $type (@payment_types) {
- my $hash = $types{$type}; # avoid autovivification
- my $name = $cfg->entry('payment type names', $type, $hash->{name});
- my $desc = $cfg->entry('payment type descs', $type,
- $hash->{desc} || $name);
- my $enabled = !$cfg->entry('payment type disable', $hash->{name}, 0);
- my @require = $hash->{require} ? @{$hash->{require}} : ();
- @require = split /,/, $cfg->entry('payment type required', $type,
- join ",", @require);
- if ($name && $desc) {
- $types{$type} =
- {
- id => $type,
- name => $name,
- desc => $desc,
- require => \@require,
- };
- }
- }
-
- for my $type (@payment_types) {
- unless ($types{$type}) {
- print STDERR "** payment type $type doesn't have a name defined\n";
- next;
- }
- $types{$type}{enabled} = 1;
- }
-
- # credit card payments require either encrypted emails enabled or
- # an online CC processing module
- if ($types{+PAYMENT_CC}) {
- my $noencrypt = $cfg->entryBool('shop', 'noencrypt', 0);
- my $ccprocessor = $cfg->entry('shop', 'cardprocessor');
-
- if ($noencrypt && !$ccprocessor) {
- $types{+PAYMENT_CC}{enabled} = 0;
- $types{+PAYMENT_CC}{message} =
- "No card processor configured and encryption disabled";
- }
- }
-
- # paypal requires api confguration
- if ($types{+PAYMENT_PAYPAL} && $types{+PAYMENT_PAYPAL}{enabled}) {
- require BSE::PayPal;
-
- unless (BSE::PayPal->configured) {
- $types{+PAYMENT_PAYPAL}{enabled} = 0;
- $types{+PAYMENT_PAYPAL}{message} = "No API configuration";
- }
- }
-
- return values %types;
-}
-
-
1;
use vars qw/@ISA/;
@ISA = qw/Squirrel::Row/;
use Carp 'confess';
+use BSE::Shop::PaymentTypes;
-our $VERSION = "1.015";
+our $VERSION = "1.016";
sub columns {
return qw/id
ccStatus2 ccTranId complete delivOrganization billOrganization
delivStreet2 billStreet2 purchase_order shipping_method
shipping_name shipping_trace
- paypal_token paypal_tran_id freight_tracking stage ccPAN/;
+ paypal_token paypal_tran_id freight_tracking stage ccPAN
+ paid_manually/;
}
sub table {
freight_tracking => "",
stage => "incomplete",
ccPAN => "",
+ paid_manually => 0,
);
}
return qw/ccNumberHash ccName ccExpiryHash ccType
paidFor paymentReceipt paymentType
ccOnline ccSuccess ccReceipt ccStatus ccStatusText
- ccStatus2 ccTranId/;
+ ccStatus2 ccTranId ccPAN paid_manually/;
}
=item billing_to_delivery_map
$self->set_ccPAN($pan);
}
+=item is_manually_paid
+
+Returns true if the order is marked as manually paid, either through
+the older PAYMENT_MANUAL paymentType value or via the newer flag.
+
+=cut
+
+sub is_manually_paid {
+ my ($self) = @_;
+
+ return $self->paidFor &&
+ ($self->paid_manually || $self->paymentType == PAYMENT_MANUAL);
+}
+
1;
use BSE::WebUtil 'refresh_to_admin';
use BSE::Util::HTML qw(:default popup_menu);
use BSE::Arrows;
-use BSE::Shop::Util qw(:payment order_item_opts nice_options);
+use BSE::Shop::Util qw(:payment order_item_opts nice_options payment_types);
-our $VERSION = "1.012";
+our $VERSION = "1.013";
my %actions =
(
);
}
+=item target order_detail
+
+Display the details of an order.
+
+Variables set:
+
+=over
+
+=item *
+
+order - the order being displayed
+
+=item *
+
+payment_types - a list of configured payment types
+
+=item *
+
+payment_type_desc - a description of the current payment type
+
+=back
+
+=cut
+
sub req_order_detail {
my ($class, $req, $errors) = @_;
my $siteuser;
my $it = BSE::Util::Iterate->new;
+ $req->set_variable(order => $order);
+ my @pay_types = payment_types();
+ $req->set_variable(payment_types => \@pay_types);
+ my ($pay_type) = grep $_->{id} == $order->paymentType, @pay_types;
+ $req->set_variable(payment_type_desc => $pay_type ? $pay_type->{desc} : "Unknown");
my %acts;
%acts =
(
}
}
+=item target order_paid
+
+Mark the order identified by C<id> as paid.
+
+Optionally accepts C<paymentType> which replaces the current payment
+type.
+
+Requires csrfp token C<shop_order_paid>.
+
+=cut
+
sub req_order_paid {
- my ($class, $req) = @_;
+ my ($self, $req) = @_;
- return $class->_set_order_paid($req, 1);
+ $req->check_csrf("shop_order_paid")
+ or return $self->req_order_list($req, "Bad or missing csrf token: " . $req->csrf_error);
+
+ return $self->_set_order_paid($req, 1);
}
+=item target order_unpaid
+
+Mark the order identified by C<id> as unpaid.
+
+Requires csrfp token C<shop_order_unpaid>.
+
+=cut
+
sub req_order_unpaid {
- my ($class, $req) = @_;
+ my ($self, $req) = @_;
- return $class->_set_order_paid($req, 0);
+ $req->check_csrf("shop_order_unpaid")
+ or return $self->req_order_list($req, "Bad or missing csrf token: " . $req->csrf_error);
+
+ return $self->_set_order_paid($req, 0);
}
sub _set_order_paid {
my $order = BSE::TB::Orders->getByPkey($id)) {
if ($order->paidFor != $value) {
if ($value) {
- $order->set_paymentType(PAYMENT_MANUAL);
+ my $pay_type = $req->cgi->param("paymentType");
+ if (defined $pay_type && $pay_type =~ /^[0-9]+$/) {
+ $order->set_paymentType($pay_type);
+ }
+ $order->set_paid_manually(1);
}
else {
- $order->paymentType == PAYMENT_MANUAL
+ $order->is_manually_paid
or return $class->req_order_detail($req, "You can only unpay manually paid orders");
}
$order->set_paidFor($value);
- my $user = $req->user;
- my $name = $user ? $user->logon : "--unknown--";
- require POSIX;
- $order->{instructions} .= "\nMarked " . ($value ? "paid" : "unpaid" ) . " by $name " . POSIX::strftime("%H:%M %d/%m/%Y", localtime);
+
+ if ($value) {
+ $req->audit
+ (
+ component => "shopadmin:order:paid",
+ level => "info",
+ object => $order,
+ msg => "Order " . $order->id . " marked paid",
+ );
+ }
+ else {
+ $req->audit
+ (
+ component => "shopadmin:order:unpaid",
+ level => "info",
+ object => $order,
+ msg => "Order " . $order->id . " marked unpaid",
+ );
+ }
$order->save();
}
<input type="submit" name="a_order_save" value="Save" />
</form>
-<:switch:>
-<:case Eq [order paidFor] "0":>
+<:.if !order.paidFor :>
<p>This order hasn't been paid</p>
-<p>If the customer has paid by cheque, transfer, etc, you can <a href="<:adminurl shopadmin a_order_paid 1 id [order id]:>">mark this order paid</a></p>
-<:case order ccOnline:>
+
+<form action="<:adminurl2 shopadmin:>" method="post">
+<input type="hidden" name="id" value="<:= order.id :>" />
+<:csrfp shop_order_paid hidden:>
+Payment type: <:.call "make_select", "name": "paymentType", "list": payment_types, "id": "id", "desc": "desc", "default": order.paymentType -:>
+<input type="submit" name="a_order_paid" value="Mark this order paid" /></form>
+<:.elsif order.is_manually_paid -:>
+<form action="<:adminurl2 shopadmin:>" method="post">
+This order has been manually marked paid via <:= payment_type_desc | html :>
+<input type="hidden" name="id" value="<:= order.id :>" />
+<:csrfp shop_order_unpaid hidden:>
+<input type="submit" name="a_order_unpaid" value="Mark this order unpaid" /></form>
+
+<:.elsif order.ccOnline:>
<p>This was processed as an online credit card transaction.</p>
-<:if Order ccSuccess:>
+<:.if order.ccSuccess:>
<p>This transaction was <b>SUCCESSFUL</b>.</p>
<table>
<tr><th>Receipt Number:</th><td><:order ccReceipt:></td></tr>
-<:ifOrder ccTranId:>
+<:.if order.ccTranId:>
<tr><th>Transaction Id:</th><td><:order ccTranId:></td></tr>
-<:or:><:eif:>
-<:ifOrder ccName:>
+<:.end if:>
+<:.if order.ccName:>
<tr><th>Card Holder:</th><td><:order ccName:></td>
-<:or:><:eif:>
-<:ifOrder ccPAN:>
+<:.end if:>
+<:.if order.ccPAN:>
<tr><th>Card Number (partial):</th><td>...<:order ccPAN:></td>
-<:or:><:eif:>
+<:.end if:>
</table>
-<:or Order:>
+<:.else:>
<p>This transaction <b>FAILED</b>.</p>
<table>
<tr><th>Status:</th><td><:order ccStatus:></td>
<tr><th>Error:</th><td><:order ccStatusText:></td>
-<:ifOrder ccStatus2:>
+<:.if order ccStatus2:>
<tr><th>More status</th><td><:order ccStatus2:></td>
-<:or:><:eif:>
+<:.end if:>
</table>
-<:eif Order:>
-<:case Eq [order paymentType] "0":><p>Payment made by credit card. Credit card details can be found in the encrypted email you received when the customer made the order.</p>
-<:if Or [order ccPAN] [order ccName]:>
+<:.end if:>
+<:.elsif order.paymentType == 0:>
+<p>Payment made by credit card. Credit card details can be found in the encrypted email you received when the customer made the order.</p>
+<:.if order.ccPAN or order.ccName :>
<table>
-<:ifOrder ccName:>
+<:.if order.ccName:>
<tr><th>Card Holder</th><td><:order ccName:></td>
-<:or:><:eif:>
-<:ifOrder ccPAN:>
+<:.end if:>
+<:.if order.ccPAN:>
<tr><th>Card Number (partial)</th><td>...<:order ccPAN:></td>
-<:or:><:eif:>
+<:.end if:>
</table>
-<:or Or:><:eif Or:>
-<:case Eq [order paymentType] "1":><p>Payment will be made by cheque.</p>
-<:case Eq [order paymentType] "2":><p>Contact the customer to arrange for payment.</p>
-<:case Eq [order paymentType] "3":><p>Paid manually (staff marked this order paid) - you can <a href="<:adminurl shopadmin a_order_unpaid 1 id [order id]:>">unmark it</a></p>
-<:case Eq [order paymentType] "4":><p>Paid via PayPal, transaction id <:order paypal_tran_id:><:ifUserCan bse_shop_order_refund_paypal:> <a href="<:adminurl shopadmin a_paypal_refund 1 id [order id]:>">Refund</a><:or:><:eif:></p>
-<:endswitch:>
+<:.end if:>
+<:.elsif order.paymentType == 1 -:>
+ <p>Payment will be made by cheque.</p>
+<:.elsif order.paymentType == 2 -:>
+ <p>Contact the customer to arrange for payment.</p>
+<:.elsif order.paymentType == 4:><p>Paid via PayPal, transaction id <:order paypal_tran_id:><:ifUserCan bse_shop_order_refund_paypal:> <a href="<:adminurl shopadmin a_paypal_refund 1 id [order id]:>">Refund</a><:or:><:eif:></p>
+<:.end if:>
<:include custom/order_detail_payment.include optional:>
-<:if Order filled:>
+<:.if order.filled:>
<p>This order was filled on <:date order whenFilled:> by <:order whoFilled:>.</p>
-<:or Order:>
-<:ifOrder complete:>
-<p>This order hasn't been filled yet. <a href="<:adminurl shopadmin id [order id] order_filled Yep filled 1 detail 1:>">Mark order filled</a>.</p><:or:><:eif:>
-<:eif Order:>
-<:if Order instructions:>
+<:.elsif order.complete:>
+<p>This order hasn't been filled yet. <a href="<:adminurl shopadmin id [order id] order_filled Yep filled 1 detail 1:>">Mark order filled</a>.</p>
+<:.end if:>
+<:.if order.instructions:>
<p style="white-space: pre-wrap;"><:order instructions:></p>
-<:or Order:><:eif Order:>
+<:.end if:>
<table class="editform" id="auditlog">
<:include admin/include/audithead.tmpl:>
--- /dev/null
+<:# utility definitions :>
+<:-.define make_select-:>
+ <select name="<:= name :>">
+ <:-.for i in list -:>
+ <option value="<:= i[id] |html :>"
+ <:- .if i[id] eq default :> selected="selected"<:.end if -:>
+ >
+ <:= i[desc] | html :>
+ <:-.end for-:>
+ </select>
+<:-.end define -:>
Column freight_tracking;varchar(255);NO;;
Column stage;varchar(20);NO;;
Column ccPAN;varchar(4);NO;;
+Column paid_manually;int(11);NO;0;
Index PRIMARY;1;[id]
Index order_cchash;0;[ccNumberHash]
Index order_userId;0;[userId;orderDate]