Edit: Found a better way, see Solution 2 below
As mentioned in the comment, the SOAP API is the way to go.
Solution 1:
Suds worked for me with slight modification (Usage of Titanium.Network.HTTPClient
instead of XMLHttpRequest
), but it does not much more than creating a SOAP envelope for the call and returning the whole XML response.
Proof-of-Concept implementation, using jQuery Deferred for request chaining:
Service.MagentoClient = function()
{
var self = this;
var suds = new SudsClient({
endpoint : "http://the-magento-host/api/v2_soap/",
targetNamespace : "urn:Magento",
});
self.login = function() {
var deferred = new $.Deferred();
var args = {
username : 'the-username',
apiKey: 'the-api-key'
};
suds.invoke("login", args, function(xmlDoc) {
self.sessionId = $(xmlDoc).find("loginReturn").text();
deferred.resolve({});
//TODO reject if no sessionid returned
});
return deferred;
};
self.setStatus = function(orderId, status, comment, notify) {
var deferred = new $.Deferred();
if (!self.sessionId) {
deferred.reject({ error: 'Login not successful.' });
return;
}
var args = {
sessionId : self.sessionId,
orderIncrementId : orderId,
status : status,
comment : comment,
notify : notify
}
suds.invoke("salesOrderAddComment", args, function(xmlDoc) {
var success = $(xmlDoc).find("salesOrderAddCommentResponse").text();
if (success) {
deferred.resolve({});
} else {
deferred.reject({ error: 'Update not successful.' });
}
});
return deferred;
};
};
Usage example:
var magento = new Service.MagentoClient();
magento.login().then(function() {
magento.setStatus('100000029', 'complete', 'soap test');
}).then(function() {
alert('Update successful');
}, function(reject) {
alert('Update failed: ' + reject.error);
});
Solution 2:
Turned out that writing an own API adapter can be really easy. With the example of this core-hack (dead link) I was able to write a clean module for a JSON-RPC adapter based on Zend_Json_Server
. It uses the same Authentication and ACL as the SOAP and XML-RPC APIs.
To use the entry point /api/jsonrpc
, the new controller has to be added to the api
route:
<config>
<frontend>
<routers>
<api>
<args>
<modules>
<my_jsonrpc before="Mage_Api">My_JsonRpc_Api</my_jsonrpc>
</modules>
</args>
</api>
</routers>
</frontend>
</config>
Update 02/2015: The above link is dead now, so I open sourced my JSON-RPC adapter as a complete extension: https://github.com/sgh-it/jsonrpc
My JS client now looks like this (again with JQuery.Deferred, but no additional 3rd party libraries for the API):
/**
* Client for the Magento API
*/
Service.MagentoClient = function()
{
var self = this;
/**
* @param string method the remote procedure to call
* @param object params parameters for the RPC
* @param callback onSuccess callback for successful request. Expects one parameter (decoded response object)
* @param callback onError callback for failed request. Expects one parameter (error message)
*
* @return void
*/
self.jsonRpc = function(method, params, onSuccess, onError) {
var request = {
method : method,
params : params,
jsonrpc : "2.0",
id : 1
};
var options = {
entryPoint : config.magentoClient.entryPoint,
method: 'post',
timeout: config.magentoClient.timeout
};
var httpClient = Titanium.Network.createHTTPClient();
httpClient.onload = function(e) {
try {
var response = JSON.parse(this.responseText);
} catch (jsonError) {
return onError(jsonError);
}
if (response.error) {
if (response.error.code == 5) { // session expired
self.sessionId = null;
}
return onError(response.error.message);
}
onSuccess(response);
};
httpClient.onerror = function(e) {
onError(e.error + '; Response:' + this.responseText);
};
httpClient.setTimeout(options.timeout);
if (httpClient.open(options.method, options.entryPoint)) {
httpClient.setRequestHeader("Content-type", "application/json");
httpClient.send(JSON.stringify(request));
} else {
onError('cannot open connection');
}
}
/**
* Retrieve session id for API
*
* @return JQuery.Deferred deferred object for asynchronous chaining
*/
self.login = function() {
var deferred = new $.Deferred();
if (self.sessionId) {
deferred.resolve();
return deferred;
}
var loginParams = config.magentoClient.login;
try {
self.jsonRpc('login', loginParams, function(response) {
if (response && response.result) {
self.sessionId = response.result;
deferred.resolve();
} else {
deferred.reject('Login failed.');
}
}, function(error) {
deferred.reject(error);
});
} catch (rpcError) {
deferred.reject(rpcError);
}
return deferred;
};
/**
* Updates order states in Magento
*
* @param string method name of the remote method
* @param object args arguments for the remote method
*
* @return JQuery.Deferred deferred object for asynchronous chaining
*/
self.call = function(method, args) {
var deferred = new $.Deferred();
if (!self.sessionId) {
deferred.reject('No session.');
return;
}
var callParams = {
sessionId : self.sessionId,
apiPath : method,
args : args
};
try {
self.jsonRpc('call', callParams, function(response) {
deferred.resolve(response.result);
}, function(error) {
deferred.reject(error);
});
} catch (rpcError) {
deferred.reject(rpcError);
}
return deferred;
};
};
Note that all methods after login are routed through call
. The method
parameter is something like sales_order.list
, the args
parameter an array or object with the method arguments.
Usage example:
var filters = [];
var magento = new Service.MagentoClient();
magento.login().then(function() {
magento.call('sales_order.list', [filters]).then(
function(orders) {
// do something with the response
}, function(error) {
alert('Magento API error: ' + error);
}
);
});
Create a di.xml [Vendor]/[Module]/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Checkout\Model\CompositeConfigProvider">
<arguments>
<argument name="configProviders" xsi:type="array">
<item name="custom_payment_config_provider" xsi:type="object">[Vendor]\[Module]\Model\CustomConfigProvider</item>
</argument>
</arguments>
</type>
</config>
Create a config provider [Vendor]/[Module]/Model/CustomConfigProvider.php
namespace [Vendor]\[Module]\Model;
use Magento\Checkout\Model\ConfigProviderInterface;
class CustomConfigProvider implements ConfigProviderInterface
{
/**
* {@inheritdoc}
*/
public function getConfig()
{
$config = [
'payment' => [
'customPayment' => [
'redirectUrl' => 'www.google.com',
]
]
];
return $config;
}
}
now you can access this from js following way
//window.checkoutConfig.payment.customPayment.redirectUrl
console.log(window.checkoutConfig.payment.customPayment.redirectUrl);
Best Answer
I was struggling with a similar matter and I found the following article, by Yireo: https://www.yireo.com/blog/2017-08-20-do-not-depend-on-window-checkoutconfig
In short, when trying to access the quote outside the checkout or cart, you need to collect the information yourself.
The important part for you is to add the information you need to your own JS component, like so:
Then create a Block-class which takes care of loading the configuration:
The above example assumes that you're using dependency injection in the
__construct()
method to load the\Magento\Checkout\Model\CompositeConfigProvider
class as$this->configProvider