Re: [w3c/payment-request] Support for gift cards and discount codes (#145)

> If so, that should be handled by the event + updateWith rather than be passed on to the UAs to handle IMO.

So, just error the last one? Could work, but it means the user might enter more codes than they need to.  If we restrict it, to say: "3", then the browser just doesn't provide an option to add another.  

> Could someone remind me of the recent discussion that sparked re-opening this?

See priorities (and related "ACTION"): 
https://www.w3.org/2018/05/03-wpwg-minutes#item03

Taking feedback thus far... 

## Proposal - multiple offer codes

This proposal enhances the Payment Request API, allowing an end user to enter one or more "offer codes" when making a purchase.

Offer codes, known also as coupon codes, promotional codes, discount codes, etc. are tokens issued by merchants that, when applied to a payment request by an end user, can affect a payment request by, for example, providing a discount.

Via the API, merchants can indicate if they support offer codes at all, and limit the number of offer codes the user can provide, as well as inform the end user of potential errors with the provided offer code(s).

## Out of scope

The following are all out of scope, and are the responsibility of merchants:

* How offer codes are issued by merchants.
* The format (e.g., capitalization, use of hyphens and spaces, etc.) of offer codes.
* Normalization, canonicalization, and verification of offer codes.

## Model

An <dfn>offer code</dfn> is a string that represents an opaque token.

An offer code can only be apply once per payment request, allowing them to be uniquely identified.

For example, "SUMMER-SALE".

## Additions to `PaymentOptions` dictionary

```JS
partial dictionary PaymentOptions {
  // 255 max, 0 means no offer codes accepted
  octet requestOfferCodes = 0;
}
```

### `requestOfferCodes` member

Indicates that the merchant allows the user to apply N offer codes during request for payment.

Value of 0 means that the merchant does not accept any offer codes.

For example:

```JS
const options = {
  requestShipping: true,
  requestOfferCodes: 3, // Up to 3 ✨
};
const request = new PaymentRequest(methods, details, options);
```

## Additions to `PaymentDetailsUpdate` dictionary

```JS
partial dictionary PaymentDetailsUpdate {
  sequence<DOMString> offerCodes;
  sequence<OfferCodeError> offerCodeErrors;
}
```

### `offerCodes` member

A list of strings representing offer codes, which are presented to the user.

For example:

```JS
// Show it
request.show({
  offerCodes: ["SPRING-SALE", "BONUS-DISCOUNT"],
  displayItems: itemsIncludingDiscounts,
});
```

### `OfferCodeErrors` member

Allows the merchant to signal errors related to one or more offer codes.

In case of duplicates, last one wins.

For example:

```JS
ev.updateWith({
  offerCodeErrors: [
    { offerCode: "SPRING-SALE", error: "Code already used." },
    // Duplicate, oops
    { offerCode: "SUMMER-SALE", error: "This is ignored." },
    { offerCode: "SUMMER-SALE", error: "Invalid code! Try again." },
  ],
});
```

## `OfferCodeError` dictionary

```JS
dictionary OfferCodeError {
  required DOMString offerCode;
  DOMString error;
}
```

### `offerCode` member

The identifier of the offending offer code.

## Additions to `PaymentRequest` interface

```JS
partial interface PaymentRequest {
  attribute EventHandler onoffercodeschange;
  readonly attribute FrozenArray<DOMString> offerCodes;
}
```

### `onoffercodeschange` attribute

Fires when the user adds, deletes, or updates an offer code.

### `offerCodes` attribute

Allows merchants to access the updated offer codes during the request for payment.

### Additions to `PaymentResponse` interface

```JS
partial interface PaymentResponse {
  readonly attribute FrozenArray<DOMString> offerCodes;
}
```

### `offerCodes` attribute

The final list of offer codes that were applied to the payment request.

## Example of usage

```JS
async function doPaymentRequest() {
  const options = { requestOfferCodes: 5 };
  const request = new PaymentRequest(methods, details, options);
  request.onoffercodeschange = ev => {
    const promise = applySweetSweetSavings(request, details);
    ev.updateWith(promise);
  };
  const response = await request.show();
  //...
  await response.complete("success");
  // post it somewhere, including the `offerCode` applied
  fetch("/invoices", {
    method: "POST",
    body: JSON.stringify(response.toJSON()),
  });
}

async function validateOfferCode(code) {
   return fetch(`is-valid?code=${code}`).then(r => r.json());
}

async function applySweetSweetSavings({ offerCodes }, { displayItems }) {
  const offerCodeErrors = await Promise.all(
    offerCodes.map(validateOfferCode)
  ).then(arr => arr.flatten());
  if (offerCodeErrors.length) {
    return { offerCodeErrors };
  }
  // It's good, update total, add display item, whatever...
  const { newTotal, additionalDisplayItem } = applySweetSavings(offerCode);
  return {
    OfferCodeError: undefined,
    total: newTotal,
    displayItems: [...displayItems, additionalDisplayItem].flatten(),
  };
}
```


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/payment-request/issues/145#issuecomment-387305939

Received on Tuesday, 8 May 2018 07:06:45 UTC