質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

ECcubeとSquareの連携。

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 114

score 0

●やりたいこと
squareのapiを使用し、ECcubeのフロントページに販売件数順に表示したい。

①squareのAPIを使い、現在のsquareの商品販売件数を取得
②上記dataをECcubeへ取り込む。
③取得したdataを販売件数順に並び替え、フロントページへ表示。

と考えておりますが、squareのどのParameterから取得していいのかがわからない状態です。

前任者の方は、ECcubeとsquareの在庫の連携は作っておりました。
今回は販売件数を取得して、ランキングのような表示をしたいとのことで、こちらの問題が浮上しました。
Squareの連携経験のお有りの方にぜひアドバイスいただきたいいと思っております。
よろしくお願いいたします。

<?php
namespace Customize;
require 'vendor/autoload.php';
use Square\SquareClient;
use Dotenv\Dotenv;
class SquareApiConnector
{
    private $client;
    private $dotenv;
    public function __construct()
    {
        $this->dotenv = new Dotenv(dirname(__FILE__, 3));
        $this->dotenv->load();
        $this->client = new SquareClient([
            'accessToken' => $_ENV['SQUARE_ACCESS_TOKEN'],
            'environment' => $_ENV['SQUARE_ENVIRONMENT'],
        ]);
    }
    /**
     * WebhookのPOSTリクエストヘッダのx-square-signatureの妥当性を判定する
     */
    public function isValidSignature($notificationBody, $notificationUrl, $notificationSignature)
    {
        // Concatenate your notification URL and
        // the JSON body of the webhook notification
        $stringToSign = $notificationUrl . $notificationBody;
        // Webhook subscription signature key defined in dev portal for app 
        // webhook listener endpoint: http://webhook.site/my-listener-endpoint
        // Note: Signature key is truncated for illustration
        $webhookSignatureKey = $_ENV['SQUARE_SIGNATURE_KEY'];
        // Generate the HMAC-SHA1 signature of the string
        // signed with your webhook signature key
        $hash = hash_hmac('sha1', $stringToSign, $webhookSignatureKey, true);
        $generatedSignature = base64_encode($hash);
        // Compare HMAC-SHA1 signatures.
        return (hash_equals($generatedSignature, $notificationSignature));
    }
    /**
     * Webhookから受信したcategory_object_idから、Squareの商品SKUを取得する
     */
    public function getProductCode($catalogObjectId)
    {
        $result = $this->retrieveCatalogObject($catalogObjectId);
        return $result->getObject()->getItemVariationData()->getSku();
    }
    /**
     * Square APIのretrieve-catalog-objectを叩く
     */
    public function retrieveCatalogObject($catalogObjectId)
    {
        $api_response = $this->client->getCatalogApi()->retrieveCatalogObject($catalogObjectId, false);
        if ($api_response->isSuccess()) {
            $result = $api_response->getResult();
            return $result;
        } else {
            $errors = $api_response->getErrors();
            foreach ($errors as $e) {
                log_error($e->getDetail());
            }
            return null;
        }
    }
    /**
     * 商品コードを元に、Squareの在庫を上書きする
     */
    public function setSquareStock($productCode, $stock)
    {
        // 商品コードでSQUAREの商品を検索する
        // 分割して取得される場合があるので、カーソルの値がなくなるまでループする
        $cursor = null;
        $items = [];
        do {
            $searchResult = $this->searchCatalogItems($productCode, $cursor);
            $items = array_merge($items, $searchResult->getItems());
            $cursor = $searchResult->getCursor();
        } while (!is_null($cursor) && $cursor != '');
        // 取得した商品配列から商品コードに合致する商品IDを取得する
        $catalogObjectId = '';
        foreach ($items as $i) {
            $variations = $i->getItemData()->getVariations();
            foreach ($variations as $v) {
                if ($v->getItemVariationData()->getSku() == $productCode){
                    $catalogObjectId = $v->getId();
                    break;
                }
            }
        }
        // 商品IDが見つからない場合はエラーログを吐いて処理を中断する
        if ($catalogObjectId == '') {
            log_error('product code not found! productCode: ' . $productCode);
            return;
        }
        // SQUAREの商品の在庫数を更新する
        $this->batchChangeInventory($catalogObjectId, (string) $stock);
    }
    /**
     * Square APIのsearch-catalog-itemsを叩く
     */
    public function searchCatalogItems($productCode, $cursor = null)
    {
        $enabled_location_ids = [$_ENV['SQUARE_LOCATION_ID']];
        $product_types = ['REGULAR'];
        $body = new \Square\Models\SearchCatalogItemsRequest();
        $body->setTextFilter($productCode);
        $body->setEnabledLocationIds($enabled_location_ids);
        $body->setProductTypes($product_types);
        if (!is_null($cursor) && $cursor != '') {
            $body->setCursor($cursor);
        }
        $api_response = $this->client->getCatalogApi()->searchCatalogItems($body);
        if ($api_response->isSuccess()) {
            return $api_response->getResult();
        } else {
            $errors = $api_response->getErrors();
            foreach ($errors as $e) {
                log_error($e->getDetail());
            }
            return null;
        }
    }
    /**
     * Square APIのbatch-change-inventoryを叩く
     * Squareの商品IDの在庫数を上書きする
     */
    public function batchChangeInventory($catalogObjectId, $stock)
    {
        $physical_count = new \Square\Models\InventoryPhysicalCount();
        $physical_count->setCatalogObjectId($catalogObjectId);
        $physical_count->setState('IN_STOCK');
        $physical_count->setLocationId($_ENV['SQUARE_LOCATION_ID']);
        $physical_count->setQuantity($stock);
        $physical_count->setOccurredAt(date("Y-m-d\TH:i:s.000+09:00"));
        $inventory_change = new \Square\Models\InventoryChange();
        $inventory_change->setType('PHYSICAL_COUNT');
        $inventory_change->setPhysicalCount($physical_count);
        $changes = [$inventory_change];
        $body = new \Square\Models\BatchChangeInventoryRequest();
        $body->setIdempotencyKey(uniqid());
        $body->setChanges($changes);
        $body->setIgnoreUnchangedCounts(true);
        $api_response = $this->client->getInventoryApi()->batchChangeInventory($body);
        if ($api_response->isSuccess()) {
            log_info('success inventory updated! catalogObjectId: ' . $catalogObjectId . ' stock: ' . $stock);
            return $api_response->getResult();
        } else {
            $errors = $api_response->getErrors();
            foreach ($errors as $e) {
                log_error($e->getDetail());
            }
            return null;
        }
    }
    /**
     * Square APIのlist-catalogを叩く
     * Squareの商品を全て取得する
     */
    public function listCatalog($cursor = null){
        $api_response = $this->client->getCatalogApi()->listCatalog($cursor, 'ITEM');
        dump($api_response);
        if ($api_response->isSuccess()) {
            log_info('success get list catalogs!');
            return $api_response->getResult();
        } else {
            $errors = $api_response->getErrors();
            foreach ($errors as $e) {
                log_error($e->getDetail());
            }
            return null;
        }
    }
    /**
     * Square APIのBatch-retrieve-inventory-countsを叩く
     * Squareの在庫を全て取得する
     * ただし、在庫数はステータスがIN_STOCKのもののみを取得
     */
    public function batchRetrieveInventoryCounts($cursor = null){
        $location_ids = [$_ENV['SQUARE_LOCATION_ID']];
        $states = ['IN_STOCK'];
        $body = new \Square\Models\BatchRetrieveInventoryCountsRequest();
        $body->setLocationIds($location_ids);
        $body->setStates($states);
        if (!is_null($cursor)) {
            $body->setCursor($cursor);
        }
        $api_response = $this->client->getInventoryApi()->batchRetrieveInventoryCounts($body);
        if ($api_response->isSuccess()) {
            log_info('success batch retrieve inventory counts!');
            return $api_response->getResult();
        } else {
            $errors = $api_response->getErrors();
            foreach ($errors as $e) {
                log_error($e->getDetail());
            }
            return null;
        }
    }
    /**
     * Squareの全商品の在庫数を含む情報を返す
     */
    public function getItemInventoryData() {
        // 商品情報を取得
        // 分割して取得される場合があるので、カーソルの値がなくなるまでループする
        $cursor = null;
        $listCatalogs = [];
        dump($listCatalogs);
        do {
            $catalogResult = $this->listCatalog($cursor);
            $listCatalogs = array_merge($listCatalogs, $catalogResult->getObjects());
            $cursor = $catalogResult->getCursor();
        } while (!is_null($cursor));
        // 商品在庫情報を取得
        // 分割して取得される場合があるので、カーソルの値がなくなるまでループする
        $cursor = null;
        $inventoryCounts = [];
        do {
            $inventoryCountsResult = $this->batchRetrieveInventoryCounts($cursor);
            $inventoryCounts = array_merge($inventoryCounts, $inventoryCountsResult->getCounts());
            $cursor = $inventoryCountsResult->getCursor();
        } while (!is_null($cursor));
        $idHash = [];
        foreach ($listCatalogs as $catalog) {
            $itemData = $catalog->getItemData();
            $variations = $itemData->getVariations();
            foreach($variations as $v) {
                $item = [
                    'id' => $v->getId(),
                    'name' => $itemData->getName(),
                    'code' => $v->getItemVariationData()->getSku(),
                    // batchRetrieveInventoryCountsはIN_STOCKが0の在庫データを返さないので0で初期化
                    'stock' => 0
                ];
                $idHash[$item['id']] = $item;
            }
        }
        foreach ($inventoryCounts as $inventory) {
            $id = $inventory->getCatalogObjectId();
            $item = $idHash[$id];
            $item['stock'] = $inventory->getQuantity();
            $idHash[$item['id']] = $item;
        }
        $codeHash = [];
        foreach ($idHash as $value) {
            $codeHash[$value['code']] = $value;
        }
        return $codeHash;
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • YUOKAWARA

    2021/06/22 11:42

    かしこまりました。
    ご意見ありがとうございます。
    こちらAPIを再度調べ直して叩いてみます。

    キャンセル

  • YUOKAWARA

    2021/07/19 17:04

    こちらドキュメントを確認し、Retrieve inventory adjustmentというAPIがそれに近いと思い調べてみました。
    こちらのAPIが在庫が減ったときに、SOLDというステータスで販売した数量を確認している様です。
    ただ、こちらの中身を確認しましたが、「何個販売している」という値はありませんでした。

    キャンセル

  • tanat

    2021/07/19 19:04

    このコメント欄はコメントをした人くらいしか見ていないので、質問に追記されることをお勧めします。

    キャンセル

回答 1

0

FKMさんのコメントにある通り、
(作り方次第ですが)EC-CUBE側で注文情報は管理しているはずで、
その情報を取得する方が筋が良いかと思います。


*以下はざっとAPIを探してみただけの情報なので、参考程度と思って頂ければ。

SquareのAPIで情報を取得するのであれば、注文関連のAPIかなと思います。
(商品販売件数=注文のデータのはずなので)

Search orders
で注文一覧を取得して、そのorderIDを使って

Retrieve order
で注文の詳細を取得して集計して表示という感じでいけそうな気がします。

この場合、リアルタイムに販売数を取得するのは厳しいはずなので、
一定時間ごとにデータを取得してランキングを作るようなPHPを作って、cron等で実行するなどの工夫が必要かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る