Magento – Include customer address in customerCustomerCreate API call

apicustomercustomer-addresssoapwsdl

Due to business and technical requirements, all customers must have an associated billing address when they're first created. We've got this working great on the frontend and backend; however, there's currently no way to pass the address via the customerCustomerCreate v2 SOAP method.

Is it possible to somehow extend this method to accept the following billing address fields?

  • Street
  • City
  • State
  • Zip
  • Country

If so:

  1. How would I add these to the WSDL?
  2. How would I convert the submitted API data into an associated address? Is there some event I could observe?

Thanks!

Best Answer

I think the best approach would be to implement your own API method based on existing customer and address methods. You'll have to create a custom module.

Module structure:

-Foo/
--Bar/
---etc/
----api.xml
----config.xml
----wsdl.xml
---Model/
----Customer/
-----Api/
------V2.php
-----Api.php

etc/api.xml

<?xml version="1.0"?>
<config>
    <api>
        <resources>
            <foo_bar translate="title" module="foo_bar">
                <model>foo_bar/customer_api</model>
                <title>Customer API</title>
                <acl>foo_bar</acl>
                <methods>
                    <create translate="title" module="foo_bar">
                        <title>Create customer</title>
                        <acl>foo_bar/create</acl>
                    </create>
                </methods>
                <faults module="foo_bar">
                    <data_invalid>
                        <code>100</code>
                        <message>Invalid customer data. Details in error message.</message>
                    </data_invalid>
                </faults>
            </foo_bar>
        </resources>
        <v2>
            <resources_function_prefix>
                <foo_bar>fooBar</foo_bar>
            </resources_function_prefix>
        </v2>
        <acl>
            <resources>
                <foo_bar translate="title" module="foo_bar">
                     <title>Foo Bar</title>
                     <sort_order>3</sort_order>
                     <create translate="title" module="foo_bar">
                        <title>Create</title>
                     </create>
                </foo_bar>
            </resources>
        </acl>
    </api>
</config>

etc/wsdl.xml

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"
             name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}">
    <types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento">
            <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" />
            <complexType name="fooBarCreateCustomerData">
                <all>
                    <element name="customer_id" type="xsd:int" minOccurs="0" />
                    <element name="email" type="xsd:string" minOccurs="0" />
                    <element name="firstname" type="xsd:string" minOccurs="0" />
                    <element name="lastname" type="xsd:string" minOccurs="0" />
                    <element name="middlename" type="xsd:string" minOccurs="0" />
                    <element name="password" type="xsd:string" minOccurs="0" />
                    <element name="website_id" type="xsd:int" minOccurs="0" />
                    <element name="store_id" type="xsd:int" minOccurs="0" />
                    <element name="group_id" type="xsd:int" minOccurs="0" />
                    <element name="prefix" type="xsd:string" minOccurs="0" />
                    <element name="suffix" type="xsd:string" minOccurs="0" />
                    <element name="dob" type="xsd:string" minOccurs="0" />
                    <element name="taxvat" type="xsd:string" minOccurs="0" />
                    <element name="gender" type="xsd:int" minOccurs="0" />
                </all>
            </complexType>
            <complexType name="fooBarCreateAddressData">
                <all>
                    <element name="city" type="xsd:string" minOccurs="0" />
                    <element name="company" type="xsd:string" minOccurs="0" />
                    <element name="country_id" type="xsd:string" minOccurs="0" />
                    <element name="fax" type="xsd:string" minOccurs="0" />
                    <element name="firstname" type="xsd:string" minOccurs="0" />
                    <element name="lastname" type="xsd:string" minOccurs="0" />
                    <element name="middlename" type="xsd:string" minOccurs="0" />
                    <element name="postcode" type="xsd:string" minOccurs="0" />
                    <element name="prefix" type="xsd:string" minOccurs="0" />
                    <element name="region_id" type="xsd:int" minOccurs="0" />
                    <element name="region" type="xsd:string" minOccurs="0" />
                    <element name="street" type="typens:ArrayOfString" minOccurs="0" />
                    <element name="suffix" type="xsd:string" minOccurs="0" />
                    <element name="telephone" type="xsd:string" minOccurs="0" />
                    <element name="is_default_billing" type="xsd:boolean" minOccurs="0" />
                    <element name="is_default_shipping" type="xsd:boolean" minOccurs="0" />
                </all>
            </complexType>
        </schema>
    </types>
    <message name="fooBarCreateRequest">
        <part name="sessionId" type="xsd:string" />
        <part name="customerData" type="typens:fooBarCreateCustomerData" />
        <part name="addressData" type="typens:fooBarCreateAddressData" />
    </message>
    <message name="fooBarCreateResponse">
        <part name="result" type="xsd:int" />
    </message>
    <portType name="{{var wsdl.handler}}PortType">
        <operation name="fooBarCreate">
            <documentation>Create customer</documentation>
            <input message="typens:fooBarCreateRequest" />
            <output message="typens:fooBarCreateResponse" />
        </operation>
    </portType>
    <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
        <operation name="fooBarCreate">
            <soap:operation soapAction="urn:{{var wsdl.handler}}Action" />
            <input>
                <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </input>
            <output>
                <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </output>
        </operation>
    </binding>
</definitions>

Model/Customer/Api.php

<?php

class Foo_Bar_Model_Customer_Api extends Mage_Customer_Model_Customer_Api
{
    public function create($customerData, $addressData)
    {
        $customer = Mage::getModel('customer/customer');
        Mage::log($customerData, null, 'customerData.log', true);

        try {
            $customer->setData($this->_prepareData($customerData));
            $address = Mage::getModel('customer/address');

            foreach ($this->getAllowedAttributes($address) as $attributeCode=>$attribute) {
                if (isset($addressData->$attributeCode)) {
                    $address->setData($attributeCode, $addressData->$attributeCode);
                }
            }

            if (isset($addressData->is_default_billing)) {
                $address->setIsDefaultBilling($addressData->is_default_billing);
            }

            if (isset($addressData->is_default_shipping)) {
                $address->setIsDefaultShipping($addressData->is_default_shipping);
            }

            $customer->addAddress($address)
                ->save();
        } catch (Mage_Core_Exception $e) {
            $this->_fault('data_invalid', $e->getMessage());
        }

        return $customer->getId();
    }
}

Model/Customer/Api/V2.php

<?php

class Foo_Bar_Model_Customer_Api_V2 extends Foo_Bar_Model_Customer_Api
{
    protected function _prepareData($data)
    {
        if (null !== ($_data = get_object_vars($data))) {
            return parent::_prepareData($_data);
        }
        return array();
    }
}

And that's it. Code could use some minor tuning but it works. I did not include etc/config.xmlas it's already a long answer and you can easily figure it out on your own.

And finally the sample API call:

<?php

$client = new SoapClient('http://magento.local/api/v2_soap?wsdl=1');

$customer = array(
    'email'             => 'apicustomer@example.com',
    'firstname'         => 'Firstname',
    'lastname'          => 'Lastname',
    'password'          => 'password',
    'website_id'        => 1,
    'store_id'          => 1,
    'group_id'          => 1,
);
$address = array(
    'firstname'             => 'Firstname',
    'lastname'              => 'Lastname',
    'create_address'        => true,
    'city'                  => 'City',
    'company'               => 'Company',
    'country_id'            => 'US',
    'region_id'             => 12,
    'postcode'              => '90210',
    'street'                => array('Street Line 1', 'Street Line 2'),
    'telephone'             => '1234567890',
    'is_default_billing'    => true,
    'is_default_shipping'   => true
);

try {
    $session = $client->login('apiuser', 'apipassword');
    $result = $client->fooBarCreate($session, $customer, $address);
} catch (SoapFault $fault) {
    echo $fault->getMessage();
}