Skip to content

Commit 646fc6f

Browse files
authored
Merge pull request #15 from magento-architects/graphql-cart-schema
[ongoing discussion] Draft for cart operations and other GraphQL improvements
2 parents 8b462d4 + ca3a063 commit 646fc6f

15 files changed

+797
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
type Query {
2+
cart(input: CartQueryInput): CartQueryOutput
3+
}
4+
5+
input CartQueryInput {
6+
cart_id: String!
7+
}
8+
9+
type CartQueryOutput {
10+
cart: Cart
11+
}
12+
13+
type Cart {
14+
id: String!
15+
16+
line_items_count: Int!
17+
items_quantity: Float!
18+
19+
selected_payment_method: CheckoutPaymentMethod
20+
available_payment_methods: [CheckoutPaymentMethod]!
21+
22+
customer: CheckoutCustomer
23+
customer_notes: String
24+
25+
gift_cards_amount_used: Money
26+
applied_gift_cards: [CartGiftCard]
27+
28+
is_multishipping: Boolean!
29+
is_virtual: Boolean!
30+
}
31+
32+
type CheckoutCustomer {
33+
is_guest: Boolean!
34+
email: String!
35+
prefix: String
36+
first_name: String!
37+
last_name: String!
38+
middle_name: String
39+
suffix: String
40+
gender: GenderEnum
41+
date_of_birth: String
42+
vat_number: String # Do we need it at all on storefront? Do we need more details
43+
}
44+
45+
enum GenderEnum {
46+
MALE
47+
FEMALE
48+
}
49+
50+
type CheckoutPaymentMethod {
51+
code: String!
52+
label: String!
53+
balance: Money
54+
sort_order: Int
55+
}
56+
57+
type CartGiftCard {
58+
code: String!
59+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
type Query {
2+
setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput
3+
setShippingAddressesOnCart(input: SetShippingAddressesOnCartInput): SetShippingAddressesOnCartOutput
4+
setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput
5+
}
6+
7+
input SetShippingMethodsOnCartInput {
8+
shipping_methods: [ShippingMethodForAddressInput!]!
9+
}
10+
11+
input ShippingMethodForAddressInput {
12+
cart_address_id: String!
13+
shipping_method_code: String!
14+
}
15+
16+
input SetBillingAddressOnCartInput {
17+
customer_address_id: Int
18+
address: CartAddressInput
19+
}
20+
21+
input SetShippingAddressesOnCartInput {
22+
customer_address_id: Int # Can be provided in one-page checkout and is required for multi-shipping checkout
23+
address: CartAddressInput
24+
cart_items: [CartItemQuantityInput!]
25+
}
26+
27+
input CartItemQuantityInput {
28+
cart_item_id: String!
29+
quantity: Float!
30+
}
31+
32+
input CartAddressInput {
33+
firstname: String!
34+
lastname: String!
35+
company: String
36+
street: [String!]!
37+
city: String!
38+
region: String
39+
postcode: String
40+
country_code: String!
41+
telephone: String!
42+
save_in_address_book: Boolean!
43+
}
44+
45+
type SetShippingAddressesOnCartOutput {
46+
cart: Cart!
47+
}
48+
49+
type SetShippingMethodsOnCartOutput {
50+
cart: Cart!
51+
}
52+
53+
type SetBillingAddressOnCartOutput {
54+
cart: Cart!
55+
}
56+
57+
type Cart {
58+
addresses: [CartAddress]!
59+
}
60+
61+
type CartAddress {
62+
firstname: String!
63+
lastname: String!
64+
company: String
65+
street: [String!]!
66+
city: String!
67+
region: CartAddressRegion
68+
postcode: String
69+
country: CartAddressCountry!
70+
telephone: String!
71+
address_type: AdressTypeEnum!
72+
73+
selected_shipping_method: CheckoutShippingMethod
74+
available_shipping_methods: [CheckoutShippingMethod]!
75+
76+
items_weight: Float
77+
customer_notes: String
78+
gift_cards_amount_used: Money
79+
applied_gift_cards: [CartGiftCard]
80+
81+
cart_items: [CartItemQuantity]
82+
}
83+
84+
type CartItemQuantity {
85+
cart_item_id: String!
86+
quantity: Float!
87+
}
88+
89+
type CartAddressCountry {
90+
code: String
91+
label: String
92+
}
93+
94+
type CartAddressRegion {
95+
code: String
96+
label: String
97+
}
98+
99+
enum AdressTypeEnum {
100+
SHIPPING
101+
BILLING
102+
}
103+
104+
type CheckoutShippingMethod {
105+
code: String
106+
label: String
107+
free_shipping: Boolean!
108+
error_message: String
109+
# TODO: Add more complex structure for shipping rates
110+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
interface CartItemInterface {
2+
prices: CartItemPrices
3+
}
4+
5+
type Cart {
6+
prices: CartPrices
7+
}
8+
9+
type CartAddress {
10+
prices: CartAddressPrices
11+
# additional fields will be added later
12+
}
13+
14+
interface CartPricesInterface {
15+
grand_total: Money
16+
17+
# price display settings should be requested via store config query
18+
subtotal_including_tax: Money
19+
subtotal_excluding_tax: Money
20+
21+
subtotal_with_discount_excluding_tax: Money
22+
discount_tax_compensation: Money #Should we have subtotal with discount including tax instead, is it different from grand_total?
23+
24+
applied_taxes: [CartTaxItem]! # Should include regular taxes and WEEE taxes
25+
applied_discounts: [CartDiscountItem]!
26+
}
27+
28+
type CartItemPrices implements CartPricesInterface {
29+
price_including_tax: Money
30+
price_excluding_tax: Money
31+
32+
custom_price: Money
33+
}
34+
35+
type CartAddressPrices implements CartPricesInterface {
36+
37+
shipping_including_tax: Money
38+
shipping_excluding_tax: Money
39+
40+
shipping_discount: Money # Do we need shipping_with_discount_including_tax?
41+
shipping_discount_tax_compensation: Money
42+
}
43+
44+
type CartPrices implements CartPricesInterface {
45+
}
46+
47+
type CartTaxItem {
48+
amount: Money!
49+
label: String!
50+
}
51+
52+
type CartDiscountItem {
53+
amount: Money!
54+
label: String!
55+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
type Mutation {
2+
applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput
3+
removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput
4+
}
5+
6+
input ApplyCouponToCartInput {
7+
cart_id: String!
8+
coupon_code: String!
9+
}
10+
11+
type ApplyCouponToCartOutput {
12+
cart: Cart!
13+
}
14+
15+
type Cart {
16+
applied_coupon: AppliedCoupon
17+
}
18+
19+
type CartAddress {
20+
applied_coupon: AppliedCoupon
21+
}
22+
23+
type AppliedCoupon {
24+
# Wrapper allows for future extension of coupon info
25+
code: String!
26+
}
27+
28+
input RemoveCouponFromCartInput {
29+
cart_id: String!
30+
}
31+
32+
type RemoveCouponFromCartOutput {
33+
cart: Cart
34+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
**Overview**
2+
3+
As a Magento developer, I need to manipulate the shopping cart via GraphQL so that I can programmatically create orders on behalf of a shopper.
4+
5+
GraphQL needs to provide sufficient mutations (ways to create/update/delete data) for a developer to build out the storefront checkout experience for a shopper.
6+
7+
**Use cases:**
8+
- Both guest and registered shoppers can add new items to cart
9+
- Both guest and registered shoppers can update item qty in cart
10+
- Both guest and registered shoppers can remove items from cart
11+
- Both guest and registered shoppers can update the configuration (for a configurable product) or quantity of a previously added configurable product in cart
12+
- Edit Item link > Product page > Update configuration or qty > Update Cart
13+
14+
**Main decision points:**
15+
16+
- Separate mutations for each product type while adding items to cart. Each operation will be supporting bulk use case
17+
- Uniform interface for guest vs customer
18+
- Separate mutations for each checkout step
19+
- Create empty cart
20+
- Add items to cart
21+
- Set shipment method
22+
- Set payment method
23+
- Set addresses
24+
- Same granularity for updates and removals
25+
- Possibility to combine mutations for checkout steps
26+
- Can create "order in one call" mutation in the future if needed
27+
- Hashed IDs for cart items
28+
- Single input object
29+
- Async nature of the flow must be supported on the client side (via AJAX calls)
30+
- Server-side asynchronous mutations can be supported in the future on framework level in a way similar to Async REST.
31+
32+
**Proposed schema for adding items to cart:**
33+
34+
- [AddSimpleProductToCart](AddSimpleProductToCart.graphqls)
35+
- [AddBundleProductToCart](AddBundleProductToCart.graphqls)
36+
- [AddConfigurableProductToCart](AddConfigurableProductToCart.graphqls)
37+
- [AddDownloadableProductToCart](AddDownloadableProductToCart.graphqls)
38+
- [AddGiftCardProductToCart](AddGiftCardProductToCart.graphqls)
39+
- [AddGroupedProductToCart](AddGroupedProductToCart.graphqls)
40+
- [AddVirtualProductToCart](AddVirtualProductToCart.graphqls)
41+
42+
43+
**My Account area impacted:**
44+
- Cart
45+
- Minicart
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
type Mutation {
2+
addBundleProductsToCart(input: AddBundleProductsToCartInput): AddBundleProductsToCartOutput
3+
updateBundleProductsInCart(input: UpdateBundleProductsInCartInput): UpdateBundleProductsInCartOutput
4+
}
5+
6+
input UpdateBundleProductsInCartInput {
7+
cart_id: String!
8+
cartItems: [UpdateBundleProductCartItemInput!]!
9+
}
10+
11+
input UpdateBundleProductCartItemInput {
12+
details: UpdateCartItemDetailsInput!
13+
bundle_options:[BundleOptionInput!]
14+
customizable_options:[CustomizableOptionInput]
15+
}
16+
17+
input AddBundleProductsToCartInput {
18+
cart_id: String!
19+
cartItems: [BundleProductCartItemInput!]!
20+
}
21+
22+
input BundleProductCartItemInput {
23+
details: CartItemDetailsInput!
24+
bundle_options:[BundleOptionInput!]!
25+
customizable_options:[CustomizableOptionInput!]
26+
}
27+
28+
input BundleOptionInput {
29+
id: Int!
30+
quantity: Float!
31+
value: [String!]!
32+
}
33+
34+
type AddBundleProductsToCartOutput {
35+
cart: Cart!
36+
}
37+
38+
type BundleCartItem implements CartItemInterface {
39+
customizable_options: [SelectedCustomizableOption]!
40+
bundle_options: [SelectedBundleOption!]!
41+
}
42+
43+
type SelectedBundleOption {
44+
id: Int!
45+
label: String!
46+
type: String!
47+
# No quantity here even though it is set on option level in the input
48+
values: [SelectedBundleOptionValue!]!
49+
sort_order: Int!
50+
}
51+
52+
type SelectedBundleOptionValue {
53+
id: Int!
54+
label: String!
55+
quantity: Float! # Quantity is displayed on option value level, while is set on option level
56+
price: CartItemSelectedOptionValuePrice!
57+
sort_order: Int!
58+
}
59+

0 commit comments

Comments
 (0)