【Apex】カスタム住所項目の緯度経度の取得

2022年に引き続き、2回目のアドベントカレンダー参加です(\*'ω'*)

# きっかけ
カスタム住所項目がWinter'23にリリースされてから1年が過ぎ、扱うことも増えてきました。

設定自体の煩雑さはさておき
今回はカスタム住所項目の緯度経度を取るのにちょび苦戦したので記事にします。
最後に**2住所間の直線距離を取得するメソッドのサンプルコード**も書いてます。

# 標準住所項目の緯度経度の取得方法

以下のヘルプ記事が参考になりますが、
データインテグレーションルールを有効化するだけです。
[Addressクラス](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_class_system_Address.htm#apex_system_Address_getDistance)の変数に入れてあげたらlatitude、longitudeのプロパティで参照できます。

https://help.salesforce.com/s/articleView?id=sf.data_dot_com_clean_admin_automatically_get_geocodes_for_addresses.htm&type=5

# カスタム住所項目の緯度経度の取得方法

カスタム住所項目にはデータインテグレーションルールがないので
GoogleMapのAPIをコールする必要があります。
緯度経度取るためだけに外部連携、、ぐぬぬ。

### APIキーの取得

こちらの記事が分かりやすかったです。

https://excellent.ne.jp/homepage/3699/

HTTPリファラー(ウェブサイト) を設定すると
「**API keys with referer restrictions cannot be used with this API.**」
のエラーが出るので別の制限を設けること

### Apexでコールアウト処理を実装する

APIキーが取得できたら↓のヘルプどおり実装
リモートサイトまたは指定ログイン情報の設定も忘れずどうぞ

https://help.salesforce.com/s/articleView?id=sf.fields_caf_geocode.htm&type=5

# サンプルコード
**2住所間の直線距離を取得するメソッド**です。

★★★はAPIキーをいれてください。
カスタム住所項目(Address__c)の緯度経度をAPIで取得し
標準項目(Account__r.ShippingAddress)との距離をAddress.getDistance()で取得しています。
レスポンスボディは必要な要素だけ抜いてます。

殴り書きで汚くてスミマセン(\*'ω'*)


```Apex:GeoCode
public class GeoCode {
    public static Double GetDistance(Id id) {
        // レコードを取得
        CustomObject__c customObject = [SELECT Address__c, Account__r.ShippingAddress FROM CustomObject__c WHERE Id = :id];
        
        // Google Geocoding APIを呼び出し
        String key='★★★';
        Http httpProtocol = new Http();
        HttpRequest request = new HttpRequest();
        String endpoint = 'https://maps.googleapis.com/maps/api/geocode/json?address='+ customObject.Address__c +'&key='+key;
        request.setEndPoint(endpoint);
        request.setMethod('GET');
        
        // レスポンスを処理
        HttpResponse response = httpProtocol.send(request);
        Map<String, Object> results = (Map<String, Object>)JSON.deserializeUntyped(response.getBody());
        List<Object> addressComponents = (List<Object>)results.values()[0];
        Map<String, Object> component = (Map<String, Object>)addressComponents[0];
        Map<String, Object> geometry = (Map<String, Object>)component.get('geometry');
        Map<String, Object> location = (Map<String, Object>)geometry.get('location');
        
        // 緯度と経度を取得
        Double lat = (Double)location.get('lat');
        Double lng = (Double)location.get('lng');
        System.Location loc = System.Location.newInstance(lat,lng);
       
        // 標準項目との直線距離を取得
        Address shippingAddress = customObject.Account__r.ShippingAddress;
        return shippingAddress.getDistance(loc, 'km');
    }
}
```

# 実行結果
カスタム住所項目(Address__c)には**東京駅**の住所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/eb498308-373a-98d8-b0e4-c8fbb7d77d73.png)

標準項目(Account__r.ShippingAddress)には**新宿駅**の住所
※「JAPAN」にしないとデータインテグレーションルールが動かない(-_-;)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/777157b5-91f2-7763-1939-c7b298b249e2.png)


アノニマスウィンドウで実行した結果が**5.94km**
`System.debug(GeoCode.GetDistance('a0A2r000000HQYgEAO'));`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/f5a43191-dd09-185f-de0e-87d3b7ef38cb.png)

Googleマップの画面で測定した距離が**5.92km**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/a0a9841c-5a9e-887f-580c-f415d60e4fa1.png)


東京駅の住所が1丁目と広範囲であるかつ
レスポンスの処理で'location'を取ってきている（'northeast'と'southwest'もある）ので
若干ズレが出たましたが
ちゃんと住所を入れてくれたら実用できるのではないかと!(\*'ω'*)


でもわざわざAPI叩くのはもったいない気がするので
Salesforceさん、カスタム住所項目も簡単に緯度経度取れるようにしてください～～

# あとがき
Salesforce開発に携わって4年目になりました。
開発者不足で大御所扱いされる最近です。ぴえ～～。
2024年は変化の一年となり忙しくなりそうですが、Qiita投稿は適度に続けたいです！
それではみなさん、メリークリスマス＆よいお年を(\*'ω'*)