0

It's been awhile since I have done any Perl work and I need to write a credit card processing module. The module will have several sub routines, but once I figure out how to do one, I can do the rest. The first subroutine is add customer info. The information that I need is customer number, first name, last name, address, city, state and zip. All of this information will be provided by the calling program, but some of the fields could be blank.

sub addCustomer()
{
    my $tx = new Business::OnlinePayment("USAePay");
    $tx->content(
        login           => LOGIN,
        password        => PASSWORD,
        type            => "CC",
        action          => 'Recurring Authorization',
        description    => 'Business::OnlinePayment test',
        amount         => '49.95',
        invoice_number => '100100',
        name           => 'Tofu Beast',
        card_number    => '46464646464646',
        expiration     => '11/08',
        address        => '1234 Bean Curd Lane, San Francisco',
        zip            => '94102',
    );
    $tx->submit();

    if($tx->is_success()) {
        print "Card processed successfully: ".$tx->authorization."\n";
    } else {
        print "Card was rejected: ".$tx->error_message."\n";
    }
}
Craig
  • 1,205
  • 2
  • 21
  • 54
  • 2
    You should start by reading and absorbing [Perl subroutines](http://perldoc.perl.org/perlsub.html) and [Perl module style guide](http://perldoc.perl.org/perlmodstyle.html) – Borodin Nov 03 '15 at 17:12
  • Possible duplicate of [Perl Subroutine Arguments](http://stackoverflow.com/questions/19234209/perl-subroutine-arguments) – Matt Jacob Nov 03 '15 at 17:16
  • Don't use prototypes (the parentheses in the `sub` declaration). They are not required, and they do not do what you think they do. They will more likely give you strange errors than anything else. They are used to make subroutines mimic built-in functions, nothing else. Yours should be `sub addCustomer {`. – TLP Nov 03 '15 at 17:16

3 Answers3

2

Traditional way:

addCustomer($number, $firstName, $lastName, $address, $city, $state, $zip);

sub addCustomer {
    my ($number, $firstName, $lastName, $address, $city, $state, $zip) = @_;
    ...

For so many parameters, named parameters might be more readable:

addCustomer( number     => $number,
             first_name => $firstName,
             last_name  => $lastName,
             address    => $address,
             city       => $city,
             state      => $state,
             zip        => $zip,
           );

sub addCustomer {
    my %opts = ( city => 'New York', # The defaults.
                 @_);

In newer Perl versions (5.20+), you can also use the signatures feature.

use feature qw{ signatures };

sub addCustomer($number, $firstName, $lastName, $address, $city, $state, $zip) {

For the blank parameters, use undef or q() if you don't use the named parameters:

addCustomer(123, q(), 'Doe', '123 Street', 'London', undef, 'WC1A1BN')
choroba
  • 231,213
  • 25
  • 204
  • 289
  • 1
    Note that it is unlikely that another installation will have Perl v5.20 available, so if there is any intention of writing something portable then you should stick to the traditional techniques – Borodin Nov 03 '15 at 17:16
  • Why use `q()` when the simplest way to put it is `''` or `""`, something that everyone understands. – TLP Nov 03 '15 at 17:18
  • @TLP: [PBP](https://www.safaribooksonline.com/library/view/perl-best-practices/0596001738/ch04.html) – choroba Nov 03 '15 at 17:19
  • @choroba Where in there does it say that you should use `q()` over `''`? – TLP Nov 03 '15 at 17:50
  • @TLP Did you click the link? (PBP is a link to the relevant chapter.) It's in there... unfortunately (can't say I agree with that suggestion). – Matt Jacob Nov 03 '15 at 18:24
2

You want to not do this:

sub addCustomer()

Because that prototypes your sub as having no parameters. You probably don't want to prototype at all, because perl prototypes aren't what everyone else calls prototypes.

But you can read args from @_ - which is a list of input scalars - which can be references, but don't need to be.

my ( $first_arg, $second, $another, @everything_else ) = @_; 

Note - assigning to a list will consume the rest of the values, so you can't:

my ( @stuff, $last_arg ) = @_; 

And for a long list passing in a hash or a hash reference can be useful.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
1

Pass the parameters in as a hash (or, more accurately as a hash reference).

# Outside of the subroutine
my %new_customer = (
    login          => LOGIN,
    password       => PASSWORD,
    type           => "CC",
    action         => 'Recurring Authorization',
    description    => 'Business::OnlinePayment test',
    amount         => '49.95',
    invoice_number => '100100',
    name           => 'Tofu Beast',
    card_number    => '46464646464646',
    expiration     => '11/08',
    address        => '1234 Bean Curd Lane, San Francisco',
    zip            => '94102',
);

add_customer(\%new_customer);

# Your subroutine
sub add_customer {
    my ($cust_ref) = @_;

    # Note: Don't use indirect object notation
    my $tx = Business::OnlinePayment->new("USAePay");

    $tx->content( %$cust_ref );
    $tx->submit();

    if ($tx->is_success()) {
        print "Card processed successfully: ".$tx->authorization."\n";
    } else {
        print "Card was rejected: ".$tx->error_message."\n";
    }
}
Dave Cross
  • 68,119
  • 3
  • 51
  • 97