@vue-storefront/checkout-com
Advanced tools
Comparing version 0.0.4-prealpha.710 to 0.0.4-prealpha.895
import path from 'path'; | ||
import proxyMiddleware from '@vue-storefront/checkout-com/nuxt/proxyMiddleware'; | ||
const defaultPaymentMethods = { | ||
cc: true, | ||
paypal: true, | ||
klarna: false | ||
}; | ||
const paymentMethodSdk = { | ||
cc: 'https://cdn.checkout.com/js/framesv2.min.js', | ||
paypal: null, | ||
klarna: 'https://x.klarnacdn.net/kp/lib/v1/api.js' | ||
}; | ||
const isScriptInArray = (headEntries, scriptUrl) => headEntries.some(entry => entry.src === scriptUrl); | ||
const canAddScript = (scripts, enabled, paymentMethod) => enabled && | ||
paymentMethodSdk[paymentMethod] && | ||
!isScriptInArray(scripts, paymentMethodSdk[paymentMethod]); | ||
export default function CheckoutComModule(moduleOptions) { | ||
const scripts = this.options.head.script; | ||
this.addPlugin({ | ||
src: path.resolve(__dirname, './plugin.js'), | ||
options: { | ||
publicKey: moduleOptions.publicKey | ||
} | ||
options: moduleOptions | ||
}); | ||
this.addServerMiddleware({ | ||
path: '/cko-api/payment-instruments', | ||
handler: proxyMiddleware({ | ||
publicKey: moduleOptions.publicKey, | ||
secretKey: moduleOptions.secretKey, | ||
ctApiUrl: moduleOptions.ctApiUrl | ||
}) | ||
}); | ||
const paymentMethods = { | ||
...defaultPaymentMethods, | ||
...moduleOptions.paymentMethods | ||
}; | ||
for (const [paymentMethod, enabled] of Object.entries(paymentMethods)) { | ||
if (canAddScript(scripts, enabled, paymentMethod)) { | ||
scripts.push({ | ||
src: paymentMethodSdk[paymentMethod], | ||
async: true | ||
}); | ||
} | ||
} | ||
const { successComponent, errorComponent } = moduleOptions; | ||
@@ -12,0 +52,0 @@ |
import { setup } from '@vue-storefront/checkout-com'; | ||
export default () => { | ||
setup({ | ||
publicKey: '<%= options.publicKey %>' | ||
}); | ||
setup(JSON.parse('<%= JSON.stringify(options) %>')); | ||
}; |
{ | ||
"name": "@vue-storefront/checkout-com", | ||
"version": "0.0.4-prealpha.710+63a603ffa", | ||
"version": "0.0.4-prealpha.895+f8528b0ae", | ||
"sideEffects": false, | ||
@@ -14,4 +14,5 @@ "main": "lib/index.cjs.js", | ||
"dependencies": { | ||
"@vue/composition-api": "^0.3.4", | ||
"@vue/composition-api": "^0.6.7", | ||
"axios": "^0.19.2", | ||
"express": "^4.17.1", | ||
"vue": "^2.6.x" | ||
@@ -26,3 +27,3 @@ }, | ||
}, | ||
"gitHead": "63a603ffa9ae3efc7b488c7bbf1d9f0b9d7072ea" | ||
"gitHead": "f8528b0ae6553218d3177b87fa83081e0fd74bfa" | ||
} |
367
README.md
# Checkout.com Nuxt module | ||
## How to install | ||
1. Open your `nuxt.config.js` | ||
2. At the bottom of `modules` add: | ||
1. Open your theme directory and run: | ||
``` | ||
yarn add @vue-storefront/checkout-com | ||
``` | ||
If you are Developing Core of Vue Storefront Next you might need to add `@vue-storefront/checkout-com` to `useRawSource` attribute in one of `buildModules`: | ||
```js | ||
['@vue-storefront/checkout-com/nuxt', { publicKey: 'pk_test_your-public-key' }], | ||
['@vue-storefront/nuxt', { | ||
coreDevelopment: true, | ||
useRawSource: { | ||
dev: [ | ||
'@vue-storefront/commercetools', | ||
'@vue-storefront/core', | ||
'@vue-storefront/checkout-com' | ||
], | ||
prod: [ | ||
'@vue-storefront/commercetools', | ||
'@vue-storefront/core', | ||
'@vue-storefront/checkout-com' | ||
] | ||
} | ||
}], | ||
``` | ||
2. Open your `nuxt.config.js` | ||
3. At the bottom of `modules` add: | ||
```js | ||
['@vue-storefront/checkout-com/nuxt', { | ||
publicKey: 'pk_test_your-public-key', | ||
secretKey: 'sk_test_your-secret-key', | ||
ctApiUrl: 'https://your-commerctools-instance.com' | ||
}], | ||
``` | ||
## Credit card component | ||
1. Import `useCkoCard`: | ||
## Render payment handlers & finalize payment | ||
1. Import `useCko`: | ||
```js | ||
import { useCkoCard } from '@vue-storefront/checkout-com'; | ||
import { useCko } from '@vue-storefront/checkout-com'; | ||
``` | ||
2. `useCkoCard` returns: | ||
2. `useCko` returns: | ||
```ts | ||
interface { | ||
availableMethods: { name: string, [key: string]: any }, | ||
error: Error | null, | ||
submitDisabled: Boolean, | ||
submitForm: async(), | ||
makePayment: async({ cartId }), | ||
initForm: (): void | ||
selectedPaymentMethod: CkoPaymentType, | ||
savePaymentInstrument: boolean, | ||
storedPaymentInstruments: PaymentInstrument[], | ||
submitDisabled: ComputedRef<boolean>, | ||
loadAvailableMethods: (cartId: string, email?: string): { id, apms }, | ||
initForm: (): void, | ||
submitCardForm: (): void, | ||
makePayment: ({ cartId, email, contextDataId }): Promise<Response | void>, | ||
setPaymentInstrument: (token: string): void, | ||
setSavePaymentInstrument: (newSavePaymentInstrument: boolean): void, | ||
loadSavePaymentInstrument: (): boolean, | ||
removePaymentInstrument: (customerId: string, paymentInstrument: string): Promise<void>, | ||
loadStoredPaymentInstruments: (customerId: string): Promise<void> | ||
} | ||
@@ -28,28 +64,111 @@ ``` | ||
```js | ||
const { submitForm, submitDisabled, initForm } = useCkoCard(); | ||
const { cart } = useCart(); | ||
const { setBillingDetails } = useCheckout(); | ||
const { isAuthenticated, user } = useUser(); | ||
const { | ||
initForm, | ||
loadAvailableMethods, | ||
availableMethods, | ||
submitDisabled, | ||
storedPaymentInstruments, | ||
loadStoredPaymentInstruments, | ||
error | ||
} = useCko(); | ||
``` | ||
3. Execute `initForm` in `setup`. It will set `submitDisabled` to true and create Card Component in `onMounted` hook. | ||
4. When `submitDisabled` changes to false - it means provided Card's data is proper and you could allow your user go forward. Card's token will be stored in localStorage for a moment. | ||
3. `setBillingDetails` to save billing address. So you will be able to fetch `availableMethods` which base on your billing address (server-side) | ||
4. Run `loadStoredPaymentInstruments` for logged in user to load stored payment instruments. They will be loaded to `storedPaymentInstruments` array of `PaymentInstrument`s. Caution: This interface is being used for storing credit cards currently. It might have different shape for stored different payment methods in the future. Interface: | ||
```ts | ||
interface PaymentInstrument { | ||
id: string; | ||
type: string; | ||
expiry_month: number; | ||
expiry_year: number; | ||
scheme: string; | ||
last4: string; | ||
fingerprint: string; | ||
bin: string; | ||
card_type: string; | ||
card_category: string; | ||
issuer: string; | ||
issuer_country: string; | ||
product_id: string; | ||
product_type: string; | ||
avs_check: string; | ||
cvv_check: string; | ||
payouts: string; | ||
fast_funds: string; | ||
payment_instrument_id: string; | ||
} | ||
``` | ||
Example of usage: | ||
```ts | ||
if (isAuthenticated.value && cart.value && cart.value.customerId) { | ||
await loadStoredPaymentInstruments(cart.value.customerId); | ||
} | ||
``` | ||
4. Run `loadAvailableMethods` - first argument is cartId (access it via `cart.value.id`) - second for authenticated customer is an email (access it via `user.value.email`). Then it will return `interface { id, apms: Array<any> }` and set `apms` inside `availableMethods`. E.g: | ||
```js | ||
onMounted(async () => { | ||
await loadAvailableMethods(cart.value.id, user.value && user.value.email); | ||
}) | ||
``` | ||
5. Execute `initForm`. It mounts different payment handlers depends on arguments (check details below). If you are calling it after load component - **use `onMounted` to make sure DOM Element where it should be mounted already exists**. Card's Frames will be mounted in DOM element with class `card-frame`. | ||
## Finalizing payment | ||
1. In this step you need: | ||
```ts | ||
interface PaymentMethods { | ||
card?: boolean; | ||
klarna?: boolean; | ||
paypal?: boolean; | ||
} | ||
interface PaymentMethodsConfig { | ||
card?: Omit<Configuration, 'publicKey'>; | ||
klarna?: any; | ||
paypal?: any; | ||
} | ||
const initForm = (initMethods: PaymentMethods = null, config: PaymentMethodsConfig = {}): void | ||
``` | ||
`initMethods` - if it is `null` - method will try to mount handler for each supported payment method | ||
- if it is `{}` - nothing will be mounted | ||
- in object, you can specify which method you want to mount, e.g: `{ card: true }` but it will still check whether it is supported or not | ||
`config` allows to specify configuration for some payment handler, e.g. for card Frames we could use: | ||
```js | ||
const { makePayment, error: paymentError } = useCkoCard(); | ||
const { cart } = useCart(); | ||
const { | ||
placeOrder | ||
} = useCheckout(); | ||
{ | ||
card: { | ||
localization: 'es-ES' | ||
} | ||
} | ||
``` | ||
This configuration will have bigger priority than one from `nuxt.config.js`. The thing is you cannot overwrite is `publicKey` there. Signature for Frames looks like that: | ||
```ts | ||
(params?: Omit<Configuration, 'publicKey'>): void | ||
``` | ||
Unfortunately, Checkout.com is not sharing any component for Saved Cards. After using `loadStoredPaymentInstruments` you can access an array of them via `storedPaymentInstruments`. Show them to user in a way you want. To choose certain Stored Instrument call `setPaymentInstrument(item.id)` where `item` is single element of `storePaymentInstruments` array. | ||
6. When `submitDisabled` changes to false - it means provided Card's data is proper and you could allow your user go forward. Card's token will be stored in localStorage for a moment. | ||
7. Call `submitCardForm` function on card form submit (only for Credit Card method - not necessary for Stored Payment Method). It requires mounted `Frames` instance as it uses `Frames.submitCard()` under the hood. | ||
8. Then you need to make Payment | ||
`error` - contains error message from the response if you do not use 3ds or we have some server related issues. If the user just removed stored token from localStorage it will have `There is no payment token` inside. | ||
`makePayment` - it proceeds with the payment and removes card token afterward. Returns Promise<Payment> if succeed, or Promise<null> if failed. | ||
2. You should `makePayment` at first (remember to check if everything went ok): | ||
9. You should call `makePayment` at first (remember to check if everything went ok): | ||
```js | ||
// If it is guest | ||
const payment = await makePayment({ cartId: cart.value.id }); | ||
// If it is customer | ||
const payment = await makePayment({ cartId: cart.value.id, email: user.value && user.value.email }); | ||
// If you've already loaded available payment methods with same useCko composable instance | ||
const payment = await makePayment(); | ||
if (!payment) return; | ||
``` | ||
3. If so, place an order: | ||
10. If there is any error, you can access it via `error.value`. Otherwise, it will be nullish | ||
11. If no errors, place an order: | ||
```js | ||
@@ -59,3 +178,3 @@ const order = await placeOrder(); | ||
4. `payment.data.redirect_url` contains 3DS Auth redirect url if it is required by bank. You have to support it: | ||
12. `payment.data.redirect_url` contains 3DS Auth redirect url if it is required by bank. You have to support it: | ||
```js | ||
@@ -68,3 +187,3 @@ if (payment.data.redirect_url) { | ||
5. After 3DS Auth, user will be redirected to one of these urls. They are being created inside `makePayment` method: | ||
13. After 3DS Auth, user will be redirected to one of these urls. They are being created inside `makePayment` method: | ||
```js | ||
@@ -74,1 +193,199 @@ success_url: `${window.location.origin}/cko/payment-success`, | ||
``` | ||
## Changing current payment method | ||
It is important to set proper CKO's Payment Method in `useCko` instance so it will be able to figure out proper payload to send in `makePayment`. To do that: | ||
```js | ||
import { useCko, CkoPaymentType } from '@vue-storefront/checkout-com' | ||
// ... | ||
const { | ||
initForm, | ||
loadAvailableMethods, | ||
submitCardForm, | ||
makePayment, | ||
selectPaymentMethod, // Here | ||
setPaymentInstrument, | ||
setSavePaymentInstrument, | ||
loadSavePaymentInstrument, | ||
selectedPaymentMethod, | ||
loadStoredPaymentInstruments, | ||
removePaymentInstrument, | ||
storedPaymentInstruments, | ||
submitDisabled, | ||
error | ||
} = useCko(); | ||
``` | ||
Currently, these are available payment methods: | ||
```ts | ||
enum CkoPaymentType { | ||
NOT_SELECTED = 0, | ||
CREDIT_CARD = 1, | ||
SAVED_CARD, | ||
KLARNA, // Not supported yet | ||
PAYPAL // Not supported yet | ||
} | ||
``` | ||
By default, `selectPaymentMethod` equals `CkoPaymentType.NOT_SELECTED`. | ||
If user uses stored payment call `setSavePaymentInstrument` and it will set `selectPaymentMethod.value = CkoPaymentType.SAVED_CARD` | ||
```js | ||
setPaymentInstrument(item.id); | ||
``` | ||
If user uses credit card use: | ||
```js | ||
selectPaymentMethod.value = CkoPaymentType.CREDIT_CARD | ||
``` | ||
## Allowing user to decide whether save payment instrument or not | ||
`useCko` composable shares `savePaymentInstrument` ref and `setSavePaymentInstrument` method for that purpose. It is also being stored in the localStorage and autoloaded in `onMounted` hook. Remember to always use `setSavePaymentInstrument` after `savePaymentInstrument` update state in localStorage. E.g: | ||
```js | ||
const { | ||
initForm, | ||
loadAvailableMethods, | ||
submitCardForm, | ||
makePayment, | ||
selectPaymentMethod, | ||
setPaymentInstrument, | ||
setSavePaymentInstrument, // Save | ||
loadSavePaymentInstrument, // Load | ||
selectedPaymentMethod, | ||
loadStoredPaymentInstruments, | ||
removePaymentInstrument, | ||
storedPaymentInstruments, | ||
submitDisabled, | ||
error | ||
} = useCko(); | ||
const savePaymentInstrument = ref(loadSavePaymentInstrument()); | ||
``` | ||
```vue | ||
<SfCheckbox | ||
@change="setSavePaymentInstrument(savePaymentInstrument)" | ||
v-model="savePaymentInstrument" | ||
label="Save payment instrument" | ||
name="savePaymentInstrument" | ||
class="form__element" | ||
/> | ||
``` | ||
## Autoloading SDK | ||
Checkout.com supports 3 payment methods - Credit Card, Klarna & Paypal. By default, module fetches SDK only for Credit Card (Frames). You can customize it with module's config `paymentMethods` attribute. E.g: | ||
```js | ||
['@vue-storefront/checkout-com/nuxt', { | ||
// ... | ||
paymentMethods: { | ||
cc: true, | ||
paypal: false, | ||
klarna: true | ||
} | ||
}] | ||
``` | ||
## Customizing Frames | ||
In `nuxt.config.js` module's config you can use each attribute from [this page](https://docs.checkout.com/quickstart/integrate/frames/frames-customization-guide), e.g: | ||
```js | ||
['@vue-storefront/checkout-com/nuxt', { | ||
// ... | ||
card: { | ||
localization: 'KO-KR', | ||
styles: { | ||
'card-number': { | ||
color: 'red' | ||
}, | ||
base: { | ||
color: '#72757e', | ||
fontSize: '19px', | ||
minWidth: '60px' | ||
}, | ||
invalid: { | ||
color: 'red' | ||
}, | ||
placeholder: { | ||
base: { | ||
color: 'cyan', | ||
fontSize: '50px' | ||
} | ||
} | ||
} | ||
} | ||
}] | ||
``` | ||
`localization` attribute must be a string or fulfill `CustomLocalization` interface: | ||
```ts | ||
interface CustomLocalization { | ||
cardNumberPlaceholder: string; | ||
expiryMonthPlaceholder: string; | ||
expiryYearPlaceholder: string; | ||
cvvPlaceholder: string; | ||
} | ||
``` | ||
## Fetching available payment methods | ||
At first, you have to save billing address in your backend to do that. You can do it just after `setBillingDetails` call from `Creadit card component` step. Then you can easily use `loadAvailableMethods` method. It requires reference as the first argument - which is cartId. E.g: | ||
```js | ||
// Somewhere inside Vue3's setup method | ||
const { cart } = useCart(); | ||
const { user } = useUser(); | ||
const { loadAvailableMethods, availableMethods } = useCko(); | ||
const { setBillingDetails } = useCheckout(); | ||
const handleFormSubmit = async () => { | ||
await setBillingDetails(billingDetails.value, { save: true }); | ||
// If it is Guest | ||
const response = await loadAvailableMethods(cart.value.id); | ||
// If it is Customer | ||
const response = await loadAvailableMethods(cart.value.id, user.value.email); | ||
console.log('Server respond with ', response) | ||
console.log('Array of available payment methods ', availableMethods) | ||
}; | ||
``` | ||
Response might look like: | ||
```json | ||
{ | ||
"id": "cid_XXX", | ||
"apms": [ | ||
{ | ||
"name": "paypal", | ||
"schema": "https://somewebsite.com/apms/paypal.json", | ||
"show": true | ||
} | ||
] | ||
} | ||
``` | ||
`availableMethods` might look like: | ||
```json | ||
[ | ||
{ | ||
"name": "card" | ||
}, | ||
{ | ||
"name": "klarna", | ||
"some_key": "123" | ||
}, | ||
{ | ||
"name": "paypal", | ||
"some_key": "456" | ||
} | ||
] | ||
``` | ||
## Removing Stored Payment Instrument | ||
`useCko` composable shares `removePaymentInstrument` method for that purpose. Keep in mind you use `storedPaymentMethods[i].id` for payment but `storedPaymentMethods[i].payment_instrument` for removing it from the vault. Use it like: | ||
```ts | ||
const { | ||
removePaymentInstrument, | ||
// ... | ||
} = useCko(); | ||
const { isAuthenticated } = useUser(); | ||
const { cart } = useCart(); | ||
const removeMinePaymentInstrument = async (paymentInstrument: string): Promise<void> => { | ||
if (isAuthenticated.value && cart.value && cart.value.customerId) { | ||
await removePaymentInstrument(cart.value.customerId, paymentInstrument); | ||
} | ||
} | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
21240
135
2
387
4
7
1
2
+ Addedexpress@^4.17.1
+ Added@vue/composition-api@0.6.7(transitive)
+ Addedaccepts@1.3.8(transitive)
+ Addedarray-flatten@1.1.1(transitive)
+ Addedbody-parser@1.20.3(transitive)
+ Addedbytes@3.1.2(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedcontent-disposition@0.5.4(transitive)
+ Addedcontent-type@1.0.5(transitive)
+ Addedcookie@0.7.1(transitive)
+ Addedcookie-signature@1.0.6(transitive)
+ Addeddebug@2.6.9(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddepd@2.0.0(transitive)
+ Addeddestroy@1.2.0(transitive)
+ Addedee-first@1.1.1(transitive)
+ Addedencodeurl@1.0.22.0.0(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedescape-html@1.0.3(transitive)
+ Addedetag@1.8.1(transitive)
+ Addedexpress@4.21.1(transitive)
+ Addedfinalhandler@1.3.1(transitive)
+ Addedforwarded@0.2.0(transitive)
+ Addedfresh@0.5.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhttp-errors@2.0.0(transitive)
+ Addediconv-lite@0.4.24(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedipaddr.js@1.9.1(transitive)
+ Addedmedia-typer@0.3.0(transitive)
+ Addedmerge-descriptors@1.0.3(transitive)
+ Addedmethods@1.1.2(transitive)
+ Addedmime@1.6.0(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedms@2.0.02.1.3(transitive)
+ Addednegotiator@0.6.3(transitive)
+ Addedobject-inspect@1.13.3(transitive)
+ Addedon-finished@2.4.1(transitive)
+ Addedparseurl@1.3.3(transitive)
+ Addedpath-to-regexp@0.1.10(transitive)
+ Addedproxy-addr@2.0.7(transitive)
+ Addedqs@6.13.0(transitive)
+ Addedrange-parser@1.2.1(transitive)
+ Addedraw-body@2.5.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsend@0.19.0(transitive)
+ Addedserve-static@1.16.2(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedsetprototypeof@1.2.0(transitive)
+ Addedside-channel@1.0.6(transitive)
+ Addedstatuses@2.0.1(transitive)
+ Addedtoidentifier@1.0.1(transitive)
+ Addedtslib@2.8.1(transitive)
+ Addedtype-is@1.6.18(transitive)
+ Addedunpipe@1.0.0(transitive)
+ Addedutils-merge@1.0.1(transitive)
+ Addedvary@1.1.2(transitive)
- Removed@vue/composition-api@0.3.4(transitive)
- Removedtslib@1.14.1(transitive)
Updated@vue/composition-api@^0.6.7