=item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L<FS::prepay_credit>)
+=item paycvv - Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card
+
=item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy
=item payname - name on card or billing name
}
# packages
- local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'};
- $error = $self->order_pkgs($cust_pkgs, \$seconds);
+ #local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'};
+ $error = $self->order_pkgs($cust_pkgs, \$seconds, %options);
if ( $error ) {
$dbh->rollback if $oldAutoCommit;
return $error;
}
-=item order_pkgs
+=item order_pkgs HASHREF, [ , OPTION => VALUE ... ] ]
+
+Like the insert method on an existing record, this method orders a package
+and included services atomicaly. Pass a Tie::RefHash data structure to this
+method containing FS::cust_pkg and FS::svc_I<tablename> objects. There should
+be a better explanation of this, but until then, here's an example:
+
+ use Tie::RefHash;
+ tie %hash, 'Tie::RefHash'; #this part is important
+ %hash = (
+ $cust_pkg => [ $svc_acct ],
+ ...
+ );
+ $cust_main->order_pkgs( \%hash, 'noexport'=>1 );
+
+Currently available options are: I<noexport>
-document me. like ->insert(%cust_pkg) on an existing record
+If I<noexport> is set true, no provisioning jobs (exports) are scheduled.
+(You can schedule them later with the B<reexport> method for each
+cust_pkg object. Using the B<reexport> method on the cust_main object is not
+recommended, as existing services will also be reexported.)
=cut
my $self = shift;
my $cust_pkgs = shift;
my $seconds = shift;
+ my %options = @_;
local $SIG{HUP} = 'IGNORE';
local $SIG{INT} = 'IGNORE';
local $FS::UID::AutoCommit = 0;
my $dbh = dbh;
+ local $FS::svc_Common::noexport_hack = 1 if $options{'noexport'};
+
foreach my $cust_pkg ( keys %$cust_pkgs ) {
$cust_pkg->custnum( $self->custnum );
my $error = $cust_pkg->insert;
=item reexport
-document me. Re-schedules all exports by calling the B<reexport> method
-of all associated packages (see L<FS::cust_pkg>). If there is an error,
-returns the error; otherwise returns false.
+Re-schedules all exports by calling the B<reexport> method of all associated
+packages (see L<FS::cust_pkg>). If there is an error, returns the error;
+otherwise returns false.
=cut
or return gettext('invalid_card'); # . ": ". $self->payinfo;
return gettext('unknown_card_type')
if cardtype($self->payinfo) eq "Unknown";
+ if ( defined $self->dbdef_table->column('paycvv') ) {
+ if ( length($self->paycvv) ) {
+ if ( cardtype($self->payinfo) eq 'American Express card' ) {
+ $self->paycvv =~ /^(\d{4})$/
+ or return "CVV2 (CID) for American Express cards is four digits.";
+ $self->paycvv($1);
+ } else {
+ $self->paycvv =~ /^(\d{3})$/
+ or return "CVV2 (CVC2/CID) is three digits.";
+ $self->paycvv($1);
+ }
+ } else {
+ $self->paycvv('');
+ }
+ }
} elsif ( $self->payby eq 'CHEK' || $self->payby eq 'DCHK' ) {
$payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
$payinfo = "$1\@$2";
$self->payinfo($payinfo);
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
} elsif ( $self->payby eq 'LECB' ) {
$payinfo =~ /^1?(\d{10})$/ or return 'invalid btn billing telephone number';
$payinfo = $1;
$self->payinfo($payinfo);
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
} elsif ( $self->payby eq 'BILL' ) {
$error = $self->ut_textn('payinfo');
return "Illegal P.O. number: ". $self->payinfo if $error;
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
} elsif ( $self->payby eq 'COMP' ) {
$error = $self->ut_textn('payinfo');
return "Illegal comp account issuer: ". $self->payinfo if $error;
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
} elsif ( $self->payby eq 'PREPAY' ) {
return "Illegal prepayment identifier: ". $self->payinfo if $error;
return "Unknown prepayment identifier"
unless qsearchs('prepay_credit', { 'identifier' => $self->payinfo } );
+ $self->paycvv('') if $self->dbdef_table->column('paycvv');
}
$self->tax =~ /^(Y?)$/ or return "Illegal tax: ". $self->tax;
$self->tax($1);
- $self->otaker(getotaker);
+ $self->otaker(getotaker) unless $self->otaker;
#warn "AFTER: \n". $self->_dump;
my %content;
if ( $method eq 'CC' ) {
+
$content{card_number} = $self->payinfo;
$self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
$content{expiration} = "$2/$1";
- if ( qsearch('cust_pay', { 'custnum' => $self->custnum,
+
+ $content{cvv2} = $self->paycvv
+ if defined $self->dbdef_table->column('paycvv')
+ && length($self->paycvv);
+
+ $content{recurring_billing} = 'YES'
+ if qsearch('cust_pay', { 'custnum' => $self->custnum,
'payby' => 'CARD',
- 'payinfo' => $self->payinfo, } )
- ) {
- $content{recurring_billing} = 'YES';
- }
+ 'payinfo' => $self->payinfo, } );
+
} elsif ( $method eq 'ECHECK' ) {
my($account_number,$routing_code) = $self->payinfo;
( $content{account_number}, $content{routing_code} ) =
}
+ #remove paycvv after initial transaction
+ #make this disable-able via a config option if anyone insists?
+ # (though that probably violates cardholder agreements)
+ if ( defined $self->dbdef_table->column('paycvv')
+ && length($self->paycvv)
+ && ! grep { $_ eq cardtype($self->payinfo) } $conf->config('cvv-save')
+ ) {
+ my $new = new FS::cust_main { $self->hash };
+ $new->paycvv('');
+ my $error = $new->replace($self);
+ if ( $error ) {
+ warn "error removing cvv: $error\n";
+ }
+ }
+
#result handling
if ( $transaction->is_success() ) {