SOLVED
This is the diagnosis and solution to the error message(s)
Sage Pay error: Status: MALFORMED 3147 : The BillingState field is required
or
Sage Pay error: Status: MALFORMED 3147 : The DeliveryState field is required
As per the Sage Pay protocol 2.23 specification the’ BillingState’ and ‘DeliveryState’ values must be the 2 letters state codes only not a value in the address. Check the Protocol 2.23 documentation for more details.
I created a dB table and added it to my ecommerce database to store the state codes;
I had to create parallel pages to introduce a separate U.S. Checkout pathway which meant creating U.S. versions of the following forms
User registration
Update user profile
Checkout
Confirm
and edit
to Protox-VSPF.php
The reason for this is the US 2 digit codes are required for US purchases from US card holders or from non US customers having the product shipped to a US address. These codes mean nothing nor are there are any compatible codes for the rest of the planet so you still need to either capture these separately or omit the county/state field completely which is no good when printing address labels later.
You need to add the following to Protox-VSPF.php
(In my case around line 28)
, $tBillingState,$tShippingState
ALSO add this
(In my case around line 100)
if ($tBillingState) {
$retStr .= "BillingState=" . $tBillingState . "&";
}
if ($tShippingState) {
$retStr .= "DeliveryState=" . $tShippingState . "&";
}
You need to add this code to the bottom of your confirm.php
Look for the function WA_Protx_VSPFormHash (around line 580 in my script)
Within the value pairs crypt input array at the end after the last values before the closing /> input tags and above the modify button.
"".((isset($_POST["state_province"]))?$_POST["state_province"]:"") ."", "".((isset($_POST["shipping_state_province"]))?$_POST["shipping_state_province"]:"") ."");
Simply upload the scripts and replace the existing ones; Please back up your existing files first so you can roll back if it goes wrong.
This will work in the case of a US registered user shipping to a US address however will still generate a error if a non US citizen is shipping to the US this can be fixed by amending the following input value on the checkout.php page.
STATE_PROVINCE
<input type="text" name="state_province" id="state_province" value="<?php if($row_UserRS1['UserCountry'] == "United States" || $row_UserRS1['UserCountry']=="United States Minor Outlying Islands" || $row_UserRS1['UserCountry']=="Virgin Islands, US") {echo $row_UserRS1['UserState'];} else {echo '';} ?>" placeholder="LEAVE BLANK"/>
That solves both instances however you will not be logging the County/state address field for non US customers unless you do as I and create a parallel system and you will need to ensure they are still using the original forms.
I hope this helps if you remember Back up everything you can always go back and are risking nothing.
Thanks very much to Jason and all at Webassist for the prompt response and fantastic support.
All the best
Steve