mglaman / commerce_checkout_api

Exploring a checkout API for Drupal Commerce
1 stars 1 forks source link

Implementation notes #1

Open mglaman opened 6 years ago

mglaman commented 6 years ago

Drupal Commerce allows for a completely custom checkout experience.

First: we cannot make any assumptions about the checkout or available features. We'll need the API to provide a description of what is required by the consumer.

Second: shipping. Shipping will probably have to be a second-class citizen, at first.

Third: We can't assume the cart module or API exists, but work well with them.

References:

The community started some efforts:

Ideas

POST /checkout/summary

This returns a summary of the order if it were to enter checkout.

We need to consider accepting an order ID AND a blob of purchasable entities (making a mock order.) Former discussed in next documented request.

If there is an error due to availability, or something else we should return a 400 status code and why the order would fail checkout.

Request

{
  "addresses": {
    "billing": {
      "countryCode": "US",
      "postalCode": "53177",
      "locality": "Milwaukee",
      "addressLine1": "Pabst Blue Ribbon Dr",
      "administrativeArea": "WI",
      "givenName": "Frederick",
      "familyName": "Pabst"
    },
    "shipping": {}
  },
  "couponCodes": [],
  "order_items": [
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "3",
      "quantity": "1"
    },
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "6",
      "quantity": "10"
    }
  ]
}

Response

Status code: 200

{
  "store_id": 1,
  "total_price": {
    "number": "303.98",
    "currency_code": "USD"
  },
  "adjustments": [
    {
      "type": "promotion",
      "label": "Über summer special",
      "amount": {
        "number": "-10.00",
        "currency_code": "USD"
      }
    }
  ],
  "order_items": [
    {
      "type": "physical_product_variation",
      "purchased_entity": 4,
      "title": "Drupal Commerce Hoodie - Green, Small",
      "quantity": "1.00",
      "unit_price": {
        "number": "52.00",
        "currency_code": "USD"
      },
      "total_price": {
        "number": "104.00",
        "currency_code": "USD"
      }
    },
    {
      "type": "physical_product_variation",
      "purchased_entity": 15,
      "title": "Pronto600 Instant Camera",
      "quantity": "10.00",
      "unit_price": {
        "number": "99.99",
        "currency_code": "USD"
      },
      "total_price": {
        "number": "199.98",
        "currency_code": "USD"
      }
    }
  ],
  "shipments": []
}

GET /checkout/summary/{order_id}

This returns a summary for a specified order. There are quite a few problems here, as we do not have any kind of "ownership" in the checkout. Ownership is decided by the cart module. So someone could enumerate through the summary and possibly expose another customer's order and information.

Response

Status code: 200

{
  "store_id": 1,
  "total_price": {
    "number": "303.98",
    "currency_code": "USD"
  },
  "adjustments": [
    {
      "type": "promotion",
      "label": "Über summer special",
      "amount": {
        "number": "-10.00",
        "currency_code": "USD"
      }
    }
  ],
  "order_items": [
    {
      "type": "physical_product_variation",
      "purchased_entity": 4,
      "title": "Drupal Commerce Hoodie - Green, Small",
      "quantity": "1.00",
      "unit_price": {
        "number": "52.00",
        "currency_code": "USD"
      },
      "total_price": {
        "number": "104.00",
        "currency_code": "USD"
      }
    },
    {
      "type": "physical_product_variation",
      "purchased_entity": 15,
      "title": "Pronto600 Instant Camera",
      "quantity": "10.00",
      "unit_price": {
        "number": "99.99",
        "currency_code": "USD"
      },
      "total_price": {
        "number": "199.98",
        "currency_code": "USD"
      }
    }
  ],
  "shipments": []
}

POST /checkout

Anonymous / New card

{
  "addresses": {
    "billing": {
      "countryCode": "US",
      "postalCode": "53177",
      "locality": "Milwaukee",
      "addressLine1": "Pabst Blue Ribbon Dr",
      "administrativeArea": "WI",
      "givenName": "Frederick",
      "familyName": "Pabst"
    },
    "shipping": {}
  },
  "couponCodes": [],
  "order_items": [
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "3",
      "quantity": "1"
    },
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "6",
      "quantity": "10"
    }
  ],
  "payment": {
    "gateway": "braintree",
    "nonce": "NONCE FROM MANUAL INTEGRATION"
  }
}

Existing user and card

{
  "addresses": {
    "billing": {
      "countryCode": "US",
      "postalCode": "53177",
      "locality": "Milwaukee",
      "addressLine1": "Pabst Blue Ribbon Dr",
      "administrativeArea": "WI",
      "givenName": "Frederick",
      "familyName": "Pabst"
    },
    "shipping": {}
  },
  "couponCodes": [],
  "order_items": [
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "3",
      "quantity": "1"
    },
    {
      "purchased_entity_type": "commerce_product_variation",
      "purchased_entity_id": "6",
      "quantity": "10"
    }
  ],
  "payment": {
    "paymentMethodId": 10
  }
}

POST /checkout/{order_id}

{
  "payment": {
    "paymentMethodId": 10
  }
}
mglaman commented 6 years ago

Welp, see https://github.com/solody/commerce_checkout_api

https://www.drupal.org/project/commerce_cart_api/issues/2970959

mglaman commented 6 years ago

Both the summary and finalize need to run checks against violations. See https://www.drupal.org/project/commerce/issues/2948117

That means the payload returned should be

{
   "violations": [],
  "order" {}
}