B2C CommerceCloud から CoreのAPIを呼び出す

B2C CommerceCloud（以下B2CC）のSFRAを利用してサイトを拡張する際に、Coreとの連携や、外部システムのAPIを利用する、ということはよくあることと思います（B2CCだからってこともないですが）

そこで参考にしやすいシンプルなPluginカートリッジ（[Service Cloud Connector](https://github.com/SalesforceCommerceCloud/service-cloud-connector "Service Cloud Connector")
）があったのでその紹介とともに、SFRAのカスタマイズ方法について少し触れていきたいと思います。
※例の如く、B2C CommerceCloudアカウントが無いと、上記Githubリポジトリは参照できません。。。
ソースコードの全量がみたい！という方がいればひっそりコンタクトください
※Pluginカートリッジは、B2CCが提供しているカートリッジです。他にもWishlistや店舗受け取り機能を付与するカートリッジなどがあります。

##概要
service cloud connector は B2C Commerceの case/customer/order/shipment/payment などのデータをService CloudにRestを利用して連携する機能を持ったPluginカーリッジです。SalesforceからB2C Commerceへは B2C Commerce Open Commerce API (OCAPI)を利用して、データを連携します。

今回は、B2CCからCore側のRestAPIを呼び出す部分を紹介します。


## SFRAの拡張方法
B2C CommerceのSFRA（Storefront Reference Architecture） では 基本的な機能を実装している baseカートリッジが提供されており、そこからcustomカートリッジやPluginカートリッジなどの利用し、機能を拡張していきます。
TOP、PLP、PDP、カート、チェックアウト（決済は含まず）などの、ECの基本的な機能は、baseカートリッジで実装されており、そこに、CSSでの装飾や、独自要件の追加実装をします。

参考：[SFRA Architecture](https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp?topic=%2Fcom.demandware.dochelp%2Fcontent%2Fb2c_commerce%2Ftopics%2Fsfra%2Fb2c_sfra.html&resultof=%22%73%66%72%61%22%20)

次のセクションで、baseカートリッジのソースと、PlugInカートリッジのソースコードの一部を記載します。

## 実際のソースコード
### Controller
Order.js(baseカートリッジ）
Confirmメソッドは、注文の確定時に呼び出される処理で、エラーが無ければ、注文確定画面への遷移が行われます。

ファイルパス
`/cartridges/app_storefront_base/cartridge/controllers/Order.js`


```
server.get(
    'Confirm',
    consentTracking.consent,
    server.middleware.https,
    csrfProtection.generateToken,
    function (req, res, next) {
        var reportingUrlsHelper = require('*/cartridge/scripts/reportingUrls');
        var OrderMgr = require('dw/order/OrderMgr');
        var OrderModel = require('*/cartridge/models/order');
        var Locale = require('dw/util/Locale');
        var order = OrderMgr.getOrder(req.querystring.ID);
        var token = req.querystring.token ? req.querystring.token : null;
        if (!order
            || !token
            || token !== order.orderToken
            || order.customer.ID !== req.currentCustomer.raw.ID
        ) {
            res.render('/error', {
                message: Resource.msg('error.confirmation.error', 'confirmation', null)
            });

            return next();
        }

    // 〜〜省略〜〜

        return next();
    }
);
```


Order.js(PlugInカートリッジ）
Pluginカートリッジのフォルダ構成は、baseカートリッジと同一にして、同じ場所に該当ファイルを配置します。

ファイルパス
`/cartridges/plugin_service_cloud/cartridge/controllers/Order.js`
plugin_service_cloud が カートリッジ名で、それ以下のフォルダ構成がbaseカートリッジと同一になっています。


```
var server = require('server');
server.extend(module.superModule);

//server.append で baseカートリッジのConfirmに処理を追加しています。
server.append('Confirm', function (req, res, next) {
    var OrderMgr = require('dw/order/OrderMgr');
    var order = OrderMgr.getOrder(req.querystring.ID);
    // hookを利用して、apiを呼び出します。
    require('dw/system/HookMgr').callHook('app.order.created', 'created', order);

    next();
});

server.append('CreateAccount', function (req, res, next) {
    this.on('route:Complete', function (requ, resp) {
        if(customer.authenticated){
            require('dw/system/HookMgr').callHook('app.account.created', 'created', customer);
        }
    });
    next();
});

module.exports = server.exports();

```

拡張の詳細については[こちらのヘルプ](https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp?topic=%2Fcom.demandware.dochelp%2Fcontent%2Fb2c_commerce%2Ftopics%2Fsfra%2Fb2c_customizing_controllers_and_routes.html&resultof=%22%73%65%72%76%65%72%2e%61%70%70%65%6e%64%22%20)

### Api コール部分
認証情報（接続アプリケーションの情報など）は、BuisinessManagerの設定で保持しています。
カスタム表示ラベルやカスタムメタデータ型をイメージしてもらうとそれが近いかもしれません。

処理としては、Restを呼び出し、呼び出し後、結果を元に、B2CCの注文情報を更新しています（連携済みステータスに更新）


`/cartridges/int_service_cloud/cartridge/scripts/hooks/customerOrder.js`

```
~~~省略~~~
/**
 * This method will export the given {order} details to Service Cloud through REST API
 * If the async mode is disabled
 *
 * @param {dw.order.Order} order
 * @param {String} status
 */
function handleExport(order, status) {
    var svc;
    var endpoint;

    // Retrieve the current site and it's operation-mode value
    var Site = require('dw/system/Site').getCurrent();
    var isSyncMode = Site.getCustomPreferenceValue('sscIsAsync');

    // Exit early if we're not running in asynchronous-mode
    if (!isSyncMode) { return; }

    var sccOrderModel = new (require('../models/order'))(order);

    svc = ServiceMgr.restCreate();
    endpoint = ServiceMgr.restEndpoints.create.order;
    
    // Check if the svc variable is not undefined
    // Cannot use empty() as empty(svc) returns false even if the service is correctly initialized
    if (typeof svc === 'undefined' || empty(endpoint)) {
        return;
    }

    sccOrderModel.updateStatus(status);

    // ServiceMgr.restEndpoints.create.order は CoreのEndpointの services/apexrest/Order/Placement です
    var result = svc.call(ServiceMgr.restEndpoints.create.order, JSON.stringify(sccOrderModel));

    if (result.status === 'OK') {
        if (result.object && !result.object.isError && !result.object.isAuthError) {
            sccOrderModel.updateStatus('exported');
            sccOrderModel.updateExternalId(result.object.responseObj.recordId);
            sccOrderModel.updateSyncResponseText('Successfully Exported');
        } else {
            sccOrderModel.updateSyncResponseText(result.object.errorText);
        }
    } else {
        sccOrderModel.updateSyncResponseText(result.msg);
    }

}
exports.created = orderCreated;

```
SalesforceRestAPIのendpointを定義しているクラスや、パラメータのmodelクラスなどは別途あり、それらを呼び出しているクラスです。
※長いので一部処理を消しています。

svc.callでRestAPIを実行していますが、変数svcは、B2CCが提供しているライブラリ（[dw/svc/LocalServiceRegistry](https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp?topic=%2Fcom.demandware.dochelp%2FDWAPI%2Fscriptapi%2Fhtml%2Fapi%2Fclass_dw_svc_LocalServiceRegistry.html&resultof=%22%4c%6f%63%61%6c%53%65%72%76%69%63%65%52%65%67%69%73%74%72%79%22%20%22%6c%6f%63%61%6c%73%65%72%76%69%63%65%72%65%67%69%73%74%72%79%22%20))と、前述の認証情報を元に定義されています。

ちなみにですが、APIのリクエスト情報にカスタム情報を追加したい場合は、はCCのModel（パラメータ定義
クラス）を更新しつつ、Core側のカスタムメタデータ型で管理しているマッピング情報を追加すれば追加できます。

## まとめ
かんたんではありますが、Pluginカートリッジの紹介と、B2CCのカスタマイズやAPI連携部分の紹介をしてみました。
このように、B2CCのSFRAでは、すべての処理を0から作成するのではなく、ベースの処理を拡張するような形で開発を行います。今回紹介したのはPluginカートリッジですが、自身でカスタマイズする際に作るカスタムカートリッジでもそれは同様です。

今回は紹介していませんが、B2CCが提供しているAPI、Open Commerce APIや、新しく提供されている[commerce api](https://developer.commercecloud.com/s/article/CommerceAPI)についても記事にできたらなと思います。

それでは皆様、良いお年をー。