highsidelabs / walmart-api-php

PHP SDK for Walmart's Marketplace Partner, Content Provider, and 1P Supplier APIs.
https://highsidelabs.co
BSD 3-Clause "New" or "Revised" License
22 stars 19 forks source link

Supplier APIs not working #10

Open cnx7 opened 1 year ago

cnx7 commented 1 year ago

I think the code is in an incomplete state,and many methods cannot correspond to it ?

jlevers commented 1 year ago

Could you please give some details on the problem or problems you're encountering? This library is not yet stable (we're still on major version 0), so there are definitely still issues to be worked out. I don't have any Supplier credentials on Walmart, so there are likely to be issues with that part of the codebase, since I haven't been able to test any of it.

cnx7 commented 1 year ago

src/Walmart.php warehouseSupplier() return type does not exist, I think it should be returning Apis/Supplier/SupplierApi

This is not important, the main error lies in the subsequent interface signature, which is still calling the verification of the Market. After slightly modifying the parameters, the verification signature still cannot pass. The signature method here is different from the request address and the Market interface.

I am currently running out of time to verify and refactor the project. Our old code is still working properly, although it may appear different from the latest documentation.

The following are the methods we can currently request to successfully obtain an order. Is there any reference value

class WalmartSupplier
{
    private $url = 'https://api-gateway.walmart.com/v3/';
    private string $consumerId;
    private string $privateKey;

    public function __construct($consumerId, $privateKey)
    {
        $this->consumerId = $consumerId;
        $this->privateKey = $privateKey;
    }

    public function listOrder($params)
    {
        $timestamp = time() * 1000;
        $url       = $this->url . 'orders?' . http_build_query($params);
        $signature = $this->GetWalmartAuthSignature($url, 'GET', $timestamp);

        $headers = [
            'WM_QOS.CORRELATION_ID: ' . mt_rand(),
            'WM_SVC.NAME: Drop Ship Vendor Services',
            'WM_SEC.TIMESTAMP: ' . $timestamp,
            'WM_SEC.AUTH_SIGNATURE: ' . $signature,
            'WM_CONSUMER.ID: ' . $this->consumerId,
            'WM_CONSUMER.CHANNEL.TYPE: ' . WALMART_CHANNEL_TYPE,  // WM_CONSUMER.CHANNEL.TYPE
            'Content-Type:application/x-www-form-urlencoded',
            'Accept:application/json'
        ];

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HEADER, false);
//        curl_setopt($curl, CURLOPT_VERBOSE, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl, CURLOPT_POST, 0);
        //curl_setopt ( $curl, CURLOPT_POSTFIELDS, 'grant_type=client_credentials' );
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        return json_decode(curl_exec($curl));
    }

    public function GetWalmartAuthSignature($URL, $RequestMethod, $Timestamp)
    {
        $AuthData = "{$this->consumerId}\n{$URL}\n{$RequestMethod}\n$Timestamp\n";
        // GET AN OPENSSL USABLE PRIVATE KEY FROMM THE WALMART SUPPLIED SECRET
        $Pem        = $this->ConvertPkcs8ToPem(base64_decode($this->privateKey));
        $PrivateKey = openssl_pkey_get_private($Pem);
        // SIGN THE DATA. USE sha256 HASH
        $Hash = defined("OPENSSL_ALGO_SHA256") ? OPENSSL_ALGO_SHA256 : "sha256";
        if (openssl_sign($AuthData, $Signature, $PrivateKey, $Hash)) {
            return base64_encode($Signature);
        }
        return '';
    }

    private function ConvertPkcs8ToPem($der)
    {
        static $BEGIN_MARKER = "-----BEGIN PRIVATE KEY-----";
        static $END_MARKER = "-----END PRIVATE KEY-----";
        $key = base64_encode($der);
        $pem = $BEGIN_MARKER . "\n";
        $pem .= chunk_split($key, 64, "\n");
        $pem .= $END_MARKER . "\n";
        return $pem;
    }
}
$consumerId = '';
$privateKey = '';
$walmart = new WalmartSupplier($consumerId, $privateKey);
$params    = [
    'shipNode'         => 43739,
    'createdStartDate' => gmdate("Y-m-d\TH:i:s", (time() - 86400 * 4)),
    'createdEndDate'   => gmdate("Y-m-d\TH:i:s"),
];
$orderList = $walmart->listOrder($params);
jlevers commented 1 year ago

Give the latest version a try (v0.7.0). I don't have Supplier credentials, so I'm not able to test this call myself, but I fixed the warehouseSupplier() issue (use supplier() instead), and signature-based auth is working for me.

cnx7 commented 1 year ago

I only test function getAllOrders, here are the issues found:

  1. src/Apis/Supplier/US/DSVOrdersApi.php called $partnerApiKey = $this->config->getApiKey('partner', $requestInfo); but src/Configuration.php defined partnerId
  2. I noticed that there be errors when calling the Market method to obtain the Accesstoken. I think the supplier's API getAccesstoken method should be independent of the API market. And he doesn't need clientId and clientSecret, default host https://api-gateway.walmart.com.
  3. This interface does not require an Accesstoken, so I removed it first, But request header need WM_CONSUMER.CHANNEL.TYPE
  4. All the above modifications were made. After successfully requesting data, there was an error in serializing the data and empty data was obtained, The following is the raw data returned after the HTTP request:
    {"list":{"meta":{"totalCount":10,"limit":1,"nextCursor":"?limit=1&hasMoreElements=true&soIndex=10&poIndex=1&sellerId=0&bizRole=DSV&createdStartDate=2023-08-14T03:10:19.746Z&createdEndDate=2023-08-21T03:10:19.746Z&shipNode=43739&vendorId=43739"},"elements":{"order":[{"purchaseOrderId":"11111111","customerOrderId":"22222222","customerEmailId":"email@relay.walmart.com","orderDate":1692537988575,"mart":"Walmart.com","shippingInfo":{"phone":"1234567890","estimatedDeliveryDate":1693259940000,"estimatedShipDate":1692669600000,"methodCode":"Standard","postalAddress":{"name":"name data","address1":"address data","address2":null,"city":"city data","state":"PA","postalCode":"17112","country":"USA","addressType":"RESIDENTIAL"}},"orderLines":{"orderLine":[{"lineNumber":"1","item":{"productName":"productName data","sku":"sku data"},"charges":{"charge":[{"chargeType":"PRODUCT","chargeName":"ItemPrice","chargeAmount":{"currency":"USD","amount":23.99},"tax":{"taxName":"Tax1","taxAmount":{"currency":"USD","amount":1.44}}}]},"orderLineQuantity":{"unitOfMeasurement":"EACH","amount":"1"},"statusDate":1692546988838,"orderLineStatuses":{"orderLineStatus":[{"status":"Created","subSellerId":null,"statusQuantity":{"unitOfMeasurement":"EACH","amount":"1"},"cancellationReason":null,"trackingInfo":null,"returnCenterAddress":null}]},"refund":null,"originalCarrierMethod":"67","fulfillment":{"fulfillmentOption":"DELIVERY","shipMethod":null,"storeId":null,"pickUpDateTime":1693259940000,"pickUpBy":null,"shippingProgramType":"THREE_TO_FIVE_DAY"}}]},"paymentType":["CREDITCARD"],"orderSummary":{"totalAmount":{"currencyAmount":32.41,"currencyUnit":"USD"},"orderSubTotal":[{"subTotalType":"PRODUCT","totalAmount":{"currencyAmount":30.97,"currencyUnit":"USD"}},{"subTotalType":"TAX","totalAmount":{"currencyAmount":1.44,"currencyUnit":"USD"}}]},"pickupPersons":[{"name":{"firstName":"firstName","lastName":"lastName"},"phone":{"completeNumber":"1234567890"}}],"pickupPerson":[{"name":{"firstName":"firstName","lastName":"lastName"},"phone":{"completeNumber":"1234567890"}}]}]}}}