MiniVend Akopia Services

[Date Prev][Date Next][Thread Prev][Thread Next][Minivend by date ][Minivend by thread ]

ECML



Dear All,

In case you want to be the first one on your block to support
the newly-announced ECML, I have made up a little module.
It takes the now-standard MiniVend checkout form names and
maps them.

To use, just copy the included ECML.pm to lib/Vend, and
then put in your minivend.cfg:

UserTag ecml Order name function
UserTag ecml posNumber 2
UserTag ecml addAttr
UserTag ecml Routine <<EOR
sub {
#::logError("ecml raw: @_");
	use Vend::ECML;
	Vend::ECML::ecml(@_);
}
EOR

In your checkout form, you put things like:

	[ecml fname]
	[ecml lname]
	[ecml address]

and of course:

	[ecml name=country options="US=United States, CA=Canada"]

which should automagically pull names out of country.asc. 8-)

I have attached a MV3.14 checkout form with some of the fields
put in.

Somewhere in the form, you will see:

<INPUT TYPE=hidden NAME=mv_click CHECKED VALUE="ECML_map">
[set ECML_map]
[ecml function=mapback]
[/set]

This maps the form inputs back into the old-style variables.

Hope you enjoy leading the pack!

-- 
Mike Heins                          http://www.minivend.com/  ___ 
                                    Internet Robotics        |_ _|____
                                    131 Willow Lane, Floor 2  | ||  _ \
It's a little-known fact            Oxford, OH  45056         | || |_) |
that the Y1K problem caused         <mikeh@minivend.com>     |___|  _ <
the Dark Ages. -- unknown           513.523.7621 FAX 7501        |_| \_\
#!/usr/bin/perl

# Vend::ECML -- map MiniVend forms/userdb to ECML checkout

package Vend::ECML;

use vars qw/$VERSION/;

use strict;
$VERSION = '0.01';

sub version {
	return $VERSION;
}

my $warnsave = $^W;
$^W = 0;
my $ecml_comment_map = <<EOF;
title	Ecom_ShipTo_Postal_Name_Prefix	4
first name	Ecom_ShipTo_Postal_Name_First	15
middle name	Ecom_ShipTo_Postal_Name_Middle	15
last name	Ecom_ShipTo_Postal_Name_Last	15
name suffix	Ecom_ShipTo_Postal_Name_Suffix	4
street1	Ecom_ShipTo_Postal_Street_Line1	20
street2	Ecom_ShipTo_Postal_Street_Line2	20
street3	Ecom_ShipTo_Postal_Street_Line3	20
city	Ecom_ShipTo_Postal_City	22
state or province	Ecom_ShipTo_Postal_StateProv	2
zip or postal code	Ecom_ShipTo_Postal_PostalCode	14
country	Ecom_ShipTo_Postal_CountryCode	2
phone	Ecom_ShipTo_Telecom_Phone_Number	10
email	Ecom_ShipTo_Online_Email	40
title	Ecom_BillTo_Postal_Name_Prefix	4
first name	Ecom_BillTo_Postal_Name_First	15
middle name	Ecom_BillTo_Postal_Name_Middle	15
last name	Ecom_BillTo_Postal_Name_Last	15
name suffix	Ecom_BillTo_Postal_Name_Suffix	4
street1	Ecom_BillTo_Postal_Street_Line1	20
street2	Ecom_BillTo_Postal_Street_Line2	20
street3	Ecom_BillTo_Postal_Street_Line3	20
city	Ecom_BillTo_Postal_City	22
state or province	Ecom_BillTo_Postal_StateProv	2
zip or postal code	Ecom_BillTo_Postal_PostalCode	14
country	Ecom_BillTo_Postal_CountryCode	2
phone	Ecom_BillTo_Telecom_Phone_Number	10
email	Ecom_BillTo_Online_Email	40
title	Ecom_ReceiptTo_Postal_Name_Prefix	4
first name	Ecom_ReceiptTo_Postal_Name_First	15
middle name	Ecom_ReceiptTo_Postal_Name_Middle	15
last name	Ecom_ReceiptTo_Postal_Name_Last	15
name suffix	Ecom_ReceiptTo_Postal_Name_Suffix	4
street1	Ecom_ReceiptTo_Postal_Street_Line1	20
street2	Ecom_ReceiptTo_Postal_Street_Line2	20
street3	Ecom_ReceiptTo_Postal_Street_Line3	20
city	Ecom_ReceiptTo_Postal_City	22
state or province	Ecom_ReceiptTo_Postal_StateProv	2
zip or postal code	Ecom_ReceiptTo_Postal_PostalCode	14
country	Ecom_ReceiptTo_Postal_CountryCode	2
phone	Ecom_ReceiptTo_Telecom_Phone_Number	10
email	Ecom_ReceiptTo_Online_Email	40
card	Ecom_Payment_Card_Name	30
card type Ecom_Payment_Card_Type	4
card number Ecom_Payment_Card_Number	19
cardholder verification value Ecom_Payment_Card_Verification	4
card expiration date day Ecom_Payment_Card_ExpDate_Day	2
card expiration date month Ecom_Payment_Card_ExpDate_Month	2
card expiration date year Ecom_Payment_Card_ExpDate_Year	4
payment protocols available Ecom_Payment_Card_Protocol	20
consumer generated order ID Ecom_ConsumerOrderID	20
schema version number Ecom_SchemaVersion	30
end transaction flag Ecom_TransactionComplete
EOF

my $ecml_field_map = <<EOF;
title	Ecom_ShipTo_Postal_Name_Prefix	4
name	Ecom_ShipTo_Postal_Name_Combined	40	
fname	Ecom_ShipTo_Postal_Name_First	20	
mname	Ecom_ShipTo_Postal_Name_Middle	3	
lname	Ecom_ShipTo_Postal_Name_Last	20	
name_suffix	Ecom_ShipTo_Postal_Name_Suffix	4
address	Ecom_ShipTo_Postal_Street_Line1	30
address1	Ecom_ShipTo_Postal_Street_Line1	30
address2	Ecom_ShipTo_Postal_Street_Line2	30
address3	Ecom_ShipTo_Postal_Street_Line3	30
city	Ecom_ShipTo_Postal_City	22
state	Ecom_ShipTo_Postal_StateProv	2
zip	Ecom_ShipTo_Postal_PostalCode	14
country	Ecom_ShipTo_Postal_CountryCode	2	select	country
phone_day	Ecom_ShipTo_Telecom_Phone_Number	14
phone	Ecom_ShipTo_Telecom_Phone_Number	14
email	Ecom_ShipTo_Online_Email	40	
b_title	Ecom_BillTo_Postal_Name_Prefix	4	
b_fname	Ecom_BillTo_Postal_Name_First	15	
b_mname	Ecom_BillTo_Postal_Name_Middle	15	
b_lname	Ecom_BillTo_Postal_Name_Last	15	
b_name_suffix	Ecom_BillTo_Postal_Name_Suffix	4
b_address	Ecom_BillTo_Postal_Street_Line1	20
b_address1	Ecom_BillTo_Postal_Street_Line1	20
b_address2	Ecom_BillTo_Postal_Street_Line2	20
b_address3	Ecom_BillTo_Postal_Street_Line3	20
b_city	Ecom_BillTo_Postal_City	22
b_state	Ecom_BillTo_Postal_StateProv	2
b_zip	Ecom_BillTo_Postal_PostalCode	14	
b_country	Ecom_BillTo_Postal_CountryCode	2
b_phone	Ecom_BillTo_Telecom_Phone_Number	14
b_phone_day	Ecom_BillTo_Telecom_Phone_Number	14
b_email	Ecom_BillTo_Online_Email	40
r_title	Ecom_ReceiptTo_Postal_Name_Prefix	4	
r_fname	Ecom_ReceiptTo_Postal_Name_First	15	
r_mname	Ecom_ReceiptTo_Postal_Name_Middle	15	
r_lname	Ecom_ReceiptTo_Postal_Name_Last	15
r_name_suffix	Ecom_ReceiptTo_Postal_Name_Suffix	4
r_address1	Ecom_ReceiptTo_Postal_Street_Line1	20
r_address2	Ecom_ReceiptTo_Postal_Street_Line2	20
r_address3	Ecom_ReceiptTo_Postal_Street_Line3	20
r_city	Ecom_ReceiptTo_Postal_City	22
r_state	Ecom_ReceiptTo_Postal_StateProv	2
r_zip	Ecom_ReceiptTo_Postal_PostalCode	14	
r_country	Ecom_ReceiptTo_Postal_CountryCode	2
r_phone_day	Ecom_ReceiptTo_Telecom_Phone_Number	10
r_phone	Ecom_ReceiptTo_Telecom_Phone_Number	10
r_email	Ecom_ReceiptTo_Online_Email	40
c_name	Ecom_Payment_Card_Name	30
mv_credit_card_type	Ecom_Payment_Card_Type	4
mv_credit_card_number	Ecom_Payment_Card_Number	19
mv_credit_card_verify	Ecom_Payment_Card_Verification	4
mv_credit_card_exp_day	Ecom_Payment_Card_ExpDate_Day	2
mv_credit_card_exp_month	Ecom_Payment_Card_ExpDate_Month	2
mv_credit_card_exp_year	Ecom_Payment_Card_ExpDate_Year	4
payment_protocols_available	Ecom_Payment_Card_Protocol	20
mv_order_number	Ecom_ConsumerOrderID	20
ecml_version	Ecom_SchemaVersion	30
end_transaction_flag	Ecom_TransactionComplete	1
EOF

	$ecml_comment_map =~ s/\s+$//;
	$ecml_field_map =~ s/\s+$//;

	my (@comments) = split /\n/, $ecml_comment_map;
	my (@fields) = split /\n/, $ecml_field_map;
	
	my $ECML = {};

	for(@comments) {
		my ($comment, $ecml, $min_length) = split /\t/, $_;
		$ECML->{$ecml} = {} unless $ECML->{$ecml};
		$ECML->{$ecml}->{ecml} = $ecml;
		$ECML->{$ecml}->{comment} = $comment;
	}

	for(@fields) {
		my ($map_to, $ecml, $size, $widget, $db, $name, $attribute, $outboard) = split /\t/, $_;
		$ECML->{$ecml} = {} unless $ECML->{$ecml};
		my $ref = $ECML->{$ecml} || {};
		$ref->{ecml} = $ecml;
		$ref->{map_to} = $map_to;
		$ref->{size} = $size if $size;
		$ref->{widget} = $widget || '';
		$ref->{db} = $db || '';
		$ref->{attribute} = $attribute || '';
		$ref->{name} = $name || '';
		$ECML->{$map_to} = $ref;
	}
$^W = $warnsave;

sub output_ecml_database {
	my $out = "ecml\tmap_to\tlength\tcomment\twidget\tdb\tattribute\tname\n";
	
	for (keys %$ECML) {
		$out .= join "\t", @{$ECML->{$_}}{qw/ ecml map_to length comment widget db attribute name/};
		$out .= "\n";
		$out .= join "\t", @{$ECML->{$_}}{qw/ map_to ecml length comment widget db attribute name/};
		$out .= "\n";
	}
	return $out;
}

sub widget {
	my ($self) = @_;
	if(! $self->{name}) {
		$self->{ecml_error} = "no name passed for widget";
		return undef;
	}
	my $def = defined $ECML->{$self->{name}}
				? $ECML->{$self->{name}}
				: {};
#::logError(Vend::Util::uneval($def));
	my $name = defined $def->{ecml}
				? $def->{ecml}
				: $self->{name};
	my $run = '';
	my ($len, $type, $value, $maxlength, $size, $fname, $extra, $select);
	$fname = $name;
	if($fname =~ /\W/) {
		$fname =~ s/"/&quot;/g;
		$fname = qq{"$fname"};
	}
	unless($self->{clear}) {
		$value = $self->{value}	|| $::Values->{$name}
								|| $::Values->{$self->{name}}
								|| '';
	}
	else {
		$value = '';
	}
	if(! $def->{widget} || "\L$def->{widget}" eq 'text') {
		$size = $self->{size} || $def->{size} || '40';
		$extra = defined $self->{extra} ? " $self->{extra}" : '';
		$value =~ s/"/&quot;/g;
		$run = qq{<INPUT NAME=$name VALUE="$value" SIZE=$size$extra>};
	}
	elsif ($def->{widget} eq 'select') {
		$run .= qq{<SELECT NAME=$fname};
		$run .= ' MULTIPLE' if Vend::Util::is_yes($self->{multiple});
		$run .= " SIZE=$size" if defined $self->{size};
		$run .= '>';
		my @opts;
		if($self->{options}) {
			@opts = split /\s*,\s*/, $self->{options};
		}
		if($def->{db}) {
			my $label = $self->{label_field} || 'name';
			my $args = '';
			$args .= <<EOF;
fi=$def->{db}
ra=yes
rf=0,$label
tf=$label
ml=1000
rd==
EOF
			my $optlist = Vend::Interpolate::tag_search($args);
			$optlist =~ s/\s+$//;
			$optlist =~ s/^\s+//;
			push (@opts, split /\n+/, $optlist);
		}
		if($self->{none}) {
			unshift(@opts, "= -- NONE --");
		}
		my $default = $value;
		for (@opts) {
			$run .= '<OPTION';
			$select = '';
			s/\*$// and $select = 1;
			if ($default) {
				$select = '';
			}
			my ($value,$label) = split /=/, $_, 2;
			if($label) {
				$value =~ s/"/&quot;/;
				$run .= qq| VALUE="$value"|;
			}
			if ($default) {
				my $regex = quotemeta $value;
				$default =~ /(?:\0|^)$regex(?:\0|$)/ and $select = 1;
			}
			$run .= ' SELECTED' if $select;
			$run .= '>';
			if($label) {
				$run .= $label;
			}
			else {
				$run .= $value;
			}
		}
		$run .= '</SELECT>';
	}
	return $run;
}

sub mapback {
	my @targets = grep /^Ecom_/, keys %$ECML;
	for (@targets) {
		next unless defined $CGI::values{$_};
		$CGI::values{$ECML->{$_}{map_to}} = $CGI::values{$_};
	}
	return '';
}

sub new {
	my ($class, $opt) = @_;
	$opt = {} unless $opt;
	return bless $opt, $class;
}

sub ecml {
	my ($name, $function, $opt) = @_;
#::logError("ecml name=$name func=$function opt=$opt");
	my $self = new Vend::ECML $opt;
	$self->{name} = $name if $name;
	$function = 'widget' unless $function;
	$self->{function} = $function;
	unless ($self->can($function) ) {
		::logError("unknown ECML function $function");
		$::Scratch->{mv_ecml_error} = logError("unknown ECML function $function");
		undef $::Scratch->{mv_ecml_status};
		return undef unless $opt->{show};
		return $::Scratch->{mv_ecml_error};
	}
#::logError(Vend::Util::uneval($self));
	my $status = $self->$function();
	if(! $status) {
		$::Scratch->{mv_ecml_error} = $self->{failure}
									|| $self->{ecml_error}
									|| "$function failed";
		return $::Scratch->{mv_ecml_error} if $self->{show};
		return $status unless $self->{hide};
		return '';
	}
	$::Scratch->{mv_ecml_message} = $self->{success};
	return $self->{success} if $self->{show};
	return '' if $self->{hide};
	return $status;
}

1;
Title: [L]Check out[/L] -- __COMPANY__
[include pages/logobar] [if session logged_in] [then] [set [L]Log out[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=logout clear=1] [/set]
[L]Hi[/L] [value name]! [L]You are logged in as user[/L] [value mv_username].
Change your password
[if type=data term="userdb::acl::[data session username]"] Check order status [/if]
[/then] [else] [set Login] mv_todo=return mv_nextpage=ord/checkout [userdb login] [/set] [if session failure]

[data session failure]

[/if] [L]If you have an account with us, please enter your user name and password[/L]. (test/test for testing)

[L]Username[/L] [page new_account][L]Create a new account[/L][/page]
[L]Password[/L]   
[/else][/if]
[if items] [then] [item-list] [/item-list]
[L]Order details[/L]
remove [item-description] [item-quantity] @ [item-price] [item-subtotal]
Back to cart
[L]Subtotal[/L] [subtotal]
[L]Sales Tax[/L] [salestax]
[L]Shipping[/L] [shipping]
[L]TOTAL[/L] [total-cost]

[/then] [else]

[L]No items in your basket.[/L]

[L]You can enter information, and it will be saved, but no checkout will happen until you order something![/L] [/else] [/if]

[L]Shipping Address[/L]
[L]First Name[/L] [ecml fname]
[L]Last Name[/L] [ecml lname]
[L]Address[/L] [ecml address1]
[ecml address2]


[L]City[/L]
[ecml city]
[L]State/Province[/L]
[ecml name=state extra='onChange="check_tax(this.form)"']

[L]Zip/Postal Code[/L]
[ecml zip]
[L]Email Address[/L] [ecml email]
  [L]Country[/L] [ecml name=country options="US=United States, CA=Canada"]
[L]Daytime Phone[/L]
[ecml name=phone_day] [L]Evening[/L]
[L]We need these fields to process your order[/L]
[if session logged_in] [userdb function=get_shipping_names] [set [L]Save shipping[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=set_shipping] [/set] [set [L]Recall shipping[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=get_shipping] [/set] [set [L]DELETE shipping[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=delete_shipping] [/set] [if value address_book] [/if]
You can create a new entry for the shipping address in your address book.
Nickname:
You can save the shipping address to an entry in your address book.
[loop arg="[value address_book]" ] [loop-code] [/loop]
You can recall a shipping address from your address book.
[loop arg="[value address_book]" ] [loop-code] [/loop]
You can DELETE a shipping address from your address book.
[loop arg="[value address_book]" ] [loop-code] [/loop]
[/if]

[L]Choose your shipping method[/L]

[if session ship_message]
[L]Note[/L]: [data session ship_message]
[/if]
[L]Credit Card Information[/L]        

[L]Card Number[/L] (test number 4111 1111 1111 1111)
[L]Expires[/L]
[L]Pay by credit card[/L]
[L]I will call with payment information[/L]
[if value tried_credit_card] [L]Force this card number to be taken[/L]
[/if]
[L]Billing Address (if different)[/L]
[L]Name[/L]
[L]Address[/L]
[L]City[/L], [L]State[/L], [L]Postal Code[/L]
[if session logged_in] [userdb function=get_billing_names] [set [L]Save billing[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=set_billing] [/set] [set [L]Recall billing[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=get_billing] [/set] [set [L]DELETE billing[/L]] mv_todo=return mv_nextpage=ord/checkout [userdb function=delete_billing] [/set] [if value accounts] [/if]
You can create a new entry for the billing address in your account book.
Nickname:
You can save the billing address to an entry in your account book.
[loop arg="[value accounts]" ] [loop-code] [/loop]
You can recall a billing address from your account book.
[loop arg="[value accounts]" ] [loop-code] [/loop]
You can DELETE a billing address from your account book.
[loop arg="[value accounts]" ] [loop-code] [/loop]
[/if] [set [L]Place Order![/L]] mv_todo=submit [if config CyberCash]mv_cyber_mode=__CYBER_MODE__ [/if] [/set] [set ECML_map] [ecml function=mapback] [/set] [if session logged_in]
Yes No Send an email copy of my receipt
Save my information in the database [set Save_database] [userdb save] [/set] [/if]

Gift note or Special Instructions

Return to __COMPANY__ home page (make sure you save first!)
[include pages/menubar] [include pages/copyright] [set checkout_profile] name=required address=required city=required country=required [calc] my $country = q{[cgi country]}; $country =~ s/\W+//g; return 'phone_day=phone' unless $country =~ /^(US|CA|USA|UnitedStates|Canada)$/i; return "state=state_province\nzip=zip\nphone_day=phone_us"; [/calc] email=required email=email &fatal = yes [if value fax_order] &set = mv_payment Call Us [elsif config CyberCash] &set=mv_payment CyberCash Credit Card [/elsif] [elsif config CreditCardAuto] &set=mv_payment Credit Card ([default mv_credit_card_type unknown]) mv_credit_card_info=required [/elsif] [else] &set=mv_payment Will Call [/else] [/if] &final = yes &set=mv_email [value email] [/set]

Search for: Match: Format: Sort by: