13

I just looked in the Salesforce.com documentation for a way to update currency rates using Apex, but I have a vague feeling that this is not possible using standard features. I noticed that a couple of packages on AppExchange are doing this for free, but I was looking to integrate our own module since we use a different rate provider. I guess that it is related to DatedConversionRate (detailed here)

What is the best way to achieve this? I guess it's doable using a workaround such as calling the Metadata API, but not sure how to implement it. Any sample/example?

Thanks!

Andrew Fawcett
  • 40,561
  • 5
  • 99
  • 127
jpmonette
  • 4,440
  • 8
  • 38
  • 69
  • You are correct re: APEX. See SFDC doc http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_dml_non_dml_objects.htm?SearchType=Stem – cropredy Jun 26 '13 at 16:41
  • Is this the only solution I have to achieve this? https://github.com/financialforcedev/apex-mdapi – jpmonette Jun 26 '13 at 17:23
  • @AndrewFawcett How will we use your code to update more than 1 currency at a time. Since m getting too many future calls error in runtime. – sunny Nov 28 '13 at 07:24

2 Answers2

31

The Metadata API does not give access to this information, this is used for org configuration such as custom objects and fields. CurrencyType and DatedConversionRate contain record level information. As per the documentation you linked to, you can use the SOAP API to insert and udpate records in these.

All standard and custom objects can also be accessed through the SOAP API.

Which I also assume would mean the REST API aswell and indeed it does...

Here is a working REST API insert via Apex for DatedConversionRate...

    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v28.0/sobjects/DatedConversionRate/');
    req.setBody('{ "IsoCode" : "ADP", "ConversionRate" : 1.5, "StartDate" : "2013-06-26" }');
    req.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
    req.setHeader('Content-Type', 'application/json');
    req.setMethod('POST');
    HttpResponse res = h.send(req);

Here is a working REST API update via Apex for DatedConversionRate...

    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v28.0/sobjects/DatedConversionRate/04wb0000000KzHlAAK?_HttpMethod=PATCH');
    req.setBody('{ "ConversionRate" : 2.5 }');
    req.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
    req.setHeader('Content-Type', 'application/json');
    req.setMethod('POST');
    HttpResponse res = h.send(req);

Note: Using setMethod('PATCH') gives an Apex error. The documentation for HttpRequest.setMethod does not list 'PATCH' as a method, though it says 'for example', so its unclear if its saying its not supported or the documentation author just missed it out.

Fortunately you can override the Http method as a URL parameter as described here.

If you use an HTTP library that doesn't allow overriding or setting an arbitrary HTTP method name, you can send a POST request and provide an override to the HTTP method via the query string parameter _HttpMethod. In the PATCH example, you can replace the PostMethod line with one that doesn't use override: PostMethod m = new PostMethod(url + "?_HttpMethod=PATCH");

Andrew Fawcett
  • 40,561
  • 5
  • 99
  • 127
  • 2
    This is brilliant! It never occurred to me that Apex could 'callout' to the SFDC cloud. Veils lifted from my eyes! This solves another problem I had of Apex provisioning Sobject SelfServiceUser, also not supported by Apex DML – cropredy Jun 27 '13 at 01:19
  • Great, thanks for this response too Andrew! Is there a reason why Salesforce.com doesn't allow DML access to CurrencyType and other objects? – jpmonette Jun 27 '13 at 14:21
  • 2
    I suspect its purely for internal historic architecture reasons, these objects predate even Apex! :) This answer gave me a few more challenges than the other, as all you get back is 'Bad Request' if you have say for example, forgot to enable Advanced Multi-Currency in your dev org! Doh! ;-) – Andrew Fawcett Jun 27 '13 at 14:24
  • @jpmonette How did this work out for you? Did it get you going? – Andrew Fawcett Jul 25 '13 at 11:23
  • @AndrewFawcett We didn't went forward yet with the MultiCurrency project, mainly because of the reasons raised in this topic http://salesforce.stackexchange.com/questions/13392/how-to-use-advanced-currency-management-acm-in-custom-objects. We might create a homemade-module to workaround some limitations in this feature, not sure yet... Your answer was pretty awesome thought, working pretty well :) – jpmonette Jul 26 '13 at 22:33
  • 1
    Ah I see, shame, glad the answer I gave at least resolved part of you it for you though! Happy to help! :) – Andrew Fawcett Jul 26 '13 at 22:35
  • @AndrewFawcett Can you please help on a similar issue (http://salesforce.stackexchange.com/questions/49428/error-system-httpresponsestatus-unauthorized-statuscode-401-when-updating-c) – Swati Sep 15 '14 at 12:28
2

Although this is a few years old it is still awesome and saved my bacon. Part of our solution needed to remove some Dated Conversion Rate records as well. Thought I'd just throw this up here for quick reference even though everyone could probably figure it out pretty quickly.

Here is a working REST API delete via Apex for DatedConversionRate...

Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v28.0/sobjects/DatedConversionRate/04wb0000000KzHlAAK?_HttpMethod=DELETE');
req.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
req.setHeader('Content-Type', 'application/json');
req.setMethod('POST');
HttpResponse res = h.send(req);
Guy Bickel
  • 21
  • 1