diff --git a/README.md b/README.md index e9f5e8183..0515549b3 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,12 @@ ant clean all ### 5. Add your Adyen credentials to the BaseStore via Hybris backoffice -For more detailed instructions you can visit the [documentation page](https://docs.adyen.com/developers/plug-ins-and-partners/hybris) +For more detailed instructions you can visit the [documentation page](https://github.com/Adyen/adyen-hybris/wiki) Please make sure your merchant has Variant true in API and responses section so that you get paymentMethod back in response. ## Supported payment methods +A reference of all supported payment methods is [here](https://github.com/Adyen/adyen-hybris/wiki#supported-payment-methods). ### Credit Cards @@ -72,7 +73,7 @@ Credit Card payments are supported using Checkout Components. ### Apple Pay -[Apple Pay](https://docs.adyen.com/payment-methods/apple-pay/) is supported using Checkout Components. +Apple Pay is supported using Checkout Components. ### Ratepay @@ -80,14 +81,15 @@ Ratepay is supported via Adyen API. ### AfterPay -[AfterPay](https://docs.adyen.com/payment-methods/afterpay) is supported via Adyen component and API. +AfterPay is supported via Adyen component and API. ### Boleto -[Boleto](https://docs.adyen.com/payment-methods/boleto-bancario) is supported via Adyen API. +Boleto is supported via Adyen API. ### Pix -[Pix](https://docs.adyen.com/payment-methods/pix) is supported via Adyen component and API. + +Pix is supported via Adyen component and API. ### Other alternative payment methods @@ -133,8 +135,7 @@ For Boleto payments - social security number This method will place the payment request using the previously stored payment method selection data. Upon successful response from Adyen API, it will register payment response in cart/order level. It returns an instance of OrderWSDTO obtained from OrderData of the placed order. -For Boleto, it will contain the pdf url, the base64 encoded data, expiration date and due date -https://docs.adyen.com/developers/payment-methods/boleto-bancario/boleto-payment-request +For Boleto, it will contain the pdf url, the base64 encoded data, expiration date and due date. ## 3DS2 configuration By default 3DS2 is enabled (Except for OCC). If you want to disable 3DS2 in your system, please set following property in local.properties file, build your environment and restart the server. @@ -153,8 +154,8 @@ isCardHolderNameRequired = false ``` ## Pending Order Timeout configuration -By default, an order remains in PAYMENT_PENDING status in order management for 1 hour and it is configured in dynamic order process defintiion file. -Based on which extension you are using (fulfillment or ordermanangement) timeout value can be updated in corresponding order-process.xml file. +By default, an order remains in PAYMENT_PENDING status in order management for 1 hour and it is configured in dynamic order process defintiion file. +Based on which extension you are using (fulfillment or ordermanangement) timeout value can be updated in corresponding order-process.xml file. For example, following 2 files have 60 mins configuration under waitForAdyenPendingPayment process with delay value=PT60M @@ -169,10 +170,10 @@ OrderManagement extension file - resources/adyenv6ordermanagement/process/order- ``` ## PayPal configuration -This plugin uses Adyen's Checkout Component for PayPal payments. To use that in a live environment, a PayPal Merchant Id is required [(check here how to get one)](https://docs.adyen.com/payment-methods/paypal/web-component#get-your-paypal-merchant-id). This id has to be provided when adding your Adyen credentials to the BaseStore via the backoffice [(installation step 5)](#installation). +This plugin uses Adyen's Checkout Component for PayPal payments. To use that in a live environment, a PayPal Merchant Id is required. This id has to be provided when adding your Adyen credentials to the BaseStore via the backoffice [(installation step 5)](#installation). ## SameSite Cookie Handler configuration -On Google Chrome browser versions 80 or later, it might occur that an account is logged out after trying to place an order using a credit card that requires 3D Secure authentication or using other redirect payment methods. +On Google Chrome browser versions 80 or later, it might occur that an account is logged out after trying to place an order using a credit card that requires 3D Secure authentication or using other redirect payment methods. This is a consequence of how newer versions of Chrome browsers handle the [SameSite attribute](https://web.dev/samesite-cookies-explained/) on cookies, invalidating the user session after a redirect to a third-party page happened. To avoid those issues, for SAP Commerce versions 6.x or 1905, a cookie handler included in this plugin can be used. To enable it, add the following configuration to the config/local.properties file: @@ -184,7 +185,7 @@ adyen.samesitecookie.handler.enabled=true For SAP Commerce versions 2005 and above, check how to use [SAP's SameSite Cookie Attribute Handler](https://help.sap.com/viewer/d0224eca81e249cb821f2cdf45a82ace/2005/en-US/bde41b6a42c541a08eb2a3b1993fb097.html). ## Documentation - https://docs.adyen.com/developers/plugins/hybris + https://github.com/Adyen/adyen-hybris/wiki ## Support If you have a feature request, or spotted a bug or a technical problem, create a GitHub issue. For other questions, contact our [support team](https://support.adyen.com/hc/en-us/requests/new?ticket_form_id=360000705420). diff --git a/adyenv6b2ccheckoutaddon/.classpath b/adyenv6b2ccheckoutaddon/.classpath deleted file mode 100644 index f37c77287..000000000 --- a/adyenv6b2ccheckoutaddon/.classpath +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/.project b/adyenv6b2ccheckoutaddon/.project deleted file mode 100644 index a6bde531e..000000000 --- a/adyenv6b2ccheckoutaddon/.project +++ /dev/null @@ -1,39 +0,0 @@ - - - adyenv6b2ccheckoutaddon - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full, - - - LaunchConfigHandle - <project>/.externalToolBuilders/HybrisCodeGeneration.launch - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.springframework.ide.eclipse.core.springbuilder - - - - - net.sourceforge.pmd.eclipse.plugin.pmdBuilder - - - - - - org.springframework.ide.eclipse.core.springnature - org.eclipse.jdt.core.javanature - net.sourceforge.pmd.eclipse.plugin.pmdNature - - diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/Gruntfile.js b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/Gruntfile.js new file mode 100644 index 000000000..cffa0d666 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/Gruntfile.js @@ -0,0 +1,34 @@ +module.exports = function (grunt) { + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + watch: { + syncadyenaddon: { + files: ['webroot/_ui/responsive/common/**/*.js'], + tasks: ['sync:syncadyenaddon'], + }, + }, + + sync: { + syncadyenaddon: { + files: [ + { + cwd: 'webroot/_ui/responsive/common/', + src: '**/*.js', + dest: '../../../../build/hybris/bin/modules/base-accelerator/yacceleratorstorefront/web/webroot/_ui/addons/adyenv6b2ccheckoutaddon/responsive/common/', + } + ] + }, + } + + }); + + // Plugins + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-sync'); + + // Default task(s). Run 'grunt watch' to start the watching task or add 'watch' to the task list and run 'grunt'. + grunt.registerTask('default', ['sync', 'watch']); + + +}; diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package-lock.json b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package-lock.json new file mode 100644 index 000000000..3a707a522 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package-lock.json @@ -0,0 +1,2826 @@ +{ + "name": "adyenaddon", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "adyenaddon", + "version": "0.0.1", + "license": "ISC", + "devDependencies": { + "grunt": "^1.5.3", + "grunt-contrib-watch": "^1.1.0", + "grunt-sync": "0.8.2", + "plugin": "^0.3.3" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", + "dev": true, + "dependencies": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", + "dev": true + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dref": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/dref/-/dref-0.0.6.tgz", + "integrity": "sha512-mavsfoF9FiDt11eQccNaBpxRQUNHUOruQX732cYn/L7IJLLo5KXa/FsHwnx4Z2x8hMro9heTo+S/KccdU76J2Q==", + "dev": true, + "dependencies": { + "dref": "0.0.x", + "structr": "0.2.x", + "type-component": "0.0.x" + } + }, + "node_modules/error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "dependencies": { + "string-template": "~0.2.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", + "dev": true + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==", + "dev": true, + "dependencies": { + "glob": "~5.0.0" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/findup-sync/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getobject": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "dependencies": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grunt": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "dev": true, + "dependencies": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", + "nopt": "~3.0.6", + "rimraf": "~3.0.2" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "dev": true, + "dependencies": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-cli/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "dependencies": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-legacy-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "dev": true, + "dependencies": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/grunt-legacy-log-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "dev": true, + "dependencies": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "dev": true, + "dependencies": { + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util/node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/grunt-sync": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/grunt-sync/-/grunt-sync-0.8.2.tgz", + "integrity": "sha512-PB+xKI9YPyZn3NZQXpKHfZVlxHdf1L8GMl+Wi0mLhYypWuOdZPW2EzTmSuhhFbXjkb0aIOxvII1zdZZEl9zqGg==", + "dev": true, + "dependencies": { + "fs-extra": "^6.0.1", + "glob": "^7.0.5", + "md5-file": "^2.0.3" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/md5-file": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-2.0.7.tgz", + "integrity": "sha512-kWAICpJv8fIY0Ka/90iOX9nCJ407Fgj82ceWwcxi2HvVkKGHRMS/Y4caqBaju5skNYXiQohGUjwGZ7rVgzUhRw==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/outcome": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/outcome/-/outcome-0.0.18.tgz", + "integrity": "sha512-r5lBTvoSOO1a4J/bjCy5wOKs0CUEp4+DlL3WnGLgnpWLzNVF7KIUPlYUETbZ81IQHWmvVDZ8c1913uQW65ePNg==", + "dev": true + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plugin": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/plugin/-/plugin-0.3.3.tgz", + "integrity": "sha512-iYStLjk2ROAxvOmC5pAuF6Bl+0LI5BGaJLReXNQkJDTuGd0ytohluSf/EE2iFaej2AdV0llOyBW/BWrLRkOqTg==", + "dev": true, + "dependencies": { + "async": "0.1.x", + "dref": "0.0.x", + "outcome": "0.0.x", + "resolve": "0.2.x", + "sift": "0.0.x", + "step": "0.0.x", + "structr": "0.2.x", + "toarray": "0.0.x", + "underscore": "1.4.x" + } + }, + "node_modules/plugin/node_modules/async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/plugin/node_modules/resolve": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.2.8.tgz", + "integrity": "sha512-/u93d172yGtNlqM9641bKSdPmgaJ/X9TiD/7Mrb3DtrZ/CAvfNEXAdRABvayxLst7GGWMKkD0oGFQvwn0exevg==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", + "dev": true, + "dependencies": { + "bytes": "1", + "string_decoder": "0.10" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/sift/-/sift-0.0.18.tgz", + "integrity": "sha512-AGLWQiwxBbdCWGl9g8oOEAnc/2/VmvEL2ZmiQJXg4rLbNA+Wi8beTJV4pemehLAjiqtNNUyLYCFkNmHNm4E6QQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/step": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/step/-/step-0.0.6.tgz", + "integrity": "sha512-qSSeQinUJk2w38vUFobjFoE307GqsozMC8VisOCkJLpklvKPT0ptPHwWOrENoag8rgLudvTkfP3bancwP93/Jw==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", + "dev": true + }, + "node_modules/structr": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/structr/-/structr-0.2.4.tgz", + "integrity": "sha512-hL77hWtJhhuhDb4od5ywwAnVUlq9Krzk4BCoWhfiPtTEHvqBqRUm6lJ5PQlCrMWyi8Cv4+AXA/Mu6dbeTN/fGA==", + "dev": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "dependencies": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/toarray/-/toarray-0.0.1.tgz", + "integrity": "sha512-4EEt1cngMyDQvStibtjwHav7mCYf0mLAXYQ3z03zNacXjWjIHN01j1AtjGpEuCKX5sea+ZzyZcDXgjitxOVaww==", + "dev": true + }, + "node_modules/type-component": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/type-component/-/type-component-0.0.1.tgz", + "integrity": "sha512-mDZRBQS2yZkwRQKfjJvQ8UIYJeBNNWCq+HBNstl9N5s9jZ4dkVYXEGkVPsSCEh5Ld4JM1kmrZTzjnrqSAIQ7dw==", + "dev": true + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", + "dev": true + }, + "node_modules/underscore.string": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "dependencies": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/underscore.string/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", + "dev": true, + "requires": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true + }, + "dref": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/dref/-/dref-0.0.6.tgz", + "integrity": "sha512-mavsfoF9FiDt11eQccNaBpxRQUNHUOruQX732cYn/L7IJLLo5KXa/FsHwnx4Z2x8hMro9heTo+S/KccdU76J2Q==", + "dev": true, + "requires": { + "dref": "0.0.x", + "structr": "0.2.x", + "type-component": "0.0.x" + } + }, + "error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "requires": { + "string-template": "~0.2.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==", + "dev": true, + "requires": { + "glob": "~5.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "fs-extra": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "getobject": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grunt": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "dev": true, + "requires": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", + "nopt": "~3.0.6", + "rimraf": "~3.0.2" + } + }, + "grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "dev": true, + "requires": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "dependencies": { + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, + "grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "requires": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + } + }, + "grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true + }, + "grunt-legacy-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "dev": true, + "requires": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + } + }, + "grunt-legacy-log-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "dev": true, + "requires": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + } + }, + "grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "dev": true, + "requires": { + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "dependencies": { + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + } + } + }, + "grunt-sync": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/grunt-sync/-/grunt-sync-0.8.2.tgz", + "integrity": "sha512-PB+xKI9YPyZn3NZQXpKHfZVlxHdf1L8GMl+Wi0mLhYypWuOdZPW2EzTmSuhhFbXjkb0aIOxvII1zdZZEl9zqGg==", + "dev": true, + "requires": { + "fs-extra": "^6.0.1", + "glob": "^7.0.5", + "md5-file": "^2.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", + "dev": true + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "requires": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + } + } + }, + "livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true + }, + "md5-file": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-2.0.7.tgz", + "integrity": "sha512-kWAICpJv8fIY0Ka/90iOX9nCJ407Fgj82ceWwcxi2HvVkKGHRMS/Y4caqBaju5skNYXiQohGUjwGZ7rVgzUhRw==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "outcome": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/outcome/-/outcome-0.0.18.tgz", + "integrity": "sha512-r5lBTvoSOO1a4J/bjCy5wOKs0CUEp4+DlL3WnGLgnpWLzNVF7KIUPlYUETbZ81IQHWmvVDZ8c1913uQW65ePNg==", + "dev": true + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "plugin": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/plugin/-/plugin-0.3.3.tgz", + "integrity": "sha512-iYStLjk2ROAxvOmC5pAuF6Bl+0LI5BGaJLReXNQkJDTuGd0ytohluSf/EE2iFaej2AdV0llOyBW/BWrLRkOqTg==", + "dev": true, + "requires": { + "async": "0.1.x", + "dref": "0.0.x", + "outcome": "0.0.x", + "resolve": "0.2.x", + "sift": "0.0.x", + "step": "0.0.x", + "structr": "0.2.x", + "toarray": "0.0.x", + "underscore": "1.4.x" + }, + "dependencies": { + "async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", + "dev": true + }, + "resolve": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.2.8.tgz", + "integrity": "sha512-/u93d172yGtNlqM9641bKSdPmgaJ/X9TiD/7Mrb3DtrZ/CAvfNEXAdRABvayxLst7GGWMKkD0oGFQvwn0exevg==", + "dev": true + } + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", + "dev": true, + "requires": { + "bytes": "1", + "string_decoder": "0.10" + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sift": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/sift/-/sift-0.0.18.tgz", + "integrity": "sha512-AGLWQiwxBbdCWGl9g8oOEAnc/2/VmvEL2ZmiQJXg4rLbNA+Wi8beTJV4pemehLAjiqtNNUyLYCFkNmHNm4E6QQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "step": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/step/-/step-0.0.6.tgz", + "integrity": "sha512-qSSeQinUJk2w38vUFobjFoE307GqsozMC8VisOCkJLpklvKPT0ptPHwWOrENoag8rgLudvTkfP3bancwP93/Jw==", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", + "dev": true + }, + "structr": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/structr/-/structr-0.2.4.tgz", + "integrity": "sha512-hL77hWtJhhuhDb4od5ywwAnVUlq9Krzk4BCoWhfiPtTEHvqBqRUm6lJ5PQlCrMWyi8Cv4+AXA/Mu6dbeTN/fGA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "requires": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/toarray/-/toarray-0.0.1.tgz", + "integrity": "sha512-4EEt1cngMyDQvStibtjwHav7mCYf0mLAXYQ3z03zNacXjWjIHN01j1AtjGpEuCKX5sea+ZzyZcDXgjitxOVaww==", + "dev": true + }, + "type-component": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/type-component/-/type-component-0.0.1.tgz", + "integrity": "sha512-mDZRBQS2yZkwRQKfjJvQ8UIYJeBNNWCq+HBNstl9N5s9jZ4dkVYXEGkVPsSCEh5Ld4JM1kmrZTzjnrqSAIQ7dw==", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true + }, + "underscore": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", + "integrity": "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==", + "dev": true + }, + "underscore.string": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "requires": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package.json b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package.json new file mode 100644 index 000000000..18d3e6be1 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/package.json @@ -0,0 +1,18 @@ +{ + "name": "adyenaddon", + "version": "0.0.1", + "description": "grunt config for the accelerator", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "grunt" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "grunt": "^1.5.3", + "grunt-contrib-watch": "^1.1.0", + "plugin": "^0.3.3", + "grunt-sync": "0.8.2" + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java index f36b2ac70..85200493d 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/constants/AdyenControllerConstants.java @@ -27,6 +27,7 @@ public interface AdyenControllerConstants String SELECT_PAYMENT_METHOD_PREFIX = "/checkout/multi/adyen/select-payment-method"; String SUMMARY_CHECKOUT_PREFIX = "/checkout/multi/adyen/summary"; String COMPONENT_PREFIX = "/adyen/component"; + String AMAZON_RETURN_URL = "/checkout/multi/adyen/summary/amazonpay/placeorder"; /** * Class with view name constants @@ -43,6 +44,8 @@ interface MultiStepCheckout String SelectPaymentMethod = ADDON_PREFIX + "pages/checkout/multi/selectPaymentMethodPage"; String Validate3DSPaymentPage = ADDON_PREFIX + "pages/checkout/multi/3ds_payment"; String BillingAddressformPage = ADDON_PREFIX + "pages/checkout/multi/billingAddressForm"; + String AddEditDeliveryAddressPage = ADDON_PREFIX + "pages/checkout/multi/addEditDeliveryAddressPage"; + String CountryAddressForm = ADDON_PREFIX + "pages/checkout/multi/countryAddressForm"; } } diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenAccountPageController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenAccountPageController.java new file mode 100644 index 000000000..009bab5c8 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenAccountPageController.java @@ -0,0 +1,80 @@ +package com.adyen.v6.controllers.pages; + +import com.adyen.v6.constants.AdyenControllerConstants; +import de.hybris.platform.acceleratorstorefrontcommons.controllers.pages.AbstractSearchPageController; +import de.hybris.platform.acceleratorstorefrontcommons.forms.AddressForm; +import de.hybris.platform.acceleratorstorefrontcommons.util.AddressDataUtil; +import de.hybris.platform.commercefacades.i18n.I18NFacade; +import de.hybris.platform.commercefacades.order.CheckoutFacade; +import de.hybris.platform.commercefacades.user.UserFacade; +import de.hybris.platform.commercefacades.user.data.AddressData; +import de.hybris.platform.commercefacades.user.data.CountryData; +import de.hybris.platform.commercefacades.user.data.TitleData; +import de.hybris.platform.commerceservices.enums.CountryType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.annotation.Resource; +import java.util.Collection; + +@Controller +@RequestMapping("adyen/my-account") +public class AdyenAccountPageController extends AbstractSearchPageController { + + private static final String COUNTRY_ATTR = "country"; + private static final String REGIONS_ATTR = "regions"; + private static final String ADDRESS_FORM_ATTR = "addressForm"; + private static final String ADDRESS_DATA_ATTR = "addressData"; + + @Resource(name = "i18NFacade") + private I18NFacade i18NFacade; + + @Resource(name = "userFacade") + private UserFacade userFacade; + + @Resource(name = "addressDataUtil") + private AddressDataUtil addressDataUtil; + + + @Resource(name = "acceleratorCheckoutFacade") + private CheckoutFacade checkoutFacade; + + @RequestMapping(value = "/addressform", method = RequestMethod.GET) + public String getCountryAddressForm(@RequestParam("addressCode") final String addressCode, + @RequestParam("countryIsoCode") final String countryIsoCode, final Model model) + { + model.addAttribute("supportedCountries", getCountries()); + model.addAttribute(REGIONS_ATTR, i18NFacade.getRegionsForCountryIso(countryIsoCode)); + model.addAttribute(COUNTRY_ATTR, countryIsoCode); + + final AddressForm addressForm = new AddressForm(); + model.addAttribute(ADDRESS_FORM_ATTR, addressForm); + for (final AddressData addressData : userFacade.getAddressBook()) + { + if (addressData.getId() != null && addressData.getId().equals(addressCode) + && countryIsoCode.equals(addressData.getCountry().getIsocode())) + { + model.addAttribute(ADDRESS_DATA_ATTR, addressData); + addressDataUtil.convert(addressData, addressForm); + break; + } + } + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.CountryAddressForm; + } + + @ModelAttribute("titles") + public Collection getTitles() + { + return userFacade.getTitles(); + } + + @ModelAttribute("countries") + public Collection getCountries() + { + return checkoutFacade.getCountries(CountryType.SHIPPING); + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenComponentController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenComponentController.java index 599f209aa..9e72b21f9 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenComponentController.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenComponentController.java @@ -20,16 +20,13 @@ */ package com.adyen.v6.controllers.pages; -import com.adyen.model.checkout.DefaultPaymentMethodDetails; import com.adyen.model.checkout.PaymentMethodDetails; import com.adyen.model.checkout.PaymentsDetailsResponse; import com.adyen.model.checkout.PaymentsResponse; -import com.adyen.model.checkout.details.AmazonPayDetails; -import com.adyen.model.checkout.details.ApplePayDetails; -import com.adyen.model.checkout.details.GooglePayDetails; -import com.adyen.model.checkout.details.MbwayDetails; -import com.adyen.model.checkout.details.PayPalDetails; +import com.adyen.model.checkout.details.*; import com.adyen.service.exception.ApiException; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.controllers.dtos.PaymentResultDTO; import com.adyen.v6.exceptions.AdyenComponentException; import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; import com.adyen.v6.facades.AdyenCheckoutFacade; @@ -41,8 +38,10 @@ import de.hybris.platform.acceleratorfacades.flow.CheckoutFlowFacade; import de.hybris.platform.acceleratorfacades.order.AcceleratorCheckoutFacade; import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService; +import de.hybris.platform.acceleratorstorefrontcommons.controllers.pages.AbstractCheckoutController; import de.hybris.platform.basecommerce.model.site.BaseSiteModel; import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.order.data.OrderData; import de.hybris.platform.commercefacades.user.data.AddressData; import de.hybris.platform.order.InvalidCartException; import de.hybris.platform.site.BaseSiteService; @@ -50,15 +49,11 @@ import org.apache.log4j.Logger; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -67,13 +62,11 @@ import static com.adyen.v6.constants.AdyenControllerConstants.COMPONENT_PREFIX; import static com.adyen.v6.constants.AdyenControllerConstants.SUMMARY_CHECKOUT_PREFIX; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_AMAZONPAY; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BCMC_MOBILE; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_PIX; +import static com.adyen.v6.constants.Adyenv6coreConstants.*; @RestController @RequestMapping(COMPONENT_PREFIX) -public class AdyenComponentController { +public class AdyenComponentController extends AbstractCheckoutController { private static final Logger LOGGER = Logger.getLogger(AdyenComponentController.class); @Resource(name = "adyenCheckoutFacade") @@ -92,8 +85,15 @@ public class AdyenComponentController { private BaseSiteService baseSiteService; private final List PAYMENT_METHODS_WITH_VALIDATED_TERMS = Arrays.asList(PAYMENT_METHOD_AMAZONPAY, - PAYMENT_METHOD_BCMC_MOBILE, - PAYMENT_METHOD_PIX); + PAYMENT_METHOD_BCMC_MOBILE, + PAYMENT_METHOD_PIX); + + @RequestMapping(value = "/resultHandler", method = RequestMethod.POST) + @ResponseBody + public String componentPaymentResultHandler(@RequestBody final PaymentResultDTO paymentResultDTO) throws Exception { + final OrderData orderData = getAdyenCheckoutFacade().handleResultcomponentPayment(paymentResultDTO); + return redirectToOrderConfirmationPage(orderData); + } @RequestMapping(value = "/payment", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody @@ -109,158 +109,161 @@ public String componentPayment(final HttpServletRequest request) throws AdyenCom String paymentMethod = cartData.getAdyenPaymentMethod(); PaymentMethodDetails paymentMethodDetails; - if(PayPalDetails.PAYPAL.equals(paymentMethod)) { + if (PayPalDetails.PAYPAL.equals(paymentMethod)) { paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), PayPalDetails.class); - } else if(MbwayDetails.MBWAY.equals(paymentMethod)) { + } else if (MbwayDetails.MBWAY.equals(paymentMethod)) { paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), MbwayDetails.class); - } else if(ApplePayDetails.APPLEPAY.equals(paymentMethod)) { + } else if (ApplePayDetails.APPLEPAY.equals(paymentMethod)) { paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), ApplePayDetails.class); - } else if(GooglePayDetails.GOOGLEPAY.equals(paymentMethod)) { + } else if (Adyenv6coreConstants.PAYMENT_METHOD_GOOGLE.equals(paymentMethod)) { paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), GooglePayDetails.class); - } else if(AmazonPayDetails.AMAZONPAY.equals(paymentMethod)) { - paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), AmazonPayDetails.class); - } else if(PAYMENT_METHOD_PIX.equals(paymentMethod) || PAYMENT_METHOD_BCMC_MOBILE.equals(paymentMethod)) { - paymentMethodDetails = new DefaultPaymentMethodDetails(); + } else if (UpiCollectDetails.UPI_COLLECT.equals(paymentMethod)) { + paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), UpiCollectDetails.class); + } else if (UpiDetails.UPI.equals(paymentMethod)) { + paymentMethodDetails = gson.fromJson(requestJson.get("paymentMethodDetails"), UpiDetails.class); + } else if (PAYMENT_METHOD_PIX.equals(paymentMethod) || PAYMENT_METHOD_BCMC_MOBILE.equals(paymentMethod)) { + paymentMethodDetails = new CardDetails(); paymentMethodDetails.setType(paymentMethod); - } else { - throw new InvalidCartException("checkout.error.paymentethod.formentry.invalid"); - } + } else { + throw new InvalidCartException("checkout.error.paymentethod.formentry.invalid"); + } - cartData.setAdyenReturnUrl(getReturnUrl(paymentMethod)); + cartData.setAdyenReturnUrl(getReturnUrl(paymentMethod)); - PaymentsResponse paymentsResponse = getAdyenCheckoutFacade().componentPayment(request, cartData, paymentMethodDetails); - return gson.toJson(paymentsResponse); - } catch (InvalidCartException e) { - LOGGER.error("InvalidCartException: " + e.getMessage()); - throw new AdyenComponentException(e.getMessage()); - } - catch ( ApiException e) { - LOGGER.error("ApiException: " + e.toString()); - throw new AdyenComponentException("checkout.error.authorization.payment.refused"); - } catch (AdyenNonAuthorizedPaymentException e) { - LOGGER.debug("AdyenNonAuthorizedPaymentException occurred. Payment is refused."); - throw new AdyenComponentException("checkout.error.authorization.payment.refused"); - } catch (Exception e) { - LOGGER.error("Exception", e); - throw new AdyenComponentException("checkout.error.authorization.payment.error"); + PaymentsResponse paymentsResponse = getAdyenCheckoutFacade().componentPayment(request, cartData, paymentMethodDetails); + return gson.toJson(paymentsResponse); + } catch(InvalidCartException e){ + LOGGER.error("InvalidCartException: " + e.getMessage()); + throw new AdyenComponentException(e.getMessage()); + } + catch(ApiException e){ + LOGGER.error("ApiException: " + e.toString()); + throw new AdyenComponentException("checkout.error.authorization.payment.refused"); + } catch(AdyenNonAuthorizedPaymentException e){ + LOGGER.debug("AdyenNonAuthorizedPaymentException occurred. Payment is refused."); + throw new AdyenComponentException("checkout.error.authorization.payment.refused"); + } catch(Exception e){ + LOGGER.error("Exception", e); + throw new AdyenComponentException("checkout.error.authorization.payment.error"); + } } - } - @RequestMapping(value = "/submit-details", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public String submitDetails(final HttpServletRequest request) throws AdyenComponentException { - try { - String requestJsonString = IOUtils.toString(request.getInputStream(), String.valueOf(StandardCharsets.UTF_8)); - JsonObject requestJson = new JsonParser().parse(requestJsonString).getAsJsonObject(); + @RequestMapping(value = "/submit-details", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public String submitDetails ( final HttpServletRequest request) throws AdyenComponentException { + try { + String requestJsonString = IOUtils.toString(request.getInputStream(), String.valueOf(StandardCharsets.UTF_8)); + JsonObject requestJson = new JsonParser().parse(requestJsonString).getAsJsonObject(); + + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + Type mapType = new TypeToken>() { + }.getType(); + Map details = gson.fromJson(requestJson.get("details"), mapType); + String paymentData = gson.fromJson(requestJson.get("paymentData"), String.class); + + PaymentsDetailsResponse paymentsResponse = getAdyenCheckoutFacade().componentDetails(request, details, paymentData); + return gson.toJson(paymentsResponse); + } catch (ApiException e) { + LOGGER.error("ApiException: " + e.toString()); + throw new AdyenComponentException("checkout.error.authorization.payment.refused"); + } catch (Exception e) { + LOGGER.error("Exception", e); + throw new AdyenComponentException("checkout.error.authorization.payment.error"); + } + } - Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - Type mapType = new TypeToken>() {}.getType(); - Map details = gson.fromJson(requestJson.get("details"), mapType); - String paymentData = gson.fromJson(requestJson.get("paymentData"), String.class); - - PaymentsDetailsResponse paymentsResponse = getAdyenCheckoutFacade().componentDetails(request, details, paymentData); - return gson.toJson(paymentsResponse); - } catch (ApiException e) { - LOGGER.error("ApiException: " + e.toString()); - throw new AdyenComponentException("checkout.error.authorization.payment.refused"); - } catch (Exception e) { - LOGGER.error("Exception", e); - throw new AdyenComponentException("checkout.error.authorization.payment.error"); + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + @ExceptionHandler(value = AdyenComponentException.class) + public String adyenComponentExceptionHandler (AdyenComponentException e){ + return e.getMessage(); } - } - @ResponseStatus(value = HttpStatus.BAD_REQUEST) - @ExceptionHandler(value = AdyenComponentException.class) - public String adyenComponentExceptionHandler(AdyenComponentException e) { - return e.getMessage(); - } + /** + * Validates the order form before to filter out invalid order states + * + * @return True if the order form is invalid and false if everything is valid. + * @param requestJson + */ + protected void validateOrderForm (JsonObject requestJson) throws InvalidCartException { + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + Boolean termsCheck = gson.fromJson(requestJson.get("termsCheck"), Boolean.class); + JsonObject paymentMethodDetails = requestJson.get("paymentMethodDetails").getAsJsonObject(); + String paymentMethod = gson.fromJson(paymentMethodDetails.get("type"), String.class); + + // Some methods already have the terms validated on a previous step + if (!PAYMENT_METHODS_WITH_VALIDATED_TERMS.contains(paymentMethod) + && (termsCheck == null || !termsCheck)) { + throw new InvalidCartException("checkout.error.terms.not.accepted"); + } - /** - * Validates the order form before to filter out invalid order states - * - * @return True if the order form is invalid and false if everything is valid. - * @param requestJson - */ - protected void validateOrderForm(JsonObject requestJson) throws InvalidCartException { - Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - Boolean termsCheck = gson.fromJson(requestJson.get("termsCheck"), Boolean.class); - JsonObject paymentMethodDetails = requestJson.get("paymentMethodDetails").getAsJsonObject(); - String paymentMethod = gson.fromJson(paymentMethodDetails.get("type"), String.class); - - // Some methods already have the terms validated on a previous step - if (!PAYMENT_METHODS_WITH_VALIDATED_TERMS.contains(paymentMethod) - && (termsCheck == null || !termsCheck)) { - throw new InvalidCartException("checkout.error.terms.not.accepted"); - } + if (getCheckoutFlowFacade().hasNoDeliveryAddress()) { + throw new InvalidCartException("checkout.deliveryAddress.notSelected"); + } - if (getCheckoutFlowFacade().hasNoDeliveryAddress()) { - throw new InvalidCartException("checkout.deliveryAddress.notSelected"); - } + if (getCheckoutFlowFacade().hasNoDeliveryMode()) { + throw new InvalidCartException("checkout.deliveryMethod.notSelected"); + } - if (getCheckoutFlowFacade().hasNoDeliveryMode()) { - throw new InvalidCartException("checkout.deliveryMethod.notSelected"); - } + if (getCheckoutFlowFacade().hasNoPaymentInfo()) { + throw new InvalidCartException("checkout.paymentMethod.notSelected"); + } - if (getCheckoutFlowFacade().hasNoPaymentInfo()) { - throw new InvalidCartException("checkout.paymentMethod.notSelected"); - } + final CartData cartData = getCheckoutFacade().getCheckoutCart(); - final CartData cartData = getCheckoutFacade().getCheckoutCart(); + if (!getCheckoutFacade().containsTaxValues()) { + LOGGER.error(String.format("Cart %s does not have any tax values, which means the tax cacluation was not properly done, placement of order can't continue", cartData.getCode())); + throw new InvalidCartException("checkout.error.tax.missing"); + } - if (! getCheckoutFacade().containsTaxValues()) { - LOGGER.error(String.format("Cart %s does not have any tax values, which means the tax cacluation was not properly done, placement of order can't continue", cartData.getCode())); - throw new InvalidCartException("checkout.error.tax.missing"); + if (!cartData.isCalculated()) { + LOGGER.error(String.format("Cart %s has a calculated flag of FALSE, placement of order can't continue", cartData.getCode())); + throw new InvalidCartException("checkout.error.cart.notcalculated"); + } } - if (! cartData.isCalculated()) { - LOGGER.error(String.format("Cart %s has a calculated flag of FALSE, placement of order can't continue", cartData.getCode())); - throw new InvalidCartException("checkout.error.cart.notcalculated"); + private String getReturnUrl (String paymentMethod){ + String url; + if (GooglePayDetails.GOOGLEPAY.equals(paymentMethod)) { + //Google Pay will only use returnUrl if redirected to 3DS authentication + url = SUMMARY_CHECKOUT_PREFIX + "/authorise-3d-adyen-response"; + } else { + url = COMPONENT_PREFIX + "/submit-details"; + } + BaseSiteModel currentBaseSite = baseSiteService.getCurrentBaseSite(); + return siteBaseUrlResolutionService.getWebsiteUrlForSite(currentBaseSite, true, url); } - } - private String getReturnUrl(String paymentMethod) { - String url; - if(GooglePayDetails.GOOGLEPAY.equals(paymentMethod)) { - //Google Pay will only use returnUrl if redirected to 3DS authentication - url = SUMMARY_CHECKOUT_PREFIX + "/authorise-3d-adyen-response"; - } else { - url = COMPONENT_PREFIX + "/submit-details"; + public AdyenCheckoutFacade getAdyenCheckoutFacade () { + return adyenCheckoutFacade; } - BaseSiteModel currentBaseSite = baseSiteService.getCurrentBaseSite(); - return siteBaseUrlResolutionService.getWebsiteUrlForSite(currentBaseSite, true, url); - } - public AdyenCheckoutFacade getAdyenCheckoutFacade() { - return adyenCheckoutFacade; - } + public void setAdyenCheckoutFacade (AdyenCheckoutFacade adyenCheckoutFacade){ + this.adyenCheckoutFacade = adyenCheckoutFacade; + } - public void setAdyenCheckoutFacade(AdyenCheckoutFacade adyenCheckoutFacade) { - this.adyenCheckoutFacade = adyenCheckoutFacade; - } + public CheckoutFlowFacade getCheckoutFlowFacade () { + return checkoutFlowFacade; + } - public CheckoutFlowFacade getCheckoutFlowFacade() { - return checkoutFlowFacade; - } + public void setCheckoutFlowFacade (CheckoutFlowFacade checkoutFlowFacade){ + this.checkoutFlowFacade = checkoutFlowFacade; + } - public void setCheckoutFlowFacade(CheckoutFlowFacade checkoutFlowFacade) { - this.checkoutFlowFacade = checkoutFlowFacade; - } + public AcceleratorCheckoutFacade getCheckoutFacade () { + return checkoutFacade; + } - public AcceleratorCheckoutFacade getCheckoutFacade() { - return checkoutFacade; - } + public void setCheckoutFacade (AcceleratorCheckoutFacade checkoutFacade){ + this.checkoutFacade = checkoutFacade; + } - public void setCheckoutFacade(AcceleratorCheckoutFacade checkoutFacade) { - this.checkoutFacade = checkoutFacade; - } + private boolean isValidateSessionCart () { + CartData cart = getCheckoutFacade().getCheckoutCart(); + final AddressData deliveryAddress = cart.getDeliveryAddress(); + if (deliveryAddress == null || deliveryAddress.getCountry() == null || deliveryAddress.getCountry().getIsocode() == null) { + return false; + } + return true; - private boolean isValidateSessionCart() { - CartData cart = getCheckoutFacade().getCheckoutCart(); - final AddressData deliveryAddress = cart.getDeliveryAddress(); - if (deliveryAddress == null || deliveryAddress.getCountry() == null || deliveryAddress.getCountry().getIsocode() == null) { - return false; } - return true; - } -} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java index f1abbb23e..1b6f3070a 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepController.java @@ -34,6 +34,8 @@ import com.google.gson.reflect.TypeToken; import de.hybris.platform.acceleratorservices.enums.CheckoutPciOptionEnum; import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import de.hybris.platform.acceleratorstorefrontcommons.annotations.PreValidateCheckoutStep; import de.hybris.platform.acceleratorstorefrontcommons.annotations.RequireHardLogIn; import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutStep; @@ -60,19 +62,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Type; import java.net.SocketTimeoutException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import static com.adyen.constants.HPPConstants.Response.SHOPPER_LOCALE; import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.CHALLENGESHOPPER; @@ -91,24 +88,32 @@ import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK; import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_POS; import static com.adyen.v6.constants.Adyenv6coreConstants.RATEPAY; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.DETAILS; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_CHECKOUT_SHOPPER_HOST; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_CLIENT_KEY; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_ENVIRONMENT_MODE; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.DETAILS; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.MODEL_CHECKOUT_SHOPPER_HOST; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.MODEL_CLIENT_KEY; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.MODEL_ENVIRONMENT_MODE; @Controller @RequestMapping(value = SUMMARY_CHECKOUT_PREFIX) public class AdyenSummaryCheckoutStepController extends AbstractCheckoutStepController { private static final Logger LOGGER = Logger.getLogger(AdyenSummaryCheckoutStepController.class); - private final static String SUMMARY = "summary"; + private static final String SUMMARY = "summary"; private static final String AUTHORISE_3D_SECURE_PAYMENT_URL = "/authorise-3d-adyen-response"; - private static final String CHECKOUT_RESULT_URL = "/checkout-adyen-response"; + protected static final String CHECKOUT_RESULT_URL = "/checkout-adyen-response"; private static final String REDIRECT_RESULT = "redirectResult"; private static final String ACTION = "action"; - - private static final int POS_TOTALTIMEOUT_DEFAULT = 130; + private static final String PAYLOAD = "payload"; private static final String POS_TOTALTIMEOUT_KEY = "pos.totaltimeout"; + private static final String CHECKOUT_ERROR_AUTHORIZATION_FAILED = "checkout.error.authorization.failed"; + private static final String REDIRECTING_TO_CONFIRMATION = "Redirecting to confirmation!"; + private static final String API_EXCEPTION_START_MESSAGE = "API exception "; + private static final String HANDLING_ADYEN_NON_AUTHORIZED_PAYMENT_EXCEPTION = "Handling AdyenNonAuthorizedPaymentException"; + private static final String REDIRECTING_TO_CART_PAGE = "Redirecting to cart page..."; + private static final String CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_REFUSED = "checkout.error.authorization.payment.refused"; + private static final String CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_CANCELLED = "checkout.error.authorization.payment.cancelled"; + private static final String CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_ERROR = "checkout.error.authorization.payment.error"; + private static final int POS_TOTAL_TIMEOUT_DEFAULT = 130; @Resource(name = "siteBaseUrlResolutionService") private SiteBaseUrlResolutionService siteBaseUrlResolutionService; @@ -128,7 +133,7 @@ public class AdyenSummaryCheckoutStepController extends AbstractCheckoutStepCont @Autowired private HttpServletRequest httpServletRequest; - @RequestMapping(value = "/view", method = RequestMethod.GET) + @GetMapping(value = "/view") @RequireHardLogIn @Override @PreValidateCheckoutStep(checkoutStep = SUMMARY) @@ -136,7 +141,7 @@ public String enterStep(final Model model, final RedirectAttributes redirectAttr CommerceCartModificationException { final CartData cartData = getCheckoutFacade().getCheckoutCart(); - if (cartData.getEntries() != null && ! cartData.getEntries().isEmpty()) { + if (cartData.getEntries() != null && !cartData.getEntries().isEmpty()) { for (final OrderEntryData entry : cartData.getEntries()) { final String productCode = entry.getProduct().getCode(); final ProductData product = getProductFacade().getProductForCodeAndOptions(productCode, Arrays.asList(ProductOption.BASIC, ProductOption.PRICE)); @@ -157,7 +162,11 @@ public String enterStep(final Model model, final RedirectAttributes redirectAttr model.addAttribute("metaRobots", "noindex,nofollow"); setCheckoutStepLinksForModel(model, getCheckoutStep()); - adyenCheckoutFacade.initializeSummaryData(model); + try { + adyenCheckoutFacade.initializeSummaryData(model); + } catch (ApiException e) { + e.printStackTrace(); + } return AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage; } @@ -180,22 +189,22 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm final CartData cartData = getCheckoutFlowFacade().getCheckoutCart(); - String errorMessage = "checkout.error.authorization.failed"; + String errorMessage = CHECKOUT_ERROR_AUTHORIZATION_FAILED; String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); if (adyenPaymentMethod.equals(RATEPAY)) { try { OrderData orderData = adyenCheckoutFacade.authorisePayment(request, cartData); - LOGGER.debug("Redirecting to confirmation!"); + LOGGER.debug(REDIRECTING_TO_CONFIRMATION); return redirectToOrderConfirmationPage(orderData); } catch (ApiException e) { - LOGGER.error("API exception " + e.getError(), e); + LOGGER.error(API_EXCEPTION_START_MESSAGE + e.getError(), e); } catch (AdyenNonAuthorizedPaymentException e) { - LOGGER.debug("Handling AdyenNonAuthorizedPaymentException"); + LOGGER.debug(HANDLING_ADYEN_NON_AUTHORIZED_PAYMENT_EXCEPTION); PaymentResult paymentResult = e.getPaymentResult(); - if (paymentResult.isRefused()) { + if (Objects.nonNull(paymentResult) && paymentResult.isRefused()) { errorMessage = getErrorMessageByRefusalReason(paymentResult.getRefusalReason()); - LOGGER.debug("Payment is refused " + errorMessage ); + LOGGER.debug("Payment is refused " + errorMessage); } } catch (Exception e) { LOGGER.error(ExceptionUtils.getStackTrace(e)); @@ -207,22 +216,22 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm Long paymentStartTime = System.currentTimeMillis(); request.setAttribute("paymentStartTime", paymentStartTime); OrderData orderData = adyenCheckoutFacade.initiatePosPayment(request, cartData); - LOGGER.debug("Redirecting to confirmation!"); + LOGGER.debug(REDIRECTING_TO_CONFIRMATION); return redirectToOrderConfirmationPage(orderData); } catch (SocketTimeoutException e) { try { LOGGER.debug("POS request timed out. Checking POS Payment status "); - int totalTimeout = POS_TOTALTIMEOUT_DEFAULT; - if(configurationService.getConfiguration().containsKey(POS_TOTALTIMEOUT_KEY)) { + int totalTimeout = POS_TOTAL_TIMEOUT_DEFAULT; + if (configurationService.getConfiguration().containsKey(POS_TOTALTIMEOUT_KEY)) { totalTimeout = configurationService.getConfiguration().getInt(POS_TOTALTIMEOUT_KEY); } request.setAttribute("totalTimeout", totalTimeout); OrderData orderData = adyenCheckoutFacade.checkPosPaymentStatus(request, cartData); - LOGGER.debug("Redirecting to confirmation!"); + LOGGER.debug(REDIRECTING_TO_CONFIRMATION); return redirectToOrderConfirmationPage(orderData); } catch (AdyenNonAuthorizedPaymentException nx) { errorMessage = TerminalAPIUtil.getErrorMessageForNonAuthorizedPosPayment(nx.getTerminalApiResponse()); - LOGGER.debug("AdyenNonAuthorizedPaymentException "+errorMessage); + LOGGER.debug("AdyenNonAuthorizedPaymentException " + errorMessage); } catch (SocketTimeoutException to) { LOGGER.debug("POS Status request timed out. Returning error message."); errorMessage = "checkout.error.authorization.pos.configuration"; @@ -230,10 +239,10 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm LOGGER.error("Exception", ex); } } catch (ApiException e) { - LOGGER.error("API exception " + e.getError(), e); + LOGGER.error(API_EXCEPTION_START_MESSAGE + e.getError(), e); } catch (AdyenNonAuthorizedPaymentException e) { errorMessage = TerminalAPIUtil.getErrorMessageForNonAuthorizedPosPayment(e.getTerminalApiResponse()); - LOGGER.debug("AdyenNonAuthorizedPaymentException"+ errorMessage); + LOGGER.debug("AdyenNonAuthorizedPaymentException" + errorMessage); } catch (Exception e) { LOGGER.error("Exception", e); } @@ -249,7 +258,7 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm } return redirectToOrderConfirmationPage(orderData); } catch (ApiException e) { - LOGGER.error("API exception ", e); + LOGGER.error(API_EXCEPTION_START_MESSAGE, e); } catch (AdyenNonAuthorizedPaymentException e) { LOGGER.debug("Handling AdyenNonAuthorizedPaymentException. Checking PaymentResponse."); PaymentsResponse paymentsResponse = e.getPaymentsResponse(); @@ -270,7 +279,7 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm errorMessage = getErrorMessageByRefusalReason(paymentsResponse.getRefusalReason()); } if (CHALLENGESHOPPER == paymentsResponse.getResultCode() || IDENTIFYSHOPPER == paymentsResponse.getResultCode()) { - LOGGER.debug("PaymentResponse is "+paymentsResponse.getResultCode()+", redirecting to 3DS2 flow"); + LOGGER.debug("PaymentResponse is " + paymentsResponse.getResultCode() + ", redirecting to 3DS2 flow"); return redirectTo3DSValidation(model, paymentsResponse); } } catch (Exception e) { @@ -282,7 +291,7 @@ public String placeOrder(@ModelAttribute("placeOrderForm") final PlaceOrderForm return enterStep(model, redirectModel); } - @RequestMapping(value = AUTHORISE_3D_SECURE_PAYMENT_URL, method = RequestMethod.GET) + @GetMapping(value = AUTHORISE_3D_SECURE_PAYMENT_URL) @RequireHardLogIn public String authorise3DS1Payment(final RedirectAttributes redirectModel, final HttpServletRequest request) { @@ -292,8 +301,8 @@ public String authorise3DS1Payment(final RedirectAttributes redirectModel, LOGGER.debug("Redirecting to confirmation"); return redirectToOrderConfirmationPage(orderData); } catch (AdyenNonAuthorizedPaymentException e) { - LOGGER.debug("Handling AdyenNonAuthorizedPaymentException"); - String errorMessage = "checkout.error.authorization.failed"; + LOGGER.debug(HANDLING_ADYEN_NON_AUTHORIZED_PAYMENT_EXCEPTION); + String errorMessage = CHECKOUT_ERROR_AUTHORIZATION_FAILED; PaymentsDetailsResponse response = e.getPaymentsDetailsResponse(); if (response != null && response.getResultCode() == PaymentsResponse.ResultCodeEnum.REFUSED) { LOGGER.debug("PaymentResponse is REFUSED: " + response); @@ -307,11 +316,11 @@ public String authorise3DS1Payment(final RedirectAttributes redirectModel, LOGGER.error(ExceptionUtils.getStackTrace(e)); } - LOGGER.warn("Redirecting to cart page..."); + LOGGER.warn(REDIRECTING_TO_CART_PAGE); return REDIRECT_PREFIX + CART_PREFIX; } - @RequestMapping(value = AUTHORISE_3D_SECURE_PAYMENT_URL, method = RequestMethod.POST) + @PostMapping(value = AUTHORISE_3D_SECURE_PAYMENT_URL) @RequireHardLogIn public String authorise3DSPayment(final RedirectAttributes redirectModel, final HttpServletRequest request) { @@ -324,13 +333,11 @@ public String authorise3DSPayment(final RedirectAttributes redirectModel, return redirectToOrderConfirmationPage(orderData); } catch (AdyenNonAuthorizedPaymentException e) { LOGGER.debug("Handling AdyenNonAuthorizedPaymentException. Checking PaymentResponse."); - String errorMessage = "checkout.error.authorization.failed"; + String errorMessage = CHECKOUT_ERROR_AUTHORIZATION_FAILED; PaymentsDetailsResponse paymentsDetailsResponse = e.getPaymentsDetailsResponse(); - if(paymentsDetailsResponse != null) { - if (paymentsDetailsResponse.getResultCode() == PaymentsResponse.ResultCodeEnum.REFUSED) { - errorMessage = getErrorMessageByRefusalReason(paymentsDetailsResponse.getRefusalReason()); - LOGGER.debug("PaymentResponse is REFUSED: " + errorMessage); - } + if ((paymentsDetailsResponse != null) && (paymentsDetailsResponse.getResultCode() == PaymentsResponse.ResultCodeEnum.REFUSED)) { + errorMessage = getErrorMessageByRefusalReason(paymentsDetailsResponse.getRefusalReason()); + LOGGER.debug("PaymentResponse is REFUSED: " + errorMessage); } return redirectToSelectPaymentMethodWithError(redirectModel, errorMessage); } catch (CalculationException | InvalidCartException e) { @@ -339,18 +346,20 @@ public String authorise3DSPayment(final RedirectAttributes redirectModel, LOGGER.error(ExceptionUtils.getStackTrace(e)); } - LOGGER.warn("Redirecting to cart page..."); + LOGGER.warn(REDIRECTING_TO_CART_PAGE); return REDIRECT_PREFIX + CART_PREFIX; } - @RequestMapping(value = CHECKOUT_RESULT_URL, method = RequestMethod.GET) + @GetMapping(value = CHECKOUT_RESULT_URL) @RequireHardLogIn public String handleAdyenResponse(final HttpServletRequest request, final RedirectAttributes redirectModel) { String redirectResult = request.getParameter(REDIRECT_RESULT); HashMap details = new HashMap<>(); - if (redirectResult != null && ! redirectResult.isEmpty()) { + if (redirectResult != null && !redirectResult.isEmpty()) { details.put(REDIRECT_RESULT, redirectResult); + } else if (StringUtils.isNotEmpty(request.getParameter(PAYLOAD))) { + details.put(REDIRECT_RESULT, request.getParameter(PAYLOAD)); } try { @@ -366,11 +375,11 @@ public String handleAdyenResponse(final HttpServletRequest request, final Redire } return redirectToOrderConfirmationPage(orderData); case REFUSED: - return redirectToSelectPaymentMethodWithError(redirectModel, "checkout.error.authorization.payment.refused"); + return redirectToSelectPaymentMethodWithError(redirectModel, CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_REFUSED); case CANCELLED: - return redirectToSelectPaymentMethodWithError(redirectModel, "checkout.error.authorization.payment.cancelled"); + return redirectToSelectPaymentMethodWithError(redirectModel, CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_CANCELLED); default: - return redirectToSelectPaymentMethodWithError(redirectModel, "checkout.error.authorization.payment.error"); + return redirectToSelectPaymentMethodWithError(redirectModel, CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_ERROR); } } catch (CalculationException | InvalidCartException e) { LOGGER.warn(e.getMessage(), e); @@ -378,7 +387,7 @@ public String handleAdyenResponse(final HttpServletRequest request, final Redire LOGGER.error(ExceptionUtils.getStackTrace(e)); } - LOGGER.warn("Redirecting to cart page..."); + LOGGER.warn(REDIRECTING_TO_CART_PAGE); return REDIRECT_PREFIX + CART_PREFIX; } @@ -387,11 +396,11 @@ public String handleAdyenResponse(final HttpServletRequest request, final Redire */ private void addBoletoMessage(RedirectAttributes redirectModel, final String orderCode) { //Use OrderFacade to force execution of AbstractOrder populators - OrderData orderData = orderFacade.getOrderDetailsForCode(orderCode); + OrderData orderData = orderFacade.getOrderDetailsForCodeWithoutUser(orderCode); GlobalMessages.addFlashMessage(redirectModel, - GlobalMessages.INFO_MESSAGES_HOLDER, - "Boleto PDf: Download"); + GlobalMessages.INFO_MESSAGES_HOLDER, + "Boleto PDf: Download"); } @@ -401,28 +410,27 @@ private void addBoletoMessage(RedirectAttributes redirectModel, final String ord private void addMultibancoMessage(RedirectAttributes redirectModel, final String orderCode) { //Use OrderFacade to force execution of AbstractOrder populators - OrderData orderData = orderFacade.getOrderDetailsForCode(orderCode); + OrderData orderData = orderFacade.getOrderDetailsForCodeWithoutUser(orderCode); GlobalMessages.addFlashMessage(redirectModel, - GlobalMessages.INFO_MESSAGES_HOLDER, - "

Multibanco order summary " - + "

" - + "

Amount: " - + orderData.getAdyenMultibancoAmount() - + "

" - + "

Entity: " - + orderData.getAdyenMultibancoEntity() - + "

" - + "

Deadline: " - + orderData.getAdyenMultibancoDeadline() - + "

" - + "

Reference: " - + orderData.getAdyenMultibancoReference() - + "

"); + GlobalMessages.INFO_MESSAGES_HOLDER, + "

Multibanco order summary " + + "

" + + "

Amount: " + + orderData.getAdyenMultibancoAmount() + + "

" + + "

Entity: " + + orderData.getAdyenMultibancoEntity() + + "

" + + "

Deadline: " + + orderData.getAdyenMultibancoDeadline() + + "

" + + "

Reference: " + + orderData.getAdyenMultibancoReference() + + "

"); } - private boolean is3DSPaymentMethod(String adyenPaymentMethod) { return adyenPaymentMethod.equals(PAYMENT_METHOD_CC) || adyenPaymentMethod.equals(PAYMENT_METHOD_BCMC) || adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0; } @@ -431,7 +439,7 @@ private String redirectToSelectPaymentMethodWithError(final RedirectAttributes r GlobalMessages.addFlashMessage(redirectModel, GlobalMessages.ERROR_MESSAGES_HOLDER, messageKey); final CartData cartData = getCheckoutFacade().getCheckoutCart(); - if(cartData == null || cartData.getDeliveryAddress() == null) { + if (cartData == null || cartData.getDeliveryAddress() == null) { LOGGER.debug("Redirecting to cart with error: " + messageKey); return REDIRECT_PREFIX + CART_PREFIX; } @@ -440,7 +448,7 @@ private String redirectToSelectPaymentMethodWithError(final RedirectAttributes r return REDIRECT_PREFIX + SELECT_PAYMENT_METHOD_PREFIX; } - private String redirectTo3DSValidation(Model model, PaymentsResponse paymentsResponse) { + protected String redirectTo3DSValidation(Model model, PaymentsResponse paymentsResponse) { CheckoutPaymentsAction action = paymentsResponse.getAction(); model.addAttribute(MODEL_CLIENT_KEY, adyenCheckoutFacade.getClientKey()); @@ -463,26 +471,26 @@ private String getReturnUrl(String adyenPaymentMethod) { return siteBaseUrlResolutionService.getWebsiteUrlForSite(currentBaseSite, true, url); } - private String getErrorMessageByRefusalReason(String refusalReason) { - String errorMessage; - - switch (refusalReason) { - case RefusalReason.TRANSACTION_NOT_PERMITTED: - errorMessage = "checkout.error.authorization.transaction.not.permitted"; - break; - case RefusalReason.CVC_DECLINED: - errorMessage = "checkout.error.authorization.cvc.declined"; - break; - case RefusalReason.RESTRICTED_CARD: - errorMessage = "checkout.error.authorization.restricted.card"; - break; - case RefusalReason.PAYMENT_DETAIL_NOT_FOUND: - errorMessage = "checkout.error.authorization.payment.detail.not.found"; - break; - default: - errorMessage = "checkout.error.authorization.payment.refused"; + protected String getErrorMessageByRefusalReason(String refusalReason) { + String errorMessage = CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_REFUSED; + if(refusalReason != null) { + switch (refusalReason) { + case RefusalReason.TRANSACTION_NOT_PERMITTED: + errorMessage = "checkout.error.authorization.transaction.not.permitted"; + break; + case RefusalReason.CVC_DECLINED: + errorMessage = "checkout.error.authorization.cvc.declined"; + break; + case RefusalReason.RESTRICTED_CARD: + errorMessage = "checkout.error.authorization.restricted.card"; + break; + case RefusalReason.PAYMENT_DETAIL_NOT_FOUND: + errorMessage = "checkout.error.authorization.payment.detail.not.found"; + break; + default: + errorMessage = CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_REFUSED; + } } - return errorMessage; } @@ -518,20 +526,20 @@ protected boolean validateOrderForm(final PlaceOrderForm placeOrderForm, final M } } - if (! placeOrderForm.isTermsCheck()) { + if (!placeOrderForm.isTermsCheck()) { GlobalMessages.addErrorMessage(model, "checkout.error.terms.not.accepted"); invalid = true; return invalid; } final CartData cartData = getCheckoutFacade().getCheckoutCart(); - if (! getCheckoutFacade().containsTaxValues()) { + if (!getCheckoutFacade().containsTaxValues()) { LOGGER.error(String.format("Cart %s does not have any tax values, which means the tax cacluation was not properly done, placement of order can't continue", cartData.getCode())); GlobalMessages.addErrorMessage(model, "checkout.error.tax.missing"); invalid = true; } - if (! cartData.isCalculated()) { + if (!cartData.isCalculated()) { LOGGER.error(String.format("Cart %s has a calculated flag of FALSE, placement of order can't continue", cartData.getCode())); GlobalMessages.addErrorMessage(model, "checkout.error.cart.notcalculated"); invalid = true; @@ -540,7 +548,7 @@ protected boolean validateOrderForm(final PlaceOrderForm placeOrderForm, final M return invalid; } - @RequestMapping(value = "/component-result", method = RequestMethod.POST) + @PostMapping(value = "/component-result") @RequireHardLogIn public String handleComponentResult(final HttpServletRequest request, final Model model, @@ -551,14 +559,14 @@ public String handleComponentResult(final HttpServletRequest request, LOGGER.debug("isResultError=" + isResultError + "\nresultData=" + resultData); - String errorMessageKey = "checkout.error.authorization.payment.error"; + String errorMessageKey = CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_ERROR; if (isValidResult(resultData, isResultError)) { try { OrderData orderData = adyenCheckoutFacade.handleComponentResult(resultData); return redirectToOrderConfirmationPage(orderData); } catch (AdyenNonAuthorizedPaymentException e) { - LOGGER.debug("Handling AdyenNonAuthorizedPaymentException"); + LOGGER.debug(HANDLING_ADYEN_NON_AUTHORIZED_PAYMENT_EXCEPTION); PaymentsResponse paymentsResponse = e.getPaymentsResponse(); if (paymentsResponse != null && paymentsResponse.getResultCode() != null) { switch (paymentsResponse.getResultCode()) { @@ -566,10 +574,10 @@ public String handleComponentResult(final HttpServletRequest request, LOGGER.debug("Component PaymentResponse resultCode is REDIRECTSHOPPER, redirecting shopper to 3DS flow"); return redirectTo3DSValidation(model, paymentsResponse); case REFUSED: - errorMessageKey = "checkout.error.authorization.payment.refused"; + errorMessageKey = CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_REFUSED; break; case CANCELLED: - errorMessageKey = "checkout.error.authorization.payment.cancelled"; + errorMessageKey = CHECKOUT_ERROR_AUTHORIZATION_PAYMENT_CANCELLED; break; default: break; @@ -594,7 +602,7 @@ private String redirectToOrderSummaryWithError(final Model model, final RedirectAttributes redirectAttributes, final String messageKey) throws CommerceCartModificationException, CMSItemNotFoundException { final CartData cartData = getCheckoutFacade().getCheckoutCart(); - if(cartData == null || cartData.getAdyenPaymentMethod() == null + if (cartData == null || cartData.getAdyenPaymentMethod() == null || PAYMENT_METHOD_APPLEPAY.equals(cartData.getAdyenPaymentMethod())) { return redirectToSelectPaymentMethodWithError(redirectAttributes, messageKey); } @@ -611,18 +619,19 @@ private boolean isValidResult(String resultData, String isResultError) { private Map parseDetailsFromComponent(String details) { Gson gson = new Gson(); - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); return gson.fromJson(details, mapType); } - @RequestMapping(value = "/back", method = RequestMethod.GET) + @GetMapping(value = "/back") @RequireHardLogIn @Override public String back(final RedirectAttributes redirectAttributes) { return getCheckoutStep().previousStep(); } - @RequestMapping(value = "/next", method = RequestMethod.GET) + @GetMapping(value = "/next") @RequireHardLogIn @Override public String next(final RedirectAttributes redirectAttributes) { diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/AdyenDeliveryAddressCheckoutStepController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/AdyenDeliveryAddressCheckoutStepController.java new file mode 100644 index 000000000..d12af6ff8 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/AdyenDeliveryAddressCheckoutStepController.java @@ -0,0 +1,336 @@ +package com.adyen.v6.controllers.pages.checkout.steps; + +import com.adyen.v6.constants.AdyenControllerConstants; +import de.hybris.platform.acceleratorstorefrontcommons.annotations.PreValidateCheckoutStep; +import de.hybris.platform.acceleratorstorefrontcommons.annotations.PreValidateQuoteCheckoutStep; +import de.hybris.platform.acceleratorstorefrontcommons.annotations.RequireHardLogIn; +import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutStep; +import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.validation.ValidationResults; +import de.hybris.platform.acceleratorstorefrontcommons.constants.WebConstants; +import de.hybris.platform.acceleratorstorefrontcommons.controllers.pages.checkout.steps.AbstractCheckoutStepController; +import de.hybris.platform.acceleratorstorefrontcommons.controllers.util.GlobalMessages; +import de.hybris.platform.acceleratorstorefrontcommons.forms.AddressForm; +import de.hybris.platform.acceleratorstorefrontcommons.util.AddressDataUtil; +import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException; +import de.hybris.platform.cms2.model.pages.ContentPageModel; +import de.hybris.platform.commercefacades.address.data.AddressVerificationResult; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.user.data.AddressData; +import de.hybris.platform.commercefacades.user.data.CountryData; +import de.hybris.platform.commerceservices.address.AddressVerificationDecision; +import de.hybris.platform.util.Config; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.annotation.Resource; +import java.util.Set; + + +@Controller +@RequestMapping(value = "/checkout/multi/delivery-address") +public class AdyenDeliveryAddressCheckoutStepController extends AbstractCheckoutStepController { + private static final String DELIVERY_ADDRESS = "delivery-address"; + private static final String SHOW_SAVE_TO_ADDRESS_BOOK_ATTR = "showSaveToAddressBook"; + + @Resource(name = "addressDataUtil") + private AddressDataUtil addressDataUtil; + + @Override + @RequestMapping(value = "/add", method = RequestMethod.GET) + @RequireHardLogIn + @PreValidateQuoteCheckoutStep + @PreValidateCheckoutStep(checkoutStep = DELIVERY_ADDRESS) + public String enterStep(final Model model, final RedirectAttributes redirectAttributes) throws CMSItemNotFoundException { + getCheckoutFacade().setDeliveryAddressIfAvailable(); + final CartData cartData = getCheckoutFacade().getCheckoutCart(); + + populateCommonModelAttributes(model, cartData, new AddressForm()); + + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + @RequestMapping(value = "/add", method = RequestMethod.POST) + @RequireHardLogIn + public String add(final AddressForm addressForm, final BindingResult bindingResult, final Model model, + final RedirectAttributes redirectModel) throws CMSItemNotFoundException { + final CartData cartData = getCheckoutFacade().getCheckoutCart(); + + getAddressValidator().validate(addressForm, bindingResult); + populateCommonModelAttributes(model, cartData, addressForm); + + if (bindingResult.hasErrors()) { + GlobalMessages.addErrorMessage(model, "address.error.formentry.invalid"); + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + final AddressData newAddress = addressDataUtil.convertToAddressData(addressForm); + + processAddressVisibilityAndDefault(addressForm, newAddress); + + // Verify the address data. + final AddressVerificationResult verificationResult = getAddressVerificationFacade() + .verifyAddressData(newAddress); + final boolean addressRequiresReview = getAddressVerificationResultHandler().handleResult(verificationResult, newAddress, + model, redirectModel, bindingResult, getAddressVerificationFacade().isCustomerAllowedToIgnoreAddressSuggestions(), + "checkout.multi.address.updated"); + + if (addressRequiresReview) { + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + getUserFacade().addAddress(newAddress); + + final AddressData previousSelectedAddress = getCheckoutFacade().getCheckoutCart().getDeliveryAddress(); + // Set the new address as the selected checkout delivery address + getCheckoutFacade().setDeliveryAddress(newAddress); + if (previousSelectedAddress != null && !previousSelectedAddress.isVisibleInAddressBook()) { // temporary address should be removed + getUserFacade().removeAddress(previousSelectedAddress); + } + + // Set the new address as the selected checkout delivery address + getCheckoutFacade().setDeliveryAddress(newAddress); + + return getCheckoutStep().nextStep(); + } + + protected void processAddressVisibilityAndDefault(final AddressForm addressForm, final AddressData newAddress) { + if (addressForm.getSaveInAddressBook() != null) { + newAddress.setVisibleInAddressBook(addressForm.getSaveInAddressBook().booleanValue()); + if (addressForm.getSaveInAddressBook().booleanValue() && CollectionUtils.isEmpty(getUserFacade().getAddressBook())) { + newAddress.setDefaultAddress(true); + } + } else if (getCheckoutCustomerStrategy().isAnonymousCheckout()) { + newAddress.setDefaultAddress(true); + newAddress.setVisibleInAddressBook(true); + } + } + + @RequestMapping(value = "/edit", method = RequestMethod.GET) + @RequireHardLogIn + public String editAddressForm(@RequestParam("editAddressCode") final String editAddressCode, final Model model, + final RedirectAttributes redirectAttributes) throws CMSItemNotFoundException { + final ValidationResults validationResults = getCheckoutStep().validate(redirectAttributes); + if (getCheckoutStep().checkIfValidationErrors(validationResults)) { + return getCheckoutStep().onValidation(validationResults); + } + + AddressData addressData = null; + if (StringUtils.isNotEmpty(editAddressCode)) { + addressData = getCheckoutFacade().getDeliveryAddressForCode(editAddressCode); + } + + final AddressForm addressForm = new AddressForm(); + final boolean hasAddressData = addressData != null; + if (hasAddressData) { + addressDataUtil.convert(addressData, addressForm); + } + + final CartData cartData = getCheckoutFacade().getCheckoutCart(); + populateCommonModelAttributes(model, cartData, addressForm); + + if (addressData != null) { + model.addAttribute(SHOW_SAVE_TO_ADDRESS_BOOK_ATTR, Boolean.valueOf(!addressData.isVisibleInAddressBook())); + } + + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + @RequestMapping(value = "/edit", method = RequestMethod.POST) + @RequireHardLogIn + public String edit(final AddressForm addressForm, final BindingResult bindingResult, final Model model, + final RedirectAttributes redirectModel) throws CMSItemNotFoundException { + getAddressValidator().validate(addressForm, bindingResult); + + final CartData cartData = getCheckoutFacade().getCheckoutCart(); + populateCommonModelAttributes(model, cartData, addressForm); + + if (bindingResult.hasErrors()) { + GlobalMessages.addErrorMessage(model, "address.error.formentry.invalid"); + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + final AddressData newAddress = addressDataUtil.convertToAddressData(addressForm); + + processAddressVisibility(addressForm, newAddress); + + newAddress.setDefaultAddress(CollectionUtils.isEmpty(getUserFacade().getAddressBook()) + || getUserFacade().getAddressBook().size() == 1 || Boolean.TRUE.equals(addressForm.getDefaultAddress())); + + // Verify the address data. + final AddressVerificationResult verificationResult = getAddressVerificationFacade() + .verifyAddressData(newAddress); + final boolean addressRequiresReview = getAddressVerificationResultHandler().handleResult(verificationResult, newAddress, + model, redirectModel, bindingResult, getAddressVerificationFacade().isCustomerAllowedToIgnoreAddressSuggestions(), + "checkout.multi.address.updated"); + + if (addressRequiresReview) { + if (StringUtils.isNotEmpty(addressForm.getAddressId())) { + final AddressData addressData = getCheckoutFacade().getDeliveryAddressForCode(addressForm.getAddressId()); + if (addressData != null) { + model.addAttribute(SHOW_SAVE_TO_ADDRESS_BOOK_ATTR, Boolean.valueOf(!addressData.isVisibleInAddressBook())); + model.addAttribute("edit", Boolean.TRUE); + } + } + + return AdyenControllerConstants.Views.Pages.MultiStepCheckout.AddEditDeliveryAddressPage; + } + + getUserFacade().editAddress(newAddress); + getCheckoutFacade().setDeliveryModeIfAvailable(); + getCheckoutFacade().setDeliveryAddress(newAddress); + + return getCheckoutStep().nextStep(); + } + + protected void processAddressVisibility(final AddressForm addressForm, final AddressData newAddress) { + + if (addressForm.getSaveInAddressBook() == null) { + newAddress.setVisibleInAddressBook(true); + } else { + newAddress.setVisibleInAddressBook(Boolean.TRUE.equals(addressForm.getSaveInAddressBook())); + } + } + + @RequestMapping(value = "/remove", method = + {RequestMethod.GET, RequestMethod.POST}) //NOSONAR + @RequireHardLogIn + public String removeAddress(@RequestParam("addressCode") final String addressCode, final RedirectAttributes redirectModel, + final Model model) throws CMSItemNotFoundException { + if (getCheckoutFacade().isRemoveAddressEnabledForCart()) { + final AddressData addressData = new AddressData(); + addressData.setId(addressCode); + getUserFacade().removeAddress(addressData); + GlobalMessages.addFlashMessage(redirectModel, GlobalMessages.CONF_MESSAGES_HOLDER, + "account.confirmation.address.removed"); + } + final ContentPageModel multiCheckoutSummaryPage = getContentPageForLabelOrId(MULTI_CHECKOUT_SUMMARY_CMS_PAGE_LABEL); + storeCmsPageInModel(model, multiCheckoutSummaryPage); + setUpMetaDataForContentPage(model, multiCheckoutSummaryPage); + model.addAttribute("addressForm", new AddressForm()); + + return getCheckoutStep().currentStep(); + } + + @RequestMapping(value = "/select", method = RequestMethod.POST) + @RequireHardLogIn + public String doSelectSuggestedAddress(final AddressForm addressForm, final RedirectAttributes redirectModel) { + final Set resolveCountryRegions = org.springframework.util.StringUtils + .commaDelimitedListToSet(Config.getParameter("resolve.country.regions")); + + final AddressData selectedAddress = addressDataUtil.convertToAddressData(addressForm); + final CountryData countryData = selectedAddress.getCountry(); + + if (!resolveCountryRegions.contains(countryData.getIsocode())) { + selectedAddress.setRegion(null); + } + + if (addressForm.getSaveInAddressBook() != null) { + selectedAddress.setVisibleInAddressBook(addressForm.getSaveInAddressBook().booleanValue()); + } + + if (Boolean.TRUE.equals(addressForm.getEditAddress())) { + getUserFacade().editAddress(selectedAddress); + } else { + getUserFacade().addAddress(selectedAddress); + } + + final AddressData previousSelectedAddress = getCheckoutFacade().getCheckoutCart().getDeliveryAddress(); + // Set the new address as the selected checkout delivery address + getCheckoutFacade().setDeliveryAddress(selectedAddress); + if (previousSelectedAddress != null && !previousSelectedAddress.isVisibleInAddressBook()) { // temporary address should be removed + getUserFacade().removeAddress(previousSelectedAddress); + } + + GlobalMessages.addFlashMessage(redirectModel, GlobalMessages.CONF_MESSAGES_HOLDER, "checkout.multi.address.added"); + + return getCheckoutStep().nextStep(); + } + + + /** + * This method gets called when the "Use this Address" button is clicked. It sets the selected delivery address on + * the checkout facade - if it has changed, and reloads the page highlighting the selected delivery address. + * + * @param selectedAddressCode - the id of the delivery address. + * @return - a URL to the page to load. + */ + @RequestMapping(value = "/select", method = RequestMethod.GET) + @RequireHardLogIn + public String doSelectDeliveryAddress(@RequestParam("selectedAddressCode") final String selectedAddressCode, + final RedirectAttributes redirectAttributes) { + final ValidationResults validationResults = getCheckoutStep().validate(redirectAttributes); + if (getCheckoutStep().checkIfValidationErrors(validationResults)) { + return getCheckoutStep().onValidation(validationResults); + } + if (StringUtils.isNotBlank(selectedAddressCode)) { + final AddressData selectedAddressData = getCheckoutFacade().getDeliveryAddressForCode(selectedAddressCode); + final boolean hasSelectedAddressData = selectedAddressData != null; + if (hasSelectedAddressData) { + setDeliveryAddress(selectedAddressData); + } + } + return getCheckoutStep().nextStep(); + } + + protected void setDeliveryAddress(final AddressData selectedAddressData) { + final AddressData cartCheckoutDeliveryAddress = getCheckoutFacade().getCheckoutCart().getDeliveryAddress(); + if (isAddressIdChanged(cartCheckoutDeliveryAddress, selectedAddressData)) { + getCheckoutFacade().setDeliveryAddress(selectedAddressData); + if (cartCheckoutDeliveryAddress != null && !cartCheckoutDeliveryAddress.isVisibleInAddressBook()) { // temporary address should be removed + getUserFacade().removeAddress(cartCheckoutDeliveryAddress); + } + } + } + + @RequestMapping(value = "/back", method = RequestMethod.GET) + @RequireHardLogIn + @Override + public String back(final RedirectAttributes redirectAttributes) { + return getCheckoutStep().previousStep(); + } + + @RequestMapping(value = "/next", method = RequestMethod.GET) + @RequireHardLogIn + @Override + public String next(final RedirectAttributes redirectAttributes) { + return getCheckoutStep().nextStep(); + } + + protected String getBreadcrumbKey() { + return "checkout.multi." + getCheckoutStep().getProgressBarId() + ".breadcrumb"; + } + + protected CheckoutStep getCheckoutStep() { + return getCheckoutStep(DELIVERY_ADDRESS); + } + + protected void populateCommonModelAttributes(final Model model, final CartData cartData, final AddressForm addressForm) + throws CMSItemNotFoundException { + model.addAttribute("cartData", cartData); + model.addAttribute("addressForm", addressForm); + model.addAttribute("deliveryAddresses", getDeliveryAddresses(cartData.getDeliveryAddress())); + model.addAttribute("noAddress", Boolean.valueOf(getCheckoutFlowFacade().hasNoDeliveryAddress())); + model.addAttribute("addressFormEnabled", Boolean.valueOf(getCheckoutFacade().isNewAddressEnabledForCart())); + model.addAttribute("removeAddressEnabled", Boolean.valueOf(getCheckoutFacade().isRemoveAddressEnabledForCart())); + model.addAttribute(SHOW_SAVE_TO_ADDRESS_BOOK_ATTR, Boolean.TRUE); + model.addAttribute(WebConstants.BREADCRUMBS_KEY, getResourceBreadcrumbBuilder().getBreadcrumbs(getBreadcrumbKey())); + model.addAttribute("metaRobots", "noindex,nofollow"); + if (StringUtils.isNotBlank(addressForm.getCountryIso())) { + model.addAttribute("regions", getI18NFacade().getRegionsForCountryIso(addressForm.getCountryIso())); + model.addAttribute("country", addressForm.getCountryIso()); + } + prepareDataForPage(model); + final ContentPageModel multiCheckoutSummaryPage = getContentPageForLabelOrId(MULTI_CHECKOUT_SUMMARY_CMS_PAGE_LABEL); + storeCmsPageInModel(model, multiCheckoutSummaryPage); + setUpMetaDataForContentPage(model, multiCheckoutSummaryPage); + setCheckoutStepLinksForModel(model, getCheckoutStep()); + } + +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/SelectPaymentMethodCheckoutStepController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/SelectPaymentMethodCheckoutStepController.java index 024f4bf5a..be7e1d070 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/SelectPaymentMethodCheckoutStepController.java +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/checkout/steps/SelectPaymentMethodCheckoutStepController.java @@ -20,6 +20,7 @@ */ package com.adyen.v6.controllers.pages.checkout.steps; +import com.adyen.service.exception.ApiException; import com.adyen.v6.constants.AdyenControllerConstants; import com.adyen.v6.facades.AdyenCheckoutFacade; import com.adyen.v6.forms.AddressForm; @@ -35,6 +36,7 @@ import de.hybris.platform.commercefacades.user.data.AddressData; import de.hybris.platform.commercefacades.user.data.CountryData; import de.hybris.platform.commercefacades.user.data.TitleData; +import io.swagger.annotations.Api; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -62,6 +64,7 @@ import static de.hybris.platform.acceleratorstorefrontcommons.constants.WebConstants.BREADCRUMBS_KEY; import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.POST; +import com.adyen.service.exception.ApiException; @Controller @RequestMapping(value = "/checkout/multi/adyen/select-payment-method") @@ -127,7 +130,14 @@ public String enterStep(final Model model, final RedirectAttributes redirectAttr GlobalMessages.addErrorMessage(model, "checkout.deliveryAddress.notSelected"); } else { - adyenCheckoutFacade.initializeCheckoutData(model); + try{ + adyenCheckoutFacade.initializeCheckoutData(model); + } + catch(ApiException e){ + LOGGER.debug("Invalid session Data"); + GlobalMessages.addErrorMessage(model, "basket.error.occurred"); + } + } super.prepareDataForPage(model); diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayController.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayController.java new file mode 100644 index 000000000..183b05d5d --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayController.java @@ -0,0 +1,81 @@ +package com.adyen.v6.controllers.pages.payments; + +import com.adyen.constants.ApiConstants; +import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.model.checkout.details.AmazonPayDetails; +import com.adyen.v6.controllers.pages.AdyenSummaryCheckoutStepController; +import com.adyen.v6.facades.AdyenAmazonPayFacade; +import com.adyen.v6.facades.AdyenCheckoutFacade; +import de.hybris.platform.acceleratorfacades.flow.CheckoutFlowFacade; +import de.hybris.platform.acceleratorstorefrontcommons.annotations.RequireHardLogIn; +import de.hybris.platform.acceleratorstorefrontcommons.controllers.util.GlobalMessages; +import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException; +import de.hybris.platform.commercefacades.order.OrderFacade; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commerceservices.order.CommerceCartModificationException; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER; +import static com.adyen.v6.constants.AdyenControllerConstants.SUMMARY_CHECKOUT_PREFIX; + +@Controller +@RequestMapping(value = SUMMARY_CHECKOUT_PREFIX + "/amazonpay") + +public class AdyenAmazonpayController extends AdyenSummaryCheckoutStepController { + + @Resource(name = "adyenCheckoutFacade") + protected AdyenCheckoutFacade adyenCheckoutFacade; + @Resource + protected CheckoutFlowFacade checkoutFlowFacade; + @Resource(name = "adyenAmazonPayFacade") + protected AdyenAmazonPayFacade adyenAmazonPayFacade; + @Resource(name = "orderFacade") + private OrderFacade orderFacade; + + @GetMapping(value = "/placeorder") + @RequireHardLogIn + public String placeOrder(final Model model, + final RedirectAttributes redirectModel, + final HttpServletRequest request, + @RequestParam(name = "amazonCheckoutSessionId", required = false) final String amazonCheckoutSessionId) + throws CMSItemNotFoundException, CommerceCartModificationException { + + + if (StringUtils.isBlank(amazonCheckoutSessionId)) { + GlobalMessages.addErrorMessage(model, getErrorMessageByRefusalReason(ApiConstants.RefusalReason.PAYMENT_DETAIL_NOT_FOUND)); + return enterStep(model, redirectModel); + } + + try { + final CartData cart = checkoutFlowFacade.getCheckoutCart(); + cart.setAdyenReturnUrl(adyenAmazonPayFacade.getReturnUrl(SUMMARY_CHECKOUT_PREFIX + CHECKOUT_RESULT_URL)); + + final PaymentsResponse paymentsResponse = adyenCheckoutFacade.componentPayment(request, + cart, + new AmazonPayDetails().amazonPayToken(adyenAmazonPayFacade.getAmazonPayToken(amazonCheckoutSessionId)) + ); + + if (REDIRECTSHOPPER == paymentsResponse.getResultCode()) { + return redirectTo3DSValidation(model, paymentsResponse); + } + + return redirectToOrderConfirmationPage(orderFacade.getOrderDetailsForCodeWithoutUser(paymentsResponse.getMerchantReference())); + + } catch (Exception e) { + GlobalMessages.addErrorMessage(model, getErrorMessageByRefusalReason(ApiConstants.RefusalReason.REFUSED)); + } + + return enterStep(model, redirectModel); + + } + +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/validator/AdyenAddressValidator.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/validator/AdyenAddressValidator.java new file mode 100644 index 000000000..e0fbfb3be --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/validator/AdyenAddressValidator.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. + */ +package com.adyen.v6.validator; + +import de.hybris.platform.acceleratorstorefrontcommons.forms.AddressForm; +import de.hybris.platform.acceleratorstorefrontcommons.forms.validation.AddressValidator; +import org.apache.commons.lang.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * Validator for address forms. Enforces the order of validation + */ +@Component("addressValidator") +public class AdyenAddressValidator extends AddressValidator { + private static final int MAX_FIELD_LENGTH = 255; + private static final int MAX_POSTCODE_LENGTH = 10; + private static final int POSTCODE_BR_LENGTH = 8; + + + @Override + public boolean supports(final Class aClass) { + return AddressForm.class.equals(aClass); + } + + @Override + public void validate(final Object object, final Errors errors) { + final AddressForm addressForm = (AddressForm) object; + validateStandardFields(addressForm, errors); + validateCountrySpecificFields(addressForm, errors); + } + + protected void validateStandardFields(final AddressForm addressForm, final Errors errors) { + validateStringField(addressForm.getCountryIso(), AddressField.COUNTRY, MAX_FIELD_LENGTH, errors); + validateStringField(addressForm.getFirstName(), AddressField.FIRSTNAME, MAX_FIELD_LENGTH, errors); + validateStringField(addressForm.getLastName(), AddressField.LASTNAME, MAX_FIELD_LENGTH, errors); + validateStringField(addressForm.getLine1(), AddressField.LINE1, MAX_FIELD_LENGTH, errors); + validateStringField(addressForm.getTownCity(), AddressField.TOWN, MAX_FIELD_LENGTH, errors); + validateStringField(addressForm.getPostcode(), AddressField.POSTCODE, MAX_POSTCODE_LENGTH, errors); + } + + protected void validateCountrySpecificFields(final AddressForm addressForm, final Errors errors) { + + final String isoCode = addressForm.getCountryIso(); + if (isoCode != null) { + switch (CountryCode.lookup(isoCode)) { + case CHINA: + case CANADA: + case USA: + validateStringFieldLength(addressForm.getTitleCode(), AddressField.TITLE, MAX_FIELD_LENGTH, errors); + validateFieldNotNull(addressForm.getRegionIso(), AddressField.REGION, errors); + break; + case JAPAN: + validateFieldNotNull(addressForm.getRegionIso(), AddressField.REGION, errors); + validateFieldNotNull(addressForm.getLine2(), AddressField.LINE2, errors); + break; + case BRAZIL: + validateFieldNotNull(addressForm.getRegionIso(), AddressField.REGION, errors); + validateFieldNotNull(addressForm.getLine2(), AddressField.LINE2, errors); + validateFieldNotNull(addressForm.getPostcode(), AddressField.POSTCODE, errors); + validateStringFieldLengthPostalCodeBR(addressForm.getPostcode(), AddressField.POSTCODE_BR, POSTCODE_BR_LENGTH, errors); + break; + case INDIA: + validateIndianPhoneField(addressForm.getPhone(),AddressField.PHONE_IN,errors); + default: + validateStringFieldLength(addressForm.getTitleCode(), AddressField.TITLE, MAX_FIELD_LENGTH, errors); + break; + } + } + } + + protected static void validateStringField(final String addressField, final AddressField fieldType, + final int maxFieldLength, final Errors errors) { + if (addressField == null || StringUtils.isEmpty(addressField) || (StringUtils.length(addressField) > maxFieldLength)) { + errors.rejectValue(fieldType.getFieldKey(), fieldType.getErrorKey()); + } + } + protected static void validateIndianPhoneField(final String addressField, final AddressField fieldType, final Errors errors) { + final String regexIndianPhone = "^(?:(?:\\+|0{0,2})91(\\s*[\\ -]\\s*)?|[0]?)?[789]\\d{9}|(\\d[ -]?){10}\\d$"; + final Pattern pattern = Pattern.compile(regexIndianPhone); + if(!pattern.matcher(addressField).matches()){ + errors.rejectValue(fieldType.getFieldKey(), fieldType.getErrorKey()); + } + } + + protected static void validateStringFieldLengthPostalCodeBR(final String addressField, final AddressField fieldType, + final int maxFieldLength, final Errors errors) { + if (StringUtils.isNotEmpty(addressField) && StringUtils.length(addressField) != maxFieldLength) { + errors.rejectValue(fieldType.getFieldKey(), fieldType.getErrorKey()); + } + + } + + protected static void validateStringFieldLength(final String field, final AddressField fieldType, final int maxFieldLength, + final Errors errors) { + if (StringUtils.isNotEmpty(field) && StringUtils.length(field) > maxFieldLength) { + errors.rejectValue(fieldType.getFieldKey(), fieldType.getErrorKey()); + } + } + + protected static void validateFieldNotNull(final String addressField, final AddressField fieldType, + final Errors errors) { + if (addressField == null) { + errors.rejectValue(fieldType.getFieldKey(), fieldType.getErrorKey()); + } + } + + protected enum CountryCode { + INDIA("IN"),USA("US"), CANADA("CA"), JAPAN("JP"), CHINA("CN"), BRITAIN("GB"), GERMANY("DE"), BRAZIL("BR"), DEFAULT(""); + + private String isoCode; + + private static Map lookupMap = new HashMap<>(); + + static { + for (final CountryCode code : CountryCode.values()) { + lookupMap.put(code.getIsoCode(), code); + } + } + + private CountryCode(final String isoCodeStr) { + this.isoCode = isoCodeStr; + } + + public static CountryCode lookup(final String isoCodeStr) { + CountryCode code = lookupMap.get(isoCodeStr); + if (code == null) { + code = DEFAULT; + } + return code; + } + + public String getIsoCode() { + return isoCode; + } + } + + protected enum AddressField { + TITLE("titleCode", "address.title.invalid"), FIRSTNAME("firstName", "address.firstName.invalid"), + LASTNAME("lastName", "address.lastName.invalid"), LINE1("line1", "address.line1.invalid"), + LINE2("line2", "address.line2.invalid"), TOWN("townCity", "address.townCity.invalid"), + POSTCODE("postcode", "address.postcode.invalid"), REGION("regionIso", "address.regionIso.invalid"), + COUNTRY("countryIso", "address.country.invalid"), LINE2_BR("line2", "address.line2BR.invalid"), + POSTCODE_BR("postcode", "address.postcodeBR.invalid"), + PHONE_IN("phone", "address.phoneIN.invalid"); + + private String fieldKey; + private String errorKey; + + private AddressField(final String fieldKey, final String errorKey) { + this.fieldKey = fieldKey; + this.errorKey = errorKey; + } + + public String getFieldKey() { + return fieldKey; + } + + public String getErrorKey() { + return errorKey; + } + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepControllerTest.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepControllerTest.java new file mode 100644 index 000000000..e865aed20 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/AdyenSummaryCheckoutStepControllerTest.java @@ -0,0 +1,588 @@ +package com.adyen.v6.controllers.pages; + +import com.adyen.constants.ApiConstants; +import com.adyen.model.PaymentResult; +import com.adyen.model.checkout.CheckoutPaymentsAction; +import com.adyen.model.checkout.PaymentsDetailsResponse; +import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.model.terminal.TerminalAPIResponse; +import com.adyen.service.exception.ApiException; +import com.adyen.v6.constants.AdyenControllerConstants; +import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; +import com.adyen.v6.facades.AdyenCheckoutFacade; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.acceleratorfacades.flow.CheckoutFlowFacade; +import de.hybris.platform.acceleratorfacades.order.AcceleratorCheckoutFacade; +import de.hybris.platform.acceleratorservices.enums.CheckoutPciOptionEnum; +import de.hybris.platform.acceleratorservices.storefront.util.PageTitleResolver; +import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService; +import de.hybris.platform.acceleratorstorefrontcommons.breadcrumb.Breadcrumb; +import de.hybris.platform.acceleratorstorefrontcommons.breadcrumb.ResourceBreadcrumbBuilder; +import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutGroup; +import de.hybris.platform.acceleratorstorefrontcommons.checkout.steps.CheckoutStep; +import de.hybris.platform.acceleratorstorefrontcommons.forms.PlaceOrderForm; +import de.hybris.platform.cms2.data.PagePreviewCriteriaData; +import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException; +import de.hybris.platform.cms2.model.pages.ContentPageModel; +import de.hybris.platform.cms2.model.site.CMSSiteModel; +import de.hybris.platform.cms2.servicelayer.services.CMSPageService; +import de.hybris.platform.cms2.servicelayer.services.CMSPreviewService; +import de.hybris.platform.cms2.servicelayer.services.CMSSiteService; +import de.hybris.platform.commercefacades.order.CartFacade; +import de.hybris.platform.commercefacades.order.OrderFacade; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.order.data.CartModificationData; +import de.hybris.platform.commercefacades.order.data.OrderData; +import de.hybris.platform.commerceservices.order.CommerceCartModificationException; +import de.hybris.platform.commerceservices.strategies.CheckoutCustomerStrategy; +import de.hybris.platform.servicelayer.config.ConfigurationService; +import de.hybris.platform.site.BaseSiteService; +import org.apache.commons.configuration.Configuration; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.ui.Model; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.adyen.model.checkout.PaymentsResponse.ResultCodeEnum.*; +import static com.adyen.v6.constants.AdyenControllerConstants.CART_PREFIX; +import static com.adyen.v6.constants.Adyenv6coreConstants.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.*; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenSummaryCheckoutStepControllerTest { + + private static final String PAYLOAD = "payload"; + private static final String PAYLOAD_VALUE = "value"; + private static final String REDIRECT_RESULT = "redirectResult"; + private static final String MERCHANT_REFERENCE = "merchantReference"; + private static final String REDIRECT_PREFIX = "redirect:"; + private static final String REDIRECT_URL_ORDER_CONFIRMATION = REDIRECT_PREFIX + "/checkout/orderConfirmation/"; + private static final String ORDER_CODE = "orderCode"; + private static final String SECURITY_CODE = "securityCode"; + private static final String CONTENT_PAGE_MODEL_ID = "contentPageModelId"; + private static final String CONTENT_PAGE_MODEL_TITLE = "contentPageModelTitle"; + private static final String CONTENT_PAGE_MODEL_KEYWORDS = "contentPageModelKeywords"; + private static final String CONTENT_PAGE_MODEL_DESCRIPTION = "contentPageModelDescription"; + private static final String MULTI_CHECKOUT_SUMMARY_CMS_PAGE_LABEL_MOCK = "multiStepCheckoutSummary"; + private static final String CHECKOUT_FLOW_GROUP_FOR_CHECKOUT_MOCK = "checkoutFlowGroupForCheckout"; + private static final String CURRENT_CONTROLLER = "summary"; + private static final String PROGRESS_BAR_ID = "progressBarId"; + private static final String RATEPAY = "ratepay"; + private static final String POS_TOTAL_TIMEOUT_KEY = "pos.totaltimeout"; + private static final String MOCK_BASESITE_URL = "mockBasesiteURL"; + private static final String ACTION_URL = "actionURL"; + + @InjectMocks + @Spy + private AdyenSummaryCheckoutStepController testObj; + + @Mock + private AdyenCheckoutFacade adyenCheckoutFacadeMock; + @Mock + private AcceleratorCheckoutFacade checkoutFacadeMock; + @Mock + private CheckoutFlowFacade checkoutFlowFacadeMock; + @Mock + private OrderFacade orderFacadeMock; + @Mock + private CartFacade cartFacadeMock; + @Mock + private CheckoutCustomerStrategy checkoutCustomerStrategyMock; + @Mock + private CMSPageService cmsPageServiceMock; + @Mock + private CMSSiteService cmsSiteServiceMock; + @Mock + private BaseSiteService baseSiteServiceMock; + @Mock + private CMSPreviewService cmsPreviewServiceMock; + @Mock + private SiteBaseUrlResolutionService siteBaseUrlResolutionServiceMock; + @Mock + private ConfigurationService configurationServiceMock; + @Mock + private PageTitleResolver pageTitleResolverMock; + @Mock + private ResourceBreadcrumbBuilder resourceBreadcrumbBuilderMock; + @Mock + private HttpServletRequest requestMock; + @Mock + private PaymentsDetailsResponse responseMock; + @Mock + private RedirectAttributes redirectModelMock; + @Mock + private OrderData orderDataMock; + @Mock + private CartData cartDataMock; + @Mock + private PagePreviewCriteriaData pagePreviewCriteriaDataMock; + @Mock + private CartModificationData cartModificationDataMock; + @Mock + private PlaceOrderForm placeOrderFormMock; + @Mock + private Model modelMock; + @Mock + private ContentPageModel contentPageModelMock; + @Mock + private CMSSiteModel cmsSiteModelMock; + @Mock + private CheckoutStep checkoutStepMock; + @Mock + private Configuration configurationMock; + @Mock + private HashMap details; + @Mock + private PaymentResult paymentResultMock; + @Mock + private PaymentsResponse paymentsResponseMock; + @Mock + private TerminalAPIResponse terminalApiResponseMock; + @Mock + private CheckoutPaymentsAction actionMock; + private List modifications; + + @Before + public void setUp(){ + details = new HashMap<>(Map.of(REDIRECT_RESULT, PAYLOAD_VALUE)); + modifications = new ArrayList<>(); + } + + @Test + public void handleRedirectPayload_shouldReturnResponse_whenRequestContainsPayload() throws Exception{ + mockElementsUsedInTestsForHandleRedirectPayload(); + + when(requestMock.getParameter(PAYLOAD)).thenReturn(PAYLOAD_VALUE); + + final String result =testObj.handleAdyenResponse(requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_URL_ORDER_CONFIRMATION + orderDataMock.getCode()); + } + + @Test + public void handleRedirectPayload_shouldThrowException_whenRequestNotContainsPayload() throws Exception{ + mockElementsUsedInTestsForHandleRedirectPayload(); + + when(requestMock.getParameter(PAYLOAD)).thenReturn(null); + + final String result = testObj.handleAdyenResponse(requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_PREFIX + CART_PREFIX); + } + @Test + public void placeOrder_shouldGoBackToStep_whenFormIsInvalid() throws CMSItemNotFoundException, CommerceCartModificationException { + mockElementsUsedInTestsForPlaceOrder(); + when(checkoutFlowFacadeMock.hasNoDeliveryAddress()).thenReturn(true); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldRedirectToCart_whenFormIsValidButCartIsNot() throws CMSItemNotFoundException, CommerceCartModificationException { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + modifications.add(cartModificationDataMock); + mockCartValidationOK(); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_PREFIX + CART_PREFIX); + } + + @Test + public void placeOrder_shouldGoToConfirmationPage_whenFormCartAreBothValidAndPaymentAuthorizedRatepay() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(RATEPAY); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenReturn(orderDataMock); + mockAnonymousCheckoutAndOrderGuid(); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_URL_ORDER_CONFIRMATION + ORDER_CODE); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenApiExceptionIsThrownRatepay() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(RATEPAY); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(new ApiException("", 1)); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenAnotherExceptionIsThrownRatepay() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(RATEPAY); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(new Exception()); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenAdyenNonAuthorizedPaymentExceptionIsThrownRatepay() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(RATEPAY); + when(paymentResultMock.isRefused()).thenReturn(true); + when(paymentResultMock.getRefusalReason()).thenReturn(ApiConstants.RefusalReason.TRANSACTION_NOT_PERMITTED); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(new AdyenNonAuthorizedPaymentException(paymentResultMock)); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoToConfirmationPage_whenFormCartAreBothValidAndPaymentAuthorizedPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenReturn(orderDataMock); + mockAnonymousCheckoutAndOrderGuid(); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_URL_ORDER_CONFIRMATION + ORDER_CODE); + } + + @Test + public void placeOrder_shouldGoToConfirmationPage_whenFormCartAreBothValidAndSocketTimeoutExceptionThrownButPaymentStatusIsOKPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new SocketTimeoutException()); + when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); + when(configurationMock.containsKey(POS_TOTAL_TIMEOUT_KEY)).thenReturn(true); + when(configurationMock.getInt(POS_TOTAL_TIMEOUT_KEY)).thenReturn(130); + when(adyenCheckoutFacadeMock.checkPosPaymentStatus(requestMock, cartDataMock)).thenReturn(orderDataMock); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_URL_ORDER_CONFIRMATION + ORDER_CODE); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenSocketTimeoutExceptionAndAdyenNonAuthorizedPaymentExceptionAreThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new SocketTimeoutException()); + when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); + when(configurationMock.containsKey(POS_TOTAL_TIMEOUT_KEY)).thenReturn(true); + when(configurationMock.getInt(POS_TOTAL_TIMEOUT_KEY)).thenReturn(130); + when(paymentResultMock.isRefused()).thenReturn(true); + when(paymentResultMock.getRefusalReason()).thenReturn(ApiConstants.RefusalReason.TRANSACTION_NOT_PERMITTED); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(terminalApiResponseMock.getSaleToPOIResponse()).thenReturn(null); + thisException.setTerminalApiResponse(terminalApiResponseMock); + when(adyenCheckoutFacadeMock.checkPosPaymentStatus(requestMock, cartDataMock)).thenThrow(thisException); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenSocketTimeoutExceptionAfterAnotherSocketTimeoutExceptionAreThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new SocketTimeoutException()); + when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); + when(configurationMock.containsKey(POS_TOTAL_TIMEOUT_KEY)).thenReturn(true); + when(configurationMock.getInt(POS_TOTAL_TIMEOUT_KEY)).thenReturn(130); + when(adyenCheckoutFacadeMock.checkPosPaymentStatus(requestMock, cartDataMock)).thenThrow(new SocketTimeoutException()); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenGenericExceptionAfterSocketTimeoutExceptionAreThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new SocketTimeoutException()); + when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); + when(configurationMock.containsKey(POS_TOTAL_TIMEOUT_KEY)).thenReturn(true); + when(configurationMock.getInt(POS_TOTAL_TIMEOUT_KEY)).thenReturn(130); + when(adyenCheckoutFacadeMock.checkPosPaymentStatus(requestMock, cartDataMock)).thenThrow(new Exception()); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenApiExceptionIsThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new ApiException("", 1)); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenAdyenNonAuthorizedPaymentExceptionIsThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(paymentResultMock.isRefused()).thenReturn(true); + when(paymentResultMock.getRefusalReason()).thenReturn(ApiConstants.RefusalReason.TRANSACTION_NOT_PERMITTED); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(terminalApiResponseMock.getSaleToPOIResponse()).thenReturn(null); + thisException.setTerminalApiResponse(terminalApiResponseMock); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(thisException); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenGenericExceptionIsThrownPOS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + mockAnonymousCheckoutAndOrderGuid(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_POS); + when(adyenCheckoutFacadeMock.initiatePosPayment(requestMock, cartDataMock)).thenThrow(new Exception()); + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldGoToConfirmationPage_whenFormCartAreBothValidAndPaymentAuthorizedAnotherPaymentMethod() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_PAYPAL); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenReturn(orderDataMock); + mockAnonymousCheckoutAndOrderGuid(); + when(baseSiteServiceMock.getCurrentBaseSite()).thenReturn(cmsSiteModelMock); + when(siteBaseUrlResolutionServiceMock.getWebsiteUrlForSite(anyObject(), anyBoolean(), anyString())).thenReturn(MOCK_BASESITE_URL); + mockAnonymousCheckoutAndOrderGuid(); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_URL_ORDER_CONFIRMATION + ORDER_CODE); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenApiExceptionIsThrownAnotherPaymentMethod() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_PAYPAL); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(new ApiException("", 1)); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldRedirectTo3DS_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndRedirectShopper3DS() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_CC); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(paymentsResponseMock.getResultCode()).thenReturn(REDIRECTSHOPPER); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DSPaymentPage); + } + + @Test + public void placeOrder_shouldRedirectTo3DS_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndRedirectShopperAfterpayTouch() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(AFTERPAY_TOUCH); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(actionMock.getUrl()).thenReturn(ACTION_URL); + when(paymentsResponseMock.getResultCode()).thenReturn(REDIRECTSHOPPER); + when(paymentsResponseMock.getAction()).thenReturn(actionMock); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_PREFIX + ACTION_URL); + } + + @Test + public void placeOrder_shouldRedirectTo3DS_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndRedirectShopperAnotherMethod() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(COUNTRY_CODE_SWEDEN); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(actionMock.getUrl()).thenReturn(ACTION_URL); + when(paymentsResponseMock.getResultCode()).thenReturn(REDIRECTSHOPPER); + when(paymentsResponseMock.getAction()).thenReturn(actionMock); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(REDIRECT_PREFIX + ACTION_URL); + } + + @Test + public void placeOrder_shouldGoBackToStep_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndPaymentRefused() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(COUNTRY_CODE_SWEDEN); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(paymentsResponseMock.getResultCode()).thenReturn(REFUSED); + when(paymentsResponseMock.getRefusalReason()).thenReturn(ApiConstants.RefusalReason.TRANSACTION_NOT_PERMITTED); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.CheckoutSummaryPage); + } + + @Test + public void placeOrder_shouldRedirectTo3DS_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndChallengeShopperAnotherMethod() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_CC); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(paymentsResponseMock.getResultCode()).thenReturn(CHALLENGESHOPPER); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DSPaymentPage); + } + + @Test + public void placeOrder_shouldRedirectTo3DS_whenAdyenNonAuthorizedPaymentExceptionIsThrownAndIdentifyShopperAnotherMethod() throws Exception { + mockElementsUsedInTestsForPlaceOrder(); + mockFormValidationOK(); + mockCartValidationOK(); + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_CC); + AdyenNonAuthorizedPaymentException thisException = new AdyenNonAuthorizedPaymentException(paymentResultMock); + when(paymentsResponseMock.getResultCode()).thenReturn(IDENTIFYSHOPPER); + thisException.setPaymentsResponse(paymentsResponseMock); + when(adyenCheckoutFacadeMock.authorisePayment(requestMock, cartDataMock)).thenThrow(thisException); + + final String result = testObj.placeOrder(placeOrderFormMock, modelMock, requestMock, redirectModelMock); + + assertThat(result).isEqualTo(AdyenControllerConstants.Views.Pages.MultiStepCheckout.Validate3DSPaymentPage); + } + + private void mockAnonymousCheckoutAndOrderGuid() { + when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(true); + when(orderDataMock.getGuid()).thenReturn(ORDER_CODE); + } + + private void mockFormValidationOK() { + when(checkoutFlowFacadeMock.hasNoDeliveryAddress()).thenReturn(false); + when(checkoutFlowFacadeMock.hasNoDeliveryMode()).thenReturn(false); + when(checkoutFlowFacadeMock.hasNoPaymentInfo()).thenReturn(false); + when(checkoutFlowFacadeMock.getSubscriptionPciOption()).thenReturn(CheckoutPciOptionEnum.HOP); + when(placeOrderFormMock.isTermsCheck()).thenReturn(true); + when(checkoutFacadeMock.containsTaxValues()).thenReturn(true); + when(cartDataMock.isCalculated()).thenReturn(true); + } + + private void mockCartValidationOK() throws CommerceCartModificationException { + when(cartFacadeMock.validateCartData()).thenReturn(modifications); + } + + private void mockElementsUsedInTestsForHandleRedirectPayload() throws Exception { + when(requestMock.getParameter(PAYLOAD)).thenReturn(PAYLOAD_VALUE); + when(responseMock.getMerchantReference()).thenReturn(MERCHANT_REFERENCE); + when(responseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); + when(orderDataMock.getCode()).thenReturn(ORDER_CODE); + when(adyenCheckoutFacadeMock.handleRedirectPayload((HashMap) details)).thenReturn(responseMock); + when(orderFacadeMock.getOrderDetailsForCodeWithoutUser(responseMock.getMerchantReference())).thenReturn(orderDataMock); + when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(false); + } + private void mockElementsUsedInTestsForPlaceOrder() throws CMSItemNotFoundException { + contentPageModelMock.setTitle(CONTENT_PAGE_MODEL_TITLE); + contentPageModelMock.setKeywords(CONTENT_PAGE_MODEL_KEYWORDS); + contentPageModelMock.setDescription(CONTENT_PAGE_MODEL_DESCRIPTION); + + final List breadcrumbs = new ArrayList<>(); + final CheckoutGroup checkoutGroup = new CheckoutGroup(); + final Map checkoutGroupMap = Map.of(CHECKOUT_FLOW_GROUP_FOR_CHECKOUT_MOCK, checkoutGroup); + final Map checkoutStepMap = Map.of(CURRENT_CONTROLLER, checkoutStepMock); + + checkoutGroup.setCheckoutStepMap(checkoutStepMap); + + when(placeOrderFormMock.getSecurityCode()).thenReturn(SECURITY_CODE); + when(checkoutFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); + when(checkoutFlowFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); + when(cartDataMock.getEntries()).thenReturn(null); + when(cmsPageServiceMock.getHomepage(anyObject())).thenReturn(contentPageModelMock); + when(cmsSiteServiceMock.getCurrentSite()).thenReturn(cmsSiteModelMock); + when(cmsSiteServiceMock.getStartPageLabelOrId(cmsSiteModelMock)).thenReturn(CONTENT_PAGE_MODEL_ID); + when(cmsPreviewServiceMock.getPagePreviewCriteria()).thenReturn(pagePreviewCriteriaDataMock); + when(cmsPageServiceMock.getPageForLabelOrId(MULTI_CHECKOUT_SUMMARY_CMS_PAGE_LABEL_MOCK, pagePreviewCriteriaDataMock)). + thenReturn(contentPageModelMock); + when(pageTitleResolverMock.resolveContentPageTitle(CONTENT_PAGE_MODEL_TITLE)).thenReturn(CONTENT_PAGE_MODEL_TITLE); + when(resourceBreadcrumbBuilderMock.getBreadcrumbs(anyObject())).thenReturn(breadcrumbs); + when(checkoutFacadeMock.getCheckoutFlowGroupForCheckout()).thenReturn(CHECKOUT_FLOW_GROUP_FOR_CHECKOUT_MOCK); + doReturn(checkoutGroupMap).when(testObj).getCheckoutFlowGroupMap(); + when(checkoutStepMock.previousStep()).thenReturn(REDIRECT_PREFIX); + when(checkoutStepMock.nextStep()).thenReturn(REDIRECT_PREFIX); + when(checkoutStepMock.currentStep()).thenReturn(REDIRECT_PREFIX); + when(checkoutStepMock.getProgressBarId()).thenReturn(PROGRESS_BAR_ID); + } +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayControllerTest.java b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayControllerTest.java new file mode 100644 index 000000000..b9ca6894d --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/testsrc/com/adyen/v6/controllers/pages/payments/AdyenAmazonpayControllerTest.java @@ -0,0 +1,146 @@ +package com.adyen.v6.controllers.pages.payments; + +import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.model.checkout.details.AmazonPayDetails; +import com.adyen.v6.facades.AdyenAmazonPayFacade; +import com.adyen.v6.facades.AdyenCheckoutFacade; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.acceleratorfacades.flow.CheckoutFlowFacade; +import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException; +import de.hybris.platform.commercefacades.order.OrderFacade; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.order.data.OrderData; +import de.hybris.platform.commerceservices.order.CommerceCartModificationException; +import de.hybris.platform.commerceservices.strategies.CheckoutCustomerStrategy; +import org.apache.commons.lang.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.ui.Model; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import javax.servlet.http.HttpServletRequest; + +import static com.adyen.v6.constants.AdyenControllerConstants.AMAZON_RETURN_URL; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenAmazonpayControllerTest { + + private static final String ORDER_CODE = "orderCode"; + private static final String AMAZON_PAY_TOKEN = "amazonPayToken"; + private static final String SUMMARY_PAGE_REDIRECT = "summaryPageRedirect"; + private static final String AMAZON_CHECKOUT_SESSION_ID = "amazonCheckoutSessionId"; + private static final String REDIRECT_CHECKOUT_ORDER_CONFIRMATION_PAGE = "redirect:/checkout/orderConfirmation/orderCode"; + private static final String REDIRECT_3DS = "addon:/adyenv6b2ccheckoutaddon/pages/checkout/multi/3ds_payment"; + private static final String REDIRECT_RESULT = "redirectResult"; + private static final String URL = "url"; + + @Spy + @InjectMocks + private AdyenAmazonpayController testObj; + + @Mock + private OrderFacade orderFacadeMock; + @Mock + private CheckoutFlowFacade checkoutFlowFacadeMock; + @Mock + private AdyenCheckoutFacade adyenCheckoutFacadeMock; + @Mock + private AdyenAmazonPayFacade adyenAmazonPayFacadeMock; + @Mock + private CheckoutCustomerStrategy checkoutCustomerStrategyMock; + + @Mock + private Model modelMock; + @Mock + private CartData cartDataMock; + @Mock + private OrderData orderDataMock; + @Mock + private HttpServletRequest requestMock; + @Mock + private PaymentsResponse paymentResponseMock; + @Mock + private RedirectAttributes redirectModelMock; + + @Test + public void placeOrder_shouldRedirectToSummaryPage_whenCheckoutSessionIdAndRedirectResultAreEmpty() throws CMSItemNotFoundException, CommerceCartModificationException { + doReturn(SUMMARY_PAGE_REDIRECT).when(testObj).enterStep(modelMock, redirectModelMock); + + final String result = testObj.placeOrder(modelMock, redirectModelMock, requestMock, StringUtils.EMPTY); + + assertThat(result).isEqualTo(SUMMARY_PAGE_REDIRECT); + } + + @Test + public void placeOrder_shouldRedirectToSummaryPage_whenCheckoutSessionIdAndRedirectResultAreNull() throws CMSItemNotFoundException, CommerceCartModificationException { + doReturn(SUMMARY_PAGE_REDIRECT).when(testObj).enterStep(modelMock, redirectModelMock); + + final String result = testObj.placeOrder(modelMock, redirectModelMock, requestMock, null); + + assertThat(result).isEqualTo(SUMMARY_PAGE_REDIRECT); + } + + @Test + public void placeOrder_shouldRedirectToOrderPlaced_whenCheckoutSessionIdIsValid() throws Exception { + when(orderDataMock.getCode()).thenReturn(ORDER_CODE); + when(paymentResponseMock.getMerchantReference()).thenReturn(ORDER_CODE); + when(checkoutFlowFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); + when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(Boolean.FALSE); + when(orderFacadeMock.getOrderDetailsForCodeWithoutUser(ORDER_CODE)).thenReturn(orderDataMock); + when(adyenAmazonPayFacadeMock.getAmazonPayToken(AMAZON_CHECKOUT_SESSION_ID)).thenReturn(AMAZON_PAY_TOKEN); + when(adyenCheckoutFacadeMock.componentPayment(eq(requestMock), eq(cartDataMock), isA(AmazonPayDetails.class))).thenReturn(paymentResponseMock); + when(adyenAmazonPayFacadeMock.getReturnUrl(AMAZON_RETURN_URL)).thenReturn(URL); + + final String result = testObj.placeOrder(modelMock, redirectModelMock, requestMock, AMAZON_CHECKOUT_SESSION_ID); + + + assertThat(result).isEqualTo(REDIRECT_CHECKOUT_ORDER_CONFIRMATION_PAGE); + } + + @Test + public void placeOrder_shouldRedirectTo3DSValidation_whenCheckoutSessionIdIsValidAndResponseCodeIsRedirectShopper() throws Exception { + when(orderDataMock.getCode()).thenReturn(ORDER_CODE); + when(paymentResponseMock.getMerchantReference()).thenReturn(ORDER_CODE); + when(paymentResponseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER); + when(checkoutFlowFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); + when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(Boolean.FALSE); + when(orderFacadeMock.getOrderDetailsForCodeWithoutUser(ORDER_CODE)).thenReturn(orderDataMock); + when(adyenAmazonPayFacadeMock.getAmazonPayToken(AMAZON_CHECKOUT_SESSION_ID)).thenReturn(AMAZON_PAY_TOKEN); + when(adyenCheckoutFacadeMock.componentPayment(eq(requestMock), eq(cartDataMock), isA(AmazonPayDetails.class))).thenReturn(paymentResponseMock); + when(adyenAmazonPayFacadeMock.getReturnUrl(AMAZON_RETURN_URL)).thenReturn(URL); + when(adyenCheckoutFacadeMock.getClientKey()).thenReturn("clientKey"); + when(adyenCheckoutFacadeMock.getCheckoutShopperHost()).thenReturn("host"); + when(adyenCheckoutFacadeMock.getEnvironmentMode()).thenReturn("environment"); + when(adyenCheckoutFacadeMock.getShopperLocale()).thenReturn("shopperLocale"); + + final String result = testObj.placeOrder(modelMock, redirectModelMock, requestMock, AMAZON_CHECKOUT_SESSION_ID); + + + assertThat(result).isEqualTo(REDIRECT_3DS); + } + + @Test + public void placeOrder_shouldRedirectToSummaryPage_whenAnExceptionIsThrownDuringThePaymentProcess() throws Exception { + when(paymentResponseMock.getMerchantReference()).thenReturn(ORDER_CODE); + when(checkoutFlowFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); + doReturn(SUMMARY_PAGE_REDIRECT).when(testObj).enterStep(modelMock, redirectModelMock); + when(adyenAmazonPayFacadeMock.getAmazonPayToken(AMAZON_CHECKOUT_SESSION_ID)).thenReturn(AMAZON_PAY_TOKEN); + when(adyenCheckoutFacadeMock.componentPayment(eq(requestMock), eq(cartDataMock), isA(AmazonPayDetails.class))).thenThrow(Exception.class); + when(adyenAmazonPayFacadeMock.getReturnUrl(AMAZON_RETURN_URL)).thenReturn(URL); + + final String result = testObj.placeOrder(modelMock, redirectModelMock, requestMock, AMAZON_CHECKOUT_SESSION_ID); + + assertThat(result).isEqualTo(SUMMARY_PAGE_REDIRECT); + } + +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties index 92e012792..52eb7da17 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base.properties @@ -32,6 +32,7 @@ payment.method.last.name=Last name payment.method.issuer.selector=Please select issuer payment.method.terminal.selector=Select your terminal payment.method.telephonenumber=Phone Number +payment.method.label.information=Bank Card checkout.summary.spinner.message=Please wait while your payment is processed. Do not click back or refresh the page. checkout.summary.component.mbway.payment=Provide your MB WAY account data to finalize your payment diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_en.properties b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_en.properties index 92e012792..80afd85a6 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_en.properties +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_en.properties @@ -36,4 +36,11 @@ payment.method.telephonenumber=Phone Number checkout.summary.spinner.message=Please wait while your payment is processed. Do not click back or refresh the page. checkout.summary.component.mbway.payment=Provide your MB WAY account data to finalize your payment checkout.summary.component.notavailable=This payment method is not available on your current browser or device -checkout.summary.component.generateqr = Generate QR Code \ No newline at end of file +checkout.summary.component.generateqr = Generate QR Code + +address.line2BR = House number or name +address.line2BR.invalid = Please, enter a house number or name +address.postcodeBR.invalid = Please, the postcode has to contains 8 digits +address.postcodeBR.invalid.addressForm.postcode = Please, the postcode has to contain 8 digits +address.phoneIN.invalid.addressForm.phone = Please introduce a correct phone number, the phone number is invalid +customersupport_backoffice_addressForm.phone1=Phone Number \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_pt.properties b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_pt.properties index ec926c6c1..ddf73ad6a 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_pt.properties +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/messages/base_pt.properties @@ -34,4 +34,11 @@ payment.method.terminal.selector=Selecione o terminal payment.method.telephonenumber=Número de telefone checkout.summary.spinner.message=Aguarde... -checkout.summary.component.generateqr = Gerar QR Code \ No newline at end of file +checkout.summary.component.generateqr = Gerar QR Code + +address.line2BR = Número ou nome da casa +address.line2BR.invalid = Please, enter a house number or name +address.postcodeBR.invalid = Please, the postcode has to contains 8 digits +address.postcodeBR.invalid.addressForm.postcode = Please, the postcode has to contains 8 digits +address.phoneIN.invalid.addressForm.phone = Please introduce a correct phone number, the phone number is invalid +customersupport_backoffice_addressForm.phone1=Phone Number \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormElements.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormElements.tag new file mode 100644 index 000000000..50fc69e15 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormElements.tag @@ -0,0 +1,89 @@ +<%@ attribute name="regions" required="true" type="java.util.List"%> +<%@ attribute name="country" required="false" type="java.lang.String"%> +<%@ attribute name="tabIndex" required="false" type="java.lang.Integer"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="formElement" tagdir="/WEB-INF/tags/responsive/formElement" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ taglib prefix="theme" tagdir="/WEB-INF/tags/shared/theme" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> +<%@ taglib prefix="ycommerce" uri="http://hybris.com/tld/ycommercetags" %> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormSelector.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormSelector.tag new file mode 100644 index 000000000..17efc479c --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/addressFormSelector.tag @@ -0,0 +1,102 @@ +<%@ attribute name="supportedCountries" required="true" type="java.util.List"%> +<%@ attribute name="regions" required="true" type="java.util.List"%> +<%@ attribute name="country" required="false" type="java.lang.String"%> +<%@ attribute name="cancelUrl" required="false" type="java.lang.String"%> +<%@ attribute name="addressBook" required="false" type="java.lang.String"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="formElement" tagdir="/WEB-INF/tags/responsive/formElement"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> +<%@ taglib prefix="address" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="ycommerce" uri="http://hybris.com/tld/ycommercetags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + + + + + +
+
+ + + + + + +
+ +
+
+ + + +
+ +
+ + + + + + + + + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ + + + + + +
+
+
+
+
+
+
+
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/adyenLibrary.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/adyenLibrary.tag new file mode 100644 index 000000000..25f811230 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/adyenLibrary.tag @@ -0,0 +1,45 @@ +<%-- + ~ ###### + ~ ###### + ~ ############ ####( ###### #####. ###### ############ ############ + ~ ############# #####( ###### #####. ###### ############# ############# + ~ ###### #####( ###### #####. ###### ##### ###### ##### ###### + ~ ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### + ~ ###### ###### #####( ###### #####. ###### ##### ##### ###### + ~ ############# ############# ############# ############# ##### ###### + ~ ############ ############ ############# ############ ##### ###### + ~ ###### + ~ ############# + ~ ############ + ~ + ~ Adyen Hybris Extension + ~ + ~ Copyright (c) 2017 Adyen B.V. + ~ This file is open source and available under the MIT license. + ~ See the LICENSE file for more info. + --%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ attribute name="dfUrl" required="false" type="java.lang.String"%> +<%@ attribute name="showDefaultCss" required="false" type="java.lang.Boolean"%> + + + + + + + + + + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/alternativeMethod.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/alternativeMethod.tag index f2038403c..f9e4b5025 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/alternativeMethod.tag +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/alternativeMethod.tag @@ -52,7 +52,7 @@ - + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/billingAddressFormElements.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/billingAddressFormElements.tag index aeac85d11..158e7aa18 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/billingAddressFormElements.tag +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/billingAddressFormElements.tag @@ -18,7 +18,7 @@ + items="${regions}" itemValue="${useShortRegionIso ? 'isocodeShort' : 'isocode'}" tabindex="${tabindex + 7}" selectCSSClass="form-control"/> @@ -31,14 +31,14 @@ + items="${regions}" itemValue="${useShortRegionIso ? 'isocodeShort' : 'isocode'}" tabindex="${tabindex + 7}" selectCSSClass="form-control"/> + items="${regions}" itemValue="${useShortRegionIso ? 'isocodeShort' : 'isocode'}" tabindex="${tabindex + 3}" selectCSSClass="form-control"/> @@ -55,12 +55,25 @@ + items="${regions}" itemValue="${useShortRegionIso ? 'isocodeShort' : 'isocode'}" tabindex="${tabindex + 5}" selectCSSClass="form-control"/> + + + + + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/checkoutOrderSummary.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/checkoutOrderSummary.tag index 2b1d54b5b..2f458fbb0 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/checkoutOrderSummary.tag +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/checkoutOrderSummary.tag @@ -10,17 +10,23 @@ - + <%-- Components --%> +
+ + +
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag index c309cb65b..ca966df80 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/tags/responsive/securedFieldsMethod.tag @@ -29,7 +29,7 @@
- ${creditCardLabel} + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/account/accountEditAddressPage.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/account/accountEditAddressPage.jsp new file mode 100644 index 000000000..13dc5c38f --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/account/accountEditAddressPage.jsp @@ -0,0 +1,40 @@ +<%@ page trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="address" tagdir="/WEB-INF/tags/responsive/address"%> +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + + + + + + + + + + + + + + +
+
+ +
+
+ + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds_payment.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds_payment.jsp index 2afa0d4d7..f775726e2 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds_payment.jsp +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/3ds_payment.jsp @@ -1,48 +1,49 @@ <%@ page trimDirectiveWhitespaces="true" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> +<%@ taglib prefix="json" uri="http://www.atg.com/taglibs/json" %> - - - + + + + + + + + + + + - -
-
- -
+ +
+
+ +
- \ No newline at end of file + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/addEditDeliveryAddressPage.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/addEditDeliveryAddressPage.jsp new file mode 100644 index 000000000..b67841b5e --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/addEditDeliveryAddressPage.jsp @@ -0,0 +1,98 @@ +<%@ page trimDirectiveWhitespaces="true"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="template" tagdir="/WEB-INF/tags/responsive/template"%> +<%@ taglib prefix="cms" uri="http://hybris.com/tld/cmstags"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="cms" uri="http://hybris.com/tld/cmstags"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="address" tagdir="/WEB-INF/tags/responsive/address"%> +<%@ taglib prefix="multi-checkout" tagdir="/WEB-INF/tags/responsive/checkout/multi"%> +<%@ taglib prefix="ycommerce" uri="http://hybris.com/tld/ycommercetags" %> +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> + + + + + +
+
+
+ + +
+ + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+ +
    +
  • + ${fn:escapeXml(deliveryAddress.title)}  + ${fn:escapeXml(deliveryAddress.firstName)}  + ${fn:escapeXml(deliveryAddress.lastName)} +
    + ${fn:escapeXml(deliveryAddress.line1)}  + ${fn:escapeXml(deliveryAddress.line2)} +
    + ${fn:escapeXml(deliveryAddress.town)} + +  ${fn:escapeXml(deliveryAddress.region.name)} + +
    + ${fn:escapeXml(deliveryAddress.country.name)}  + ${fn:escapeXml(deliveryAddress.postalCode)} +
  • +
+ +
+
+
+
+ + +
+ + +
+ + + +
+
+
+
+ + + +
+ + + +
+
+ +
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/checkoutSummaryPage.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/checkoutSummaryPage.jsp index 40e878f13..2da57bf8c 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/checkoutSummaryPage.jsp +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/checkoutSummaryPage.jsp @@ -8,64 +8,97 @@ <%@ taglib prefix="ycommerce" uri="http://hybris.com/tld/ycommercetags" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="order" tagdir="/WEB-INF/tags/responsive/order" %> - +<%@ taglib prefix="adyen" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="json" uri="http://www.atg.com/taglibs/json" %> - - - - + @@ -135,7 +170,7 @@
-
+
diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/countryAddressForm.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/countryAddressForm.jsp new file mode 100644 index 000000000..6d5a2d254 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/countryAddressForm.jsp @@ -0,0 +1,11 @@ +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ taglib prefix="address" tagdir="/WEB-INF/tags/addons/adyenv6b2ccheckoutaddon/responsive" %> + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp index 8ef99fde4..14e1f7dd2 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/WEB-INF/views/responsive/pages/checkout/multi/selectPaymentMethodPage.jsp @@ -16,94 +16,132 @@ - - - - + @@ -118,11 +156,13 @@ + id="adyen-encrypted-form" action="${selectPaymentMethod}" + > + @@ -170,7 +210,8 @@ tabindex="11"/> - + <%-- Billing Information end --%> diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/css/adyenv6b2ccheckoutaddon.css b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/css/adyenv6b2ccheckoutaddon.css index 525ccd2c6..ae747a198 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/css/adyenv6b2ccheckoutaddon.css +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/css/adyenv6b2ccheckoutaddon.css @@ -98,4 +98,14 @@ div#section_break { .chckt-pm-applepay { display: none; } -} \ No newline at end of file +} + +.visible-xs.side-margins { + margin-left: 20px; + margin-right: 20px; +} + +.adyen-checkout__dropdown__list { + position:relative !important; + max-height: 280px; +} diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen.checkout.js b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen.checkout.js index d4c1aabe3..a9ce023ff 100644 --- a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen.checkout.js +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen.checkout.js @@ -27,21 +27,22 @@ var AdyenCheckoutHybris = (function () { card: null, oneClickCards: {}, selectedCardBrand: null, - sepaDirectDebit:null, + sepaDirectDebit: null, afterPay: null, bcmc: null, + paypalButton: null, convertCardBrand: function () { var cardBrand = this.selectedCardBrand; - if ( cardBrand === CardBrand.Visa ) { + if (cardBrand === CardBrand.Visa) { return CardBrand.Electron; } - if ( cardBrand === CardBrand.MasterCard ) { + if (cardBrand === CardBrand.MasterCard) { return CardBrand.Maestro; } - if ( cardBrand === CardBrand.Elo ) { + if (cardBrand === CardBrand.Elo) { return CardBrand.EloDebit; } }, @@ -52,9 +53,9 @@ var AdyenCheckoutHybris = (function () { }, getCardType: function () { - var cardType =$( '#adyen_combo_card_type' ).val(); - if ( cardType === "" || cardType == undefined ) - cardType= "credit"; + var cardType = $('#adyen_combo_card_type').val(); + if (cardType === "" || cardType == undefined) + cardType = "credit"; return cardType; }, @@ -63,19 +64,19 @@ var AdyenCheckoutHybris = (function () { }, validateForm: function () { - var paymentMethod = $( 'input[type=radio][name=paymentMethod]:checked' ).val(); + var paymentMethod = $('input[type=radio][name=paymentMethod]:checked').val(); - if ( paymentMethod === "" ) { - window.alert( "Please select a payment method" ); + if (paymentMethod === "") { + window.alert("Please select a payment method"); return false; } // Check if it is a valid card and encrypt - if ( paymentMethod === "adyen_cc" ) { + if (paymentMethod === "adyen_cc") { var isInvalidCard = !this.card.isValid || (this.isDebitCard() && !this.isValidBrandType()); - if ( isInvalidCard ) { + if (isInvalidCard) { window.alert('Please check your card details.'); this.card.showValidation(); document.getElementById("card-div").scrollIntoView(); @@ -84,7 +85,7 @@ var AdyenCheckoutHybris = (function () { this.copyCardData(); } - if (paymentMethod.indexOf( "adyen_oneclick_" ) === 0) { + if (paymentMethod.indexOf("adyen_oneclick_") === 0) { var recurringReference = paymentMethod.slice("adyen_oneclick_".length); var oneClickCard = this.oneClickCards[recurringReference]; @@ -92,33 +93,32 @@ var AdyenCheckoutHybris = (function () { window.alert('This credit card is not allowed'); return false; } - if ( ['bcmc','maestro'].indexOf(oneClickCard.props.brand) >= 0 ) { - this.copyOneClickCardBrandData( recurringReference, oneClickCard.props.brand ) - } - else { - this.copyOneClickCardData( recurringReference, oneClickCard.data.paymentMethod.encryptedSecurityCode, oneClickCard.props.brand ); + if (['bcmc', 'maestro'].indexOf(oneClickCard.props.brand) >= 0) { + this.copyOneClickCardBrandData(recurringReference, oneClickCard.props.brand) + } else { + this.copyOneClickCardData(recurringReference, oneClickCard.data.paymentMethod.encryptedSecurityCode, oneClickCard.props.brand); } } - $( 'input[name="txvariant"]' ).remove(); + $('input[name="txvariant"]').remove(); - if ( ['eps','ideal'].indexOf(paymentMethod) >= 0 ) { + if (['eps', 'ideal','onlinebanking_IN', 'onlineBanking_PL'].indexOf(paymentMethod) >= 0) { var issuerIdField = document.getElementById('issuerId'); - if( issuerIdField.value === "" ) { + if (issuerIdField.value === "") { window.alert("Please select an issuer"); return false; } } - if ( paymentMethod === "pos" ) { - var terminalId = $( '#adyen_pos_terminal' ); - if( terminalId.val() === "" ) { + if (paymentMethod === "pos") { + var terminalId = $('#adyen_pos_terminal'); + if (terminalId.val() === "") { window.alert("Please select a terminal"); return false; } } - if( paymentMethod === "sepadirectdebit" ){ - if( !this.sepaDirectDebit.state.isValid ) { + if (paymentMethod === "sepadirectdebit") { + if (!this.sepaDirectDebit.state.isValid) { window.alert("Invalid SEPA Owner Name and IBAN number"); return false; } @@ -132,8 +132,8 @@ var AdyenCheckoutHybris = (function () { return false; } var dob = $("input[name=dateOfBirth]").val(); - if ( dob ) { - $( "#dob" ).val( dob ); + if (dob) { + $("#dob").val(dob); } } @@ -147,9 +147,9 @@ var AdyenCheckoutHybris = (function () { } if (paymentMethod === "giftcard") { - $( 'input[name="giftCardBrand"]' ).val($( 'input[type=radio][name=paymentMethod]:checked' ).attr('brand')); + $('input[name="giftCardBrand"]').val($('input[type=radio][name=paymentMethod]:checked').attr('brand')); } - + if (paymentMethod === "bcmc") { if (!this.bcmc.state.isValid) { window.alert("Please fill all the details"); @@ -158,80 +158,81 @@ var AdyenCheckoutHybris = (function () { return false; } var state = this.bcmc.data.paymentMethod; - $( 'input[name="encryptedCardNumber"]' ).val( state.encryptedCardNumber ); - $( 'input[name="encryptedExpiryMonth"]' ).val( state.encryptedExpiryMonth ); - $( 'input[name="encryptedExpiryYear"]' ).val( state.encryptedExpiryYear ); - $( 'input[name="cardHolder"]' ).val( state.holderName ); - $( 'input[name="cardBrand"]' ).val( 'bcmc' ); - $( 'input[name="cardType"]' ).val( 'debit' ); - $( 'input[name="browserInfo"]' ).val( JSON.stringify( this.bcmc.data.browserInfo ) ); - } - + $('input[name="encryptedCardNumber"]').val(state.encryptedCardNumber); + $('input[name="encryptedExpiryMonth"]').val(state.encryptedExpiryMonth); + $('input[name="encryptedExpiryYear"]').val(state.encryptedExpiryYear); + $('input[name="cardHolder"]').val(state.holderName); + $('input[name="cardBrand"]').val('bcmc'); + $('input[name="cardType"]').val('debit'); + $('input[name="browserInfo"]').val(JSON.stringify(this.bcmc.data.browserInfo)); + } + return true; }, - copyCardData: function() { + copyCardData: function () { var state = this.card.data.paymentMethod; - $( 'input[name="encryptedCardNumber"]' ).val( state.encryptedCardNumber ); - $( 'input[name="encryptedExpiryMonth"]' ).val( state.encryptedExpiryMonth ); - $( 'input[name="encryptedExpiryYear"]' ).val( state.encryptedExpiryYear ); - $( 'input[name="encryptedSecurityCode"]' ).val( state.encryptedSecurityCode ); - $( 'input[name="cardHolder"]' ).val( state.holderName ); - if(this.card.data.storePaymentMethod!=null){ - $( 'input[name="rememberTheseDetails"]' ).val( this.card.data.storePaymentMethod );} - - if ( this.isDebitCard() ) { - $( 'input[name="cardBrand"]' ).val( this.convertCardBrand() ); - $( 'input[name="cardType"]' ).val( this.getCardType() ); + $('input[name="encryptedCardNumber"]').val(state.encryptedCardNumber); + $('input[name="encryptedExpiryMonth"]').val(state.encryptedExpiryMonth); + $('input[name="encryptedExpiryYear"]').val(state.encryptedExpiryYear); + $('input[name="encryptedSecurityCode"]').val(state.encryptedSecurityCode); + $('input[name="cardHolder"]').val(state.holderName); + if (this.card.data.storePaymentMethod != null) { + $('input[name="rememberTheseDetails"]').val(this.card.data.storePaymentMethod); + } + + if (this.isDebitCard()) { + $('input[name="cardBrand"]').val(this.convertCardBrand()); + $('input[name="cardType"]').val(this.getCardType()); } else { - $( 'input[name="cardBrand"]' ).val(this.selectedCardBrand); + $('input[name="cardBrand"]').val(this.selectedCardBrand); } - $( 'input[name="browserInfo"]' ).val( JSON.stringify( this.card.data.browserInfo ) ); + $('input[name="browserInfo"]').val(JSON.stringify(this.card.data.browserInfo)); }, - copyOneClickCardData: function ( recurringReference, cvc, brand ) { - $( "#selectedReference" ).val( recurringReference ); - $( 'input[name="encryptedSecurityCode"]' ).val( cvc ); - $( 'input[name="browserInfo"]' ).val( JSON.stringify( this.card.data.browserInfo ) ); + copyOneClickCardData: function (recurringReference, cvc, brand) { + $("#selectedReference").val(recurringReference); + $('input[name="encryptedSecurityCode"]').val(cvc); + $('input[name="browserInfo"]').val(JSON.stringify(this.card.data.browserInfo)); if (brand) { - $( 'input[name="cardBrand"]' ).val( brand ); + $('input[name="cardBrand"]').val(brand); } }, - copyOneClickCardBrandData: function ( recurringReference, brand ) { - $( "#selectedReference" ).val( recurringReference ); - $( 'input[name="cardBrand"]' ).val( brand ); - $( 'input[name="browserInfo"]' ).val( JSON.stringify( this.card.data.browserInfo ) ); + copyOneClickCardBrandData: function (recurringReference, brand) { + $("#selectedReference").val(recurringReference); + $('input[name="cardBrand"]').val(brand); + $('input[name="browserInfo"]').val(JSON.stringify(this.card.data.browserInfo)); }, /** * Set Custom values for certain payment methods */ setCustomPaymentMethodValues: function () { - var paymentMethod = $( 'input[type=radio][name=paymentMethod]:checked' ).val(); - var dob = $( '#p_method_adyen_hpp_' + paymentMethod + '_dob' ).val(); - if ( dob ) { - $( "#dob" ).val( dob ); + var paymentMethod = $('input[type=radio][name=paymentMethod]:checked').val(); + var dob = $('#p_method_adyen_hpp_' + paymentMethod + '_dob').val(); + if (dob) { + $("#dob").val(dob); } - var ssn = $( '#p_method_adyen_hpp_' + paymentMethod + '_ssn' ); - if ( ssn ) { - $( "#socialSecurityNumber" ).val( ssn.val() ); + var ssn = $('#p_method_adyen_hpp_' + paymentMethod + '_ssn'); + if (ssn) { + $("#socialSecurityNumber").val(ssn.val()); } - var terminalId = $( '#adyen_pos_terminal' ); - if ( terminalId ) { - $( "#terminalId" ).val( terminalId.val() ); + var terminalId = $('#adyen_pos_terminal'); + if (terminalId) { + $("#terminalId").val(terminalId.val()); } - var firstName = $( '#p_method_adyen_hpp_' + paymentMethod + '_first_name' ).val(); + var firstName = $('#p_method_adyen_hpp_' + paymentMethod + '_first_name').val(); if (firstName) { - $( "#firstName" ).val(firstName); + $("#firstName").val(firstName); } - var lastName = $( '#p_method_adyen_hpp_' + paymentMethod + '_last_name' ).val(); + var lastName = $('#p_method_adyen_hpp_' + paymentMethod + '_last_name').val(); if (lastName) { - $( "#lastName" ).val(lastName); + $("#lastName").val(lastName); } }, @@ -240,50 +241,107 @@ var AdyenCheckoutHybris = (function () { * * @param element */ - createDobDatePicker: function ( element ) { - $( "." + element ).datepicker( { + createDobDatePicker: function (element) { + $("." + element).datepicker({ dateFormat: this.dobDateFormat, changeMonth: true, changeYear: true, yearRange: "-120:+0" - } ); + }); }, - togglePaymentMethod: function ( paymentMethod ) { - $( ".payment_method_details" ).hide(); - $( ".chckt-pm__details" ).hide(); + togglePaymentMethod: function (paymentMethod) { + $(".payment_method_details").hide(); + $(".chckt-pm__details").hide(); - $( "#dd_method_" + paymentMethod ).show(); - $( "#adyen_hpp_" + paymentMethod + "_container" ).show(); + $("#dd_method_" + paymentMethod).show(); + $("#adyen_hpp_" + paymentMethod + "_container").show(); }, createDfValue: function () { - window.dfDo( "dfValue" ); + window.dfDo("dfValue"); + }, + + checkTermsAndConditions: function (checked) { + $('.adyen-terms-conditions-check').prop('checked', checked) + if (checked) { + actions.enable(); + $('.adyen-terms-conditions-check-error').addClass('hidden'); + } else { + actions.disable(); + $('.adyen-terms-conditions-check-error').removeClass('hidden'); + } + }, + + showCheckTermsAndConditionsError: function (checked) { + const $errorMessage = $('.adyen-terms-conditions-check-error'); + if ($('.adyen-terms-conditions-check').prop('checked')) { + $errorMessage.addClass('hidden'); + } else { + $errorMessage.removeClass('hidden'); + } }, - initiateCheckout: function ( locale, environment, clientKey ) { - var configuration = { - locale: locale,// shopper's locale - environment: environment, - clientKey: clientKey, + + /** + * + * @returns {Promise} + * @param initConfig + * @param fnCallbackArray + */ + initiateCheckout: async function (initConfig, fnCallbackArray) { + const configuration = { + ...initConfig, + analytics: { + enabled: false // Set to false to not send analytics data to Adyen. + }, risk: { enabled: false - } + }, + onPaymentCompleted: (result, component) => { + console.info(result, component); + }, + onError: (error, component) => { + console.error(error.name, error.message, error.stack, component); + }, }; - this.checkout = new AdyenCheckout( configuration ); - }, + this.checkout = await AdyenCheckout(configuration); + for (let callback of Object.keys(fnCallbackArray)) { + const params = fnCallbackArray[callback]; + if (params && params.hasOwnProperty('label') && !!params.label) { + for (const label of params.label) { + const paramsWithLabel = { + ...params, + label: label + }; + this[callback](paramsWithLabel); + } + } else { + this[callback](params); + } + } + }, - initiateOneClickCard: function(storedCard) { - var oneClickCardNode = document.getElementById("one-click-card_" + storedCard.storedPaymentMethodId); - var oneClickCard = this.checkout.create('card', storedCard); - oneClickCard.mount(oneClickCardNode); - this.oneClickCards[storedCard.storedPaymentMethodId] = oneClickCard; + initiateOneClickCard: function (storedCardList) { + if (storedCardList && storedCardList.length) { + for (const storedCard of storedCardList) { + const oneClickCardNode = document.getElementById("one-click-card_" + storedCard.storedPaymentMethodId); + const oneClickCard = this.checkout.create('card', storedCard); + oneClickCard.mount(oneClickCardNode); + this.oneClickCards[storedCard.storedPaymentMethodId] = oneClickCard; + } + } }, - initiateCard: function (allowedCards, showRememberDetails, cardHolderNameRequired) { - var context = this; - this.card = this.checkout.create( 'card', { + /** + * + * @param functionParameters + */ + initiateCard: function (functionParameters) { + const {allowedCards, showRememberDetails, cardHolderNameRequired} = functionParameters; + const context = this; + this.card = this.checkout.create('card', { type: 'card', hasHolderName: true, holderNameRequired: cardHolderNameRequired, @@ -293,34 +351,38 @@ var AdyenCheckoutHybris = (function () { }); - function copyCardBrand(event) { + function copyCardBrand (event) { context.selectedCardBrand = event.brand; } this.card.mount(document.getElementById('card-div')); }, + /** + * + */ initiateSepaDirectDebit: function () { - var context = this; - var sepaDirectDebitNode = document.getElementById( 'adyen_hpp_sepadirectdebit_container' ); - this.sepaDirectDebit = this.checkout.create( 'sepadirectdebit', { - onChange: handleOnChange - } ); + const sepaDirectDebitNode = document.getElementById('adyen_hpp_sepadirectdebit_container'); + if (this.checkout) { + this.sepaDirectDebit = this.checkout.create('sepadirectdebit', { + onChange: handleOnChange + }); + + function handleOnChange (event) { + var sepaOwnerNameField = document.getElementById('sepaOwnerName'); + var sepaIbanNumberField = document.getElementById('sepaIbanNumber'); - function handleOnChange ( event ) { - var sepaOwnerNameField = document.getElementById( 'sepaOwnerName' ); - var sepaIbanNumberField = document.getElementById( 'sepaIbanNumber' ); + var sepaOwnerName = event.data.paymentMethod["ownerName"] + var sepaIbanNumber = event.data.paymentMethod["iban"] - var sepaOwnerName = event.data.paymentMethod[ "ownerName" ] - var sepaIbanNumber = event.data.paymentMethod[ "iban" ] + sepaOwnerNameField.value = sepaOwnerName; + sepaIbanNumberField.value = sepaIbanNumber; + } - sepaOwnerNameField.value = sepaOwnerName; - sepaIbanNumberField.value = sepaIbanNumber; + this.sepaDirectDebit.mount(sepaDirectDebitNode); } - this.sepaDirectDebit.mount( sepaDirectDebitNode ); }, - initiateIdeal: function (idealDetails) { var idealNode = document.getElementById('adyen_hpp_ideal_container'); var ideal = this.checkout.create('ideal', { @@ -329,7 +391,7 @@ var AdyenCheckoutHybris = (function () { onChange: handleChange // Gets triggered whenever a user selects a bank// Gets triggered once the state is valid }); - function handleChange(event) { + function handleChange (event) { var issuerIdField = document.getElementById('issuerId'); var issuerId = event.data.paymentMethod.issuer; issuerIdField.value = issuerId; @@ -342,16 +404,126 @@ var AdyenCheckoutHybris = (function () { } }, + initiateOnlinebankingIN: function () { + let onlineBankingInNode = document.getElementById('adyen_hpp_onlinebanking_IN_container'); + let onlineBankingIn = this.checkout.create('onlinebanking_IN', { + onChange: handleChange // Gets triggered whenever a user selects a bank// Gets triggered once the state is valid + }); + + function handleChange (event) { + let issuerIdField = document.getElementById('issuerId'); + let issuerId = event.data.paymentMethod.issuer; + issuerIdField.value = issuerId; + } + + try { + onlineBankingIn.mount(onlineBankingInNode); + } catch (e) { + console.log('Something went wrong trying to mount the onlineBanking_In component: ${e}'); + } + }, + initiateOnlineBankingPL: function () { + let onlineBankingPlNode = document.getElementById('adyen_hpp_onlineBanking_PL_container'); + let onlineBankingPl = this.checkout.create('onlineBanking_PL', { + onChange: handleChange // Gets triggered whenever a user selects a bank// Gets triggered once the state is valid + }); + + function handleChange (event) { + let issuerIdField = document.getElementById('issuerId'); + let issuerId = event.data.paymentMethod.issuer; + issuerIdField.value = issuerId; + } + + try { + onlineBankingPl.mount(onlineBankingPlNode); + } catch (e) { + console.log('Something went wrong trying to mount the onlineBanking_PL component: ${e}'); + } + }, + + initiateWalletIN: function () { + let walletInNode = document.getElementById('adyen_hpp_wallet_IN_container'); + let walletIn = this.checkout.create('wallet_IN', { + onChange: handleChange // Gets triggered whenever a user selects a bank// Gets triggered once the state is valid + }); + + function handleChange (event) { + let issuerIdField = document.getElementById('issuerId'); + let issuerId = event.data.paymentMethod.issuer; + issuerIdField.value = issuerId; + } + + try { + walletIn.mount(walletInNode); + } catch (e) { + console.log('Something went wrong trying to mount the upi_In component: ${e}'); + } + }, + + initiateUPI: function () { + const label = this.getVisibleLabel(); + const self = this; + const uPINode = document.getElementById('adyen-component-button-container-' + label); + let upi = this.checkout.create('upi', { + onPaymentCompleted: handlePaymentResult, + defaultMode:'vpa', + showPayButton:true, + }); + + function handlePaymentResult(result, component){ + $.ajax({ + url: ACC.config.encodedContextPath + '/adyen/component/resultHandler', + type: "POST", + data: JSON.stringify({ + resultCode: result.resultCode, + sessionData: result.sessionData + }), + contentType: "application/json; charset=utf-8", + success: function (data) { + try { + window.location.href = ACC.config.encodedContextPath + "/" + data.replace("redirect:/",""); + } catch (e) { + console.log('Error redirecting the user to the placeOrder page'); + AdyenCheckoutHybris.handleResult(ErrorMessages.PaymentError, true); + } + }, + error: function (xmlHttpResponse, exception) { + var responseMessage = xmlHttpResponse.responseJSON; + if (xmlHttpResponse.status === 400) { + AdyenCheckoutHybris.handleResult(responseMessage, true); + } else { + console.log('Error on handling the redirect to the placeOrder page: ' + responseMessage); + handleResult(ErrorMessages.PaymentError, true); + } + } + }) + } + try { + upi.mount(uPINode); + } catch (e) { + console.log('Something went wrong trying to mount the upi component: ${e}'); + } + }, + + initiatePaytm: function () { + let payTmNode = document.getElementById('adyen_hpp_paytm_container'); + let payTm = this.checkout.create('paytm'); + try { + payTm.mount(payTmNode); + } catch (e) { + console.log('Something went wrong trying to mount the paytm component: ${e}'); + } + }, initiateEps: function (epsDetails) { var epsNode = document.getElementById('adyen_hpp_eps_container'); var eps = this.checkout.create('eps', { - details: epsDetails, // The array of issuers coming from the /paymentMethods api call + issuers: epsDetails, // The array of issuers coming from the /paymentMethods api call showImage: true, // Optional, defaults to true onChange: handleOnChange // Gets triggered once the shopper selects an issuer }); - function handleOnChange(event) { + function handleOnChange (event) { var issuerIdField = document.getElementById('issuerId'); var issuerId = event.data.paymentMethod.issuer; issuerIdField.value = issuerId; @@ -364,11 +536,20 @@ var AdyenCheckoutHybris = (function () { } }, - initiatePaypal: function (amount, isImmediateCapture, paypalMerchantId, label) { - var paypalNode = document.getElementById('adyen-component-button-container-' + label); - var self = this; - - var adyenComponent = this.checkout.create("paypal", { + /** + * + * @param params + */ + initiatePaypal: function (params) { + const {amount, isImmediateCapture, paypalMerchantId, label} = params; + const paypalNode = document.getElementById('adyen-component-button-container-' + label); + const self = this; + + const adyenComponent = this.checkout.create("paypal", { + style: { // Optional configuration for PayPal payment buttons. + layout: "vertical", + color: "gold" + }, environment: this.checkout.options.environment, amount: { currency: amount.currency, @@ -378,27 +559,46 @@ var AdyenCheckoutHybris = (function () { intent: isImmediateCapture ? "capture" : "authorize", merchantId: (this.checkout.options.environment === 'test') ? null : paypalMerchantId, // Your PayPal Merchant ID. Required for accepting live payments. }, - onChange: function(state, component) { + blockPayPalCreditButton: true, + blockPayPalPayLaterButton: true, + onInit: (data, actions) => { + actions.enable(); + $(document).on('change', '.adyen-terms-conditions-check', function (event) { + const checked = (event.target.checked) + $('.adyen-terms-conditions-check').prop('checked', checked) + if (checked) { + actions.enable(); + } else { + actions.disable(); + } + self.showCheckTermsAndConditionsError(); + }); + }, + onClick: function () { + // Show a validation error if the checkbox is not checked + self.showCheckTermsAndConditionsError(); + }, + onChange: function (state, component) { if (!state.isValid) { self.enablePlaceOrder(label); } }, - onSubmit: function(state, component) { + onSubmit: function (state, component) { if (!state.isValid) { self.enablePlaceOrder(label); return false; } self.makePayment(state.data.paymentMethod, component, self.handleResult, label); }, - onCancel: function(data, component) { + onCancel: function (data, component) { // Sets your prefered status of the component when a PayPal payment is cancelled. self.handleResult(ErrorMessages.PaymentCancelled, true); }, - onError: function(error, component) { + onError: function (error, component) { // Sets your prefered status of the component when an error occurs. self.handleResult(ErrorMessages.PaymentError, true); }, - onAdditionalDetails: function(state, component) { + onAdditionalDetails: function (state, component) { self.submitDetails(state.data, self.handleResult); } }); @@ -410,10 +610,34 @@ var AdyenCheckoutHybris = (function () { } }, - initiateApplePay: function (amount, countryCode, applePayMerchantIdentifier, applePayMerchantName, label) { - var applePayNode = document.getElementById('adyen-component-button-container-' + label); - var self = this; - var adyenComponent = this.checkout.create("applepay", { + initiateApplePay: function (params) { + const {amount, countryCode, applePayMerchantIdentifier, applePayMerchantName, label} = params; + const applePayNode = document.getElementById('adyen-component-button-container-' + label); + const self = this; + const applePayConfiguration = { + //onValidateMerchant is required if you're using your own Apple Pay certificate + onValidateMerchant: (resolve, reject, validationURL) => { + if (self.isTermsAccepted(label)) { + resolve(); + } else { + reject(); + self.handleResult(ErrorMessages.TermsNotAccepted, true); + } + // Your server uses the validation URL to request a session from the Apple Pay server. + // Call resolve(MERCHANTSESSION) or reject() to complete merchant validation. + /*validateMerchant(validationURL) + .then(response => { + // Complete merchant validation with resolve(MERCHANTSESSION) after receiving an opaque merchant session object, MerchantSession + resolve(response); + }) + .catch(error => { + // Complete merchant validation with reject() if any error occurs + reject(); + });*/ + console.log(validationURL, reject, resolve); + } + }; + const adyenComponent = this.checkout.create("applepay", { amount: { currency: amount.currency, value: amount.value @@ -449,20 +673,25 @@ var AdyenCheckoutHybris = (function () { }); adyenComponent.isAvailable() - .then(function() { + .then(function () { adyenComponent.mount(applePayNode); }) - .catch(function(e) { + .catch(function (e) { // Apple Pay is not available console.log('Something went wrong trying to mount the Apple Pay component: ' + e); self.handleResult(ErrorMessages.PaymentNotAvailable, true); }); }, - - initiateGooglePay: function (amount, merchantAccount, label) { - var googlePayNode = document.getElementById('adyen-component-button-container-' + label); - var self = this; - var adyenComponent = this.checkout.create("paywithgoogle", { + + /** + * + * @param params + */ + initiateGooglePay: function (params) { + const {amount, merchantAccount, label} = params; + const googlePayNode = document.getElementById('adyen-component-button-container-' + label); + const self = this; + const adyenComponent = this.checkout.create("paywithgoogle", { environment: this.checkout.options.environment, amount: { currency: amount.currency, @@ -473,20 +702,20 @@ var AdyenCheckoutHybris = (function () { merchantName: merchantAccount }, buttonColor: "white", - onChange: function(state, component) { + onChange: function (state, component) { if (!state.isValid) { self.hideSpinner(); } }, - onSubmit: function(state, component) { + onSubmit: function (state, component) { if (!state.isValid) { self.hideSpinner(); return false; } - state.showSpinner(); - state.makePayment(state.data.paymentMethod, component, state.handleResult, label); + self.showSpinner(); + self.makePayment(state.data.paymentMethod, component, self.handleResult, label); }, - onClick: function(resolve, reject) { + onClick: function (resolve, reject) { if (self.isTermsAccepted(label)) { resolve(); } else { @@ -497,102 +726,91 @@ var AdyenCheckoutHybris = (function () { }); adyenComponent.isAvailable() - .then(function() { + .then(function () { adyenComponent.mount(googlePayNode); }) - .catch(function(e) { + .catch(function (e) { // Google Pay is not available console.log('Something went wrong trying to mount the Google Pay component: ' + e); self.handleResult(ErrorMessages.PaymentNotAvailable, true); }); }, - - initiateAmazonPay: function (amount, deliveryAddress, amazonPayConfiguration) { - var label = this.getVisibleLabel(); - var url = new URL(window.location.href); - var componentConfiguration; - if(url.searchParams.has('amazonCheckoutSessionId')) { - // Complete payment, amazon session already created - componentConfiguration = { - amount: amount, - amazonCheckoutSessionId: url.searchParams.get('amazonCheckoutSessionId'), - showOrderButton: false, - onSubmit: (state, component) => { - if (!state.isValid) { - component.setStatus('ready'); - this.hideSpinner(); - return false; - } - component.setStatus('loading'); - this.showSpinner(); - this.makePayment(state.data.paymentMethod, component, this.handleResult, label); - } - }; - } else { - // Pre-payment, login and choose amazon pay method - componentConfiguration = { - environment: this.checkout.options.environment, - addressDetails: { - name: deliveryAddress.firstName + ' ' + deliveryAddress.lastName, - addressLine1: deliveryAddress.line1, - addressLine2: deliveryAddress.line2, - city: deliveryAddress.town, - postalCode: deliveryAddress.postalCode, - countryCode: deliveryAddress.country.isocode, - phoneNumber: deliveryAddress.phone - }, - amount: amount, - configuration: amazonPayConfiguration, - productType: 'PayAndShip', - checkoutMode: 'ProcessOrder', - returnUrl: window.location.origin + ACC.config.encodedContextPath + '/checkout/multi/adyen/summary/view', - onClick: (resolve, reject) => { - if (this.isTermsAccepted(label)) { - resolve(); - } else { - reject(); - this.handleResult(ErrorMessages.TermsNotAccepted, true); - } - } - }; + + /** + * + * @param params + */ + initiateAmazonPay: function (params) { + const {amount, deliveryAddress, amazonPayConfiguration, locale} = params; + const label = this.getVisibleLabel(); + let componentConfiguration; + let state = ''; + if (deliveryAddress.country.isocode === 'US') { + state = deliveryAddress.region.isocodeShort; } - - var amazonPayNode = document.getElementById('adyen-component-button-container-' + label); - var adyenComponent = this.checkout.create("amazonpay", componentConfiguration); - + + componentConfiguration = { + environment: this.checkout.options.environment, + addressDetails: { + name: deliveryAddress.firstName + ' ' + deliveryAddress.lastName, + addressLine1: deliveryAddress.line1, + addressLine2: deliveryAddress.line2, + city: deliveryAddress.town, + stateOrRegion: state, + postalCode: deliveryAddress.postalCode, + countryCode: deliveryAddress.country.isocode, + phoneNumber: deliveryAddress.phone || '0' + }, + region: amazonPayConfiguration.region, + amount: amount, + locale: locale, + configuration: amazonPayConfiguration, + checkoutMode: 'ProcessOrder', + productType: 'PayAndShip', + placement: 'Checkout', + returnUrl: window.location.origin + ACC.config.encodedContextPath + '/checkout/multi/adyen/summary/amazonpay/placeorder', + onClick: (resolve, reject) => { + if (this.isTermsAccepted(label)) { + resolve(); + } else { + reject(); + this.handleResult(ErrorMessages.TermsNotAccepted, true); + } + } + }; + const amazonPayNode = document.getElementById('adyen-component-button-container-' + label); + const adyenComponent = this.checkout.create("amazonpay", componentConfiguration); try { adyenComponent.mount(amazonPayNode); - if(url.searchParams.has('amazonCheckoutSessionId')) { - adyenComponent.submit(); - } } catch (e) { console.log('Something went wrong trying to mount the Amazon Pay component: ' + e); this.handleResult(ErrorMessages.PaymentNotAvailable, true); } }, - initiateMbway: function (label) { + initiateMbway: function (params) { + const {label} = params; var mbwayNode = document.getElementById('adyen-component-container-' + label); var self = this; var adyenComponent = this.checkout.create("mbway", { showPayButton: false, - onChange: function(state, component) { + onChange: function (state, component) { if (!state.isValid) { self.enablePlaceOrder(label); } }, - onSubmit: function(state, component) { + onSubmit: function (state, component) { if (!state.isValid) { self.enablePlaceOrder(label); return; } self.makePayment(state.data.paymentMethod, component, self.handleResult, label); }, - onAdditionalDetails: function(state, component) { + onAdditionalDetails: function (state, component) { self.submitDetails(state.data, self.handleResult); }, - onError: function(error, component) { + onError: function (error, component) { console.log('Something went wrong trying to make the MBWay payment: ' + error); self.handleResult(ErrorMessages.PaymentError, true); } @@ -623,7 +841,8 @@ var AdyenCheckoutHybris = (function () { } }, - initiatePix: function (label) { + initiatePix: function (params) { + const {label, issuers} = params; $("#generateqr-" + label).click(function () { AdyenCheckoutHybris.showSpinner(); if (!AdyenCheckoutHybris.isTermsAccepted(label)) { @@ -631,10 +850,11 @@ var AdyenCheckoutHybris = (function () { } else { $("#generateqr-" + label).hide(); $(".checkbox").hide(); - var actionHandler = { - handleAction : function (action) { + var actionHandler = { + handleAction: function (action) { AdyenCheckoutHybris.checkout.createFromAction(action, { - onAdditionalDetails : function(state) { + issuers: issuers, + onAdditionalDetails: function (state) { AdyenCheckoutHybris.hideSpinner(); AdyenCheckoutHybris.submitDetails(state.data, AdyenCheckoutHybris.handleResult); } @@ -642,7 +862,7 @@ var AdyenCheckoutHybris = (function () { AdyenCheckoutHybris.hideSpinner(); } }; - AdyenCheckoutHybris.makePayment({ type: "pix" }, actionHandler, AdyenCheckoutHybris.handleResult, label); + AdyenCheckoutHybris.makePayment({type: "pix"}, actionHandler, AdyenCheckoutHybris.handleResult, label); } }); }, @@ -660,7 +880,8 @@ var AdyenCheckoutHybris = (function () { } }, - initiateBcmcMobile: function (label) { + initiateBcmcMobile: function (params) { + const {label} = params; $("#generateqr-" + label).click(function () { AdyenCheckoutHybris.showSpinner(); if (!AdyenCheckoutHybris.isTermsAccepted(label)) { @@ -668,10 +889,10 @@ var AdyenCheckoutHybris = (function () { } else { $("#generateqr-" + label).hide(); $(".checkbox").hide(); - var actionHandler = { - handleAction : function (action) { + var actionHandler = { + handleAction: function (action) { AdyenCheckoutHybris.checkout.createFromAction(action, { - onAdditionalDetails : function(state) { + onAdditionalDetails: function (state) { AdyenCheckoutHybris.hideSpinner(); AdyenCheckoutHybris.submitDetails(state.data, AdyenCheckoutHybris.handleResult); } @@ -679,16 +900,21 @@ var AdyenCheckoutHybris = (function () { AdyenCheckoutHybris.hideSpinner(); } }; - AdyenCheckoutHybris.makePayment({ type: "bcmc_mobile" }, actionHandler, AdyenCheckoutHybris.handleResult, label); + AdyenCheckoutHybris.makePayment({type: "bcmc_mobile"}, actionHandler, AdyenCheckoutHybris.handleResult, label); } }); }, + /** + * @param form + * @param useSpinner + * @param label + */ configureButton: function (form, useSpinner, label) { $(document).ready(function () { $("#placeOrder-" + label).click(function () { $(this).prop('disabled', true); - if(useSpinner) { + if (useSpinner) { AdyenCheckoutHybris.showSpinner(); } form.submit(); @@ -701,16 +927,16 @@ var AdyenCheckoutHybris = (function () { url: ACC.config.encodedContextPath + '/adyen/component/payment', type: "POST", data: JSON.stringify({ - paymentMethodDetails: data, - termsCheck: document.getElementById('terms-conditions-check-' + label).checked - }), + paymentMethodDetails: data, + termsCheck: document.getElementById('terms-conditions-check-' + label).checked + }), contentType: "application/json; charset=utf-8", success: function (data) { try { var response = JSON.parse(data); if (response.resultCode && response.resultCode === 'Pending' && response.action) { component.handleAction(response.action); - } else if (response.resultCode && (response.resultCode === 'Authorised' || response.resultCode === 'RedirectShopper') ) { + } else if (response.resultCode && (response.resultCode === 'Authorised' || response.resultCode === 'RedirectShopper')) { handleResult(response, false); } else { handleResult(ErrorMessages.PaymentError, true); @@ -763,10 +989,11 @@ var AdyenCheckoutHybris = (function () { }) }, - isTermsAccepted: function(label) { + isTermsAccepted: function (label) { return document.getElementById('terms-conditions-check-' + label).checked; }, + handleResult: function (data, error) { if (error) { document.querySelector("#resultData").value = data; @@ -780,20 +1007,23 @@ var AdyenCheckoutHybris = (function () { showSpinner: function () { document.getElementById("spinner_wrapper").style.display = "flex"; }, + hideSpinner: function () { document.getElementById("spinner_wrapper").style.display = "none"; }, + enablePlaceOrder: function (label) { //hide spinner this.hideSpinner(); //enable button $("#placeOrder-" + label).prop('disabled', false); }, + getVisibleLabel: function () { - if(!(window.getComputedStyle(document.getElementById('adyen-checkout-visible-xs')).display === "none")) { + if (!(window.getComputedStyle(document.getElementById('adyen-checkout-visible-xs')).display === "none")) { return 'visible-xs'; } - if(!(window.getComputedStyle(document.getElementById('adyen-checkout-hidden-xs')).display === "none")) { + if (!(window.getComputedStyle(document.getElementById('adyen-checkout-hidden-xs')).display === "none")) { return 'hidden-xs'; } console.log('Something went wrong while trying to compute current visible label'); diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_deliveryaddress.js b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_deliveryaddress.js new file mode 100644 index 000000000..6b9485707 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/webroot/_ui/responsive/common/js/adyen_deliveryaddress.js @@ -0,0 +1,65 @@ +$( document ).ready( function () { + + var spinner = $( "" ); + + function bindCountrySpecificAddressForms (){ + $(document).on("change",'#adyenCountrySelector select', function (){ + var options = { + 'addressCode': '', + 'countryIsoCode': $(this).val() + }; + displayCountrySpecificAddressForm(options, showAddressFormButtonPanel); + }); + + } + + function showAddressFormButtonPanel () { + if ($('#adyenCountrySelector :input').val() !== '') + { + $('#addressform_button_panel').show(); + } + } + + function displayCountrySpecificAddressForm (options, callback) + { + $.ajax({ + url: ACC.config.encodedContextPath + '/adyen/my-account/addressform', + async: true, + data: options, + dataType: "html", + beforeSend: function () + { + $("#i18nAddressForm").html(spinner); + } + }).done(function (data) + { + $("#i18nAddressForm").html($(data).html()); + if (typeof callback == 'function') + { + callback.call(); + } + + for (const phoneInputPhoneNumber of document.querySelectorAll('input[type=text][name="billingAddress.phoneNumber"]')) { + phoneInputPhoneNumber.addEventListener('change', phoneFormatter, false); + phoneInputPhoneNumber.addEventListener('blur', phoneFormatter, false); + } + + for (const phoneInput of document.querySelectorAll('input[type=text][name=phone]')) { + phoneInput.addEventListener('change', phoneFormatter, false); + phoneInput.addEventListener('blur', phoneFormatter, false); + } + }); + } + + bindCountrySpecificAddressForms(); + + function phoneFormatter(event) { + const input = event.target; + let rawValue = input.value; + if (rawValue && rawValue.length) { + const prefix = rawValue[0] === '+' ? '+' : ''; + input.value = prefix + input.value.replace(/[^0-9]/g, ""); + } + } + +} ); diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/yarn.lock b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/yarn.lock new file mode 100644 index 000000000..dd742ae91 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/acceleratoraddon/web/yarn.lock @@ -0,0 +1,1003 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"abbrev@1": + "integrity" "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "resolved" "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" + "version" "1.1.1" + +"ansi-styles@^4.1.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"argparse@^1.0.7": + "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "sprintf-js" "~1.0.2" + +"array-each@^1.0.1": + "integrity" "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==" + "resolved" "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz" + "version" "1.0.1" + +"array-slice@^1.0.0": + "integrity" "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + "resolved" "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz" + "version" "1.1.0" + +"async@^2.6.0": + "integrity" "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==" + "resolved" "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + "version" "2.6.4" + dependencies: + "lodash" "^4.17.14" + +"async@~3.2.0": + "integrity" "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + "resolved" "https://registry.npmjs.org/async/-/async-3.2.4.tgz" + "version" "3.2.4" + +"async@0.1.x": + "integrity" "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==" + "resolved" "https://registry.npmjs.org/async/-/async-0.1.22.tgz" + "version" "0.1.22" + +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"body@^5.1.0": + "integrity" "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==" + "resolved" "https://registry.npmjs.org/body/-/body-5.1.0.tgz" + "version" "5.1.0" + dependencies: + "continuable-cache" "^0.3.1" + "error" "^7.0.0" + "raw-body" "~1.1.0" + "safe-json-parse" "~1.0.1" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" + dependencies: + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" + +"braces@^3.0.2": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "fill-range" "^7.0.1" + +"bytes@1": + "integrity" "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==" + "resolved" "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz" + "version" "1.0.0" + +"call-bind@^1.0.0": + "integrity" "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==" + "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "function-bind" "^1.1.1" + "get-intrinsic" "^1.0.2" + +"chalk@~4.1.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"colors@~1.1.2": + "integrity" "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==" + "resolved" "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz" + "version" "1.1.2" + +"concat-map@0.0.1": + "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"continuable-cache@^0.3.1": + "integrity" "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==" + "resolved" "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz" + "version" "0.3.1" + +"dateformat@~3.0.3": + "integrity" "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" + "resolved" "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz" + "version" "3.0.3" + +"debug@^3.1.0": + "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + "version" "3.2.7" + dependencies: + "ms" "^2.1.1" + +"detect-file@^1.0.0": + "integrity" "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==" + "resolved" "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz" + "version" "1.0.0" + +"dref@0.0.x": + "integrity" "sha512-mavsfoF9FiDt11eQccNaBpxRQUNHUOruQX732cYn/L7IJLLo5KXa/FsHwnx4Z2x8hMro9heTo+S/KccdU76J2Q==" + "resolved" "https://registry.npmjs.org/dref/-/dref-0.0.6.tgz" + "version" "0.0.6" + dependencies: + "dref" "0.0.x" + "structr" "0.2.x" + "type-component" "0.0.x" + +"error@^7.0.0": + "integrity" "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==" + "resolved" "https://registry.npmjs.org/error/-/error-7.2.1.tgz" + "version" "7.2.1" + dependencies: + "string-template" "~0.2.1" + +"esprima@^4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" + +"eventemitter2@~0.4.13": + "integrity" "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==" + "resolved" "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz" + "version" "0.4.14" + +"exit@~0.1.2": + "integrity" "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==" + "resolved" "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + "version" "0.1.2" + +"expand-tilde@^2.0.0", "expand-tilde@^2.0.2": + "integrity" "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==" + "resolved" "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "homedir-polyfill" "^1.0.1" + +"extend@^3.0.2": + "integrity" "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "resolved" "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" + "version" "3.0.2" + +"faye-websocket@~0.10.0": + "integrity" "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==" + "resolved" "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz" + "version" "0.10.0" + dependencies: + "websocket-driver" ">=0.5.1" + +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "to-regex-range" "^5.0.1" + +"findup-sync@^4.0.0": + "integrity" "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==" + "resolved" "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "detect-file" "^1.0.0" + "is-glob" "^4.0.0" + "micromatch" "^4.0.2" + "resolve-dir" "^1.0.1" + +"findup-sync@~0.3.0": + "integrity" "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==" + "resolved" "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz" + "version" "0.3.0" + dependencies: + "glob" "~5.0.0" + +"fined@^1.2.0": + "integrity" "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==" + "resolved" "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "expand-tilde" "^2.0.2" + "is-plain-object" "^2.0.3" + "object.defaults" "^1.1.0" + "object.pick" "^1.2.0" + "parse-filepath" "^1.0.1" + +"flagged-respawn@^1.0.1": + "integrity" "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + "resolved" "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz" + "version" "1.0.1" + +"for-in@^1.0.1": + "integrity" "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" + "resolved" "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" + "version" "1.0.2" + +"for-own@^1.0.0": + "integrity" "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==" + "resolved" "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "for-in" "^1.0.1" + +"fs-extra@^6.0.1": + "integrity" "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==" + "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "graceful-fs" "^4.1.2" + "jsonfile" "^4.0.0" + "universalify" "^0.1.0" + +"fs.realpath@^1.0.0": + "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" + +"gaze@^1.1.0": + "integrity" "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==" + "resolved" "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz" + "version" "1.1.3" + dependencies: + "globule" "^1.0.0" + +"get-intrinsic@^1.0.2": + "integrity" "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==" + "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz" + "version" "1.1.3" + dependencies: + "function-bind" "^1.1.1" + "has" "^1.0.3" + "has-symbols" "^1.0.3" + +"getobject@~1.0.0": + "integrity" "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==" + "resolved" "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz" + "version" "1.0.2" + +"glob@^7.0.5", "glob@^7.1.3", "glob@~7.1.1", "glob@~7.1.6": + "integrity" "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" + "version" "7.1.7" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.0.4" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"glob@~5.0.0": + "integrity" "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==" + "resolved" "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" + "version" "5.0.15" + dependencies: + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "2 || 3" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"global-modules@^1.0.0": + "integrity" "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==" + "resolved" "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "global-prefix" "^1.0.1" + "is-windows" "^1.0.1" + "resolve-dir" "^1.0.0" + +"global-prefix@^1.0.1": + "integrity" "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==" + "resolved" "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "expand-tilde" "^2.0.2" + "homedir-polyfill" "^1.0.1" + "ini" "^1.3.4" + "is-windows" "^1.0.1" + "which" "^1.2.14" + +"globule@^1.0.0": + "integrity" "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==" + "resolved" "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz" + "version" "1.3.4" + dependencies: + "glob" "~7.1.1" + "lodash" "^4.17.21" + "minimatch" "~3.0.2" + +"graceful-fs@^4.1.2", "graceful-fs@^4.1.6": + "integrity" "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + "version" "4.2.10" + +"grunt-cli@~1.4.3": + "integrity" "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==" + "resolved" "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz" + "version" "1.4.3" + dependencies: + "grunt-known-options" "~2.0.0" + "interpret" "~1.1.0" + "liftup" "~3.0.1" + "nopt" "~4.0.1" + "v8flags" "~3.2.0" + +"grunt-contrib-watch@^1.1.0": + "integrity" "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==" + "resolved" "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "async" "^2.6.0" + "gaze" "^1.1.0" + "lodash" "^4.17.10" + "tiny-lr" "^1.1.1" + +"grunt-known-options@~2.0.0": + "integrity" "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==" + "resolved" "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz" + "version" "2.0.0" + +"grunt-legacy-log-utils@~2.1.0": + "integrity" "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==" + "resolved" "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "chalk" "~4.1.0" + "lodash" "~4.17.19" + +"grunt-legacy-log@~3.0.0": + "integrity" "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==" + "resolved" "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "colors" "~1.1.2" + "grunt-legacy-log-utils" "~2.1.0" + "hooker" "~0.2.3" + "lodash" "~4.17.19" + +"grunt-legacy-util@~2.0.1": + "integrity" "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==" + "resolved" "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "async" "~3.2.0" + "exit" "~0.1.2" + "getobject" "~1.0.0" + "hooker" "~0.2.3" + "lodash" "~4.17.21" + "underscore.string" "~3.3.5" + "which" "~2.0.2" + +"grunt-sync@0.8.2": + "integrity" "sha512-PB+xKI9YPyZn3NZQXpKHfZVlxHdf1L8GMl+Wi0mLhYypWuOdZPW2EzTmSuhhFbXjkb0aIOxvII1zdZZEl9zqGg==" + "resolved" "https://registry.npmjs.org/grunt-sync/-/grunt-sync-0.8.2.tgz" + "version" "0.8.2" + dependencies: + "fs-extra" "^6.0.1" + "glob" "^7.0.5" + "md5-file" "^2.0.3" + +"grunt@^1.5.3": + "integrity" "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==" + "resolved" "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz" + "version" "1.5.3" + dependencies: + "dateformat" "~3.0.3" + "eventemitter2" "~0.4.13" + "exit" "~0.1.2" + "findup-sync" "~0.3.0" + "glob" "~7.1.6" + "grunt-cli" "~1.4.3" + "grunt-known-options" "~2.0.0" + "grunt-legacy-log" "~3.0.0" + "grunt-legacy-util" "~2.0.1" + "iconv-lite" "~0.4.13" + "js-yaml" "~3.14.0" + "minimatch" "~3.0.4" + "mkdirp" "~1.0.4" + "nopt" "~3.0.6" + "rimraf" "~3.0.2" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"has-symbols@^1.0.3": + "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + "version" "1.0.3" + +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "function-bind" "^1.1.1" + +"homedir-polyfill@^1.0.1": + "integrity" "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==" + "resolved" "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "parse-passwd" "^1.0.0" + +"hooker@~0.2.3": + "integrity" "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==" + "resolved" "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz" + "version" "0.2.3" + +"http-parser-js@>=0.5.1": + "integrity" "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + "resolved" "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" + "version" "0.5.8" + +"iconv-lite@~0.4.13": + "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" + "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + "version" "0.4.24" + dependencies: + "safer-buffer" ">= 2.1.2 < 3" + +"inflight@^1.0.4": + "integrity" "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@2": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"ini@^1.3.4": + "integrity" "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "resolved" "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + "version" "1.3.8" + +"interpret@~1.1.0": + "integrity" "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==" + "resolved" "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz" + "version" "1.1.0" + +"is-absolute@^1.0.0": + "integrity" "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==" + "resolved" "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "is-relative" "^1.0.0" + "is-windows" "^1.0.1" + +"is-core-module@^2.9.0": + "integrity" "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" + "version" "2.11.0" + dependencies: + "has" "^1.0.3" + +"is-extglob@^2.1.1": + "integrity" "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + "version" "2.1.1" + +"is-glob@^4.0.0": + "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" + "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "is-extglob" "^2.1.1" + +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" + +"is-plain-object@^2.0.3", "is-plain-object@^2.0.4": + "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==" + "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + "version" "2.0.4" + dependencies: + "isobject" "^3.0.1" + +"is-relative@^1.0.0": + "integrity" "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==" + "resolved" "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "is-unc-path" "^1.0.0" + +"is-unc-path@^1.0.0": + "integrity" "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==" + "resolved" "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "unc-path-regex" "^0.1.2" + +"is-windows@^1.0.1": + "integrity" "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "resolved" "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" + "version" "1.0.2" + +"isexe@^2.0.0": + "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"isobject@^3.0.0", "isobject@^3.0.1": + "integrity" "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + "version" "3.0.1" + +"js-yaml@~3.14.0": + "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + "version" "3.14.1" + dependencies: + "argparse" "^1.0.7" + "esprima" "^4.0.0" + +"jsonfile@^4.0.0": + "integrity" "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==" + "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" + "version" "4.0.0" + optionalDependencies: + "graceful-fs" "^4.1.6" + +"kind-of@^6.0.2": + "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + "version" "6.0.3" + +"liftup@~3.0.1": + "integrity" "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==" + "resolved" "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "extend" "^3.0.2" + "findup-sync" "^4.0.0" + "fined" "^1.2.0" + "flagged-respawn" "^1.0.1" + "is-plain-object" "^2.0.4" + "object.map" "^1.0.1" + "rechoir" "^0.7.0" + "resolve" "^1.19.0" + +"livereload-js@^2.3.0": + "integrity" "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==" + "resolved" "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz" + "version" "2.4.0" + +"lodash@^4.17.10", "lodash@^4.17.14", "lodash@^4.17.21", "lodash@~4.17.19", "lodash@~4.17.21": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" + +"make-iterator@^1.0.0": + "integrity" "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==" + "resolved" "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "kind-of" "^6.0.2" + +"map-cache@^0.2.0": + "integrity" "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" + "resolved" "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" + "version" "0.2.2" + +"md5-file@^2.0.3": + "integrity" "sha512-kWAICpJv8fIY0Ka/90iOX9nCJ407Fgj82ceWwcxi2HvVkKGHRMS/Y4caqBaju5skNYXiQohGUjwGZ7rVgzUhRw==" + "resolved" "https://registry.npmjs.org/md5-file/-/md5-file-2.0.7.tgz" + "version" "2.0.7" + +"micromatch@^4.0.2": + "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "braces" "^3.0.2" + "picomatch" "^2.3.1" + +"minimatch@^3.0.4", "minimatch@~3.0.2", "minimatch@~3.0.4", "minimatch@2 || 3": + "integrity" "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz" + "version" "3.0.8" + dependencies: + "brace-expansion" "^1.1.7" + +"mkdirp@~1.0.4": + "integrity" "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + "version" "1.0.4" + +"ms@^2.1.1": + "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + "version" "2.1.3" + +"nopt@~3.0.6": + "integrity" "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==" + "resolved" "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" + "version" "3.0.6" + dependencies: + "abbrev" "1" + +"nopt@~4.0.1": + "integrity" "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==" + "resolved" "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "abbrev" "1" + "osenv" "^0.1.4" + +"object-assign@^4.1.0": + "integrity" "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "version" "4.1.1" + +"object-inspect@^1.9.0": + "integrity" "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" + "version" "1.12.2" + +"object.defaults@^1.1.0": + "integrity" "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==" + "resolved" "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "array-each" "^1.0.1" + "array-slice" "^1.0.0" + "for-own" "^1.0.0" + "isobject" "^3.0.0" + +"object.map@^1.0.1": + "integrity" "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==" + "resolved" "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "for-own" "^1.0.0" + "make-iterator" "^1.0.0" + +"object.pick@^1.2.0": + "integrity" "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==" + "resolved" "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" + "version" "1.3.0" + dependencies: + "isobject" "^3.0.1" + +"once@^1.3.0": + "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"os-homedir@^1.0.0": + "integrity" "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==" + "resolved" "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + "version" "1.0.2" + +"os-tmpdir@^1.0.0": + "integrity" "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + "resolved" "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + "version" "1.0.2" + +"osenv@^0.1.4": + "integrity" "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==" + "resolved" "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz" + "version" "0.1.5" + dependencies: + "os-homedir" "^1.0.0" + "os-tmpdir" "^1.0.0" + +"outcome@0.0.x": + "integrity" "sha512-r5lBTvoSOO1a4J/bjCy5wOKs0CUEp4+DlL3WnGLgnpWLzNVF7KIUPlYUETbZ81IQHWmvVDZ8c1913uQW65ePNg==" + "resolved" "https://registry.npmjs.org/outcome/-/outcome-0.0.18.tgz" + "version" "0.0.18" + +"parse-filepath@^1.0.1": + "integrity" "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==" + "resolved" "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "is-absolute" "^1.0.0" + "map-cache" "^0.2.0" + "path-root" "^0.1.1" + +"parse-passwd@^1.0.0": + "integrity" "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==" + "resolved" "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" + "version" "1.0.0" + +"path-is-absolute@^1.0.0": + "integrity" "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-parse@^1.0.7": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" + +"path-root-regex@^0.1.0": + "integrity" "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==" + "resolved" "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz" + "version" "0.1.2" + +"path-root@^0.1.1": + "integrity" "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==" + "resolved" "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz" + "version" "0.1.1" + dependencies: + "path-root-regex" "^0.1.0" + +"picomatch@^2.3.1": + "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + "version" "2.3.1" + +"plugin@^0.3.3": + "integrity" "sha512-iYStLjk2ROAxvOmC5pAuF6Bl+0LI5BGaJLReXNQkJDTuGd0ytohluSf/EE2iFaej2AdV0llOyBW/BWrLRkOqTg==" + "resolved" "https://registry.npmjs.org/plugin/-/plugin-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "async" "0.1.x" + "dref" "0.0.x" + "outcome" "0.0.x" + "resolve" "0.2.x" + "sift" "0.0.x" + "step" "0.0.x" + "structr" "0.2.x" + "toarray" "0.0.x" + "underscore" "1.4.x" + +"qs@^6.4.0": + "integrity" "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==" + "resolved" "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + "version" "6.11.0" + dependencies: + "side-channel" "^1.0.4" + +"raw-body@~1.1.0": + "integrity" "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==" + "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz" + "version" "1.1.7" + dependencies: + "bytes" "1" + "string_decoder" "0.10" + +"rechoir@^0.7.0": + "integrity" "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==" + "resolved" "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz" + "version" "0.7.1" + dependencies: + "resolve" "^1.9.0" + +"resolve-dir@^1.0.0", "resolve-dir@^1.0.1": + "integrity" "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==" + "resolved" "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "expand-tilde" "^2.0.0" + "global-modules" "^1.0.0" + +"resolve@^1.19.0", "resolve@^1.9.0": + "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + "version" "1.22.1" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"resolve@0.2.x": + "integrity" "sha512-/u93d172yGtNlqM9641bKSdPmgaJ/X9TiD/7Mrb3DtrZ/CAvfNEXAdRABvayxLst7GGWMKkD0oGFQvwn0exevg==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-0.2.8.tgz" + "version" "0.2.8" + +"rimraf@~3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "glob" "^7.1.3" + +"safe-buffer@>=5.1.0": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"safe-json-parse@~1.0.1": + "integrity" "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==" + "resolved" "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz" + "version" "1.0.1" + +"safer-buffer@>= 2.1.2 < 3": + "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + "version" "2.1.2" + +"side-channel@^1.0.4": + "integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==" + "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "call-bind" "^1.0.0" + "get-intrinsic" "^1.0.2" + "object-inspect" "^1.9.0" + +"sift@0.0.x": + "integrity" "sha512-AGLWQiwxBbdCWGl9g8oOEAnc/2/VmvEL2ZmiQJXg4rLbNA+Wi8beTJV4pemehLAjiqtNNUyLYCFkNmHNm4E6QQ==" + "resolved" "https://registry.npmjs.org/sift/-/sift-0.0.18.tgz" + "version" "0.0.18" + +"sprintf-js@^1.1.1": + "integrity" "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz" + "version" "1.1.2" + +"sprintf-js@~1.0.2": + "integrity" "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "version" "1.0.3" + +"step@0.0.x": + "integrity" "sha512-qSSeQinUJk2w38vUFobjFoE307GqsozMC8VisOCkJLpklvKPT0ptPHwWOrENoag8rgLudvTkfP3bancwP93/Jw==" + "resolved" "https://registry.npmjs.org/step/-/step-0.0.6.tgz" + "version" "0.0.6" + +"string_decoder@0.10": + "integrity" "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + "version" "0.10.31" + +"string-template@~0.2.1": + "integrity" "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" + "resolved" "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz" + "version" "0.2.1" + +"structr@0.2.x": + "integrity" "sha512-hL77hWtJhhuhDb4od5ywwAnVUlq9Krzk4BCoWhfiPtTEHvqBqRUm6lJ5PQlCrMWyi8Cv4+AXA/Mu6dbeTN/fGA==" + "resolved" "https://registry.npmjs.org/structr/-/structr-0.2.4.tgz" + "version" "0.2.4" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-preserve-symlinks-flag@^1.0.0": + "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + "version" "1.0.0" + +"tiny-lr@^1.1.1": + "integrity" "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==" + "resolved" "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "body" "^5.1.0" + "debug" "^3.1.0" + "faye-websocket" "~0.10.0" + "livereload-js" "^2.3.0" + "object-assign" "^4.1.0" + "qs" "^6.4.0" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "is-number" "^7.0.0" + +"toarray@0.0.x": + "integrity" "sha512-4EEt1cngMyDQvStibtjwHav7mCYf0mLAXYQ3z03zNacXjWjIHN01j1AtjGpEuCKX5sea+ZzyZcDXgjitxOVaww==" + "resolved" "https://registry.npmjs.org/toarray/-/toarray-0.0.1.tgz" + "version" "0.0.1" + +"type-component@0.0.x": + "integrity" "sha512-mDZRBQS2yZkwRQKfjJvQ8UIYJeBNNWCq+HBNstl9N5s9jZ4dkVYXEGkVPsSCEh5Ld4JM1kmrZTzjnrqSAIQ7dw==" + "resolved" "https://registry.npmjs.org/type-component/-/type-component-0.0.1.tgz" + "version" "0.0.1" + +"unc-path-regex@^0.1.2": + "integrity" "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==" + "resolved" "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz" + "version" "0.1.2" + +"underscore.string@~3.3.5": + "integrity" "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==" + "resolved" "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz" + "version" "3.3.6" + dependencies: + "sprintf-js" "^1.1.1" + "util-deprecate" "^1.0.2" + +"underscore@1.4.x": + "integrity" "sha512-ZqGrAgaqqZM7LGRzNjLnw5elevWb5M8LEoDMadxIW3OWbcv72wMMgKdwOKpd5Fqxe8choLD8HN3iSj3TUh/giQ==" + "resolved" "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz" + "version" "1.4.4" + +"universalify@^0.1.0": + "integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + "resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + "version" "0.1.2" + +"util-deprecate@^1.0.2": + "integrity" "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "version" "1.0.2" + +"v8flags@~3.2.0": + "integrity" "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==" + "resolved" "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz" + "version" "3.2.0" + dependencies: + "homedir-polyfill" "^1.0.1" + +"websocket-driver@>=0.5.1": + "integrity" "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==" + "resolved" "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" + "version" "0.7.4" + dependencies: + "http-parser-js" ">=0.5.1" + "safe-buffer" ">=5.1.0" + "websocket-extensions" ">=0.1.1" + +"websocket-extensions@>=0.1.1": + "integrity" "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + "resolved" "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz" + "version" "0.1.4" + +"which@^1.2.14": + "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" + "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "isexe" "^2.0.0" + +"which@~2.0.2": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"wrappy@1": + "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" diff --git a/adyenv6b2ccheckoutaddon/extensioninfo.xsd b/adyenv6b2ccheckoutaddon/extensioninfo.xsd new file mode 100644 index 000000000..7b0f1b274 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/extensioninfo.xsd @@ -0,0 +1,237 @@ + + + + + + + Configures the available modules of the extension. + + + + Configures the available modules of the extension. + + + + + + + + + + Configures the available modules of the extension. + + + + + Configures the set of extensions required by the extension at compile time. If you set 'autoload=true' in the localextensions.xml file, you will not need to reference any core extensions here. + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + + Configures a web module for the extension. Required directory: /web. + + + + + Configures an hMC module for the extension. Required directory: /hmc. + + + + + Configures metadata. + + + + + + + Name of the extension. Do not use special characters or spaces. + + + + + Optionally defines the version of this extension. If not defined the build process assumes it being the same version as the platform. + + + + + Prefix used for generated extension classes, such as the classes for Constants. Default is "[extensionname]". + + + + + Prefix for generated Java classes, such as the abstract classes for getter and setter methods. Default is "Generated". + + + + + Deprecated. Default is "false". + + + + + If 'true' this extension is treated like platform/ext core extensions and is automtically added to all other extension dependencies. + + + + + Class name of the manager class. Default is "[classprefix]Manager" + + + + + Class name of the manager's superclass. Default is de.hybris.platform.jalo.extension.Extension. + + + + + Short description of this extension. Is used by the hybris package manager. + + + + + If 'true' uses maven and external-dependencies.xml file for fetching required libraries into \lib and \web\webroot\WEB-INF\lib. + + + + + If 'true' types introduced by this extension are SLD safe by default and contains no JALO logic. + + + + + + + Configures the set of extensions required by the extension at compile time. + + + + Name of an extension which is required at compile time. + + + + + Allowed range of versions of the required extension. Is used by the hybris package manager. + + + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + Deprecated. Not used anymore. + + + + + Package root where extension and item classes will be generated to. + + + + + Fully qualified Java class name of the extension's manager. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'src' directory is available + + + + + If "true", item and extension classes will be generated. Only needed in case of "sourceavailable=true". Default is "false". + + + + + Deprecated. Will always be evaluated to 'true'. Generated item and extension classes will use java generics and annotations. + + + + + If "true", the generated item and extension classes will use the partOf handler, so partOf references will be removed if the holding item is removed. Default is "true". + + + + + + + Configures an hMC module for the extension. Required directory: /web. + + + + Webroot where the web application will be available at. + + + + + Deprecated. Not used anymore. + + + + + If "true", JSP files will be pre-compiled as part of the build process. If "false", JSP files will be compiled when first used by the application server. Default is "true". + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'web/src' directory is available + + + + + + + Configures an hmc module for the extension. Required directory: /hmc. + + + + Deprecated. Not used anymore. + + + + + Name of the extension's HMCExtension class. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'hmc/src' directory is available + + + + + + + Configures metadata. + + + + Metadata key. + + + + + Metadata value. + + + + + + + A class name including full package name. + + + + + diff --git a/adyenv6b2ccheckoutaddon/project.properties b/adyenv6b2ccheckoutaddon/project.properties new file mode 100644 index 000000000..cfcb6d3c3 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/project.properties @@ -0,0 +1,33 @@ +#Mon, 24 Apr 2023 17:01:32 +0200 +# ----------------------------------------------------------------------- +# [y] hybris Platform +# +# Copyright (c) 2000-2016 hybris AG +# All rights reserved. +# +# This software is the confidential and proprietary information of hybris +# ("Confidential Information"). You shall not disclose such Confidential +# Information and shall use it only in accordance with the terms of the +# license agreement you entered into with hybris. +# +# +# ----------------------------------------------------------------------- + +# you can put key/value pairs here. +# Use Config.getParameter(..) to retrieve the values during runtime. + +adyenv6b2ccheckoutaddon.key=value + +# Specifies the location of the spring context file added automatically to the global platform application context. +adyenv6b2ccheckoutaddon.application-context=adyenv6b2ccheckoutaddon-spring.xml + + + +adyenv6b2ccheckoutaddon.javascript.paths.responsive=/responsive/common/js/adyen.checkout.js;/responsive/common/js/adyen_billingaddress.js;/responsive/common/js/adyen_deliveryaddress.js +adyenv6b2ccheckoutaddon.css.paths.responsive=/responsive/common/css/adyenv6b2ccheckoutaddon.css; + +csrf.allowed.url.patterns=/[^/]+(/[^?]*)+(sop-response)$,/[^/]+(/[^?]*)+(merchant_callback)$,/[^/]+(/[^?]*)+(hop-response)$,/[^/]+(/[^?]*)+(adyen-response)$,/adyen(/[^?]*)+$ + +yacceleratorstorefront.additionalWebSpringConfigs.adyenv6b2ccheckoutaddon=classpath\:/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml + +yacceleratorstorefront.wro4jconfigscan.adyenv6b2ccheckoutaddon=true diff --git a/adyenv6b2ccheckoutaddon/project.properties.template b/adyenv6b2ccheckoutaddon/project.properties.template index 53406445a..df683f847 100644 --- a/adyenv6b2ccheckoutaddon/project.properties.template +++ b/adyenv6b2ccheckoutaddon/project.properties.template @@ -22,7 +22,7 @@ adyenv6b2ccheckoutaddon.application-context=adyenv6b2ccheckoutaddon-spring.xml yacceleratorstorefront.additionalWebSpringConfigs.adyenv6b2ccheckoutaddon=classpath:/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml -adyenv6b2ccheckoutaddon.javascript.paths.responsive=/responsive/common/js/adyen.checkout.js;/responsive/common/js/adyen_billingaddress.js +adyenv6b2ccheckoutaddon.javascript.paths.responsive=/responsive/common/js/adyen.checkout.js;/responsive/common/js/adyen_billingaddress.js;/responsive/common/js/adyen_deliveryaddress.js adyenv6b2ccheckoutaddon.css.paths.responsive=/responsive/common/css/adyenv6b2ccheckoutaddon.css; -csrf.allowed.url.patterns=/[^/]+(/[^?]*)+(sop-response)$,/[^/]+(/[^?]*)+(merchant_callback)$,/[^/]+(/[^?]*)+(hop-response)$,/[^/]+(/[^?]*)+(adyen-response)$,/adyen(/[^?]*)+$ \ No newline at end of file +csrf.allowed.url.patterns=/[^/]+(/[^?]*)+(sop-response)$,/[^/]+(/[^?]*)+(merchant_callback)$,/[^/]+(/[^?]*)+(hop-response)$,/[^/]+(/[^?]*)+(adyen-response)$,/adyen(/[^?]*)+$ diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-testclasses.xml b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-testclasses.xml deleted file mode 100644 index c63e1ac91..000000000 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon-testclasses.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - com.adyen.v6.jalo.Adyenv6b2ccheckoutaddonTest - - \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/adyenv6b2ccheckoutaddon-testclasses.xml b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/adyenv6b2ccheckoutaddon-testclasses.xml new file mode 100644 index 000000000..30a470e06 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/adyenv6b2ccheckoutaddon-testclasses.xml @@ -0,0 +1 @@ +com.adyen.v6.facades.AdyenCheckoutFacadeTest \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-deContentCatalog/cms-content.impex b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-deContentCatalog/cms-content.impex index a3cdad3ae..eb1118d01 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-deContentCatalog/cms-content.impex +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-deContentCatalog/cms-content.impex @@ -1,3 +1,8 @@ $contentCatalog=apparel-deContentCatalog $contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Staged])[default=$contentCatalog:Staged] $jarResourceCms=jar:com.adyen.v6.constants.Adyenv6b2ccheckoutaddonConstants&/adyenv6b2ccheckoutaddon/import/cockpit/cmscockpit +$addonExtensionName=adyenv6b2ccheckoutaddon + +INSERT_UPDATE JspIncludeComponent;$contentCV[unique=true];uid[unique=true];name;page;actions(uid,$contentCV);&componentRef + ;;AccountAddEditAddressComponent;Account Add Edit Address Component;/WEB-INF/views/addons/$addonExtensionName/responsive/pages/account/accountEditAddressPage.jsp;;AccountAddEditAddressComponent + diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-ukContentCatalog/cms-content.impex b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-ukContentCatalog/cms-content.impex index 7171e84a8..eb2f6a9c8 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-ukContentCatalog/cms-content.impex +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/apparel-ukContentCatalog/cms-content.impex @@ -1,3 +1,8 @@ $contentCatalog=apparel-ukContentCatalog $contentCV=catalogVersion(CatalogVersion.catalog(Catalog.id[default=$contentCatalog]),CatalogVersion.version[default=Staged])[default=$contentCatalog:Staged] $jarResourceCms=jar:com.adyen.v6.constants.Adyenv6b2ccheckoutaddonConstants&/adyenv6b2ccheckoutaddon/import/cockpit/cmscockpit +$addonExtensionName=adyenv6b2ccheckoutaddon + +INSERT_UPDATE JspIncludeComponent;$contentCV[unique=true];uid[unique=true];name;page;actions(uid,$contentCV);&componentRef + ;;AccountAddEditAddressComponent;Account Add Edit Address Component;/WEB-INF/views/addons/$addonExtensionName/responsive/pages/account/accountEditAddressPage.jsp;;AccountAddEditAddressComponent + diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/electronicsContentCatalog/cms-content.impex b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/electronicsContentCatalog/cms-content.impex index 0178b1998..f26af0456 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/electronicsContentCatalog/cms-content.impex +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/contentCatalogs/electronicsContentCatalog/cms-content.impex @@ -4,6 +4,9 @@ $jarResourceCms=jar:com.adyen.v6.constants.Adyenv6b2ccheckoutaddonConstants&/ady $addonExtensionName=adyenv6b2ccheckoutaddon +INSERT_UPDATE JspIncludeComponent;$contentCV[unique=true];uid[unique=true];name;page;actions(uid,$contentCV);&componentRef + ;;AccountAddEditAddressComponent;Account Add Edit Address Component;/WEB-INF/views/addons/$addonExtensionName/responsive/pages/account/accountEditAddressPage.jsp;;AccountAddEditAddressComponent + ## Configure page for My Subscriptions / Subscription details / ... INSERT_UPDATE ContentPage;$contentCV[unique=true];uid[unique=true];name;masterTemplate(uid,$contentCV);label;defaultPage[default='true'];approvalStatus(code)[default='approved'];homepage[default='false'] ;;adyenStoredCards;Manage My Stored Cards;AccountPageTemplate;/my-account/stored-cards diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/stores/electronics/store.impex b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/stores/electronics/store.impex index b14b11957..037e8743c 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/stores/electronics/store.impex +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/import/stores/electronics/store.impex @@ -8,7 +8,7 @@ $languages=ja,en,de,zh $defaultLanguage=en $unitedKingdom=GB,GG,IM,JE $europeNotUK=AD,AL,AT,BA,BE,BG,BY,CH,CY,CZ,DE,DK,EE,ES,FI,FO,FR,GI,GL,GR,HR,HU,IE,IS,IT,LI,LT,LU,LV,MC,MD,ME,MK,MT,NL,NO,PL,PT,RO,RS,RU,SE,SI,SK,SM,TR,UA,VA -$asianCountries=CN,JP,VN,HK,KP,KR +$asianCountries=JP,VN,HK,KP,KR $deliveryCountries=$unitedKingdom,$europeNotUK,$asianCountries,US $orderProcessCode=order-process $pickupInStoreMode=BUY_AND_COLLECT @@ -27,4 +27,4 @@ UPDATE BaseStore;uid[unique=true];checkoutFlowGroup #% if: "responsive".equalsIgnoreCase(Config.getParameter("commerceservices.default.desktop.ui.experience")); UPDATE BaseStore;uid[unique=true];checkoutFlowGroup ;$storeUid;$adyenResponsiveCheckoutGroup -#% endif: \ No newline at end of file +#% endif: diff --git a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml index 8a9eb55b0..c0b929266 100644 --- a/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml +++ b/adyenv6b2ccheckoutaddon/resources/adyenv6b2ccheckoutaddon/web/spring/adyenv6b2ccheckoutaddon-web-spring.xml @@ -193,4 +193,13 @@ + + + + + + + + diff --git a/adyenv6b2ccheckoutaddon/resources/items.xsd b/adyenv6b2ccheckoutaddon/resources/items.xsd new file mode 100644 index 000000000..8aa3c6bb9 --- /dev/null +++ b/adyenv6b2ccheckoutaddon/resources/items.xsd @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + Corresponding Java class in the hybris Suite; will also be used as the code of the atomic type. + + + + + If 'true', the AtomicType will be created during initialization. + + + + + Deprecated. Has no effect for atomic types. Default is 'true'. + + + + + Defines the class which will be extended. Default is 'java.lang.Object'. + + + + + + + + Defines a list of atomic types. + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + + + + + A CollectionType defines a collection of typed elements. Attention: If using a collection type for persistent attributes (not jalo) you can not search on that attribute and you are limited in size of collection. Consider to use a relation instead. + + + + The code (that is, qualifier) of the CollectionType. + + + + + The type of elements of this CollectionType. + + + + + If 'true', the CollectionType will be created during initialization. + + + + + Deprecated. Has no effect for collection types. Default is 'true'. + + + + + Configures the type of this collection: 'set', 'list', 'collection'. The getter / setter methods will use corresponding Java collection interfaces. Default is 'collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + + + Defines a list of collection types. + + + + + + A CollectionType defines a collection of typed elements. + + + + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + The mapped database table. Must be globally unique. + + + + + The mapped item type code. Must be globally unique + + + + + The mapped dump property database table to be used for this item. Default is 'props'. + + + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Configures deployment information for this relation (table name and typecode). + + + + + Configures the generated attribute at source relation end + + + + + Configures the generated attribute at target relation end + + + + + + The typecode. + + + + + A localized n-m relation can have a link between two items for each language. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', the item will be created during initialization. + + + + + Deprecated. Will have no effect for relations. + + + + + + + + Defines a list of relation types. + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + + + + Configures the generated attribute at one relation end. + + + + + Documents this relation attribute. Will be cited at javadoc of generated getters/setters. + + + + + Defines properties for the attribute. + + + + + Allows to configure model generation for this relation attribute used at servicelayer. + + + + + Allows to configure custom properties for the relation attribute. + + + + + + Type of attribute which will be generated at type configured for opposite relation end. + + + + + Qualifier of attribute which will be generated at type configured for opposite relation end. If navigable is not set to false the qualifier is mandatory. Default is empty. + + + + + The (meta)type which describes the attributes type. Must be type extending RelationDescriptor. Default is 'RelationDescriptor'. + + + + + The cardinality of this relation end. Choose 'one' for 'one' part of a 1:n relation or 'many' when part of a n:m relation. A 1:1 relation is not supported. Default is 'many'. + + + + + + The element is the 'one' part of a 1:n relation + + + + + The element is part of a n:m relation + + + + + + + + Is the relation navigable from this side. Can only be disabled for one side of many to many relation. If disabled, no qualifier as well as modifiers can be defined. Default is 'true'. + + + + + Configures the type of this collection if element has cardinality 'many'. Related attribute getter / setter will use corresponding java collection interfaces. Default is 'Collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + If 'true' an additional ordering attribute will be generated for maintaining ordering. Default is 'false'. + + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Allows changing enum model settings. + + + + + Configures one value of this Enumeration. + + + + + + The unique code of this Enumeration. + + + + + If 'true', the item will be created during initialization. + + + + + If 'false' no constants will be generated at constant class of extension as well as at corresponding servicelayer enum class. Default is 'true'. + + + + + Specifies the name of the associated jalo class. The specified class must extend de.hybris.platform.jalo.enumeration.EnumerationValue and will not be generated. By specifying a jalo class you can change the implementation to use for the values of this enumeration. By default EnumerationValue class is used. + + + + + Whether it is possible to add new values by runtime. Also results in different types of enums: 'true' results in 'classic' hybris enums, 'false' results in Java enums. Default is false. Both kinds of enums are API compatible, and switching between enum types is possible by running a system update. + + + + + Marks enum as deprecated since specified version. + + + + + + + Defines a list of enumeration types. + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + + + + Configures a database index for enclosing type. + + + + + Configures a single index key. + + + + + Configures a single index include column. + + + + + + The name prefix of the index. + + + + + If 'true' this index will be ommitted while in initialization process even if there were precendent declarations.This attribute has effect only if replace = true. + + + + + If 'true' this index is a replacement/redeclaration for already existing index. + + + + + If 'true', the value of this attribute has to be unique within all instances of this index. Attributes with persistence type set to 'jalo' can not be unique. Default is 'false'. + + + + + Determines index creation mode. + + + + + + Create index on all supported databases (default) + + + + + Force creation on Database which by default prevents index creation by external configuration + + + + + Create index only on SAP Hana database + + + + + Create index only on MySQL database + + + + + Create index only on Oracle database + + + + + Create index only on MSSQL Server database + + + + + Create index only on HSQL database + + + + + Create index only on PostgreSQL database + + + + + + + + + + Configures a single index key. + + + + Type attribute to be indexed. + + + + + Elements will be indexed case-insensitive. Default is 'false'. + + + + + + + Configures a single index include column. + + + + Type attribute to be indexed. + + + + + + + Defines an attribute of a type. + + + + + Configures a default value for this attribute used if no value is provided. The default value is calculated by initialization and will not be re-calculated by runtime. + + + + + Gives a description for this attribute only used for the javadoc of generated attribute methods. + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + Configures advanced settings for this attribute definition. + + + + + Allows to configure custom properties for this attribute. + + + + + Allows to configure model generation settings for this attribute. Models are used by the hybris ServiceLayer. + + + + + + Lets you re-define the attribute definition from an inherited type. In essence, you can use a different type of attribute as well as different modifier combinations than on the supertype. Default is 'false'. + + + + + Qualifier of this attribute. Attribute qualifiers must be unique across a single type. + + + + + The type of the attribute, such as 'Product', 'int' or 'java.lang.String'. Primitive java types will be mapped to the corresponding atomic type. For example: 'int' will be mapped to the atomic type 'java.lang.Integer' with implicit default value. + + + + + Advanced setting. Specifies the metatype for the attributes definition. Must be a type extending AttributeDescriptor. Default is 'AttributeDescriptor'. + + + + + If 'true', the attribute descriptor will be created during initialization. Default is 'true'. + + + + + If 'true', getter and setter methods for this attribute will be generated during a hybris Suite build. Default is 'true'. + + + + + References an attribute of the same type. Only values of the referenced attribute can be selected as values for this attribute. Typical example: the default delivery address of a customer must be one of the addresses set for the customer. Default is 'false'. + + + + + + + Allows to configure model generation for this attribute used at servicelayer. + + + + + + Allows to configure alternative getter methods at generated model. + + + + + + + Allows to configure alternative setter methods at generated model. + + + + + + + Whether getter and setter methods for the model representation of the attribute will be generated. Default is 'true'. + + + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + Allows to configure model constructor signatures. + + + + + + + Whether a model for the type and models for subtypes will be generated. Default is 'true'. + + + + + + + Allows to configure model constructor signatures. + + + + Add here, as comma separated list, the attribute qualifiers for the constructor signature in the model. + + + + + + + Allows to configure alternative methods at generated model. + + + + + + + + Name of the alternative getter method. + + + + + + + Will the method be marked deprecated? Default is + false. + + + + + + + Version since when this method is marked as deprecated. Settting deprecatedSince attribute automatically + sets deprecated attribute to true. + + + + + + Will this method be the default method and replace the original one instead of adding it additional? Default is false. + + + + + + + Defines custom properties. + + + + + Defines a custom property. + + + + + + + + Defines a custom property. + + + + + The value of the custom property. + + + + + + The name of the custom property. + + + + + + + Configures a list of attributes. + + + + + Defines a single attribute. + + + + + + + + Configures a list of indexes. + + + + + Configures a single index. + + + + + + + + Specifies a specific ComposedType. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + + Defines a list of custom properties for this type. + + + + + Defines the list of item attributes. + + + + + Defines the database indexes for this type. + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + The unique code of this type. + + + + + Defines the class, which will be extended. Default is 'GenericItem'. + + + + + Specifies the name of the associated jalo class. Default is [extension-root-package].jalo.[type-code] which will be generated if not existent. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', type gets marked as singleton which will be evaluated by some modules like hmc or impex, with that allowing only one instance per system. Default is 'false'. + + + + + DEPRECATED. Use 'implements JaloOnlyItem' in your bean. If 'true', the item will only exists in the jalo layer and isn't backed by an entity bean. Default is 'false'. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + If 'true', the sourcecode for this item will be created. Default is 'true'. + + + + + Marks type and jalo class as abstract. If 'true', the type can not be instantiated. Default is 'false'. + + + + + The (meta)type which describes the assigned type. Must be a type extensing ComposedType. Default is 'ComposedType'. + + + + + Marks item as deprecated since specified version. + + + + + + + Defines a grouping of item types. + + + + + Specifies a specific ComposedType. + + + + + Specifies a group of ComposedTypes to allow better structuring within the items.xml file. + + + + + + + + + + Specifies a specific ComposedType. + + + + + + Defines the name of this group. Only for structural purpose, will have no effect on runtime. Default is empty. + + + + + + + Defines the types of your extension. + + + + + + Defines the list of AtomicType's for your extension. + + + + + Defines the list of CollectionType's for your extension. + + + + + Defines the list of EnumerationType's for your extension. + + + + + Defines the list of MapType's for your extension. + + + + + Defines the list of RelationType's for your extension. + + + + + Defines the list of ComposedType's for your extension. + + + + + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + The unique code of the map. + + + + + The type of the key attributes. + + + + + The type of the value attributes. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'false'. + + + + + + + Specifies a list of map types. + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + + + + + Specifies further properties of an attribute which can be redeclared at other extensions. + + + + Defines if this attribute is readable (that is, if a getter method will be generated). Default is 'true'. The visibility of the getter depends on the value of the private attribute. + + + + + Defines if this attribute is writable (that is, if a setter method will be generated). Default is 'true'. The visibility of the setter depends on the value of the private attribute. + + + + + Defines if this attribute is searchable by a FlexibleSearch. Default is 'true'. Attributes with persistence type set to 'jalo' can not be searchable. + + + + + Defines if this attribute is mandatory or optional. Default is 'true' for optional. Set to 'false' for mandatory. + + + + + Defines the Java visibility of the generated getter and setter methods for this attribute. If 'true', the visibility modifier of generated methods is set to 'protected'; if 'false', the visibility modifier is 'public'. Default is 'false' for 'public' generated methods. Also, you will have no generated methods in the ServiceLayer if 'true'. + + + + + If 'true', the attribute will only be writable during the item creation. Setting this to 'true' is only useful in combination with write='false'. Default is 'false'. + + + + + Defines if this attribute is removable. Default is 'true'. + + + + + Defines if the assigned attribute value only belongs to the current instance of this type. Default is 'false'. + + + + + If 'true', the value of this attribute has to be unique within all instances of this type. If there are multiple attributes marked as unique, then their combined values must be unique. Will not be evaluated at jalo layer, if you want to manage the attribute directly using jalo layer you have to ensure uniqueness manually. Default is 'false'. + + + + + If 'true' the attribute value will be stored in the 'global' property table, otherwise a separate column (inside the table of the associated type)will be created for storing its values. Default is 'false'. + + + + + If 'true', the attribute value will be stored in an encrypted way. Default is 'false'. + + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent), and 'property' (persistent). + + + + + Configures a persistence definition for a specific database used at create statement. + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + + Attribte will be stored persistent. + + + + + Attribte will be stored non-persistent (deprecated, please use dynamic instead). + + + + + Deprecated. + + + + + Defines that attribute dynamic. + + + + + + + + Deprecated. Only usable in relation with 'cmp' and 'property'(compatibility reasons) persistence type. Default is empty. + + + + + Spring bean id that handles dynamic attributes implementation. + + + + + + + Configures a persistence definition for a specific database. + + + + + The attribute type used in the create statement of the database table, such as 'varchar2(4000)'. + + + + + + + + + The database the given definition will be used for. One of 'oracle', 'mysql', 'sqlserver' or 'hsql'. Default is empty which configures fallback for non specified databases. + + + + + + + Defines a default value text. + + + + + + + Configures a single element. + + + + The unique code of this element. + + + + + + + Configures a single enum model pojo. + + + + Defines the package for the actual enum model pojo. + + + + + + + Configures a single enum value. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + + The unique code of this element. + + + + + + + Configures the code of an enumeration value element. Must start with a letter or underscore. + + + + + + + + + Configures the code of an element. + + + + + + + Deprecated. Defines a reference to a deployment definition. + + + + + + + Configures the class to use for enclosing element. + + + + diff --git a/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_en.properties b/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_en.properties index 106a4aa96..885d2794e 100644 --- a/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_en.properties +++ b/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_en.properties @@ -15,3 +15,15 @@ # type...description=XY # # yourcustomlocalekey=value + +address.line2BR = House number or name +address.line2BR.invalid = Please, enter a house number or name +address.postcodeBR.invalid = Please, the postcode has to contains 8 digits +address.phoneIN.invalid = Please introduce a correct phone number, the phone number is invalid +address.postcodeBR.invalid.addressForm.postcode = Please, the postcode has to contain 8 digits +address.phoneIN.invalid.addressForm.phone = Please introduce a correct phone number, the phone number is invalid +customersupport_backoffice_addressForm.phone1=Phone Number + +checkout.error.authorization.failed = There was an internal technical error, please choose any other payment method to place your order. If the error persist, please contact us. +checkout.error.cart.notcalculated = There was an internal technical error, please choose any other payment method to place your order. If the error persist, please contact us. +checkout.error.tax.missing = There was an internal technical error, please choose any other payment method to place your order. If the error persist, please contact us. diff --git a/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_pt.properties b/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_pt.properties index 2491ada56..1d1f404f8 100644 --- a/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_pt.properties +++ b/adyenv6b2ccheckoutaddon/resources/localization/adyenv6b2ccheckoutaddon-locales_pt.properties @@ -16,3 +16,9 @@ # # yourcustomlocalekey=value +address.line2BR = Número ou nome da casa +address.line2BR.invalid = Please, enter a house number or name +address.postcodeBR.invalid = Please, the postcode has to contains 8 digits +address.postcodeBR.invalid.addressForm.postcode = Please, the postcode has to contains 8 digits +address.phoneIN.invalid.addressForm.phone = Please introduce a correct phone number, the phone number is invalid +customersupport_backoffice_addressForm.phone1=Phone Number \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/ruleset.xml b/adyenv6b2ccheckoutaddon/ruleset.xml deleted file mode 100644 index 4aaf67b2f..000000000 --- a/adyenv6b2ccheckoutaddon/ruleset.xml +++ /dev/null @@ -1,767 +0,0 @@ - - - - - - Java PMD ruleset for hybris - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6b2ccheckoutaddon/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java b/adyenv6b2ccheckoutaddon/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java index 223ff352b..0c2a025be 100644 --- a/adyenv6b2ccheckoutaddon/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java +++ b/adyenv6b2ccheckoutaddon/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java @@ -24,11 +24,15 @@ import com.adyen.model.checkout.CheckoutPaymentsAction; import com.adyen.model.checkout.PaymentsDetailsResponse; import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.converters.PaymentsDetailsResponseConverter; import com.adyen.v6.converters.PaymentsResponseConverter; import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; +import com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.model.RequestInfo; import com.adyen.v6.repository.OrderRepository; +import com.adyen.v6.service.AdyenBusinessProcessService; import com.adyen.v6.service.AdyenOrderService; import com.adyen.v6.service.AdyenTransactionService; import com.adyen.v6.service.DefaultAdyenPaymentService; @@ -46,10 +50,15 @@ import de.hybris.platform.core.model.order.OrderModel; import de.hybris.platform.core.model.order.payment.PaymentInfoModel; import de.hybris.platform.core.model.user.CustomerModel; +import de.hybris.platform.order.CalculationService; +import de.hybris.platform.order.CartFactory; import de.hybris.platform.order.CartService; import de.hybris.platform.order.InvalidCartException; +import de.hybris.platform.order.exceptions.CalculationException; +import de.hybris.platform.servicelayer.dto.converter.Converter; import de.hybris.platform.servicelayer.i18n.CommonI18NService; import de.hybris.platform.servicelayer.keygenerator.KeyGenerator; +import de.hybris.platform.servicelayer.model.ModelService; import de.hybris.platform.servicelayer.session.SessionService; import de.hybris.platform.store.BaseStoreModel; import de.hybris.platform.store.services.BaseStoreService; @@ -58,6 +67,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import javax.servlet.http.HttpServletRequest; @@ -67,65 +77,67 @@ import java.util.Map; import static com.adyen.constants.ApiConstants.Redirect.Data.MD; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_CC; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.SESSION_LOCKED_CART; +import static com.adyen.v6.constants.Adyenv6coreConstants.*; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.SESSION_LOCKED_CART; +import static com.adyen.v6.model.RequestInfo.ACCEPT_HEADER; +import static com.adyen.v6.model.RequestInfo.USER_AGENT_HEADER; import static de.hybris.platform.order.impl.DefaultCartService.SESSION_CART_PARAMETER_NAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @UnitTest @RunWith(MockitoJUnitRunner.class) public class AdyenCheckoutFacadeTest { + public static final String CODE = "code"; + + @Spy + @InjectMocks + private DefaultAdyenCheckoutFacade adyenCheckoutFacade; + @Mock private BaseStoreService baseStoreServiceMock; - @Mock private SessionService sessionServiceMock; - @Mock private CartService cartServiceMock; - @Mock private OrderFacade orderFacadeMock; - @Mock private CheckoutFacade checkoutFacadeMock; - @Mock private DefaultAdyenPaymentService adyenPaymentServiceMock; - @Mock private AdyenTransactionService adyenTransactionServiceMock; - @Mock private OrderRepository orderRepositoryMock; - @Mock private AdyenOrderService adyenOrderServiceMock; - @Mock private CheckoutCustomerStrategy checkoutCustomerStrategyMock; - @Mock private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock; - @Mock private CommonI18NService commonI18NServiceMock; - @Mock private KeyGenerator keyGeneratorMock; + @Mock + private PaymentsDetailsResponseConverter paymentsDetailsResponseConverterMock; + @Mock + private ModelService modelServiceMock; + @Mock + private AdyenBusinessProcessService adyenBusinessProcessServiceMock; + @Mock + private Converter orderConverterMock; + @Mock + private CartFactory cartFactoryMock; + @Mock + private CalculationService calculationServiceMock; - @InjectMocks - private DefaultAdyenCheckoutFacade adyenCheckoutFacade; - + @Mock + private OrderModel orderModelMock; private CartModel cartModelMock; private PaymentResult paymentResultMock; @@ -135,7 +147,7 @@ public class AdyenCheckoutFacadeTest { private PaymentsResponse paymentsResponse; @Before - public void setUp() throws SignatureException, InvalidCartException { + public void setUp() throws SignatureException, InvalidCartException, CalculationException { BaseStoreModel baseStoreModelMock = mock(BaseStoreModel.class); cartModelMock = mock(CartModel.class); OrderData orderDataMock = mock(OrderData.class); @@ -144,16 +156,20 @@ public void setUp() throws SignatureException, InvalidCartException { paymentsDetailsResponseMock = mock(PaymentsDetailsResponse.class); CartData cartDataMock = mock(CartData.class); + doNothing().when(calculationServiceMock).calculate(cartModelMock); + + doReturn(orderDataMock).when(orderConverterMock).convert(orderModelMock); when(baseStoreModelMock.getAdyenMerchantAccount()).thenReturn("merchantAccount"); when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); - when(cartModelMock.getCode()).thenReturn("code"); + when(cartModelMock.getCode()).thenReturn(CODE); when(cartServiceMock.getSessionCart()).thenReturn(cartModelMock); + when(cartFactoryMock.createCart()).thenReturn(cartModelMock); - when(orderDataMock.getCode()).thenReturn("code"); + when(orderDataMock.getCode()).thenReturn(CODE); when(checkoutFacadeMock.placeOrder()).thenReturn(orderDataMock); - when(cartDataMock.getCode()).thenReturn("code"); + when(cartDataMock.getCode()).thenReturn(CODE); when(checkoutFacadeMock.getCheckoutCart()).thenReturn(cartDataMock); when(paymentResultMock.getPspReference()).thenReturn("pspRef"); @@ -175,6 +191,8 @@ public void setUp() throws SignatureException, InvalidCartException { when(commonI18NServiceMock.getCurrentLanguage()).thenReturn(languageModel); when(keyGeneratorMock.generate()).thenReturn(new Object()); adyenCheckoutFacade.setPaymentsResponseConverter(new PaymentsResponseConverter()); + adyenCheckoutFacade.setPaymentsDetailsResponseConverter(paymentsDetailsResponseConverterMock); + adyenCheckoutFacade.setOrderConverter(orderConverterMock); } @Test @@ -214,8 +232,13 @@ public void testAuthorizeCardPayment() throws Exception { when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(true); when(checkoutCustomerStrategyMock.getCurrentUserForCheckout()).thenReturn(null); when(adyenPaymentServiceMock.authorisePayment(any(CartData.class), any(RequestInfo.class), any(CustomerModel.class))).thenReturn(paymentsResponse); - when(orderRepositoryMock.getOrderModel("code")).thenReturn(orderModelMock); + when(orderRepositoryMock.getOrderModel(CODE)).thenReturn(orderModelMock); when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_CC); + when(requestMock.getHeader(USER_AGENT_HEADER)).thenReturn("userAgent"); + when(requestMock.getHeader(ACCEPT_HEADER)).thenReturn("acceptHeader"); + when(requestMock.getRemoteAddr()).thenReturn("addr"); + when(requestMock.getRequestURI()).thenReturn("uri"); + when(requestMock.getRequestURL()).thenReturn(new StringBuffer("url")); adyenCheckoutFacade.authorisePayment(requestMock, cartDataMock); @@ -232,11 +255,6 @@ public void testAuthorizeCardPayment() throws Exception { assertEquals(paymentsResponse, e.getPaymentsResponse()); } - //Lock the cart - verify(sessionServiceMock).setAttribute(SESSION_LOCKED_CART, cartModelMock); - verify(sessionServiceMock).removeAttribute(SESSION_CART_PARAMETER_NAME); - - //When payment is refused paymentsResponse.setResultCode(PaymentsResponse.ResultCodeEnum.REFUSED); @@ -252,42 +270,35 @@ public void testAuthorizeCardPayment() throws Exception { @Test public void testHandle3DResponse() throws Exception { Map detailsMap = mock(Map.class); - OrderModel orderModelMock = mock(OrderModel.class); PaymentInfoModel paymentInfoModelMock = mock(PaymentInfoModel.class); //When payment is authorized when(paymentResultMock.isAuthorised()).thenReturn(true); when(sessionServiceMock.getAttribute(SESSION_LOCKED_CART)).thenReturn(cartModelMock); - when(adyenPaymentServiceMock.authorise3DSPayment(anyMap())).thenReturn(paymentsDetailsResponseMock); - when(orderRepositoryMock.getOrderModel("code")).thenReturn(orderModelMock); - - //When payment is authorized + when(adyenPaymentServiceMock.authorise3DSPayment(detailsMap)).thenReturn(paymentsDetailsResponseMock); + when(orderRepositoryMock.getOrderModel(CODE)).thenReturn(orderModelMock); when(paymentsResponseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); - + when(paymentsDetailsResponseMock.getMerchantReference()).thenReturn(CODE); + when(paymentsDetailsResponseConverterMock.convert(paymentsDetailsResponseMock)).thenReturn(paymentsResponseMock); + when(paymentsDetailsResponseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); when(cartModelMock.getPaymentInfo()).thenReturn(paymentInfoModelMock); when(paymentInfoModelMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_ONECLICK); + doNothing().when(adyenBusinessProcessServiceMock).triggerOrderProcessEvent(orderModelMock, Adyenv6coreConstants.PROCESS_EVENT_ADYEN_PAYMENT_RESULT); + when(checkoutCustomerStrategyMock.isAnonymousCheckout()).thenReturn(true); adyenCheckoutFacade.handle3DSResponse(detailsMap); - //the order should be created - verifyAuthorized(orderModelMock); + verify(adyenPaymentServiceMock).authorise3DSPayment(detailsMap); //When is not authorized - when(paymentsResponseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.REFUSED); + when(paymentsDetailsResponseMock.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.REFUSED); try { adyenCheckoutFacade.handle3DSResponse(detailsMap); fail("Expecting exception"); } catch (AdyenNonAuthorizedPaymentException e) { //throw exception with getPaymentsResponse details - assertEquals(paymentsResponseMock, e.getPaymentsResponse()); - } - - try { - adyenCheckoutFacade.handle3DSResponse(detailsMap); - //throw SignatureException - fail("Expecting exception"); - } catch (SignatureException ignored) { + assertEquals(paymentsDetailsResponseMock, e.getPaymentsDetailsResponse()); } } @@ -302,7 +313,7 @@ private CartData createCartData() { deliveryAddress.setCountry(new CountryData()); cartData.setTotalPrice(priceData); - cartData.setCode("code"); + cartData.setCode(CODE); cartData.setDeliveryAddress(deliveryAddress); return cartData; @@ -310,7 +321,7 @@ private CartData createCartData() { private void verifyAuthorized(OrderModel orderModelMock) throws InvalidCartException { //authorized transactions should be stored - verify(adyenTransactionServiceMock).authorizeOrderModel(cartModelMock, "code", "pspRef"); + verify(adyenTransactionServiceMock).authorizeOrderModel(cartModelMock, CODE, "pspRef"); //order should be created verify(checkoutFacadeMock).placeOrder(); //update of order metadata should happen diff --git a/adyenv6backoffice/.classpath b/adyenv6backoffice/.classpath deleted file mode 100644 index 05324295d..000000000 --- a/adyenv6backoffice/.classpath +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6backoffice/.project b/adyenv6backoffice/.project deleted file mode 100644 index ce6317a52..000000000 --- a/adyenv6backoffice/.project +++ /dev/null @@ -1,39 +0,0 @@ - - - adyenv6backoffice - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full, - - - LaunchConfigHandle - <project>/.externalToolBuilders/HybrisCodeGeneration.launch - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.springframework.ide.eclipse.core.springbuilder - - - - - net.sourceforge.pmd.eclipse.plugin.pmdBuilder - - - - - - org.springframework.ide.eclipse.core.springnature - org.eclipse.jdt.core.javanature - net.sourceforge.pmd.eclipse.plugin.pmdNature - - diff --git a/adyenv6backoffice/backoffice/resources/cancelorderaction/definition.xml b/adyenv6backoffice/backoffice/resources/cancelorderaction/definition.xml new file mode 100644 index 000000000..1aa4d4f5c --- /dev/null +++ b/adyenv6backoffice/backoffice/resources/cancelorderaction/definition.xml @@ -0,0 +1,29 @@ + + + + + cancelorder.action + Cancel Order Action + hybris + 0.1 + + com.adyen.v6.backoffice.widgets.actions.cancel.AdyenCancelOrderAction + de.hybris.platform.core.model.order.OrderModel + de.hybris.platform.core.model.order.OrderModel + + icons/icon_action_cancel_default.png + icons/icon_action_cancel_disabled.png + icons/icon_action_cancel_hover.png + + + + + + + + + + diff --git a/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_default.png b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_default.png new file mode 100644 index 000000000..de417d1d9 Binary files /dev/null and b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_default.png differ diff --git a/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_disabled.png b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_disabled.png new file mode 100644 index 000000000..ed7d35786 Binary files /dev/null and b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_disabled.png differ diff --git a/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_hover.png b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_hover.png new file mode 100644 index 000000000..1e4f41da6 Binary files /dev/null and b/adyenv6backoffice/backoffice/resources/cancelorderaction/icons/icon_action_cancel_hover.png differ diff --git a/adyenv6backoffice/backoffice/resources/cancelorderaction/labels/labels_en.properties b/adyenv6backoffice/backoffice/resources/cancelorderaction/labels/labels_en.properties new file mode 100644 index 000000000..57e67d2c7 --- /dev/null +++ b/adyenv6backoffice/backoffice/resources/cancelorderaction/labels/labels_en.properties @@ -0,0 +1,12 @@ +# ----------------------------------------------------------------------- +# [y] hybris Platform +# +# Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved. +# +# This software is the confidential and proprietary information of SAP +# ("Confidential Information"). You shall not disclose such Confidential +# Information and shall use it only in accordance with the terms of the +# license agreement you entered into with SAP. +# ----------------------------------------------------------------------- + +actionName=Cancel diff --git a/adyenv6backoffice/backoffice/src/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderAction.java b/adyenv6backoffice/backoffice/src/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderAction.java new file mode 100644 index 000000000..c1cdce5a3 --- /dev/null +++ b/adyenv6backoffice/backoffice/src/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderAction.java @@ -0,0 +1,27 @@ +package com.adyen.v6.backoffice.widgets.actions.cancel; + +import com.hybris.cockpitng.actions.ActionContext; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.omsbackoffice.actions.order.cancel.CancelOrderAction; +import org.apache.commons.collections.CollectionUtils; + +/** + * Adyen extension of the customersupportbackoffice CancelOrderAction + *

+ * Not allowing partial order or order entry cancellations as not supported + * by Adyen + */ +public class AdyenCancelOrderAction extends CancelOrderAction { + + /** + * {@inheritDoc} + */ + @Override + public boolean canPerform(final ActionContext actionContext) { + OrderModel order = actionContext.getData(); + return order != null && CollectionUtils.isNotEmpty(order.getEntries()) && + CollectionUtils.isNotEmpty(order.getPaymentTransactions()) && order.getPaymentTransactions().size() == 1 && + getOrderCancelService().isCancelPossible(order, getUserService().getCurrentUser(), false, false).isAllowed() && + !getNotCancellableOrderStatus().contains(order.getStatus()); + } +} diff --git a/adyenv6backoffice/backoffice/testsrc/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderActionTest.java b/adyenv6backoffice/backoffice/testsrc/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderActionTest.java new file mode 100644 index 000000000..52aef1547 --- /dev/null +++ b/adyenv6backoffice/backoffice/testsrc/com/adyen/v6/backoffice/widgets/actions/cancel/AdyenCancelOrderActionTest.java @@ -0,0 +1,102 @@ +package com.adyen.v6.backoffice.widgets.actions.cancel; + +import com.hybris.cockpitng.actions.ActionContext; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.core.enums.OrderStatus; +import de.hybris.platform.core.model.order.AbstractOrderEntryModel; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.user.UserModel; +import de.hybris.platform.ordercancel.CancelDecision; +import de.hybris.platform.ordercancel.OrderCancelService; +import de.hybris.platform.payment.model.PaymentTransactionModel; +import de.hybris.platform.servicelayer.user.UserService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenCancelOrderActionTest { + + @Mock + private ActionContext actionContextMock; + @Mock + private OrderModel orderModelMock; + @Mock + private AbstractOrderEntryModel orderEntryMock; + @Mock + private OrderCancelService orderCancelServiceMock; + @Mock + private UserService userServiceMock; + @Mock + private UserModel userMock; + @Mock + private PaymentTransactionModel paymentTransactionModelMock; + @Mock + private CancelDecision cancelDecisionMock; + private List notCancellableOrderStatus = Arrays.asList(OrderStatus.PAYMENT_NOT_VOIDED, OrderStatus.TAX_NOT_VOIDED); + + @InjectMocks + private AdyenCancelOrderAction testObj = new AdyenCancelOrderAction() { + @Override + protected List getNotCancellableOrderStatus() { + return notCancellableOrderStatus; + } + }; + + @Before + public void setUp() { + when(actionContextMock.getData()).thenReturn(orderModelMock); + when(orderModelMock.getEntries()).thenReturn(singletonList(orderEntryMock)); + when(userServiceMock.getCurrentUser()).thenReturn(userMock); + when(orderModelMock.getStatus()).thenReturn(OrderStatus.CREATED); + when(orderCancelServiceMock.isCancelPossible(orderModelMock, userMock, false, false)).thenReturn(cancelDecisionMock); + when(cancelDecisionMock.isAllowed()).thenReturn(true); + when(orderModelMock.getPaymentTransactions()).thenReturn(singletonList(paymentTransactionModelMock)); + } + + @Test + public void canPerform_WhenOrderNull_ShouldReturnFalse() { + when(actionContextMock.getData()).thenReturn(null); + + assertFalse(testObj.canPerform(actionContextMock)); + } + + @Test + public void canPerform_WhenNoEntries_ShouldReturnFalse() { + when(orderModelMock.getEntries()).thenReturn(emptyList()); + + assertFalse(testObj.canPerform(actionContextMock)); + } + + @Test + public void canPerform_WhenCancelNotPossible_ShouldReturnFalse() { + when(cancelDecisionMock.isAllowed()).thenReturn(false); + + assertFalse(testObj.canPerform(actionContextMock)); + } + + @Test + public void canPerform_WhenOrderStatusNotSatisfied_ShouldReturnFalse() { + when(orderModelMock.getStatus()).thenReturn(OrderStatus.PAYMENT_NOT_VOIDED); + + assertFalse(testObj.canPerform(actionContextMock)); + } + + @Test + public void canPerform_WhenAllChecksAreTrue_ShouldReturnTrue() { + assertTrue(testObj.canPerform(actionContextMock)); + } +} diff --git a/adyenv6backoffice/buildcallbacks.xml b/adyenv6backoffice/buildcallbacks.xml index 3ce49e393..088243d92 100644 --- a/adyenv6backoffice/buildcallbacks.xml +++ b/adyenv6backoffice/buildcallbacks.xml @@ -101,6 +101,14 @@ + + + + + + + + diff --git a/adyenv6backoffice/extensioninfo.xml b/adyenv6backoffice/extensioninfo.xml index 31a2b0d13..24ba6bb33 100644 --- a/adyenv6backoffice/extensioninfo.xml +++ b/adyenv6backoffice/extensioninfo.xml @@ -17,6 +17,9 @@ + + + diff --git a/adyenv6backoffice/extensioninfo.xsd b/adyenv6backoffice/extensioninfo.xsd new file mode 100644 index 000000000..7b0f1b274 --- /dev/null +++ b/adyenv6backoffice/extensioninfo.xsd @@ -0,0 +1,237 @@ + + + + + + + Configures the available modules of the extension. + + + + Configures the available modules of the extension. + + + + + + + + + + Configures the available modules of the extension. + + + + + Configures the set of extensions required by the extension at compile time. If you set 'autoload=true' in the localextensions.xml file, you will not need to reference any core extensions here. + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + + Configures a web module for the extension. Required directory: /web. + + + + + Configures an hMC module for the extension. Required directory: /hmc. + + + + + Configures metadata. + + + + + + + Name of the extension. Do not use special characters or spaces. + + + + + Optionally defines the version of this extension. If not defined the build process assumes it being the same version as the platform. + + + + + Prefix used for generated extension classes, such as the classes for Constants. Default is "[extensionname]". + + + + + Prefix for generated Java classes, such as the abstract classes for getter and setter methods. Default is "Generated". + + + + + Deprecated. Default is "false". + + + + + If 'true' this extension is treated like platform/ext core extensions and is automtically added to all other extension dependencies. + + + + + Class name of the manager class. Default is "[classprefix]Manager" + + + + + Class name of the manager's superclass. Default is de.hybris.platform.jalo.extension.Extension. + + + + + Short description of this extension. Is used by the hybris package manager. + + + + + If 'true' uses maven and external-dependencies.xml file for fetching required libraries into \lib and \web\webroot\WEB-INF\lib. + + + + + If 'true' types introduced by this extension are SLD safe by default and contains no JALO logic. + + + + + + + Configures the set of extensions required by the extension at compile time. + + + + Name of an extension which is required at compile time. + + + + + Allowed range of versions of the required extension. Is used by the hybris package manager. + + + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + Deprecated. Not used anymore. + + + + + Package root where extension and item classes will be generated to. + + + + + Fully qualified Java class name of the extension's manager. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'src' directory is available + + + + + If "true", item and extension classes will be generated. Only needed in case of "sourceavailable=true". Default is "false". + + + + + Deprecated. Will always be evaluated to 'true'. Generated item and extension classes will use java generics and annotations. + + + + + If "true", the generated item and extension classes will use the partOf handler, so partOf references will be removed if the holding item is removed. Default is "true". + + + + + + + Configures an hMC module for the extension. Required directory: /web. + + + + Webroot where the web application will be available at. + + + + + Deprecated. Not used anymore. + + + + + If "true", JSP files will be pre-compiled as part of the build process. If "false", JSP files will be compiled when first used by the application server. Default is "true". + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'web/src' directory is available + + + + + + + Configures an hmc module for the extension. Required directory: /hmc. + + + + Deprecated. Not used anymore. + + + + + Name of the extension's HMCExtension class. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'hmc/src' directory is available + + + + + + + Configures metadata. + + + + Metadata key. + + + + + Metadata value. + + + + + + + A class name including full package name. + + + + + diff --git a/adyenv6backoffice/resources/adyenv6backoffice-backoffice-config.xml b/adyenv6backoffice/resources/adyenv6backoffice-backoffice-config.xml index b79b87743..8841406ed 100644 --- a/adyenv6backoffice/resources/adyenv6backoffice-backoffice-config.xml +++ b/adyenv6backoffice/resources/adyenv6backoffice-backoffice-config.xml @@ -18,6 +18,19 @@ + + + + + actiongroup.common + + + + + + @@ -28,6 +41,7 @@ + @@ -38,6 +52,11 @@ + + + + + diff --git a/adyenv6backoffice/resources/adyenv6backoffice-backoffice-widgets.xml b/adyenv6backoffice/resources/adyenv6backoffice-backoffice-widgets.xml new file mode 100644 index 000000000..0341fba71 --- /dev/null +++ b/adyenv6backoffice/resources/adyenv6backoffice-backoffice-widgets.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-testclasses.xml b/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-testclasses.xml new file mode 100644 index 000000000..aefa884bd --- /dev/null +++ b/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-testclasses.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-webtestclasses.xml b/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-webtestclasses.xml new file mode 100644 index 000000000..08d5e7ede --- /dev/null +++ b/adyenv6backoffice/resources/adyenv6backoffice/adyenv6backoffice-webtestclasses.xml @@ -0,0 +1 @@ +com.adyen.v6.backoffice.widgets.actions.cancel.AdyenCancelOrderActionTest \ No newline at end of file diff --git a/adyenv6backoffice/resources/backoffice/adyenv6backoffice_bof.jar b/adyenv6backoffice/resources/backoffice/adyenv6backoffice_bof.jar new file mode 100644 index 000000000..264467e18 Binary files /dev/null and b/adyenv6backoffice/resources/backoffice/adyenv6backoffice_bof.jar differ diff --git a/adyenv6backoffice/resources/beans.xsd b/adyenv6backoffice/resources/beans.xsd new file mode 100644 index 000000000..8c08411ae --- /dev/null +++ b/adyenv6backoffice/resources/beans.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the type of bean. Allowed are 'bean' or 'event'. + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Marks property as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + \ No newline at end of file diff --git a/adyenv6backoffice/resources/cockpitng/cng/css/adyenv6backoffice_common.scss b/adyenv6backoffice/resources/cockpitng/cng/css/adyenv6backoffice_common.scss new file mode 100644 index 000000000..b943cdaa6 --- /dev/null +++ b/adyenv6backoffice/resources/cockpitng/cng/css/adyenv6backoffice_common.scss @@ -0,0 +1,24 @@ +@import "customersupportbackoffice_common.scss"; + +.y-toolbar-leftslot .cng-action-group{ + .ya-com_adyen_v6_backoffice_widgets_actions_adyencancelorderaction{ + padding: 2px 10px; + tr { + vertical-align: middle; + } + } +} + +.y-toolbar-leftslot .cng-action-group { + .ya-com_adyen_v6_backoffice_widgets_actions_adyencancelorderaction{ + &:hover { + background: $white; + color: $warehousing-action-buttons--color; + transition: background-color 0.3s ease 0s; + } + &.cng-action-disabled:hover { + color: inherit; + background: none; + } + } +} diff --git a/adyenv6backoffice/resources/items.xsd b/adyenv6backoffice/resources/items.xsd new file mode 100644 index 000000000..8aa3c6bb9 --- /dev/null +++ b/adyenv6backoffice/resources/items.xsd @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + Corresponding Java class in the hybris Suite; will also be used as the code of the atomic type. + + + + + If 'true', the AtomicType will be created during initialization. + + + + + Deprecated. Has no effect for atomic types. Default is 'true'. + + + + + Defines the class which will be extended. Default is 'java.lang.Object'. + + + + + + + + Defines a list of atomic types. + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + + + + + A CollectionType defines a collection of typed elements. Attention: If using a collection type for persistent attributes (not jalo) you can not search on that attribute and you are limited in size of collection. Consider to use a relation instead. + + + + The code (that is, qualifier) of the CollectionType. + + + + + The type of elements of this CollectionType. + + + + + If 'true', the CollectionType will be created during initialization. + + + + + Deprecated. Has no effect for collection types. Default is 'true'. + + + + + Configures the type of this collection: 'set', 'list', 'collection'. The getter / setter methods will use corresponding Java collection interfaces. Default is 'collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + + + Defines a list of collection types. + + + + + + A CollectionType defines a collection of typed elements. + + + + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + The mapped database table. Must be globally unique. + + + + + The mapped item type code. Must be globally unique + + + + + The mapped dump property database table to be used for this item. Default is 'props'. + + + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Configures deployment information for this relation (table name and typecode). + + + + + Configures the generated attribute at source relation end + + + + + Configures the generated attribute at target relation end + + + + + + The typecode. + + + + + A localized n-m relation can have a link between two items for each language. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', the item will be created during initialization. + + + + + Deprecated. Will have no effect for relations. + + + + + + + + Defines a list of relation types. + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + + + + Configures the generated attribute at one relation end. + + + + + Documents this relation attribute. Will be cited at javadoc of generated getters/setters. + + + + + Defines properties for the attribute. + + + + + Allows to configure model generation for this relation attribute used at servicelayer. + + + + + Allows to configure custom properties for the relation attribute. + + + + + + Type of attribute which will be generated at type configured for opposite relation end. + + + + + Qualifier of attribute which will be generated at type configured for opposite relation end. If navigable is not set to false the qualifier is mandatory. Default is empty. + + + + + The (meta)type which describes the attributes type. Must be type extending RelationDescriptor. Default is 'RelationDescriptor'. + + + + + The cardinality of this relation end. Choose 'one' for 'one' part of a 1:n relation or 'many' when part of a n:m relation. A 1:1 relation is not supported. Default is 'many'. + + + + + + The element is the 'one' part of a 1:n relation + + + + + The element is part of a n:m relation + + + + + + + + Is the relation navigable from this side. Can only be disabled for one side of many to many relation. If disabled, no qualifier as well as modifiers can be defined. Default is 'true'. + + + + + Configures the type of this collection if element has cardinality 'many'. Related attribute getter / setter will use corresponding java collection interfaces. Default is 'Collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + If 'true' an additional ordering attribute will be generated for maintaining ordering. Default is 'false'. + + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Allows changing enum model settings. + + + + + Configures one value of this Enumeration. + + + + + + The unique code of this Enumeration. + + + + + If 'true', the item will be created during initialization. + + + + + If 'false' no constants will be generated at constant class of extension as well as at corresponding servicelayer enum class. Default is 'true'. + + + + + Specifies the name of the associated jalo class. The specified class must extend de.hybris.platform.jalo.enumeration.EnumerationValue and will not be generated. By specifying a jalo class you can change the implementation to use for the values of this enumeration. By default EnumerationValue class is used. + + + + + Whether it is possible to add new values by runtime. Also results in different types of enums: 'true' results in 'classic' hybris enums, 'false' results in Java enums. Default is false. Both kinds of enums are API compatible, and switching between enum types is possible by running a system update. + + + + + Marks enum as deprecated since specified version. + + + + + + + Defines a list of enumeration types. + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + + + + Configures a database index for enclosing type. + + + + + Configures a single index key. + + + + + Configures a single index include column. + + + + + + The name prefix of the index. + + + + + If 'true' this index will be ommitted while in initialization process even if there were precendent declarations.This attribute has effect only if replace = true. + + + + + If 'true' this index is a replacement/redeclaration for already existing index. + + + + + If 'true', the value of this attribute has to be unique within all instances of this index. Attributes with persistence type set to 'jalo' can not be unique. Default is 'false'. + + + + + Determines index creation mode. + + + + + + Create index on all supported databases (default) + + + + + Force creation on Database which by default prevents index creation by external configuration + + + + + Create index only on SAP Hana database + + + + + Create index only on MySQL database + + + + + Create index only on Oracle database + + + + + Create index only on MSSQL Server database + + + + + Create index only on HSQL database + + + + + Create index only on PostgreSQL database + + + + + + + + + + Configures a single index key. + + + + Type attribute to be indexed. + + + + + Elements will be indexed case-insensitive. Default is 'false'. + + + + + + + Configures a single index include column. + + + + Type attribute to be indexed. + + + + + + + Defines an attribute of a type. + + + + + Configures a default value for this attribute used if no value is provided. The default value is calculated by initialization and will not be re-calculated by runtime. + + + + + Gives a description for this attribute only used for the javadoc of generated attribute methods. + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + Configures advanced settings for this attribute definition. + + + + + Allows to configure custom properties for this attribute. + + + + + Allows to configure model generation settings for this attribute. Models are used by the hybris ServiceLayer. + + + + + + Lets you re-define the attribute definition from an inherited type. In essence, you can use a different type of attribute as well as different modifier combinations than on the supertype. Default is 'false'. + + + + + Qualifier of this attribute. Attribute qualifiers must be unique across a single type. + + + + + The type of the attribute, such as 'Product', 'int' or 'java.lang.String'. Primitive java types will be mapped to the corresponding atomic type. For example: 'int' will be mapped to the atomic type 'java.lang.Integer' with implicit default value. + + + + + Advanced setting. Specifies the metatype for the attributes definition. Must be a type extending AttributeDescriptor. Default is 'AttributeDescriptor'. + + + + + If 'true', the attribute descriptor will be created during initialization. Default is 'true'. + + + + + If 'true', getter and setter methods for this attribute will be generated during a hybris Suite build. Default is 'true'. + + + + + References an attribute of the same type. Only values of the referenced attribute can be selected as values for this attribute. Typical example: the default delivery address of a customer must be one of the addresses set for the customer. Default is 'false'. + + + + + + + Allows to configure model generation for this attribute used at servicelayer. + + + + + + Allows to configure alternative getter methods at generated model. + + + + + + + Allows to configure alternative setter methods at generated model. + + + + + + + Whether getter and setter methods for the model representation of the attribute will be generated. Default is 'true'. + + + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + Allows to configure model constructor signatures. + + + + + + + Whether a model for the type and models for subtypes will be generated. Default is 'true'. + + + + + + + Allows to configure model constructor signatures. + + + + Add here, as comma separated list, the attribute qualifiers for the constructor signature in the model. + + + + + + + Allows to configure alternative methods at generated model. + + + + + + + + Name of the alternative getter method. + + + + + + + Will the method be marked deprecated? Default is + false. + + + + + + + Version since when this method is marked as deprecated. Settting deprecatedSince attribute automatically + sets deprecated attribute to true. + + + + + + Will this method be the default method and replace the original one instead of adding it additional? Default is false. + + + + + + + Defines custom properties. + + + + + Defines a custom property. + + + + + + + + Defines a custom property. + + + + + The value of the custom property. + + + + + + The name of the custom property. + + + + + + + Configures a list of attributes. + + + + + Defines a single attribute. + + + + + + + + Configures a list of indexes. + + + + + Configures a single index. + + + + + + + + Specifies a specific ComposedType. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + + Defines a list of custom properties for this type. + + + + + Defines the list of item attributes. + + + + + Defines the database indexes for this type. + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + The unique code of this type. + + + + + Defines the class, which will be extended. Default is 'GenericItem'. + + + + + Specifies the name of the associated jalo class. Default is [extension-root-package].jalo.[type-code] which will be generated if not existent. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', type gets marked as singleton which will be evaluated by some modules like hmc or impex, with that allowing only one instance per system. Default is 'false'. + + + + + DEPRECATED. Use 'implements JaloOnlyItem' in your bean. If 'true', the item will only exists in the jalo layer and isn't backed by an entity bean. Default is 'false'. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + If 'true', the sourcecode for this item will be created. Default is 'true'. + + + + + Marks type and jalo class as abstract. If 'true', the type can not be instantiated. Default is 'false'. + + + + + The (meta)type which describes the assigned type. Must be a type extensing ComposedType. Default is 'ComposedType'. + + + + + Marks item as deprecated since specified version. + + + + + + + Defines a grouping of item types. + + + + + Specifies a specific ComposedType. + + + + + Specifies a group of ComposedTypes to allow better structuring within the items.xml file. + + + + + + + + + + Specifies a specific ComposedType. + + + + + + Defines the name of this group. Only for structural purpose, will have no effect on runtime. Default is empty. + + + + + + + Defines the types of your extension. + + + + + + Defines the list of AtomicType's for your extension. + + + + + Defines the list of CollectionType's for your extension. + + + + + Defines the list of EnumerationType's for your extension. + + + + + Defines the list of MapType's for your extension. + + + + + Defines the list of RelationType's for your extension. + + + + + Defines the list of ComposedType's for your extension. + + + + + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + The unique code of the map. + + + + + The type of the key attributes. + + + + + The type of the value attributes. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'false'. + + + + + + + Specifies a list of map types. + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + + + + + Specifies further properties of an attribute which can be redeclared at other extensions. + + + + Defines if this attribute is readable (that is, if a getter method will be generated). Default is 'true'. The visibility of the getter depends on the value of the private attribute. + + + + + Defines if this attribute is writable (that is, if a setter method will be generated). Default is 'true'. The visibility of the setter depends on the value of the private attribute. + + + + + Defines if this attribute is searchable by a FlexibleSearch. Default is 'true'. Attributes with persistence type set to 'jalo' can not be searchable. + + + + + Defines if this attribute is mandatory or optional. Default is 'true' for optional. Set to 'false' for mandatory. + + + + + Defines the Java visibility of the generated getter and setter methods for this attribute. If 'true', the visibility modifier of generated methods is set to 'protected'; if 'false', the visibility modifier is 'public'. Default is 'false' for 'public' generated methods. Also, you will have no generated methods in the ServiceLayer if 'true'. + + + + + If 'true', the attribute will only be writable during the item creation. Setting this to 'true' is only useful in combination with write='false'. Default is 'false'. + + + + + Defines if this attribute is removable. Default is 'true'. + + + + + Defines if the assigned attribute value only belongs to the current instance of this type. Default is 'false'. + + + + + If 'true', the value of this attribute has to be unique within all instances of this type. If there are multiple attributes marked as unique, then their combined values must be unique. Will not be evaluated at jalo layer, if you want to manage the attribute directly using jalo layer you have to ensure uniqueness manually. Default is 'false'. + + + + + If 'true' the attribute value will be stored in the 'global' property table, otherwise a separate column (inside the table of the associated type)will be created for storing its values. Default is 'false'. + + + + + If 'true', the attribute value will be stored in an encrypted way. Default is 'false'. + + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent), and 'property' (persistent). + + + + + Configures a persistence definition for a specific database used at create statement. + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + + Attribte will be stored persistent. + + + + + Attribte will be stored non-persistent (deprecated, please use dynamic instead). + + + + + Deprecated. + + + + + Defines that attribute dynamic. + + + + + + + + Deprecated. Only usable in relation with 'cmp' and 'property'(compatibility reasons) persistence type. Default is empty. + + + + + Spring bean id that handles dynamic attributes implementation. + + + + + + + Configures a persistence definition for a specific database. + + + + + The attribute type used in the create statement of the database table, such as 'varchar2(4000)'. + + + + + + + + + The database the given definition will be used for. One of 'oracle', 'mysql', 'sqlserver' or 'hsql'. Default is empty which configures fallback for non specified databases. + + + + + + + Defines a default value text. + + + + + + + Configures a single element. + + + + The unique code of this element. + + + + + + + Configures a single enum model pojo. + + + + Defines the package for the actual enum model pojo. + + + + + + + Configures a single enum value. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + + The unique code of this element. + + + + + + + Configures the code of an enumeration value element. Must start with a letter or underscore. + + + + + + + + + Configures the code of an element. + + + + + + + Deprecated. Defines a reference to a deployment definition. + + + + + + + Configures the class to use for enclosing element. + + + + diff --git a/adyenv6backoffice/ruleset.xml b/adyenv6backoffice/ruleset.xml deleted file mode 100644 index 73c9d8bfb..000000000 --- a/adyenv6backoffice/ruleset.xml +++ /dev/null @@ -1,755 +0,0 @@ - - - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - Java PMD ruleset for hybris - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6core/.classpath b/adyenv6core/.classpath deleted file mode 100644 index 212c22abf..000000000 --- a/adyenv6core/.classpath +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6core/.project b/adyenv6core/.project deleted file mode 100644 index 2e3113bf0..000000000 --- a/adyenv6core/.project +++ /dev/null @@ -1,39 +0,0 @@ - - - adyenv6core - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full, - - - LaunchConfigHandle - <project>/.externalToolBuilders/HybrisCodeGeneration.launch - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.springframework.ide.eclipse.core.springbuilder - - - - - net.sourceforge.pmd.eclipse.plugin.pmdBuilder - - - - - - org.springframework.ide.eclipse.core.springnature - org.eclipse.jdt.core.javanature - net.sourceforge.pmd.eclipse.plugin.pmdNature - - diff --git a/adyenv6core/extensioninfo.xml b/adyenv6core/extensioninfo.xml index b2d2e7d88..957a1bdb3 100644 --- a/adyenv6core/extensioninfo.xml +++ b/adyenv6core/extensioninfo.xml @@ -11,13 +11,17 @@ ~ terms of the license agreement you entered into with SAP Hybris. --> - + + + + + diff --git a/adyenv6core/extensioninfo.xsd b/adyenv6core/extensioninfo.xsd new file mode 100644 index 000000000..7b0f1b274 --- /dev/null +++ b/adyenv6core/extensioninfo.xsd @@ -0,0 +1,237 @@ + + + + + + + Configures the available modules of the extension. + + + + Configures the available modules of the extension. + + + + + + + + + + Configures the available modules of the extension. + + + + + Configures the set of extensions required by the extension at compile time. If you set 'autoload=true' in the localextensions.xml file, you will not need to reference any core extensions here. + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + + Configures a web module for the extension. Required directory: /web. + + + + + Configures an hMC module for the extension. Required directory: /hmc. + + + + + Configures metadata. + + + + + + + Name of the extension. Do not use special characters or spaces. + + + + + Optionally defines the version of this extension. If not defined the build process assumes it being the same version as the platform. + + + + + Prefix used for generated extension classes, such as the classes for Constants. Default is "[extensionname]". + + + + + Prefix for generated Java classes, such as the abstract classes for getter and setter methods. Default is "Generated". + + + + + Deprecated. Default is "false". + + + + + If 'true' this extension is treated like platform/ext core extensions and is automtically added to all other extension dependencies. + + + + + Class name of the manager class. Default is "[classprefix]Manager" + + + + + Class name of the manager's superclass. Default is de.hybris.platform.jalo.extension.Extension. + + + + + Short description of this extension. Is used by the hybris package manager. + + + + + If 'true' uses maven and external-dependencies.xml file for fetching required libraries into \lib and \web\webroot\WEB-INF\lib. + + + + + If 'true' types introduced by this extension are SLD safe by default and contains no JALO logic. + + + + + + + Configures the set of extensions required by the extension at compile time. + + + + Name of an extension which is required at compile time. + + + + + Allowed range of versions of the required extension. Is used by the hybris package manager. + + + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + Deprecated. Not used anymore. + + + + + Package root where extension and item classes will be generated to. + + + + + Fully qualified Java class name of the extension's manager. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'src' directory is available + + + + + If "true", item and extension classes will be generated. Only needed in case of "sourceavailable=true". Default is "false". + + + + + Deprecated. Will always be evaluated to 'true'. Generated item and extension classes will use java generics and annotations. + + + + + If "true", the generated item and extension classes will use the partOf handler, so partOf references will be removed if the holding item is removed. Default is "true". + + + + + + + Configures an hMC module for the extension. Required directory: /web. + + + + Webroot where the web application will be available at. + + + + + Deprecated. Not used anymore. + + + + + If "true", JSP files will be pre-compiled as part of the build process. If "false", JSP files will be compiled when first used by the application server. Default is "true". + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'web/src' directory is available + + + + + + + Configures an hmc module for the extension. Required directory: /hmc. + + + + Deprecated. Not used anymore. + + + + + Name of the extension's HMCExtension class. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'hmc/src' directory is available + + + + + + + Configures metadata. + + + + Metadata key. + + + + + Metadata value. + + + + + + + A class name including full package name. + + + + + diff --git a/adyenv6core/external-dependencies.xml b/adyenv6core/external-dependencies.xml index 85b528ad4..58664d0f7 100644 --- a/adyenv6core/external-dependencies.xml +++ b/adyenv6core/external-dependencies.xml @@ -9,5 +9,40 @@ jar + + org.apache.httpcomponents.client5 + httpclient5 + 5.1.3 + + + org.apache.httpcomponents.core5 + httpcore5 + 5.1.3 + + + com.adyen + adyen-java-api-library + 18.1.3 + + + com.google.code.gson + gson + 2.8.0 + + + javax.xml.crypto + jsr105-api + 1.0.1 + + + software.amazon.pay + amazon-pay-api-sdk-java + 2.5.1 + + + org.json + json + 20220924 + - \ No newline at end of file + diff --git a/adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/dummy.txt b/adyenv6core/lib/.lastupdate similarity index 100% rename from adyenv6b2ccheckoutaddon/acceleratoraddon/web/src/com/adyen/v6/controllers/pages/dummy.txt rename to adyenv6core/lib/.lastupdate diff --git a/adyenv6core/lib/adyen-java-api-library-14.0.0.jar b/adyenv6core/lib/adyen-java-api-library-14.0.0.jar deleted file mode 100644 index db2602465..000000000 Binary files a/adyenv6core/lib/adyen-java-api-library-14.0.0.jar and /dev/null differ diff --git a/adyenv6core/resources/adyenv6core-beans.xml b/adyenv6core/resources/adyenv6core-beans.xml index b963c0d22..e8bd4c82c 100644 --- a/adyenv6core/resources/adyenv6core-beans.xml +++ b/adyenv6core/resources/adyenv6core-beans.xml @@ -26,6 +26,7 @@ + @@ -84,6 +85,11 @@ + + + + + diff --git a/adyenv6core/resources/adyenv6core-items.xml b/adyenv6core/resources/adyenv6core-items.xml index 32ee270aa..82a02ab2d 100644 --- a/adyenv6core/resources/adyenv6core-items.xml +++ b/adyenv6core/resources/adyenv6core-items.xml @@ -49,6 +49,21 @@ + + + + + + + + + + + + + + + @@ -284,6 +299,26 @@ + + Region + + + + + AmazonPay API public key + + + + + AmazonPay API Environment + + + + + AmazonPay API Region + + + @@ -298,6 +333,10 @@ Issuer identifier (e.g. iDeal bank) + + virtualAddress filled on UPI APM(India) + + AVS check result code diff --git a/adyenv6core/resources/adyenv6core-spring.xml b/adyenv6core/resources/adyenv6core-spring.xml index 1aa32c1ac..ec5181421 100644 --- a/adyenv6core/resources/adyenv6core-spring.xml +++ b/adyenv6core/resources/adyenv6core-spring.xml @@ -13,8 +13,11 @@ + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the type of bean. Allowed are 'bean' or 'event'. + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Marks property as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + \ No newline at end of file diff --git a/adyenv6core/resources/certificates/amazonpay/DummyCertificate.pem b/adyenv6core/resources/certificates/amazonpay/DummyCertificate.pem new file mode 100644 index 000000000..5add45978 --- /dev/null +++ b/adyenv6core/resources/certificates/amazonpay/DummyCertificate.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +This is a Dummy Certificate Private Key +-----END PRIVATE KEY----- diff --git a/adyenv6core/resources/items.xsd b/adyenv6core/resources/items.xsd new file mode 100644 index 000000000..8aa3c6bb9 --- /dev/null +++ b/adyenv6core/resources/items.xsd @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + Corresponding Java class in the hybris Suite; will also be used as the code of the atomic type. + + + + + If 'true', the AtomicType will be created during initialization. + + + + + Deprecated. Has no effect for atomic types. Default is 'true'. + + + + + Defines the class which will be extended. Default is 'java.lang.Object'. + + + + + + + + Defines a list of atomic types. + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + + + + + A CollectionType defines a collection of typed elements. Attention: If using a collection type for persistent attributes (not jalo) you can not search on that attribute and you are limited in size of collection. Consider to use a relation instead. + + + + The code (that is, qualifier) of the CollectionType. + + + + + The type of elements of this CollectionType. + + + + + If 'true', the CollectionType will be created during initialization. + + + + + Deprecated. Has no effect for collection types. Default is 'true'. + + + + + Configures the type of this collection: 'set', 'list', 'collection'. The getter / setter methods will use corresponding Java collection interfaces. Default is 'collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + + + Defines a list of collection types. + + + + + + A CollectionType defines a collection of typed elements. + + + + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + The mapped database table. Must be globally unique. + + + + + The mapped item type code. Must be globally unique + + + + + The mapped dump property database table to be used for this item. Default is 'props'. + + + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Configures deployment information for this relation (table name and typecode). + + + + + Configures the generated attribute at source relation end + + + + + Configures the generated attribute at target relation end + + + + + + The typecode. + + + + + A localized n-m relation can have a link between two items for each language. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', the item will be created during initialization. + + + + + Deprecated. Will have no effect for relations. + + + + + + + + Defines a list of relation types. + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + + + + Configures the generated attribute at one relation end. + + + + + Documents this relation attribute. Will be cited at javadoc of generated getters/setters. + + + + + Defines properties for the attribute. + + + + + Allows to configure model generation for this relation attribute used at servicelayer. + + + + + Allows to configure custom properties for the relation attribute. + + + + + + Type of attribute which will be generated at type configured for opposite relation end. + + + + + Qualifier of attribute which will be generated at type configured for opposite relation end. If navigable is not set to false the qualifier is mandatory. Default is empty. + + + + + The (meta)type which describes the attributes type. Must be type extending RelationDescriptor. Default is 'RelationDescriptor'. + + + + + The cardinality of this relation end. Choose 'one' for 'one' part of a 1:n relation or 'many' when part of a n:m relation. A 1:1 relation is not supported. Default is 'many'. + + + + + + The element is the 'one' part of a 1:n relation + + + + + The element is part of a n:m relation + + + + + + + + Is the relation navigable from this side. Can only be disabled for one side of many to many relation. If disabled, no qualifier as well as modifiers can be defined. Default is 'true'. + + + + + Configures the type of this collection if element has cardinality 'many'. Related attribute getter / setter will use corresponding java collection interfaces. Default is 'Collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + If 'true' an additional ordering attribute will be generated for maintaining ordering. Default is 'false'. + + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Allows changing enum model settings. + + + + + Configures one value of this Enumeration. + + + + + + The unique code of this Enumeration. + + + + + If 'true', the item will be created during initialization. + + + + + If 'false' no constants will be generated at constant class of extension as well as at corresponding servicelayer enum class. Default is 'true'. + + + + + Specifies the name of the associated jalo class. The specified class must extend de.hybris.platform.jalo.enumeration.EnumerationValue and will not be generated. By specifying a jalo class you can change the implementation to use for the values of this enumeration. By default EnumerationValue class is used. + + + + + Whether it is possible to add new values by runtime. Also results in different types of enums: 'true' results in 'classic' hybris enums, 'false' results in Java enums. Default is false. Both kinds of enums are API compatible, and switching between enum types is possible by running a system update. + + + + + Marks enum as deprecated since specified version. + + + + + + + Defines a list of enumeration types. + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + + + + Configures a database index for enclosing type. + + + + + Configures a single index key. + + + + + Configures a single index include column. + + + + + + The name prefix of the index. + + + + + If 'true' this index will be ommitted while in initialization process even if there were precendent declarations.This attribute has effect only if replace = true. + + + + + If 'true' this index is a replacement/redeclaration for already existing index. + + + + + If 'true', the value of this attribute has to be unique within all instances of this index. Attributes with persistence type set to 'jalo' can not be unique. Default is 'false'. + + + + + Determines index creation mode. + + + + + + Create index on all supported databases (default) + + + + + Force creation on Database which by default prevents index creation by external configuration + + + + + Create index only on SAP Hana database + + + + + Create index only on MySQL database + + + + + Create index only on Oracle database + + + + + Create index only on MSSQL Server database + + + + + Create index only on HSQL database + + + + + Create index only on PostgreSQL database + + + + + + + + + + Configures a single index key. + + + + Type attribute to be indexed. + + + + + Elements will be indexed case-insensitive. Default is 'false'. + + + + + + + Configures a single index include column. + + + + Type attribute to be indexed. + + + + + + + Defines an attribute of a type. + + + + + Configures a default value for this attribute used if no value is provided. The default value is calculated by initialization and will not be re-calculated by runtime. + + + + + Gives a description for this attribute only used for the javadoc of generated attribute methods. + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + Configures advanced settings for this attribute definition. + + + + + Allows to configure custom properties for this attribute. + + + + + Allows to configure model generation settings for this attribute. Models are used by the hybris ServiceLayer. + + + + + + Lets you re-define the attribute definition from an inherited type. In essence, you can use a different type of attribute as well as different modifier combinations than on the supertype. Default is 'false'. + + + + + Qualifier of this attribute. Attribute qualifiers must be unique across a single type. + + + + + The type of the attribute, such as 'Product', 'int' or 'java.lang.String'. Primitive java types will be mapped to the corresponding atomic type. For example: 'int' will be mapped to the atomic type 'java.lang.Integer' with implicit default value. + + + + + Advanced setting. Specifies the metatype for the attributes definition. Must be a type extending AttributeDescriptor. Default is 'AttributeDescriptor'. + + + + + If 'true', the attribute descriptor will be created during initialization. Default is 'true'. + + + + + If 'true', getter and setter methods for this attribute will be generated during a hybris Suite build. Default is 'true'. + + + + + References an attribute of the same type. Only values of the referenced attribute can be selected as values for this attribute. Typical example: the default delivery address of a customer must be one of the addresses set for the customer. Default is 'false'. + + + + + + + Allows to configure model generation for this attribute used at servicelayer. + + + + + + Allows to configure alternative getter methods at generated model. + + + + + + + Allows to configure alternative setter methods at generated model. + + + + + + + Whether getter and setter methods for the model representation of the attribute will be generated. Default is 'true'. + + + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + Allows to configure model constructor signatures. + + + + + + + Whether a model for the type and models for subtypes will be generated. Default is 'true'. + + + + + + + Allows to configure model constructor signatures. + + + + Add here, as comma separated list, the attribute qualifiers for the constructor signature in the model. + + + + + + + Allows to configure alternative methods at generated model. + + + + + + + + Name of the alternative getter method. + + + + + + + Will the method be marked deprecated? Default is + false. + + + + + + + Version since when this method is marked as deprecated. Settting deprecatedSince attribute automatically + sets deprecated attribute to true. + + + + + + Will this method be the default method and replace the original one instead of adding it additional? Default is false. + + + + + + + Defines custom properties. + + + + + Defines a custom property. + + + + + + + + Defines a custom property. + + + + + The value of the custom property. + + + + + + The name of the custom property. + + + + + + + Configures a list of attributes. + + + + + Defines a single attribute. + + + + + + + + Configures a list of indexes. + + + + + Configures a single index. + + + + + + + + Specifies a specific ComposedType. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + + Defines a list of custom properties for this type. + + + + + Defines the list of item attributes. + + + + + Defines the database indexes for this type. + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + The unique code of this type. + + + + + Defines the class, which will be extended. Default is 'GenericItem'. + + + + + Specifies the name of the associated jalo class. Default is [extension-root-package].jalo.[type-code] which will be generated if not existent. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', type gets marked as singleton which will be evaluated by some modules like hmc or impex, with that allowing only one instance per system. Default is 'false'. + + + + + DEPRECATED. Use 'implements JaloOnlyItem' in your bean. If 'true', the item will only exists in the jalo layer and isn't backed by an entity bean. Default is 'false'. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + If 'true', the sourcecode for this item will be created. Default is 'true'. + + + + + Marks type and jalo class as abstract. If 'true', the type can not be instantiated. Default is 'false'. + + + + + The (meta)type which describes the assigned type. Must be a type extensing ComposedType. Default is 'ComposedType'. + + + + + Marks item as deprecated since specified version. + + + + + + + Defines a grouping of item types. + + + + + Specifies a specific ComposedType. + + + + + Specifies a group of ComposedTypes to allow better structuring within the items.xml file. + + + + + + + + + + Specifies a specific ComposedType. + + + + + + Defines the name of this group. Only for structural purpose, will have no effect on runtime. Default is empty. + + + + + + + Defines the types of your extension. + + + + + + Defines the list of AtomicType's for your extension. + + + + + Defines the list of CollectionType's for your extension. + + + + + Defines the list of EnumerationType's for your extension. + + + + + Defines the list of MapType's for your extension. + + + + + Defines the list of RelationType's for your extension. + + + + + Defines the list of ComposedType's for your extension. + + + + + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + The unique code of the map. + + + + + The type of the key attributes. + + + + + The type of the value attributes. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'false'. + + + + + + + Specifies a list of map types. + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + + + + + Specifies further properties of an attribute which can be redeclared at other extensions. + + + + Defines if this attribute is readable (that is, if a getter method will be generated). Default is 'true'. The visibility of the getter depends on the value of the private attribute. + + + + + Defines if this attribute is writable (that is, if a setter method will be generated). Default is 'true'. The visibility of the setter depends on the value of the private attribute. + + + + + Defines if this attribute is searchable by a FlexibleSearch. Default is 'true'. Attributes with persistence type set to 'jalo' can not be searchable. + + + + + Defines if this attribute is mandatory or optional. Default is 'true' for optional. Set to 'false' for mandatory. + + + + + Defines the Java visibility of the generated getter and setter methods for this attribute. If 'true', the visibility modifier of generated methods is set to 'protected'; if 'false', the visibility modifier is 'public'. Default is 'false' for 'public' generated methods. Also, you will have no generated methods in the ServiceLayer if 'true'. + + + + + If 'true', the attribute will only be writable during the item creation. Setting this to 'true' is only useful in combination with write='false'. Default is 'false'. + + + + + Defines if this attribute is removable. Default is 'true'. + + + + + Defines if the assigned attribute value only belongs to the current instance of this type. Default is 'false'. + + + + + If 'true', the value of this attribute has to be unique within all instances of this type. If there are multiple attributes marked as unique, then their combined values must be unique. Will not be evaluated at jalo layer, if you want to manage the attribute directly using jalo layer you have to ensure uniqueness manually. Default is 'false'. + + + + + If 'true' the attribute value will be stored in the 'global' property table, otherwise a separate column (inside the table of the associated type)will be created for storing its values. Default is 'false'. + + + + + If 'true', the attribute value will be stored in an encrypted way. Default is 'false'. + + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent), and 'property' (persistent). + + + + + Configures a persistence definition for a specific database used at create statement. + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + + Attribte will be stored persistent. + + + + + Attribte will be stored non-persistent (deprecated, please use dynamic instead). + + + + + Deprecated. + + + + + Defines that attribute dynamic. + + + + + + + + Deprecated. Only usable in relation with 'cmp' and 'property'(compatibility reasons) persistence type. Default is empty. + + + + + Spring bean id that handles dynamic attributes implementation. + + + + + + + Configures a persistence definition for a specific database. + + + + + The attribute type used in the create statement of the database table, such as 'varchar2(4000)'. + + + + + + + + + The database the given definition will be used for. One of 'oracle', 'mysql', 'sqlserver' or 'hsql'. Default is empty which configures fallback for non specified databases. + + + + + + + Defines a default value text. + + + + + + + Configures a single element. + + + + The unique code of this element. + + + + + + + Configures a single enum model pojo. + + + + Defines the package for the actual enum model pojo. + + + + + + + Configures a single enum value. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + + The unique code of this element. + + + + + + + Configures the code of an enumeration value element. Must start with a letter or underscore. + + + + + + + + + Configures the code of an element. + + + + + + + Deprecated. Defines a reference to a deployment definition. + + + + + + + Configures the class to use for enclosing element. + + + + diff --git a/adyenv6core/resources/localization/adyenv6core-locales_en.properties b/adyenv6core/resources/localization/adyenv6core-locales_en.properties index 42ff88364..19ca5bab2 100644 --- a/adyenv6core/resources/localization/adyenv6core-locales_en.properties +++ b/adyenv6core/resources/localization/adyenv6core-locales_en.properties @@ -50,6 +50,14 @@ type.basestore.adyenPosStoreId.description=POS store ID field is optional type.basestore.adyenPosRecurringContractMode.name=POS Recurring contract type type.basestore.adyenPaypalMerchantId.name=PayPal Merchant Id type.basestore.adyenPaypalMerchantId.description=PayPal Merchant Id, required for Live mode +type.basestore.adyenRegion.name=Region +type.basestore.adyenRegion.description=Region where is located the datacenter +type.basestore.amazonpayPublicKey.name=Amazon Public Key +type.basestore.amazonpayPublicKey.description=The public key generated on the Amazon Seller Dashboard +type.basestore.amazonpayEnvironment.name=AmazonPay Environment +type.basestore.amazonpayEnvironment.description=When testing use Sandbox,on production Live value would be used +type.basestore.amazonpayRegion.name=AmazonPay Region +type.basestore.amazonpayRegion.description=The region of the Amazon Seller shop type.paymentinfo.adyenPaymentMethod.name=Payment Method type.paymentinfo.adyenIssuerId.name=Issuer ID @@ -107,3 +115,15 @@ type.AdyenCardTypeEnum.cup.name=China Union Pay type.AdyenCardTypeEnum.cartebancaire.name=Carte Bancaire type.OrderStatus.PAYMENT_PENDING.name=Payment Pending + +type.AdyenRegions.EU.name=EU +type.AdyenRegions.AU.name=AU +type.AdyenRegions.US.name=US +type.AdyenRegions.IN.name=IN + +type.AmazonpayEnvironment.SANBOX.name=SANDBOX +type.AmazonpayEnvironment.LIVE.name=LIVE + +type.AmazonpayRegion.EU.name=EU +type.AmazonpayRegion.NA.name=NA +type.AmazonpayRegion.JP.name=JP diff --git a/adyenv6core/ruleset.xml b/adyenv6core/ruleset.xml deleted file mode 100644 index 73c9d8bfb..000000000 --- a/adyenv6core/ruleset.xml +++ /dev/null @@ -1,755 +0,0 @@ - - - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - Java PMD ruleset for hybris - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckAuthorizationAction.java b/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckAuthorizationAction.java index c98fb6b90..5e564df92 100644 --- a/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckAuthorizationAction.java +++ b/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckAuthorizationAction.java @@ -21,6 +21,8 @@ package com.adyen.v6.actions.order; import com.adyen.v6.actions.AbstractWaitableAction; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; +import com.adyen.v6.service.AdyenPaymentService; import de.hybris.platform.core.enums.OrderStatus; import de.hybris.platform.core.model.order.OrderModel; import de.hybris.platform.core.model.order.payment.PaymentInfoModel; @@ -29,6 +31,7 @@ import de.hybris.platform.payment.enums.PaymentTransactionType; import de.hybris.platform.payment.model.PaymentTransactionEntryModel; import de.hybris.platform.payment.model.PaymentTransactionModel; +import de.hybris.platform.store.services.BaseStoreService; import org.apache.log4j.Logger; import java.math.BigDecimal; @@ -39,6 +42,16 @@ public class AdyenCheckAuthorizationAction extends AbstractWaitableAction { private static final Logger LOG = Logger.getLogger(AdyenCheckAuthorizationAction.class); + private final AdyenPaymentServiceFactory adyenPaymentServiceFactory; + private final BaseStoreService baseStoreService; + + public AdyenCheckAuthorizationAction(final AdyenPaymentServiceFactory adyenPaymentServiceFactory, + final BaseStoreService baseStoreService) { + this.adyenPaymentServiceFactory = adyenPaymentServiceFactory; + this.baseStoreService = baseStoreService; + } + + @Override public String execute(final OrderProcessModel process) { LOG.debug("Process: " + process.getCode() + " in step " + getClass().getSimpleName()); @@ -79,7 +92,7 @@ private String processOrderAuthorization(final OrderProcessModel process, final return Transition.WAIT.toString(); } - BigDecimal remainingAmount = BigDecimal.valueOf(order.getTotalPrice()); + BigDecimal remainingAmount = getAdyenPaymentService(order).calculateAmountWithTaxes(order); for (final PaymentTransactionModel paymentTransactionModel : order.getPaymentTransactions()) { if (!isTransactionAuthorized(paymentTransactionModel)) { //A single not authorized transaction means not authorized @@ -110,4 +123,8 @@ private String processOrderAuthorization(final OrderProcessModel process, final return Transition.OK.toString(); } + + public AdyenPaymentService getAdyenPaymentService(final OrderModel orderModel) { + return adyenPaymentServiceFactory.createFromBaseStore(orderModel.getStore()); + } } diff --git a/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckCaptureAction.java b/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckCaptureAction.java index 08039d2c2..f155d46fa 100644 --- a/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckCaptureAction.java +++ b/adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckCaptureAction.java @@ -21,6 +21,8 @@ package com.adyen.v6.actions.order; import com.adyen.v6.actions.AbstractWaitableAction; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; +import com.adyen.v6.service.AdyenPaymentService; import com.adyen.v6.service.AdyenTransactionService; import de.hybris.platform.core.enums.OrderStatus; import de.hybris.platform.core.model.order.OrderModel; @@ -30,6 +32,7 @@ import de.hybris.platform.payment.enums.PaymentTransactionType; import de.hybris.platform.payment.model.PaymentTransactionEntryModel; import de.hybris.platform.payment.model.PaymentTransactionModel; +import de.hybris.platform.store.services.BaseStoreService; import org.apache.log4j.Logger; import java.math.BigDecimal; @@ -41,6 +44,15 @@ public class AdyenCheckCaptureAction extends AbstractWaitableAction { private static final Logger LOG = Logger.getLogger(AdyenCheckCaptureAction.class); + private final AdyenPaymentServiceFactory adyenPaymentServiceFactory; + private final BaseStoreService baseStoreService; + + public AdyenCheckCaptureAction(final AdyenPaymentServiceFactory adyenPaymentServiceFactory, + final BaseStoreService baseStoreService) { + this.adyenPaymentServiceFactory = adyenPaymentServiceFactory; + this.baseStoreService = baseStoreService; + } + @Override public Set getTransitions() { return Transition.getStringValues(); @@ -64,7 +76,7 @@ public String execute(final OrderProcessModel process) { order.setStatus(OrderStatus.PAYMENT_NOT_CAPTURED); modelService.save(order); - BigDecimal remainingAmount = new BigDecimal(order.getTotalPrice()); + BigDecimal remainingAmount = getAdyenPaymentService(order).calculateAmountWithTaxes(order); for (final PaymentTransactionModel paymentTransactionModel : order.getPaymentTransactions()) { boolean isRejected = AdyenTransactionService.getTransactionEntry( paymentTransactionModel, @@ -114,4 +126,8 @@ public String execute(final OrderProcessModel process) { LOG.debug("Process: " + process.getCode() + " Order Waiting"); return Transition.WAIT.toString(); } + + public AdyenPaymentService getAdyenPaymentService(final OrderModel orderModel) { + return adyenPaymentServiceFactory.createFromBaseStore(orderModel.getStore()); + } } diff --git a/adyenv6core/src/com/adyen/v6/commands/AdyenCaptureCommand.java b/adyenv6core/src/com/adyen/v6/commands/AdyenCaptureCommand.java index a56a4e6b8..ccb6359da 100644 --- a/adyenv6core/src/com/adyen/v6/commands/AdyenCaptureCommand.java +++ b/adyenv6core/src/com/adyen/v6/commands/AdyenCaptureCommand.java @@ -20,12 +20,7 @@ */ package com.adyen.v6.commands; -import java.math.BigDecimal; -import java.util.Currency; -import java.util.Date; -import org.apache.log4j.Logger; -import org.springframework.util.Assert; -import com.adyen.model.modification.ModificationResult; +import com.adyen.model.checkout.PaymentCaptureResource; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.repository.OrderRepository; import com.adyen.v6.service.AdyenPaymentService; @@ -37,6 +32,12 @@ import de.hybris.platform.payment.dto.TransactionStatus; import de.hybris.platform.payment.dto.TransactionStatusDetails; import de.hybris.platform.store.BaseStoreModel; +import org.apache.log4j.Logger; +import org.springframework.util.Assert; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.Date; /** * Issues a Capture request @@ -81,16 +82,16 @@ public CaptureResult perform(final CaptureRequest request) { boolean isImmediateCapture = baseStore.getAdyenImmediateCapture(); - boolean autoCapture = isImmediateCapture || ! supportsManualCapture(paymentInfo.getAdyenPaymentMethod()); + boolean autoCapture = isImmediateCapture || !supportsManualCapture(paymentInfo.getAdyenPaymentMethod()); if (autoCapture) { result.setTransactionStatus(TransactionStatus.ACCEPTED); result.setTransactionStatusDetails(TransactionStatusDetails.SUCCESFULL); } else { try { - ModificationResult modificationResult = adyenPaymentService.capture(amount, currency, originalPSPReference, reference); + final PaymentCaptureResource captures = adyenPaymentService.captures(amount, currency, originalPSPReference, reference); - if (modificationResult.getResponse().equals(CAPTURE_RECEIVED_RESPONSE)) { + if (PaymentCaptureResource.StatusEnum.RECEIVED.equals(captures.getStatus())) { result.setTransactionStatus(TransactionStatus.ACCEPTED); //Accepted so that TakePaymentAction doesn't fail result.setTransactionStatusDetails(TransactionStatusDetails.REVIEW_NEEDED); } else { diff --git a/adyenv6core/src/com/adyen/v6/commands/AdyenFollowOnRefundCommand.java b/adyenv6core/src/com/adyen/v6/commands/AdyenFollowOnRefundCommand.java index f1de2604b..d21705adf 100644 --- a/adyenv6core/src/com/adyen/v6/commands/AdyenFollowOnRefundCommand.java +++ b/adyenv6core/src/com/adyen/v6/commands/AdyenFollowOnRefundCommand.java @@ -20,11 +20,7 @@ */ package com.adyen.v6.commands; -import java.math.BigDecimal; -import java.util.Currency; -import java.util.Date; -import org.apache.log4j.Logger; -import com.adyen.model.modification.ModificationResult; +import com.adyen.model.checkout.PaymentRefundResource; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.repository.BaseStoreRepository; import com.adyen.v6.service.AdyenPaymentService; @@ -32,6 +28,12 @@ import de.hybris.platform.payment.commands.request.FollowOnRefundRequest; import de.hybris.platform.payment.commands.result.RefundResult; import de.hybris.platform.store.BaseStoreModel; +import org.apache.log4j.Logger; + +import java.math.BigDecimal; +import java.util.Currency; +import java.util.Date; + import static de.hybris.platform.payment.dto.TransactionStatus.ACCEPTED; import static de.hybris.platform.payment.dto.TransactionStatus.ERROR; import static de.hybris.platform.payment.dto.TransactionStatusDetails.REVIEW_NEEDED; @@ -74,11 +76,11 @@ public RefundResult perform(FollowOnRefundRequest request) { try { //Do the /refund API call - ModificationResult modificationResult = adyenPaymentService.refund(amount, currency, originalPSPReference, reference); + final PaymentRefundResource refunds = adyenPaymentService.refunds(amount, currency, originalPSPReference, reference); - LOG.debug("Refund response: " + modificationResult.getResponse()); + LOG.debug("Refund response: " + refunds.toString()); //change status to ACCEPTED if there is no error - if (modificationResult.getResponse().equals(REFUND_RECEIVED_RESPONSE)) { + if (PaymentRefundResource.StatusEnum.RECEIVED.equals(refunds.getStatus())) { result.setTransactionStatus(ACCEPTED); result.setTransactionStatusDetails(REVIEW_NEEDED); } diff --git a/adyenv6core/src/com/adyen/v6/commands/AdyenVoidCommand.java b/adyenv6core/src/com/adyen/v6/commands/AdyenVoidCommand.java index c4fe24253..63b9f0627 100644 --- a/adyenv6core/src/com/adyen/v6/commands/AdyenVoidCommand.java +++ b/adyenv6core/src/com/adyen/v6/commands/AdyenVoidCommand.java @@ -20,9 +20,7 @@ */ package com.adyen.v6.commands; -import java.util.Date; -import org.apache.log4j.Logger; -import com.adyen.model.modification.ModificationResult; +import com.adyen.model.checkout.PaymentReversalResource; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.repository.BaseStoreRepository; import com.adyen.v6.service.AdyenPaymentService; @@ -32,6 +30,9 @@ import de.hybris.platform.payment.dto.TransactionStatus; import de.hybris.platform.payment.dto.TransactionStatusDetails; import de.hybris.platform.store.BaseStoreModel; +import org.apache.log4j.Logger; + +import java.util.Date; /** * Issues a Cancel request @@ -65,9 +66,9 @@ public VoidResult perform(VoidRequest request) { AdyenPaymentService adyenPaymentService = adyenPaymentServiceFactory.createFromBaseStore(baseStore); try { - ModificationResult modificationResult = adyenPaymentService.cancelOrRefund(authReference, reference); + final PaymentReversalResource paymentReversalResource = adyenPaymentService.cancelOrRefunds(authReference, reference); - if (CANCELORREFUND_RECEIVED_RESPONSE.equals(modificationResult.getResponse())) { + if (PaymentReversalResource.StatusEnum.RECEIVED.equals(paymentReversalResource.getStatus())) { result.setTransactionStatus(TransactionStatus.ACCEPTED); result.setTransactionStatusDetails(TransactionStatusDetails.REVIEW_NEEDED); } else { diff --git a/adyenv6core/src/com/adyen/v6/constants/Adyenv6coreConstants.java b/adyenv6core/src/com/adyen/v6/constants/Adyenv6coreConstants.java index c017d98f5..50a98cebc 100644 --- a/adyenv6core/src/com/adyen/v6/constants/Adyenv6coreConstants.java +++ b/adyenv6core/src/com/adyen/v6/constants/Adyenv6coreConstants.java @@ -31,7 +31,7 @@ public final class Adyenv6coreConstants extends GeneratedAdyenv6coreConstants { public static final String EXTENSIONNAME = "adyenv6core"; public static final String PLUGIN_NAME = "adyen-hybris"; - public static final String PLUGIN_VERSION = "10.2.1"; + public static final String PLUGIN_VERSION = "11.0.1"; public static final String PAYMENT_PROVIDER = "Adyen"; public static final String PAYMENT_METHOD ="paymentMethod"; @@ -51,13 +51,22 @@ public final class Adyenv6coreConstants extends GeneratedAdyenv6coreConstants { final public static String PAYMENT_METHOD_AMAZONPAY = "amazonpay"; final public static String PAYMENT_METHOD_BCMC = "bcmc"; final public static String PAYMENT_METHOD_BCMC_MOBILE = "bcmc_mobile"; + final public static String PAYMENT_METHOD_GOOGLE = "paywithgoogle"; + final public static String PAYMENT_METHOD_TRUSTLY = "trustly"; + final public static String PAYMENT_METHOD_INTERAC = "interac"; + final public static String PAYMENT_METHOD_SOFORT = "directEbanking"; + final public static String PAYMENT_METHOD_DOTPAY = "dotpay"; + final public static String PAYMENT_METHOD_WECHATPAY = "wechatpayWeb"; + final public static String PAYMENT_METHOD_PAYTM = "paytm"; + final public static String PAYMENT_METHOD_BILLDESK_UPI = "billdesk_upi"; + final public static String PAYMENT_METHOD_ONLINEBANKING_PL = "onlineBanking_PL"; public static final String PROCESS_EVENT_ADYEN_CAPTURED = "AdyenCaptured"; public static final String PROCESS_EVENT_ADYEN_PAYMENT_RESULT = "AdyenPaymentResult"; public static final String PROCESS_EVENT_ADYEN_REFUNDED = "AdyenRefunded"; - public static final String KLARNA = "klarna"; + public static final String PAYMENT_METHOD_KLARNA = "klarna"; public static final String RATEPAY = "ratepay"; public static final String AFTERPAY = "afterpay_default"; public static final String AFTERPAY_TOUCH = "afterpaytouch"; @@ -72,7 +81,6 @@ public final class Adyenv6coreConstants extends GeneratedAdyenv6coreConstants { public static final String CARD_TYPE_DEBIT = "debit"; public static final String AFFIRM = "affirm"; public static final String CLEARPAY = "clearpay"; - public static final String GIFT_CARD = "giftcard"; private Adyenv6coreConstants() { //empty to avoid instantiating this constant class @@ -82,8 +90,8 @@ private Adyenv6coreConstants() { public static final String PLATFORM_LOGO_CODE = "adyenv6corePlatformLogo"; - public static final List OPENINVOICE_METHODS_API = Collections.unmodifiableList(new ArrayList() {{ - add(KLARNA); + public static final List OPENINVOICE_METHODS_API = Collections.unmodifiableList(new ArrayList<>() {{ + add(PAYMENT_METHOD_KLARNA); add(RATEPAY); add(KLARNA_SLICE); add(AFFIRM); @@ -94,21 +102,23 @@ private Adyenv6coreConstants() { }}); - public static final List OPENINVOICE_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER = Collections.unmodifiableList(new ArrayList() {{ + public static final List OPENINVOICE_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER = Collections.unmodifiableList(new ArrayList<>() {{ add(COUNTRY_CODE_SWEDEN); add(COUNTRY_CODE_DENMARK); add(COUNTRY_CODE_FINLAND); add(COUNTRY_CODE_NORWAY); }}); - public static final List PAYMENT_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER = Collections.unmodifiableList(new ArrayList() {{ + public static final List PAYMENT_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER = Collections.unmodifiableList(new ArrayList<>() {{ add(RATEPAY); add(PAYMENT_METHOD_BOLETO); add(PAYMENT_METHOD_PIX); }}); - public static final List ISSUER_PAYMENT_METHODS = Collections.unmodifiableList(new ArrayList() {{ + public static final List ISSUER_PAYMENT_METHODS = Collections.unmodifiableList(new ArrayList<>() {{ add(PAYMENT_METHOD_IDEAL); add(PAYMENT_METHOD_EPS); + add("onlinebanking_IN"); + add("onlineBanking_PL"); }}); } diff --git a/adyenv6core/src/com/adyen/v6/converters/PaymentMethodConverter.java b/adyenv6core/src/com/adyen/v6/converters/PaymentMethodConverter.java index 908d4c06f..553d9bdd1 100644 --- a/adyenv6core/src/com/adyen/v6/converters/PaymentMethodConverter.java +++ b/adyenv6core/src/com/adyen/v6/converters/PaymentMethodConverter.java @@ -23,30 +23,23 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; + +import com.adyen.model.checkout.PaymentMethod; import org.springframework.core.convert.converter.Converter; + import com.adyen.model.checkout.InputDetail; import com.adyen.model.hpp.Issuer; -public class PaymentMethodConverter implements Converter { +public class PaymentMethodConverter implements Converter { @Override - public com.adyen.model.hpp.PaymentMethod convert(com.adyen.model.checkout.PaymentMethod checkoutPaymentMethod) { + public PaymentMethod convert(com.adyen.model.checkout.PaymentMethod checkoutPaymentMethod) { if (checkoutPaymentMethod == null) { throw new IllegalArgumentException("Null PaymentMethod"); } - com.adyen.model.hpp.PaymentMethod hppPaymentMethod = new com.adyen.model.hpp.PaymentMethod(); - hppPaymentMethod.setBrandCode(checkoutPaymentMethod.getType()); - - Optional issuersInputDetail = checkoutPaymentMethod.getDetails().stream().filter(i -> "issuer".equals(i.getType())).findFirst(); - if (issuersInputDetail.isPresent()) { - List issuers = issuersInputDetail.get().getItems().stream().map(checkoutIssuer -> { - Issuer issuer = new Issuer(); - issuer.setIssuerId(checkoutIssuer.getId()); - issuer.setName(checkoutIssuer.getName()); - return issuer; - }).collect(Collectors.toList()); - hppPaymentMethod.setIssuers(issuers); - } + final PaymentMethod paymentMethod = new PaymentMethod(); - return hppPaymentMethod; + paymentMethod.setIssuers(checkoutPaymentMethod.getIssuers()); + paymentMethod.setBrand(checkoutPaymentMethod.getType()); + return paymentMethod; } } diff --git a/adyenv6core/src/com/adyen/v6/facades/AdyenAmazonPayFacade.java b/adyenv6core/src/com/adyen/v6/facades/AdyenAmazonPayFacade.java new file mode 100644 index 000000000..f14026895 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/facades/AdyenAmazonPayFacade.java @@ -0,0 +1,21 @@ +package com.adyen.v6.facades; + +/** + * Facade responsible for any direct amazonpay interaction logic + */ +public interface AdyenAmazonPayFacade { + + /** + * It gets the amazonpay Token given an already created checkout session id + * @param amazonpayCheckoutSessionId the previously created checkout session + * @return the amazonPayToken related with the amazonPay session + */ + String getAmazonPayToken(final String amazonpayCheckoutSessionId); + + /** + * Resolves the url for amazon pay controller by site + * @param url the url + * @return the complete url + */ + String getReturnUrl(final String url); +} diff --git a/adyenv6core/src/com/adyen/v6/facades/AdyenCheckoutFacade.java b/adyenv6core/src/com/adyen/v6/facades/AdyenCheckoutFacade.java index 7cdb1df3c..0efe35ee9 100644 --- a/adyenv6core/src/com/adyen/v6/facades/AdyenCheckoutFacade.java +++ b/adyenv6core/src/com/adyen/v6/facades/AdyenCheckoutFacade.java @@ -24,6 +24,8 @@ import com.adyen.model.checkout.PaymentsDetailsResponse; import com.adyen.model.checkout.PaymentsResponse; import com.adyen.service.exception.ApiException; +import com.adyen.v6.controllers.dtos.PaymentResultDTO; +import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; import com.adyen.v6.forms.AdyenPaymentForm; import de.hybris.platform.commercefacades.order.data.CartData; import de.hybris.platform.commercefacades.order.data.OrderData; @@ -93,6 +95,8 @@ public interface AdyenCheckoutFacade { */ OrderData authorisePayment(HttpServletRequest request, CartData cartData) throws Exception; + OrderData handleResultcomponentPayment(PaymentResultDTO paymentResultDTO) throws Exception; + /** * Creates a payment coming from an Adyen Checkout Component * No session handling @@ -136,9 +140,9 @@ public interface AdyenCheckoutFacade { /** * Retrieve available payment methods */ - void initializeCheckoutData(Model model); + void initializeCheckoutData(Model model) throws ApiException; - void initializeSummaryData(Model model); + void initializeSummaryData(Model model) throws ApiException; /** * Returns whether Boleto should be shown as an available payment method on the checkout page diff --git a/adyenv6core/src/com/adyen/v6/facades/impl/Amount.java b/adyenv6core/src/com/adyen/v6/facades/impl/Amount.java new file mode 100644 index 000000000..17d6c0fd2 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/facades/impl/Amount.java @@ -0,0 +1,32 @@ +package com.adyen.v6.facades.impl; + +public class Amount { + + private Long value; + private String currency; + + public Amount(){ + + } + + public Amount(Long value, String currency) { + this.value = value; + this.currency = currency; + } + + public Long getValue() { + return value; + } + + public void setValue(Long value) { + this.value = value; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } +} diff --git a/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacade.java b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacade.java new file mode 100644 index 000000000..915a57969 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacade.java @@ -0,0 +1,40 @@ +package com.adyen.v6.facades.impl; + +import com.adyen.v6.facades.AdyenAmazonPayFacade; +import com.adyen.v6.service.AdyenAmazonPayIntegratorService; +import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService; +import de.hybris.platform.site.BaseSiteService; + +/** + * {@inheritDoc} + */ +public class DefaultAdyenAmazonPayFacade implements AdyenAmazonPayFacade { + + protected final AdyenAmazonPayIntegratorService adyenAmazonPayIntegratorService; + protected final BaseSiteService baseSiteService; + protected final SiteBaseUrlResolutionService siteBaseUrlResolutionService; + + public DefaultAdyenAmazonPayFacade(final AdyenAmazonPayIntegratorService adyenAmazonPayIntegratorService, + final BaseSiteService baseSiteService, + final SiteBaseUrlResolutionService siteBaseUrlResolutionService) { + this.adyenAmazonPayIntegratorService = adyenAmazonPayIntegratorService; + this.baseSiteService = baseSiteService; + this.siteBaseUrlResolutionService = siteBaseUrlResolutionService; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAmazonPayToken(final String amazonPayCheckoutSessionId) { + return adyenAmazonPayIntegratorService.getAmazonPayTokenByCheckoutSessionId(amazonPayCheckoutSessionId); + } + + /** + * {@inheritDoc} + */ + @Override + public String getReturnUrl(final String url) { + return siteBaseUrlResolutionService.getWebsiteUrlForSite(baseSiteService.getCurrentBaseSite(), true, url); + } +} diff --git a/adyenv6core/src/com/adyen/v6/facades/DefaultAdyenCheckoutFacade.java b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java similarity index 87% rename from adyenv6core/src/com/adyen/v6/facades/DefaultAdyenCheckoutFacade.java rename to adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java index f25646289..f13af06a1 100644 --- a/adyenv6core/src/com/adyen/v6/facades/DefaultAdyenCheckoutFacade.java +++ b/adyenv6core/src/com/adyen/v6/facades/impl/DefaultAdyenCheckoutFacade.java @@ -18,19 +18,13 @@ * This file is open source and available under the MIT license. * See the LICENSE file for more info. */ -package com.adyen.v6.facades; +package com.adyen.v6.facades.impl; import com.adyen.model.Amount; import com.adyen.model.Card; import com.adyen.model.PaymentResult; -import com.adyen.model.checkout.CheckoutPaymentsAction; +import com.adyen.model.checkout.*; import com.adyen.model.checkout.CheckoutPaymentsAction.CheckoutActionType; -import com.adyen.model.checkout.PaymentMethod; -import com.adyen.model.checkout.PaymentMethodDetails; -import com.adyen.model.checkout.PaymentMethodsResponse; -import com.adyen.model.checkout.PaymentsDetailsResponse; -import com.adyen.model.checkout.PaymentsResponse; -import com.adyen.model.checkout.StoredPaymentMethod; import com.adyen.model.nexo.ErrorConditionType; import com.adyen.model.nexo.ResultType; import com.adyen.model.recurring.Recurring; @@ -40,12 +34,15 @@ import com.adyen.util.DateUtil; import com.adyen.util.Util; import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.controllers.dtos.PaymentResultDTO; import com.adyen.v6.converters.PaymentsDetailsResponseConverter; import com.adyen.v6.converters.PaymentsResponseConverter; import com.adyen.v6.converters.PosPaymentResponseConverter; import com.adyen.v6.enums.AdyenCardTypeEnum; +import com.adyen.v6.enums.AdyenRegions; import com.adyen.v6.enums.RecurringContractMode; import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; +import com.adyen.v6.facades.AdyenCheckoutFacade; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.forms.AddressForm; import com.adyen.v6.forms.AdyenPaymentForm; @@ -57,6 +54,7 @@ import com.adyen.v6.service.AdyenPaymentService; import com.adyen.v6.service.AdyenTransactionService; import com.adyen.v6.util.TerminalAPIUtil; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; @@ -109,35 +107,14 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static com.adyen.constants.ApiConstants.ThreeDS2Property.THREEDS2_CHALLENGE_TOKEN; import static com.adyen.constants.ApiConstants.ThreeDS2Property.THREEDS2_FINGERPRINT_TOKEN; import static com.adyen.constants.HPPConstants.Response.SHOPPER_LOCALE; -import static com.adyen.v6.constants.Adyenv6coreConstants.ISSUER_PAYMENT_METHODS; -import static com.adyen.v6.constants.Adyenv6coreConstants.KLARNA; -import static com.adyen.v6.constants.Adyenv6coreConstants.OPENINVOICE_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER; -import static com.adyen.v6.constants.Adyenv6coreConstants.OPENINVOICE_METHODS_API; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYBRIGHT; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHODS_ALLOW_SOCIAL_SECURITY_NUMBER; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_AMAZONPAY; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_APPLEPAY; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO_SANTANDER; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_MULTIBANCO; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_SCHEME; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_SEPA_DIRECTDEBIT; -import static com.adyen.v6.constants.Adyenv6coreConstants.RATEPAY; +import static com.adyen.v6.constants.Adyenv6coreConstants.*; import static de.hybris.platform.order.impl.DefaultCartService.SESSION_CART_PARAMETER_NAME; /** @@ -146,6 +123,16 @@ public class DefaultAdyenCheckoutFacade implements AdyenCheckoutFacade { public static final String DETAILS = "details"; + private static final String LOCALE = "locale"; + private static final String SESSION_DATA = "sessionData"; + private static final String REGION = "region"; + private static final String US_LOCALE = "en_US"; + private static final String GB_LOCALE = "en_GB"; + private static final String DE_LOCALE = "de_DE"; + private static final String FR_LOCALE = "fr_FR"; + private static final String IT_LOCALE = "it_IT"; + private static final String ES_LOCALE = "es_ES"; + private static final String US = "US"; private BaseStoreService baseStoreService; private SessionService sessionService; @@ -207,6 +194,7 @@ public class DefaultAdyenCheckoutFacade implements AdyenCheckoutFacade { public static final String MODEL_SHOW_COMBO_CARD = "showComboCard"; public static final String CHECKOUT_SHOPPER_HOST_TEST = "checkoutshopper-test.adyen.com"; public static final String CHECKOUT_SHOPPER_HOST_LIVE = "checkoutshopper-live.adyen.com"; + public static final String CHECKOUT_SHOPPER_HOST_LIVE_IN = "checkoutshopper-live-in.adyen.com"; public static final String MODEL_ISSUER_LISTS = "issuerLists"; public static final String MODEL_CONNECTED_TERMINAL_LIST = "connectedTerminalList"; public static final String MODEL_ENVIRONMENT_MODE = "environmentMode"; @@ -227,21 +215,27 @@ public DefaultAdyenCheckoutFacade() { @Override public String getCheckoutShopperHost() { - BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); + final BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); - if (baseStore.getAdyenTestMode()) { + if (Boolean.TRUE.equals(baseStore.getAdyenTestMode())) { return CHECKOUT_SHOPPER_HOST_TEST; } + if (AdyenRegions.IN.equals(baseStore.getAdyenRegion())) { + return CHECKOUT_SHOPPER_HOST_LIVE_IN; + } return CHECKOUT_SHOPPER_HOST_LIVE; } @Override public String getEnvironmentMode() { - if (baseStoreService.getCurrentBaseStore().getAdyenTestMode()) { + if (Boolean.TRUE.equals(baseStoreService.getCurrentBaseStore().getAdyenTestMode())) { return "test"; } + if (AdyenRegions.IN.equals(baseStoreService.getCurrentBaseStore().getAdyenRegion())) { + return "live-in"; + } return "live"; } @@ -256,7 +250,7 @@ public void lockSessionCart() { getSessionService().removeAttribute(SESSION_CART_PARAMETER_NAME); //Refresh session for registered users - if (! getCheckoutCustomerStrategy().isAnonymousCheckout()) { + if (!getCheckoutCustomerStrategy().isAnonymousCheckout()) { getCartService().getSessionCart(); } } @@ -362,7 +356,7 @@ public PaymentsDetailsResponse handleRedirectPayload(HashMap det private void updateOrderPaymentStatusAndInfo(OrderModel orderModel, PaymentsResponse paymentsResponse) { PaymentsResponse.ResultCodeEnum resultCode = paymentsResponse.getResultCode(); - if(PaymentsResponse.ResultCodeEnum.RECEIVED != resultCode) { + if (PaymentsResponse.ResultCodeEnum.RECEIVED != resultCode) { //payment authorisation is finished, update payment info getAdyenTransactionService().createPaymentTransactionFromResultCode(orderModel, orderModel.getCode(), @@ -370,7 +364,7 @@ private void updateOrderPaymentStatusAndInfo(OrderModel orderModel, PaymentsResp paymentsResponse.getResultCode()); } - if(PaymentsResponse.ResultCodeEnum.AUTHORISED == resultCode || PaymentsResponse.ResultCodeEnum.RECEIVED == resultCode) { + if (PaymentsResponse.ResultCodeEnum.AUTHORISED == resultCode || PaymentsResponse.ResultCodeEnum.RECEIVED == resultCode) { //remove PAYMENT_PENDING status, will be processed by order management orderModel.setStatus(null); orderModel.setStatusInfo(null); @@ -394,24 +388,13 @@ public OrderData authorisePayment(final HttpServletRequest request, final CartDa updateCartWithSessionData(cartData); String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); - if (adyenPaymentMethod.startsWith(RATEPAY)) { - PaymentResult paymentResult = getAdyenPaymentService().authorise(cartData, request, customer); - if (PaymentResult.ResultCodeEnum.AUTHORISED == paymentResult.getResultCode()) { - return createAuthorizedOrder(paymentResult); - } - if (PaymentResult.ResultCodeEnum.RECEIVED == paymentResult.getResultCode()) { - return createOrderFromPaymentResult(paymentResult); - } - throw new AdyenNonAuthorizedPaymentException(paymentResult); - } - RequestInfo requestInfo = new RequestInfo(request); requestInfo.setShopperLocale(getShopperLocale()); PaymentsResponse paymentsResponse = getAdyenPaymentService().authorisePayment(cartData, requestInfo, customer); PaymentsResponse.ResultCodeEnum resultCode = paymentsResponse.getResultCode(); CheckoutPaymentsAction action = paymentsResponse.getAction(); - if (PaymentsResponse.ResultCodeEnum.AUTHORISED == resultCode) { + if (PaymentsResponse.ResultCodeEnum.AUTHORISED == resultCode || PaymentsResponse.ResultCodeEnum.PENDING == resultCode) { return createAuthorizedOrder(paymentsResponse); } if (PaymentsResponse.ResultCodeEnum.RECEIVED == resultCode) { @@ -422,7 +405,7 @@ public OrderData authorisePayment(final HttpServletRequest request, final CartDa } if (PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER == resultCode) { placePendingOrder(resultCode); - if (adyenPaymentMethod.startsWith(KLARNA)) { + if (adyenPaymentMethod.startsWith(PAYMENT_METHOD_KLARNA)) { getSessionService().setAttribute(PAYMENT_METHOD, adyenPaymentMethod); } } else if (action != null && CheckoutActionType.THREEDS2.equals(action.getType())) { @@ -442,18 +425,25 @@ private boolean isGuestUserTokenizationEnabled() { } @Override - public PaymentsResponse componentPayment(final HttpServletRequest request, final CartData cartData, final PaymentMethodDetails paymentMethodDetails) throws Exception { - CustomerModel customer = null; - if (!getCheckoutCustomerStrategy().isAnonymousCheckout()) { - customer = getCheckoutCustomerStrategy().getCurrentUserForCheckout(); + public OrderData handleResultcomponentPayment(final PaymentResultDTO paymentResultDTO) throws Exception { + if (PaymentsResponse.ResultCodeEnum.PENDING.getValue().equals(paymentResultDTO.getResultCode()) || + PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER.getValue().equals(paymentResultDTO.getResultCode())) { + return placePendingOrder(PaymentsResponse.ResultCodeEnum.fromValue(paymentResultDTO.getResultCode())); } + if (PaymentsResponse.ResultCodeEnum.AUTHORISED.getValue().equals(paymentResultDTO.getResultCode())) { + return placeAuthorisedOrder(PaymentsResponse.ResultCodeEnum.AUTHORISED); + } + return null; + } + @Override + public PaymentsResponse componentPayment(final HttpServletRequest request, final CartData cartData, final PaymentMethodDetails paymentMethodDetails) throws Exception { updateCartWithSessionData(cartData); RequestInfo requestInfo = new RequestInfo(request); requestInfo.setShopperLocale(getShopperLocale()); - PaymentsResponse paymentsResponse = getAdyenPaymentService().componentPayment(cartData, paymentMethodDetails, requestInfo, customer); + PaymentsResponse paymentsResponse = getAdyenPaymentService().componentPayment(cartData, paymentMethodDetails, requestInfo, getCheckoutCustomerStrategy().getCurrentUserForCheckout()); if (PaymentsResponse.ResultCodeEnum.PENDING == paymentsResponse.getResultCode() || PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER == paymentsResponse.getResultCode()) { placePendingOrder(paymentsResponse.getResultCode()); return paymentsResponse; @@ -595,6 +585,23 @@ private OrderData placePendingOrder(PaymentsResponse.ResultCodeEnum resultCode) return orderData; } + private OrderData placeAuthorisedOrder(PaymentsResponse.ResultCodeEnum resultCode) throws InvalidCartException { + CartModel cartModel = getCartService().getSessionCart(); + cartModel.setStatus(OrderStatus.PAYMENT_AUTHORIZED); + cartModel.setStatusInfo(resultCode.getValue()); + getModelService().save(cartModel); + + OrderData orderData = getCheckoutFacade().placeOrder(); + + getSessionService().setAttribute(SESSION_PENDING_ORDER_CODE, orderData.getCode()); + + //Set new cart in session to avoid bugs (like going "back" on browser) + CartModel newCartModel = getCartFactory().createCart(); + getCartService().setSessionCart(newCartModel); + + return orderData; + } + /** * Create order */ @@ -604,7 +611,7 @@ private OrderData createOrderFromPaymentResult(final PaymentResult paymentResult } @Override - public void initializeCheckoutData(Model model) { + public void initializeCheckoutData(Model model) throws ApiException { final CartData cartData = getCheckoutFacade().getCheckoutCart(); AdyenPaymentService adyenPaymentService = getAdyenPaymentService(); List alternativePaymentMethods; @@ -621,34 +628,32 @@ public void initializeCheckoutData(Model model) { connectedTerminalList = adyenPaymentService.getConnectedTerminals().getUniqueTerminalIds(); } - response = adyenPaymentService.getPaymentMethodsResponse(cartData.getTotalPrice().getValue(), - cartData.getTotalPrice().getCurrencyIso(), - cartData.getDeliveryAddress().getCountry().getIsocode(), - getShopperLocale(), - customerModel.getCustomerID()); + response = adyenPaymentService.getPaymentMethodsResponse(cartData.getTotalPriceWithTax().getValue(), + cartData.getTotalPriceWithTax().getCurrencyIso(), + cartData.getDeliveryAddress().getCountry().getIsocode(), + getShopperLocale(), + customerModel.getCustomerID()); } catch (ApiException | IOException e) { LOGGER.error(ExceptionUtils.getStackTrace(e)); } - alternativePaymentMethods = response.getPaymentMethods(); - List issuerPaymentMethods = alternativePaymentMethods.stream() - .filter(paymentMethod -> ! paymentMethod.getType().isEmpty() && ISSUER_PAYMENT_METHODS.contains(paymentMethod.getType())) - .collect(Collectors.toList()); - if (! CollectionUtils.isEmpty(issuerPaymentMethods)) { + final List issuerPaymentMethods = alternativePaymentMethods.stream() + .filter(paymentMethod -> !paymentMethod.getType().isEmpty() && ISSUER_PAYMENT_METHODS.contains(paymentMethod.getType())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(issuerPaymentMethods)) { Gson gson = new Gson(); for (PaymentMethod paymentMethod : issuerPaymentMethods) { - issuerLists.put(paymentMethod.getType(), gson.toJson(paymentMethod.getDetails())); + issuerLists.put(paymentMethod.getType(), gson.toJson(paymentMethod.getIssuers())); } } Optional sepaDirectDebit = alternativePaymentMethods.stream(). - filter(paymentMethod -> ! paymentMethod.getType().isEmpty() && - PAYMENT_METHOD_SEPA_DIRECTDEBIT.contains(paymentMethod.getType())).findFirst(); + filter(paymentMethod -> !paymentMethod.getType().isEmpty() && + PAYMENT_METHOD_SEPA_DIRECTDEBIT.contains(paymentMethod.getType())).findFirst(); - if(sepaDirectDebit.isPresent()) - { + if (sepaDirectDebit.isPresent()) { model.addAttribute(PAYMENT_METHOD_SEPA_DIRECTDEBIT, true); } @@ -657,9 +662,9 @@ public void initializeCheckoutData(Model model) { .filter(paymentMethod -> !paymentMethod.getType().isEmpty() && PAYMENT_METHOD_APPLEPAY.contains(paymentMethod.getType())) .findFirst(); - if(applePayMethod.isPresent()) { + if (applePayMethod.isPresent()) { Map applePayConfiguration = applePayMethod.get().getConfiguration(); - if(!CollectionUtils.isEmpty(applePayConfiguration)) { + if (!CollectionUtils.isEmpty(applePayConfiguration)) { cartModel.setAdyenApplePayMerchantName(applePayConfiguration.get("merchantName")); cartModel.setAdyenApplePayMerchantIdentifier(applePayConfiguration.get("merchantId")); } @@ -670,9 +675,9 @@ public void initializeCheckoutData(Model model) { .filter(paymentMethod -> !paymentMethod.getType().isEmpty() && PAYMENT_METHOD_AMAZONPAY.contains(paymentMethod.getType())) .findFirst(); - if(amazonPayMethod.isPresent()) { + if (amazonPayMethod.isPresent()) { Map amazonPayConfiguration = amazonPayMethod.get().getConfiguration(); - if(!CollectionUtils.isEmpty(amazonPayConfiguration)) { + if (!CollectionUtils.isEmpty(amazonPayConfiguration)) { cartModel.setAdyenAmazonPayConfiguration(amazonPayConfiguration); } } @@ -683,8 +688,8 @@ public void initializeCheckoutData(Model model) { String creditCardLabel = null; Set allowedCards = null; PaymentMethod cardsPaymentMethod = alternativePaymentMethods.stream() - .filter(paymentMethod -> PAYMENT_METHOD_SCHEME.equals(paymentMethod.getType())) - .findAny().orElse(null); + .filter(paymentMethod -> PAYMENT_METHOD_SCHEME.equals(paymentMethod.getType())) + .findAny().orElse(null); if (cardsPaymentMethod != null) { creditCardLabel = cardsPaymentMethod.getName(); @@ -692,14 +697,14 @@ public void initializeCheckoutData(Model model) { List cardBrands = cardsPaymentMethod.getBrands(); allowedCards = allowedCards.stream() - .filter(adyenCardTypeEnum -> cardBrands.contains(adyenCardTypeEnum.getCode())) - .collect(Collectors.toSet()); + .filter(adyenCardTypeEnum -> cardBrands.contains(adyenCardTypeEnum.getCode())) + .collect(Collectors.toSet()); } //Exclude cards, boleto and iDeal alternativePaymentMethods = alternativePaymentMethods.stream() - .filter(paymentMethod -> ! paymentMethod.getType().isEmpty() && ! isHiddenPaymentMethod(paymentMethod)) - .collect(Collectors.toList()); + .filter(paymentMethod -> !paymentMethod.getType().isEmpty() && !isHiddenPaymentMethod(paymentMethod)) + .collect(Collectors.toList()); if (showRememberDetails()) { //Include stored one-click cards @@ -711,7 +716,9 @@ public void initializeCheckoutData(Model model) { cartModel.setAdyenStoredCards(recurringDetailReferences); } - Amount amount = Util.createAmount(cartData.getTotalPrice().getValue(), cartData.getTotalPrice().getCurrencyIso()); + Amount amount = Util.createAmount(cartData.getTotalPriceWithTax().getValue(), cartData.getTotalPriceWithTax().getCurrencyIso()); + + model.addAttribute(SESSION_DATA, getAdyenSessionData()); // current selected PaymentMethod model.addAttribute(MODEL_SELECTED_PAYMENT_METHOD, cartData.getAdyenPaymentMethod()); @@ -760,20 +767,37 @@ public void initializeCheckoutData(Model model) { modelService.save(cartModel); } + private CreateCheckoutSessionResponse getAdyenSessionData() throws ApiException { + try { + final CartData cartData = getCheckoutFacade().getCheckoutCart(); + return getAdyenPaymentService().getPaymentSessionData(cartData); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + @Override - public void initializeSummaryData(Model model) { + public void initializeSummaryData(Model model) throws ApiException { final CartData cartData = getCheckoutFacade().getCheckoutCart(); - AdyenPaymentService adyenPaymentService = getAdyenPaymentService(); - BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); + final AdyenPaymentService adyenPaymentService = getAdyenPaymentService(); + final BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); - Amount amount = Util.createAmount(cartData.getTotalPrice().getValue(), cartData.getTotalPrice().getCurrencyIso()); - Gson gson = new Gson(); + final Amount amount = Util.createAmount(cartData.getTotalPriceWithTax().getValue(), cartData.getTotalPriceWithTax().getCurrencyIso()); + final Gson gson = new Gson(); + final String shopperLocale = getShopperLocale(); + final String countryCode = Objects.nonNull(cartData.getDeliveryAddress()) && + Objects.nonNull(cartData.getDeliveryAddress().getCountry()) ? + cartData.getDeliveryAddress().getCountry().getIsocode() : null; model.addAttribute(MODEL_SELECTED_PAYMENT_METHOD, cartData.getAdyenPaymentMethod()); model.addAttribute(MODEL_DF_URL, adyenPaymentService.getDeviceFingerprintUrl()); model.addAttribute(MODEL_CHECKOUT_SHOPPER_HOST, getCheckoutShopperHost()); model.addAttribute(MODEL_ENVIRONMENT_MODE, getEnvironmentMode()); - model.addAttribute(SHOPPER_LOCALE, getShopperLocale()); + model.addAttribute(SHOPPER_LOCALE, shopperLocale); //Include information for components model.addAttribute(MODEL_CLIENT_KEY, baseStore.getAdyenClientKey()); @@ -784,8 +808,29 @@ public void initializeSummaryData(Model model) { model.addAttribute(MODEL_APPLEPAY_MERCHANT_IDENTIFIER, cartData.getAdyenApplePayMerchantIdentifier()); model.addAttribute(MODEL_APPLEPAY_MERCHANT_NAME, cartData.getAdyenApplePayMerchantName()); model.addAttribute(MODEL_AMAZONPAY_CONFIGURATION, gson.toJson(cartData.getAdyenAmazonPayConfiguration())); - model.addAttribute(MODEL_COUNTRY_CODE, cartData.getDeliveryAddress().getCountry().getIsocode()); + model.addAttribute(MODEL_COUNTRY_CODE, countryCode); model.addAttribute(MODEL_DELIVERY_ADDRESS, gson.toJson(cartData.getDeliveryAddress())); + model.addAttribute(SESSION_DATA, getAdyenSessionData()); + model.addAttribute(LOCALE, gson.toJson(setLocale(cartData.getAdyenAmazonPayConfiguration(), shopperLocale))); + } + + private String setLocale(final Map map, final String shopperLocale) { + if (Objects.nonNull(map) && !map.get(REGION).isBlank() && map.get(REGION).equals(US)) { + return US_LOCALE; + } else { + switch (shopperLocale) { + case "de": + return DE_LOCALE; + case "fr": + return FR_LOCALE; + case "it": + return IT_LOCALE; + case "es": + return ES_LOCALE; + default: + return GB_LOCALE; + } + } } private boolean isHiddenPaymentMethod(PaymentMethod paymentMethod) { @@ -794,10 +839,10 @@ private boolean isHiddenPaymentMethod(PaymentMethod paymentMethod) { if (paymentMethodType == null || paymentMethodType.isEmpty() || paymentMethodType.equals("scheme") || (paymentMethodType.contains("wechatpay") - && ! paymentMethodType.equals("wechatpayWeb")) || + && !paymentMethodType.equals("wechatpayWeb")) || paymentMethodType.startsWith(PAYMENT_METHOD_BOLETO) || paymentMethodType.contains(PAYMENT_METHOD_SEPA_DIRECTDEBIT) || - ISSUER_PAYMENT_METHODS.contains(paymentMethodType)) { + (ISSUER_PAYMENT_METHODS.contains(paymentMethodType) && !paymentMethodType.equals("onlinebanking_IN") && !paymentMethodType.equals("onlineBanking_PL"))) { return true; } return false; @@ -808,7 +853,7 @@ private List getStoredOneClickPaymentMethods(PaymentMethods if (response.getStoredPaymentMethods() != null) { storedPaymentMethodList = response.getStoredPaymentMethods().stream() .filter(storedPaymentMethod -> storedPaymentMethod.getSupportedShopperInteractions() != null - && storedPaymentMethod.getSupportedShopperInteractions().contains(ECOMMERCE_SHOPPER_INTERACTION)) + && storedPaymentMethod.getSupportedShopperInteractions().contains(ECOMMERCE_SHOPPER_INTERACTION)) .collect(Collectors.toList()); } @@ -819,12 +864,12 @@ private List getStoredOneClickPaymentMethods(PaymentMethods public boolean showBoleto() { BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); //Check base store settings - if (baseStore.getAdyenBoleto() == null || ! baseStore.getAdyenBoleto()) { + if (baseStore.getAdyenBoleto() == null || !baseStore.getAdyenBoleto()) { return false; } CartData cartData = getCheckoutFacade().getCheckoutCart(); - String currency = cartData.getTotalPrice().getCurrencyIso(); + String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); String country = cartData.getDeliveryAddress().getCountry().getIsocode(); //Show only on Brasil with BRL @@ -834,7 +879,7 @@ public boolean showBoleto() { @Override public boolean showComboCard() { CartData cartData = getCheckoutFacade().getCheckoutCart(); - String currency = cartData.getTotalPrice().getCurrencyIso(); + String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); return "BRL".equals(currency); } @@ -842,7 +887,7 @@ public boolean showComboCard() { public boolean showPos() { BaseStoreModel baseStore = baseStoreService.getCurrentBaseStore(); //Check base store settings for POS Enabled or not. - if (baseStore.getAdyenPosEnabled() == null || ! baseStore.getAdyenPosEnabled()) { + if (baseStore.getAdyenPosEnabled() == null || !baseStore.getAdyenPosEnabled()) { return false; } return true; @@ -857,7 +902,7 @@ public boolean showRememberDetails() { * user is logged in and the recurirng mode is set to ONECLICK or ONECLICK,RECURRING */ RecurringContractMode recurringContractMode = baseStore.getAdyenRecurringContractMode(); - if (! getCheckoutCustomerStrategy().isAnonymousCheckout()) { + if (!getCheckoutCustomerStrategy().isAnonymousCheckout()) { if (Recurring.ContractEnum.ONECLICK_RECURRING.name().equals(recurringContractMode.getCode()) || Recurring.ContractEnum.ONECLICK.name().equals(recurringContractMode.getCode())) { return true; } @@ -900,7 +945,7 @@ public PaymentInfoModel createPaymentInfo(final CartModel cartModel, AdyenPaymen paymentInfo.setAdyenPaymentMethod(adyenPaymentForm.getPaymentMethod()); paymentInfo.setAdyenIssuerId(adyenPaymentForm.getIssuerId()); - + paymentInfo.setAdyenUPIVirtualAddress(adyenPaymentForm.getUpiVirtualAddress()); paymentInfo.setAdyenRememberTheseDetails(adyenPaymentForm.getRememberTheseDetails()); paymentInfo.setAdyenSelectedReference(adyenPaymentForm.getSelectedReference()); @@ -913,7 +958,7 @@ public PaymentInfoModel createPaymentInfo(final CartModel cartModel, AdyenPaymen paymentInfo.setAdyenSepaIbanNumber(adyenPaymentForm.getSepaIbanNumber()); // AfterPay fields - paymentInfo.setAdyenTelephone(adyenPaymentForm.getTelephoneNumber()); + paymentInfo.setAdyenTelephone(cartModel.getDeliveryAddress().getPhone1()); paymentInfo.setAdyenShopperEmail(adyenPaymentForm.getShopperEmail()); paymentInfo.setAdyenShopperGender(adyenPaymentForm.getGender()); @@ -992,22 +1037,22 @@ public void handlePaymentForm(AdyenPaymentForm adyenPaymentForm, BindingResult b } //Put encrypted data to session - if (! StringUtils.isEmpty(adyenPaymentForm.getCseToken())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getCseToken())) { getSessionService().setAttribute(SESSION_CSE_TOKEN, adyenPaymentForm.getCseToken()); } - if (! StringUtils.isEmpty(adyenPaymentForm.getEncryptedCardNumber())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getEncryptedCardNumber())) { getSessionService().setAttribute(SESSION_SF_CARD_NUMBER, adyenPaymentForm.getEncryptedCardNumber()); } - if (! StringUtils.isEmpty(adyenPaymentForm.getEncryptedExpiryMonth())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getEncryptedExpiryMonth())) { getSessionService().setAttribute(SESSION_SF_EXPIRY_MONTH, adyenPaymentForm.getEncryptedExpiryMonth()); } - if (! StringUtils.isEmpty(adyenPaymentForm.getEncryptedExpiryYear())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getEncryptedExpiryYear())) { getSessionService().setAttribute(SESSION_SF_EXPIRY_YEAR, adyenPaymentForm.getEncryptedExpiryYear()); } - if (! StringUtils.isEmpty(adyenPaymentForm.getEncryptedSecurityCode())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getEncryptedSecurityCode())) { getSessionService().setAttribute(SESSION_SF_SECURITY_CODE, adyenPaymentForm.getEncryptedSecurityCode()); } - if (! StringUtils.isEmpty(adyenPaymentForm.getCardBrand())) { + if (!StringUtils.isEmpty(adyenPaymentForm.getCardBrand())) { getSessionService().setAttribute(SESSION_CARD_BRAND, adyenPaymentForm.getCardBrand()); } @@ -1041,8 +1086,7 @@ public AddressModel convertToAddressModel(final AddressForm addressForm) { addressData.setCountry(countryData); addressData.setPhone(addressForm.getPhoneNumber()); - if (addressForm.getRegionIso() != null && ! org.apache.commons.lang.StringUtils.isEmpty(addressForm.getRegionIso())) - { + if (addressForm.getRegionIso() != null && !org.apache.commons.lang.StringUtils.isEmpty(addressForm.getRegionIso())) { final RegionData regionData = getI18NFacade().getRegion(addressForm.getCountryIsoCode(), addressForm.getRegionIso()); addressData.setRegion(regionData); } @@ -1109,7 +1153,7 @@ public AdyenPaymentService getAdyenPaymentService() { @Override public OrderData initiatePosPayment(HttpServletRequest request, CartData cartData) throws Exception { CustomerModel customer = null; - if (! getCheckoutCustomerStrategy().isAnonymousCheckout()) { + if (!getCheckoutCustomerStrategy().isAnonymousCheckout()) { customer = getCheckoutCustomerStrategy().getCurrentUserForCheckout(); } //This will be used to check status later @@ -1207,7 +1251,7 @@ public OrderData handleComponentResult(String resultJson) throws Exception { OrderModel orderModel = retrievePendingOrder(orderCode); return getOrderConverter().convert(orderModel); } - + if (PaymentsResponse.ResultCodeEnum.REDIRECTSHOPPER != paymentsResponse.getResultCode()) { restoreCartFromOrder(orderCode); } @@ -1241,7 +1285,7 @@ private void restoreCartFromOrder(String orderCode) throws CalculationException, // Get cart from session CartModel cartModel; - if(getCartService().hasSessionCart()) { + if (getCartService().hasSessionCart()) { cartModel = getCartService().getSessionCart(); } // Or create new cart if no cart in session @@ -1252,17 +1296,17 @@ private void restoreCartFromOrder(String orderCode) throws CalculationException, Boolean isAnonymousCheckout = getCheckoutCustomerStrategy().isAnonymousCheckout(); - if(!isAnonymousCheckout && hasUserContextChanged(orderModel, cartModel)) { + if (!isAnonymousCheckout && hasUserContextChanged(orderModel, cartModel)) { throw new InvalidCartException("Cart from order '" + orderCode + "' not restored to session, since user or store in session changed."); } //Populate cart entries - for(AbstractOrderEntryModel entryModel : orderModel.getEntries()) { + for (AbstractOrderEntryModel entryModel : orderModel.getEntries()) { getCartService().addNewEntry(cartModel, entryModel.getProduct(), entryModel.getQuantity(), entryModel.getUnit()); } getModelService().save(cartModel); - if(!isAnonymousCheckout) { + if (!isAnonymousCheckout) { //Populate delivery address and mode AddressData deliveryAddressData = new AddressData(); getAddressPopulator().populate(orderModel.getDeliveryAddress().getOriginal(), deliveryAddressData); diff --git a/adyenv6core/src/com/adyen/v6/facades/impl/SessionRequest.java b/adyenv6core/src/com/adyen/v6/facades/impl/SessionRequest.java new file mode 100644 index 000000000..6e43e9fc6 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/facades/impl/SessionRequest.java @@ -0,0 +1,57 @@ +package com.adyen.v6.facades.impl; + +public class SessionRequest { + private String merchantAccount; + private String returnUrl; + private String reference; + private String countryCode; + private Amount amount; + + public SessionRequest(String merchantAccount, String returnUrl, String reference, String countryCode, Amount amount) { + this.merchantAccount = merchantAccount; + this.returnUrl = returnUrl; + this.reference = reference; + this.countryCode = countryCode; + this.amount = amount; + } + + public String getMerchantAccount() { + return merchantAccount; + } + + public void setMerchantAccount(String merchantAccount) { + this.merchantAccount = merchantAccount; + } + + public String getReturnUrl() { + return returnUrl; + } + + public void setReturnUrl(String returnUrl) { + this.returnUrl = returnUrl; + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public Amount getAmount() { + return amount; + } + + public void setAmount(Amount amount) { + this.amount = amount; + } +} diff --git a/adyenv6core/src/com/adyen/v6/facades/impl/SessionResponse.java b/adyenv6core/src/com/adyen/v6/facades/impl/SessionResponse.java new file mode 100644 index 000000000..7e4c94e53 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/facades/impl/SessionResponse.java @@ -0,0 +1,90 @@ +package com.adyen.v6.facades.impl; + +public class SessionResponse { + + private String countryCode; + private String expiresAt; + private String merchantAccount; + private String returnUrl; + private String sessionData; + private String id; + private String reference; + private Amount amount; + + public SessionResponse(){ + + } + public SessionResponse(String countryCode, String expiresAt, String merchantAccount, String returnUrl, String sessionData, String id, Amount amount) { + this.countryCode = countryCode; + this.expiresAt = expiresAt; + this.merchantAccount = merchantAccount; + this.returnUrl = returnUrl; + this.sessionData = sessionData; + this.id = id; + this.amount = amount; + } + + public String getReference(){ + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getExpiresAt() { + return expiresAt; + } + + public void setExpiresAt(String expiresAt) { + this.expiresAt = expiresAt; + } + + public String getMerchantAccount() { + return merchantAccount; + } + + public void setMerchantAccount(String merchantAccount) { + this.merchantAccount = merchantAccount; + } + + public String getReturnUrl() { + return returnUrl; + } + + public void setReturnUrl(String returnUrl) { + this.returnUrl = returnUrl; + } + + public String getSessionData() { + return sessionData; + } + + public void setSessionData(String sessionData) { + this.sessionData = sessionData; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Amount getAmount() { + return amount; + } + + public void setAmount(Amount amount) { + this.amount = amount; + } +} diff --git a/adyenv6core/src/com/adyen/v6/factory/AdyenPaymentServiceFactory.java b/adyenv6core/src/com/adyen/v6/factory/AdyenPaymentServiceFactory.java index 82df3bf5b..c964efbb0 100644 --- a/adyenv6core/src/com/adyen/v6/factory/AdyenPaymentServiceFactory.java +++ b/adyenv6core/src/com/adyen/v6/factory/AdyenPaymentServiceFactory.java @@ -20,7 +20,6 @@ */ package com.adyen.v6.factory; -import com.adyen.v6.converters.PaymentMethodConverter; import com.adyen.v6.service.AdyenPaymentService; import com.adyen.v6.service.DefaultAdyenPaymentService; import de.hybris.platform.store.BaseStoreModel; @@ -29,29 +28,16 @@ * Factory class for AdyenPaymentService */ public class AdyenPaymentServiceFactory { - private PaymentMethodConverter paymentMethodConverter; - private AdyenRequestFactory adyenRequestFactory; + + private final AdyenRequestFactory adyenRequestFactory; + + public AdyenPaymentServiceFactory(final AdyenRequestFactory adyenRequestFactory) { + this.adyenRequestFactory = adyenRequestFactory; + } public AdyenPaymentService createFromBaseStore(final BaseStoreModel baseStoreModel) { DefaultAdyenPaymentService adyenPaymentService = new DefaultAdyenPaymentService(baseStoreModel); - adyenPaymentService.setPaymentMethodConverter(paymentMethodConverter); adyenPaymentService.setAdyenRequestFactory(adyenRequestFactory); return adyenPaymentService; } - - public PaymentMethodConverter getPaymentMethodConverter() { - return paymentMethodConverter; - } - - public void setPaymentMethodConverter(PaymentMethodConverter paymentMethodConverter) { - this.paymentMethodConverter = paymentMethodConverter; - } - - public AdyenRequestFactory getAdyenRequestFactory() { - return adyenRequestFactory; - } - - public void setAdyenRequestFactory(AdyenRequestFactory adyenRequestFactory) { - this.adyenRequestFactory = adyenRequestFactory; - } } diff --git a/adyenv6core/src/com/adyen/v6/factory/AdyenRequestFactory.java b/adyenv6core/src/com/adyen/v6/factory/AdyenRequestFactory.java index a8fb34a6c..8f03d3da4 100644 --- a/adyenv6core/src/com/adyen/v6/factory/AdyenRequestFactory.java +++ b/adyenv6core/src/com/adyen/v6/factory/AdyenRequestFactory.java @@ -22,43 +22,34 @@ import com.adyen.builders.terminal.TerminalAPIRequestBuilder; import com.adyen.enums.VatCategory; -import com.adyen.model.AbstractPaymentRequest; -import com.adyen.model.Address; import com.adyen.model.Amount; -import com.adyen.model.BrowserInfo; -import com.adyen.model.Installments; -import com.adyen.model.Name; import com.adyen.model.PaymentRequest; -import com.adyen.model.PaymentRequest3d; +import com.adyen.model.*; import com.adyen.model.additionalData.InvoiceLine; import com.adyen.model.applicationinfo.ApplicationInfo; import com.adyen.model.applicationinfo.CommonField; import com.adyen.model.applicationinfo.ExternalPlatform; -import com.adyen.model.checkout.DefaultPaymentMethodDetails; import com.adyen.model.checkout.LineItem; import com.adyen.model.checkout.PaymentMethodDetails; import com.adyen.model.checkout.PaymentsDetailsRequest; import com.adyen.model.checkout.PaymentsRequest; +import com.adyen.model.checkout.details.CardDetails; import com.adyen.model.modification.CancelOrRefundRequest; import com.adyen.model.modification.CaptureRequest; import com.adyen.model.modification.RefundRequest; -import com.adyen.model.nexo.AmountsReq; -import com.adyen.model.nexo.DocumentQualifierType; -import com.adyen.model.nexo.MessageCategoryType; -import com.adyen.model.nexo.MessageReference; -import com.adyen.model.nexo.PaymentTransaction; -import com.adyen.model.nexo.SaleData; -import com.adyen.model.nexo.TransactionIdentification; -import com.adyen.model.nexo.TransactionStatusRequest; +import com.adyen.model.nexo.*; import com.adyen.model.recurring.DisableRequest; import com.adyen.model.recurring.Recurring; import com.adyen.model.recurring.RecurringDetailsRequest; import com.adyen.model.terminal.SaleToAcquirerData; import com.adyen.model.terminal.TerminalAPIRequest; import com.adyen.util.Util; +import com.adyen.v6.constants.Adyenv6coreConstants; import com.adyen.v6.enums.RecurringContractMode; import com.adyen.v6.model.RequestInfo; +import com.adyen.v6.paymentmethoddetails.executors.AdyenPaymentMethodDetailsBuilderExecutor; import com.google.gson.Gson; +import de.hybris.platform.commercefacades.order.data.CCPaymentInfoData; import de.hybris.platform.commercefacades.order.data.CartData; import de.hybris.platform.commercefacades.order.data.OrderEntryData; import de.hybris.platform.commercefacades.user.data.AddressData; @@ -76,34 +67,12 @@ import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Currency; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.adyen.v6.constants.Adyenv6coreConstants.AFTERPAY; -import static com.adyen.v6.constants.Adyenv6coreConstants.CARD_TYPE_DEBIT; -import static com.adyen.v6.constants.Adyenv6coreConstants.GIFT_CARD; -import static com.adyen.v6.constants.Adyenv6coreConstants.ISSUER_PAYMENT_METHODS; -import static com.adyen.v6.constants.Adyenv6coreConstants.KLARNA; -import static com.adyen.v6.constants.Adyenv6coreConstants.OPENINVOICE_METHODS_API; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYBRIGHT; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BCMC; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_BOLETO_SANTANDER; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_CC; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_FACILPAY_PREFIX; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_PAYPAL; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_PIX; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_SEPA_DIRECTDEBIT; -import static com.adyen.v6.constants.Adyenv6coreConstants.PLUGIN_NAME; -import static com.adyen.v6.constants.Adyenv6coreConstants.PLUGIN_VERSION; +import java.util.*; +import java.util.stream.Collectors; + +import static com.adyen.v6.constants.Adyenv6coreConstants.*; public class AdyenRequestFactory { - private ConfigurationService configurationService; private static final Logger LOG = Logger.getLogger(AdyenRequestFactory.class); private static final String PLATFORM_NAME = "Hybris"; @@ -111,9 +80,14 @@ public class AdyenRequestFactory { private static final String IS_3DS2_ALLOWED_PROPERTY = "is3DS2allowed"; private static final String ALLOW_3DS2_PROPERTY = "allow3DS2"; private static final String OVERWRITE_BRAND_PROPERTY = "overwriteBrand"; + private static final String DUAL_BRANDED_NOT_SELECTED_FLOW_PAYMENT_TYPE = "scheme"; + + protected final ConfigurationService configurationService; + protected final AdyenPaymentMethodDetailsBuilderExecutor adyenPaymentMethodDetailsBuilderExecutor; - public PaymentRequest3d create3DAuthorizationRequest(final String merchantAccount, final HttpServletRequest request, final String md, final String paRes) { - return createBasePaymentRequest(new PaymentRequest3d(), request, merchantAccount).set3DRequestData(md, paRes); + public AdyenRequestFactory(final ConfigurationService configurationService, final AdyenPaymentMethodDetailsBuilderExecutor adyenPaymentMethodDetailsBuilderExecutor) { + this.configurationService = configurationService; + this.adyenPaymentMethodDetailsBuilderExecutor = adyenPaymentMethodDetailsBuilderExecutor; } @Deprecated @@ -122,8 +96,9 @@ public PaymentRequest createAuthorizationRequest(final String merchantAccount, final HttpServletRequest request, final CustomerModel customerModel, final RecurringContractMode recurringContractMode) { - String amount = String.valueOf(cartData.getTotalPrice().getValue()); - String currency = cartData.getTotalPrice().getCurrencyIso(); + + String amount = String.valueOf(cartData.getTotalPriceWithTax().getValue()); + String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); String reference = cartData.getCode(); PaymentRequest paymentRequest = createBasePaymentRequest(new PaymentRequest(), request, merchantAccount).reference(reference).setAmountData(amount, currency); @@ -133,13 +108,6 @@ public PaymentRequest createAuthorizationRequest(final String merchantAccount, paymentRequest.setShopperReference(customerModel.getCustomerID()); paymentRequest.setShopperEmail(customerModel.getContactEmail()); } - - // set recurring contract - if (customerModel != null && PAYMENT_METHOD_CC.equals(cartData.getAdyenPaymentMethod())) { - Recurring recurring = getRecurringContractType(recurringContractMode, cartData.getAdyenRememberTheseDetails()); - paymentRequest.setRecurring(recurring); - } - // if address details are provided added it into the request if (cartData.getDeliveryAddress() != null) { Address deliveryAddress = setAddressData(cartData.getDeliveryAddress()); @@ -148,7 +116,7 @@ public PaymentRequest createAuthorizationRequest(final String merchantAccount, if (cartData.getPaymentInfo().getBillingAddress() != null) { // set PhoneNumber if it is provided - if (cartData.getPaymentInfo().getBillingAddress().getPhone() != null && ! cartData.getPaymentInfo().getBillingAddress().getPhone().isEmpty()) { + if (cartData.getPaymentInfo().getBillingAddress().getPhone() != null && !cartData.getPaymentInfo().getBillingAddress().getPhone().isEmpty()) { paymentRequest.setTelephoneNumber(cartData.getPaymentInfo().getBillingAddress().getPhone()); } @@ -179,312 +147,240 @@ public PaymentsRequest createPaymentsRequest(final String merchantAccount, final CustomerModel customerModel, final RecurringContractMode recurringContractMode, final Boolean guestUserTokenizationEnabled) { - PaymentsRequest paymentsRequest = new PaymentsRequest(); - String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); + final String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); + final Boolean is3DS2allowed = is3DS2Allowed(); + final PaymentsRequest paymentsRequest = new PaymentsRequest(); if (adyenPaymentMethod == null) { throw new IllegalArgumentException("Payment method is null"); } //Update payment request for generic information for all payment method types + setCommonInfoOnPaymentRequest(merchantAccount, cartData, requestInfo, customerModel, paymentsRequest); + updateApplicationInfoEcom(paymentsRequest.getApplicationInfo()); - updatePaymentRequest(merchantAccount, cartData, requestInfo, customerModel, paymentsRequest); - Boolean is3DS2allowed = is3DS2Allowed(); + paymentsRequest.setReturnUrl(cartData.getAdyenReturnUrl()); + paymentsRequest.setRedirectFromIssuerMethod(RequestMethod.POST.toString()); + paymentsRequest.setRedirectToIssuerMethod(RequestMethod.POST.toString()); //For credit cards if (PAYMENT_METHOD_CC.equals(adyenPaymentMethod) || PAYMENT_METHOD_BCMC.equals(adyenPaymentMethod)) { if (CARD_TYPE_DEBIT.equals(cartData.getAdyenCardType())) { updatePaymentRequestForDC(paymentsRequest, cartData, recurringContractMode); - } - else { + } else { updatePaymentRequestForCC(paymentsRequest, cartData, recurringContractMode); } if (is3DS2allowed) { - paymentsRequest = enhanceForThreeDS2(paymentsRequest, cartData); + enhanceForThreeDS2(paymentsRequest, cartData); } - if (customerModel != null && customerModel.getType() == CustomerType.GUEST && guestUserTokenizationEnabled) { + if (customerModel.getType() == CustomerType.GUEST && guestUserTokenizationEnabled) { paymentsRequest.setEnableOneClick(false); } } //For one click else if (adyenPaymentMethod.indexOf(PAYMENT_METHOD_ONECLICK) == 0) { - String selectedReference = cartData.getAdyenSelectedReference(); - if (selectedReference != null && ! selectedReference.isEmpty()) { - paymentsRequest.addOneClickData(selectedReference, cartData.getAdyenEncryptedSecurityCode()); - String cardBrand = cartData.getAdyenCardBrand(); - if (cardBrand != null) { - DefaultPaymentMethodDetails paymentMethodDetails = (DefaultPaymentMethodDetails) (paymentsRequest.getPaymentMethod()); - paymentMethodDetails.setType(cardBrand); - paymentsRequest.setPaymentMethod(paymentMethodDetails); - } - } + Optional.ofNullable(cartData.getAdyenSelectedReference()) + .filter(StringUtils::isNotEmpty) + .map(selectedReference -> getCardDetails(cartData, selectedReference)) + .ifPresent(paymentsRequest::setPaymentMethod); + if (is3DS2allowed) { - paymentsRequest = enhanceForThreeDS2(paymentsRequest, cartData); + enhanceForThreeDS2(paymentsRequest, cartData); } } + //For Pix APM + else if (PAYMENT_METHOD_PIX.equals(cartData.getAdyenPaymentMethod())) { + setPixData(paymentsRequest, cartData); + } //Set Boleto parameters else if (cartData.getAdyenPaymentMethod().indexOf(PAYMENT_METHOD_BOLETO) == 0) { setBoletoData(paymentsRequest, cartData); } - else if (PAYMENT_METHOD_SEPA_DIRECTDEBIT.equals(cartData.getAdyenPaymentMethod())) { - setSepaDirectDebitData(paymentsRequest, cartData); - } - //For alternate payment methods like iDeal, Paypal etc. else { updatePaymentRequestForAlternateMethod(paymentsRequest, cartData); } - ApplicationInfo applicationInfo = updateApplicationInfoEcom(paymentsRequest.getApplicationInfo()); - paymentsRequest.setApplicationInfo(applicationInfo); - - paymentsRequest.setReturnUrl(cartData.getAdyenReturnUrl()); - paymentsRequest.setRedirectFromIssuerMethod(RequestMethod.POST.toString()); - paymentsRequest.setRedirectToIssuerMethod(RequestMethod.POST.toString()); - return paymentsRequest; } + protected CardDetails getCardDetails(CartData cartData, String selectedReference) { + final CardDetails paymentMethodDetails = new CardDetails(); + paymentMethodDetails.encryptedSecurityCode(cartData.getAdyenEncryptedSecurityCode()); + paymentMethodDetails.recurringDetailReference(selectedReference); + Optional.ofNullable(cartData.getAdyenCardBrand()).ifPresent(paymentMethodDetails::setType); + return paymentMethodDetails; + } + public PaymentsRequest createPaymentsRequest(final String merchantAccount, final CartData cartData, final PaymentMethodDetails paymentMethodDetails, final RequestInfo requestInfo, final CustomerModel customerModel) { - PaymentsRequest paymentsRequest = new PaymentsRequest(); - updatePaymentRequest(merchantAccount, cartData, requestInfo, customerModel, paymentsRequest); - + final PaymentsRequest paymentsRequest = new PaymentsRequest(); + setCommonInfoOnPaymentRequest(merchantAccount, cartData, requestInfo, customerModel, paymentsRequest); + updateApplicationInfoEcom(paymentsRequest.getApplicationInfo()); paymentsRequest.setPaymentMethod(paymentMethodDetails); paymentsRequest.setReturnUrl(cartData.getAdyenReturnUrl()); - ApplicationInfo applicationInfo = updateApplicationInfoEcom(paymentsRequest.getApplicationInfo()); - paymentsRequest.setApplicationInfo(applicationInfo); - return paymentsRequest; } - public PaymentsRequest enhanceForThreeDS2(PaymentsRequest paymentsRequest, CartData cartData) { - if (paymentsRequest.getAdditionalData() == null) { - paymentsRequest.setAdditionalData(new HashMap<>()); - } - paymentsRequest.getAdditionalData().put(ALLOW_3DS2_PROPERTY, is3DS2Allowed().toString()); + protected PaymentsRequest enhanceForThreeDS2(final PaymentsRequest paymentsRequest, final CartData cartData) { + final BrowserInfo browserInfo = Optional.ofNullable(new Gson().fromJson(cartData.getAdyenBrowserInfo(), BrowserInfo.class)) + .orElse(new BrowserInfo()) + .acceptHeader(paymentsRequest.getBrowserInfo().getAcceptHeader()) + .userAgent(paymentsRequest.getBrowserInfo().getUserAgent()); + + paymentsRequest.setAdditionalData(Optional.ofNullable(paymentsRequest.getAdditionalData()).orElse(new HashMap<>())); paymentsRequest.setChannel(PaymentsRequest.ChannelEnum.WEB); - BrowserInfo browserInfo = new Gson().fromJson(cartData.getAdyenBrowserInfo(), BrowserInfo.class); - browserInfo = updateBrowserInfoFromRequest(browserInfo, paymentsRequest); paymentsRequest.setBrowserInfo(browserInfo); - return paymentsRequest; - } - public BrowserInfo updateBrowserInfoFromRequest(BrowserInfo browserInfo, PaymentsRequest paymentsRequest) { - if (browserInfo != null) { - browserInfo.setUserAgent(paymentsRequest.getBrowserInfo().getUserAgent()); - browserInfo.setAcceptHeader(paymentsRequest.getBrowserInfo().getAcceptHeader()); - } - return browserInfo; - } - - public ApplicationInfo updateApplicationInfoEcom(ApplicationInfo applicationInfo) { - updateApplicationInfoPos(applicationInfo); - CommonField adyenPaymentSource = new CommonField(); - adyenPaymentSource.setName(PLUGIN_NAME); - adyenPaymentSource.setVersion(PLUGIN_VERSION); - applicationInfo.setAdyenPaymentSource(adyenPaymentSource); - - return applicationInfo; + return paymentsRequest; } - public ApplicationInfo updateApplicationInfoPos(ApplicationInfo applicationInfo) { - if (applicationInfo == null) { - applicationInfo = new ApplicationInfo(); - } - ExternalPlatform externalPlatform = new ExternalPlatform(); - externalPlatform.setName(PLATFORM_NAME); - externalPlatform.setVersion(getPlatformVersion()); - applicationInfo.setExternalPlatform(externalPlatform); + private void updateApplicationInfoEcom(final ApplicationInfo applicationInfo) { + final CommonField version = new CommonField().name(PLUGIN_NAME).version(PLUGIN_VERSION); - CommonField merchantApplication = new CommonField(); - merchantApplication.setName(PLUGIN_NAME); - merchantApplication.setVersion(PLUGIN_VERSION); - applicationInfo.setMerchantApplication(merchantApplication); + applicationInfo.setExternalPlatform((ExternalPlatform) new ExternalPlatform() + .name(PLATFORM_NAME) + .version(getPlatformVersion())); + applicationInfo.setMerchantApplication(version); + applicationInfo.setAdyenPaymentSource(version); - return applicationInfo; } - private void updatePaymentRequest(final String merchantAccount, final CartData cartData, final RequestInfo requestInfo, final CustomerModel customerModel, PaymentsRequest paymentsRequest) { + protected void setCommonInfoOnPaymentRequest(final String merchantAccount, final CartData cartData, + final RequestInfo requestInfo, final CustomerModel customerModel, + final PaymentsRequest paymentsRequest) { //Get details from CartData to set in PaymentRequest. - String amount = String.valueOf(cartData.getTotalPrice().getValue()); - String currency = cartData.getTotalPrice().getCurrencyIso(); - String reference = cartData.getCode(); - - AddressData billingAddress = cartData.getPaymentInfo() != null ? cartData.getPaymentInfo().getBillingAddress() : null; - AddressData deliveryAddress = cartData.getDeliveryAddress(); + final String amount = String.valueOf(cartData.getTotalPriceWithTax().getValue()); + final String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); + final String reference = cartData.getCode(); + final AddressData billingAddress = cartData.getPaymentInfo() != null ? cartData.getPaymentInfo().getBillingAddress() : null; + final AddressData deliveryAddress = cartData.getDeliveryAddress(); //Get details from HttpServletRequest to set in PaymentRequest. - String userAgent = requestInfo.getUserAgent(); - String acceptHeader = requestInfo.getAcceptHeader(); - String shopperIP = requestInfo.getShopperIp(); - String origin = requestInfo.getOrigin(); - String shopperLocale = requestInfo.getShopperLocale(); - - paymentsRequest.setAmountData(amount, currency) + final String userAgent = requestInfo.getUserAgent(); + final String acceptHeader = requestInfo.getAcceptHeader(); + final String shopperIP = requestInfo.getShopperIp(); + final String origin = requestInfo.getOrigin(); + final String shopperLocale = requestInfo.getShopperLocale(); + + paymentsRequest + .amount(Util.createAmount(amount, currency)) .reference(reference) .merchantAccount(merchantAccount) - .addBrowserInfoData(userAgent, acceptHeader) + .browserInfo(new BrowserInfo().userAgent(userAgent).acceptHeader(acceptHeader)) .shopperIP(shopperIP) .origin(origin) .shopperLocale(shopperLocale) + .shopperReference(customerModel.getCustomerID()) + .shopperEmail(customerModel.getContactEmail()) + .deliveryAddress(setAddressData(deliveryAddress)) + .billingAddress(setAddressData(billingAddress)) + .telephoneNumber(billingAddress.getPhone()) .setCountryCode(getCountryCode(cartData)); - - // set shopper details from CustomerModel. - if (customerModel != null) { - paymentsRequest.setShopperReference(customerModel.getCustomerID()); - paymentsRequest.setShopperEmail(customerModel.getContactEmail()); - } - - // if address details are provided, set it to the PaymentRequest - if (deliveryAddress != null) { - paymentsRequest.setDeliveryAddress(setAddressData(deliveryAddress)); - } - - if (billingAddress != null) { - paymentsRequest.setBillingAddress(setAddressData(billingAddress)); - // set PhoneNumber if it is provided - String phone = billingAddress.getPhone(); - if (phone != null && ! phone.isEmpty()) { - paymentsRequest.setTelephoneNumber(phone); - } - } - - if (PAYMENT_METHOD_PIX.equals(cartData.getAdyenPaymentMethod())) { - setPixData(paymentsRequest, cartData); - } - } - private void updatePaymentRequestForCC(PaymentsRequest paymentsRequest, CartData cartData, RecurringContractMode recurringContractMode) { - Recurring recurringContract = getRecurringContractType(recurringContractMode); - Recurring.ContractEnum contractEnum = null; - if (recurringContract != null) { - contractEnum = recurringContract.getContract(); - } - - paymentsRequest.setEnableRecurring(false); - paymentsRequest.setEnableOneClick(false); - - String encryptedCardNumber = cartData.getAdyenEncryptedCardNumber(); - String encryptedExpiryMonth = cartData.getAdyenEncryptedExpiryMonth(); - String encryptedExpiryYear = cartData.getAdyenEncryptedExpiryYear(); - if (cartData.getAdyenInstallments() != null) { - Installments installmentObj = new Installments(); - installmentObj.setValue(cartData.getAdyenInstallments()); - paymentsRequest.setInstallments(installmentObj); - } - - if (! StringUtils.isEmpty(encryptedCardNumber) && ! StringUtils.isEmpty(encryptedExpiryMonth) && ! StringUtils.isEmpty(encryptedExpiryYear)) { + protected void updatePaymentRequestForCC(final PaymentsRequest paymentsRequest, final CartData cartData, final RecurringContractMode recurringContractMode) { + final Recurring recurringContract = getRecurringContractType(recurringContractMode); + final Recurring.ContractEnum contract = recurringContract.getContract(); + final String encryptedCardNumber = cartData.getAdyenEncryptedCardNumber(); + final String encryptedExpiryMonth = cartData.getAdyenEncryptedExpiryMonth(); + final String encryptedExpiryYear = cartData.getAdyenEncryptedExpiryYear(); - paymentsRequest.addEncryptedCardData(encryptedCardNumber, encryptedExpiryMonth, encryptedExpiryYear, cartData.getAdyenEncryptedSecurityCode(), cartData.getAdyenCardHolder()); - } - if (Recurring.ContractEnum.ONECLICK_RECURRING == contractEnum) { + if (Recurring.ContractEnum.ONECLICK_RECURRING.equals(contract)) { paymentsRequest.setEnableRecurring(true); - if(cartData.getAdyenRememberTheseDetails()) { + if(Boolean.TRUE.equals(cartData.getAdyenRememberTheseDetails())) { paymentsRequest.setEnableOneClick(true); } - } else if (Recurring.ContractEnum.ONECLICK == contractEnum && cartData.getAdyenRememberTheseDetails() ) { + } else if (Recurring.ContractEnum.ONECLICK.equals(contract) && Boolean.TRUE.equals(cartData.getAdyenRememberTheseDetails()) ) { paymentsRequest.setEnableOneClick(true); - } else if (Recurring.ContractEnum.RECURRING == contractEnum) { + } else if (Recurring.ContractEnum.RECURRING.equals(contract)) { paymentsRequest.setEnableRecurring(true); } - // Set storeDetails parameter when shopper selected to have his card details stored - if (cartData.getAdyenRememberTheseDetails()) { - DefaultPaymentMethodDetails paymentMethodDetails = (DefaultPaymentMethodDetails) paymentsRequest.getPaymentMethod(); - paymentMethodDetails.setStoreDetails(true); + if (StringUtils.isNotEmpty(encryptedCardNumber) && StringUtils.isNotEmpty(encryptedExpiryMonth) && StringUtils.isNotEmpty(encryptedExpiryYear)) { + paymentsRequest.setPaymentMethod(new CardDetails() + .encryptedCardNumber(encryptedCardNumber) + .encryptedExpiryMonth(encryptedExpiryMonth) + .encryptedExpiryYear(encryptedExpiryYear) + .encryptedSecurityCode(cartData.getAdyenEncryptedSecurityCode()) + .holderName(cartData.getAdyenCardHolder())); } // For Dual branded card set card brand as payment method type - if (!StringUtils.isEmpty(cartData.getAdyenCardBrand())) { - paymentsRequest.getPaymentMethod().setType(cartData.getAdyenCardBrand()); + if (StringUtils.isNotEmpty(cartData.getAdyenCardBrand())) { + paymentsRequest.getPaymentMethod().setType(DUAL_BRANDED_NOT_SELECTED_FLOW_PAYMENT_TYPE); + } + if (cartData.getAdyenInstallments() != null) { + Installments installmentObj = new Installments(); + installmentObj.setValue(cartData.getAdyenInstallments()); + paymentsRequest.setInstallments(installmentObj); } } - private void updatePaymentRequestForDC(PaymentsRequest paymentsRequest, CartData cartData, RecurringContractMode recurringContractMode) { + protected void updatePaymentRequestForDC(final PaymentsRequest paymentsRequest, final CartData cartData, final RecurringContractMode recurringContractMode) { - Recurring recurringContract = getRecurringContractType(recurringContractMode); - Recurring.ContractEnum contractEnum = null; - if (recurringContract != null) { - contractEnum = recurringContract.getContract(); - } + final Recurring recurringContract = getRecurringContractType(recurringContractMode); + final Recurring.ContractEnum contract = recurringContract.getContract(); + final String encryptedCardNumber = cartData.getAdyenEncryptedCardNumber(); + final String encryptedExpiryMonth = cartData.getAdyenEncryptedExpiryMonth(); + final String encryptedExpiryYear = cartData.getAdyenEncryptedExpiryYear(); + final String cardBrand = cartData.getAdyenCardBrand(); - paymentsRequest.setEnableRecurring(false); - paymentsRequest.setEnableOneClick(false); - - String encryptedCardNumber = cartData.getAdyenEncryptedCardNumber(); - String encryptedExpiryMonth = cartData.getAdyenEncryptedExpiryMonth(); - String encryptedExpiryYear = cartData.getAdyenEncryptedExpiryYear(); - if ((Recurring.ContractEnum.ONECLICK_RECURRING == contractEnum || Recurring.ContractEnum.ONECLICK == contractEnum) && cartData.getAdyenRememberTheseDetails()) { + if ((Recurring.ContractEnum.ONECLICK_RECURRING.equals(contract) || Recurring.ContractEnum.ONECLICK.equals(contract)) + && cartData.getAdyenRememberTheseDetails()) { paymentsRequest.setEnableOneClick(true); } - if (! StringUtils.isEmpty(encryptedCardNumber) && ! StringUtils.isEmpty(encryptedExpiryMonth) && ! StringUtils.isEmpty(encryptedExpiryYear)) { - paymentsRequest.addEncryptedCardData(encryptedCardNumber, encryptedExpiryMonth, encryptedExpiryYear, cartData.getAdyenEncryptedSecurityCode(), cartData.getAdyenCardHolder()); - } - // Set storeDetails parameter when shopper selected to have his card details stored - if (cartData.getAdyenRememberTheseDetails()) { - DefaultPaymentMethodDetails paymentMethodDetails = (DefaultPaymentMethodDetails) paymentsRequest.getPaymentMethod(); - paymentMethodDetails.setStoreDetails(true); + if (StringUtils.isNotEmpty(encryptedCardNumber) && StringUtils.isNotEmpty(encryptedExpiryMonth) && StringUtils.isNotEmpty(encryptedExpiryYear)) { + paymentsRequest.setPaymentMethod(new CardDetails() + .encryptedCardNumber(encryptedCardNumber) + .encryptedExpiryMonth(encryptedExpiryMonth) + .encryptedExpiryYear(encryptedExpiryYear) + .encryptedSecurityCode(cartData.getAdyenEncryptedSecurityCode()) + .holderName(cartData.getAdyenCardHolder())); } - String cardBrand = cartData.getAdyenCardBrand(); paymentsRequest.putAdditionalDataItem(OVERWRITE_BRAND_PROPERTY, "true"); paymentsRequest.getPaymentMethod().setType(cardBrand); } - private void updatePaymentRequestForAlternateMethod(PaymentsRequest paymentsRequest, CartData cartData) { - String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); - DefaultPaymentMethodDetails paymentMethod = new DefaultPaymentMethodDetails(); - paymentsRequest.setPaymentMethod(paymentMethod); - paymentMethod.setType(adyenPaymentMethod); + protected void updatePaymentRequestForAlternateMethod(final PaymentsRequest paymentsRequest, final CartData cartData) { + final String adyenPaymentMethod = cartData.getAdyenPaymentMethod(); + + paymentsRequest.setShopperName(getShopperNameFromAddress(cartData.getDeliveryAddress())); + paymentsRequest.setPaymentMethod(adyenPaymentMethodDetailsBuilderExecutor.createPaymentMethodDetails(cartData)); paymentsRequest.setReturnUrl(cartData.getAdyenReturnUrl()); - if (ISSUER_PAYMENT_METHODS.contains(adyenPaymentMethod)) { - paymentMethod.setIssuer(cartData.getAdyenIssuerId()); - } else if (adyenPaymentMethod.startsWith(KLARNA) + + if (adyenPaymentMethod.startsWith(PAYMENT_METHOD_KLARNA) || adyenPaymentMethod.startsWith(PAYMENT_METHOD_FACILPAY_PREFIX) - || OPENINVOICE_METHODS_API.contains(adyenPaymentMethod)) { + || OPENINVOICE_METHODS_API.contains(adyenPaymentMethod) + || adyenPaymentMethod.contains(RATEPAY)) { setOpenInvoiceData(paymentsRequest, cartData); - } else if (adyenPaymentMethod.equals(PAYMENT_METHOD_PAYPAL) && cartData.getDeliveryAddress() != null) { - Name shopperName = getShopperNameFromAddress(cartData.getDeliveryAddress()); - paymentsRequest.setShopperName(shopperName); - } else if (adyenPaymentMethod.equals(GIFT_CARD)) { - paymentMethod.setBrand(cartData.getAdyenGiftCardBrand()); } } - private String getCountryCode(CartData cartData) { + protected String getCountryCode(final CartData cartData) { //Identify country code based on shopper's delivery address - String countryCode = ""; - AddressData billingAddressData = cartData.getPaymentInfo() != null ? cartData.getPaymentInfo().getBillingAddress() : null; - if (billingAddressData != null) { - CountryData billingCountry = billingAddressData.getCountry(); - if (billingCountry != null) { - countryCode = billingCountry.getIsocode(); - } - } else { - AddressData deliveryAddressData = cartData.getDeliveryAddress(); - if (deliveryAddressData != null) { - CountryData deliveryCountry = deliveryAddressData.getCountry(); - if (deliveryCountry != null) { - countryCode = deliveryCountry.getIsocode(); - } - } - } - return countryCode; + return Optional.ofNullable(cartData.getPaymentInfo()) + .map(CCPaymentInfoData::getBillingAddress) + .map(billingAddress -> Optional.ofNullable(billingAddress).or(() -> Optional.ofNullable(cartData.getDeliveryAddress()))) + .filter(Optional::isPresent) + .map(Optional::get) + .map(AddressData::getCountry) + .map(CountryData::getIsocode) + .orElse(""); } public CaptureRequest createCaptureRequest(final String merchantAccount, final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) { CaptureRequest request = new CaptureRequest().fillAmount(String.valueOf(amount), currency.getCurrencyCode()) - .merchantAccount(merchantAccount) - .originalReference(authReference) - .reference(merchantReference); + .merchantAccount(merchantAccount) + .originalReference(authReference) + .reference(merchantReference); updateApplicationInfoEcom(request.getApplicationInfo()); return request; } @@ -497,9 +393,9 @@ public CancelOrRefundRequest createCancelOrRefundRequest(final String merchantAc public RefundRequest createRefundRequest(final String merchantAccount, final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) { RefundRequest request = new RefundRequest().fillAmount(String.valueOf(amount), currency.getCurrencyCode()) - .merchantAccount(merchantAccount) - .originalReference(authReference) - .reference(merchantReference); + .merchantAccount(merchantAccount) + .originalReference(authReference) + .reference(merchantReference); updateApplicationInfoEcom(request.getApplicationInfo()); return request; } @@ -557,7 +453,7 @@ public TerminalAPIRequest createTerminalAPIRequest(final CartData cartData, Cust saleData.setSaleTransactionID(transactionIdentification); //Set recurring contract, if exists - if(customer != null) { + if (customer != null) { String shopperReference = customer.getCustomerID(); String shopperEmail = customer.getContactEmail(); Recurring recurringContract = getRecurringContractType(recurringContractMode); @@ -568,7 +464,7 @@ public TerminalAPIRequest createTerminalAPIRequest(final CartData cartData, Cust saleToAcquirerData.setShopperReference(shopperReference); saleToAcquirerData.setRecurringContract(recurringContract.getContract().toString()); } - updateApplicationInfoPos(saleToAcquirerData.getApplicationInfo()); + updateApplicationInfoEcom(saleToAcquirerData.getApplicationInfo()); saleData.setSaleToAcquirerData(saleToAcquirerData); } @@ -576,8 +472,8 @@ public TerminalAPIRequest createTerminalAPIRequest(final CartData cartData, Cust PaymentTransaction paymentTransaction = new PaymentTransaction(); AmountsReq amountsReq = new AmountsReq(); - amountsReq.setCurrency(cartData.getTotalPrice().getCurrencyIso()); - amountsReq.setRequestedAmount(cartData.getTotalPrice().getValue()); + amountsReq.setCurrency(cartData.getTotalPriceWithTax().getCurrencyIso()); + amountsReq.setRequestedAmount(cartData.getTotalPriceWithTax().getValue()); paymentTransaction.setAmountsReq(amountsReq); paymentRequest.setPaymentTransaction(paymentTransaction); @@ -604,23 +500,23 @@ private Address setAddressData(AddressData addressData) { address.setStreet("NA"); // set the actual values if they are available - if (addressData.getTown() != null && ! addressData.getTown().isEmpty()) { + if (addressData.getTown() != null && !addressData.getTown().isEmpty()) { address.setCity(addressData.getTown()); } - if (addressData.getCountry() != null && ! addressData.getCountry().getIsocode().isEmpty()) { + if (addressData.getCountry() != null && !addressData.getCountry().getIsocode().isEmpty()) { address.setCountry(addressData.getCountry().getIsocode()); } - if (addressData.getLine1() != null && ! addressData.getLine1().isEmpty()) { + if (addressData.getLine1() != null && !addressData.getLine1().isEmpty()) { address.setStreet(addressData.getLine1()); } - if (addressData.getLine2() != null && ! addressData.getLine2().isEmpty()) { + if (addressData.getLine2() != null && !addressData.getLine2().isEmpty()) { address.setHouseNumberOrName(addressData.getLine2()); } - if (addressData.getPostalCode() != null && ! address.getPostalCode().isEmpty()) { + if (addressData.getPostalCode() != null && !address.getPostalCode().isEmpty()) { address.setPostalCode(addressData.getPostalCode()); } @@ -695,7 +591,7 @@ private Name getShopperNameFromAddress(AddressData addressData) { shopperName.setLastName(addressData.getLastName()); shopperName.setGender(Name.GenderEnum.UNKNOWN); - if (addressData.getTitleCode() != null && ! addressData.getTitleCode().isEmpty()) { + if (addressData.getTitleCode() != null && !addressData.getTitleCode().isEmpty()) { if (addressData.getTitleCode().equals("mrs") || addressData.getTitleCode().equals("miss") || addressData.getTitleCode().equals("ms")) { shopperName.setGender(Name.GenderEnum.FEMALE); } else { @@ -718,26 +614,26 @@ public void setOpenInvoiceData(PaymentRequest paymentRequest, CartData cartData, paymentRequest.setDateOfBirth(cartData.getAdyenDob()); } - if (cartData.getAdyenSocialSecurityNumber() != null && ! cartData.getAdyenSocialSecurityNumber().isEmpty()) { + if (cartData.getAdyenSocialSecurityNumber() != null && !cartData.getAdyenSocialSecurityNumber().isEmpty()) { paymentRequest.setSocialSecurityNumber(cartData.getAdyenSocialSecurityNumber()); } - if (cartData.getAdyenDfValue() != null && ! cartData.getAdyenDfValue().isEmpty()) { + if (cartData.getAdyenDfValue() != null && !cartData.getAdyenDfValue().isEmpty()) { paymentRequest.setDeviceFingerprint(cartData.getAdyenDfValue()); } // set the invoice lines List invoiceLines = new ArrayList(); - String currency = cartData.getTotalPrice().getCurrencyIso(); + String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); for (OrderEntryData entry : cartData.getEntries()) { // Use totalPrice because the basePrice does include tax as well if you have configured this to be calculated in the price - BigDecimal pricePerItem = entry.getTotalPrice().getValue().divide(new BigDecimal(entry.getQuantity())); + BigDecimal pricePerItem = entry.getBasePrice().getValue(); String description = "NA"; - if (entry.getProduct().getName() != null && ! entry.getProduct().getName().equals("")) { + if (entry.getProduct().getName() != null && !entry.getProduct().getName().equals("")) { description = entry.getProduct().getName(); } @@ -774,17 +670,17 @@ public void setOpenInvoiceData(PaymentRequest paymentRequest, CartData cartData, invoiceLine.setVatCategory(VatCategory.NONE); // An unique id for this item. Required for RatePay if the description of each item is not unique. - if (! entry.getProduct().getCode().isEmpty()) { + if (!entry.getProduct().getCode().isEmpty()) { invoiceLine.setItemId(entry.getProduct().getCode()); } invoiceLine.setNumberOfItems(entry.getQuantity().intValue()); - if (entry.getProduct() != null && ! entry.getProduct().getCode().isEmpty()) { + if (entry.getProduct() != null && !entry.getProduct().getCode().isEmpty()) { invoiceLine.setItemId(entry.getProduct().getCode()); } - if (entry.getProduct() != null && ! entry.getProduct().getCode().isEmpty()) { + if (entry.getProduct() != null && !entry.getProduct().getCode().isEmpty()) { invoiceLine.setItemId(entry.getProduct().getCode()); } @@ -824,11 +720,11 @@ public void setOpenInvoiceData(PaymentsRequest paymentsRequest, CartData cartDat paymentsRequest.setDateOfBirth(cartData.getAdyenDob()); } - if (cartData.getAdyenSocialSecurityNumber() != null && ! cartData.getAdyenSocialSecurityNumber().isEmpty()) { + if (cartData.getAdyenSocialSecurityNumber() != null && !cartData.getAdyenSocialSecurityNumber().isEmpty()) { paymentsRequest.setSocialSecurityNumber(cartData.getAdyenSocialSecurityNumber()); } - if (cartData.getAdyenDfValue() != null && ! cartData.getAdyenDfValue().isEmpty()) { + if (cartData.getAdyenDfValue() != null && !cartData.getAdyenDfValue().isEmpty()) { paymentsRequest.setDeviceFingerprint(cartData.getAdyenDfValue()); } @@ -842,151 +738,152 @@ public void setOpenInvoiceData(PaymentsRequest paymentsRequest, CartData cartDat // set the invoice lines List invoiceLines = new ArrayList<>(); - String currency = cartData.getTotalPrice().getCurrencyIso(); + String currency = cartData.getTotalPriceWithTax().getCurrencyIso(); for (OrderEntryData entry : cartData.getEntries()) { if (entry.getQuantity() == 0L) { // skip zero quantities continue; } - // Use totalPrice because the basePrice does include tax as well if you have configured this to be calculated in the price - BigDecimal pricePerItem = entry.getTotalPrice().getValue().divide(new BigDecimal(entry.getQuantity())); String description = "NA"; - if (entry.getProduct().getName() != null && ! entry.getProduct().getName().isEmpty()) { + if (entry.getProduct().getName() != null && !entry.getProduct().getName().isEmpty()) { description = entry.getProduct().getName(); } // Tax of total price (included quantity) - Double tax = entry.getTaxValues().stream().map(TaxValue::getAppliedValue).reduce(0.0, (x, y) -> x + y); + Double tax = entry.getTaxValues().stream().map(TaxValue::getAppliedValue).reduce(0.0, Double::sum); // Calculate Tax per quantitiy if (tax > 0) { tax = tax / entry.getQuantity().intValue(); } - // Calculate price without tax - Amount itemAmountWithoutTax = Util.createAmount(pricePerItem.subtract(new BigDecimal(tax)), currency); - Double percentage = entry.getTaxValues().stream().map(TaxValue::getValue).reduce(0.0, (x, y) -> x + y) * 100; + final Double percentage = entry.getTaxValues().stream().map(TaxValue::getValue).reduce(0.0, Double::sum) * 100; + + final LineItem invoiceLine = new LineItem(); - LineItem invoiceLine = new LineItem(); invoiceLine.setDescription(description); /* * The price for one item in the invoice line, represented in minor units. * The due amount for the item, VAT excluded. */ - invoiceLine.setAmountExcludingTax(itemAmountWithoutTax.getValue()); + final Amount itemAmount = Util.createAmount(entry.getBasePrice().getValue(), currency); - // The VAT due for one item in the invoice line, represented in minor units. - invoiceLine.setTaxAmount(Util.createAmount(BigDecimal.valueOf(tax), currency).getValue()); + if (cartData.isNet()) { + invoiceLine.setAmountExcludingTax(itemAmount.getValue()); + invoiceLine.setTaxAmount(Util.createAmount(BigDecimal.valueOf(tax), currency).getValue()); + } else { + invoiceLine.setAmountIncludingTax(itemAmount.getValue()); + } // The VAT percentage for one item in the invoice line, represented in minor units. invoiceLine.setTaxPercentage(percentage.longValue()); - // The country-specific VAT category a product falls under. Allowed values: (High,Low,None) - invoiceLine.setTaxCategory(LineItem.TaxCategoryEnum.NONE); - invoiceLine.setQuantity(entry.getQuantity()); - if (entry.getProduct() != null && ! entry.getProduct().getCode().isEmpty()) { + if (entry.getProduct() != null && !entry.getProduct().getCode().isEmpty()) { invoiceLine.setId(entry.getProduct().getCode()); } - LOG.debug("InvoiceLine Product:" + invoiceLine.toString()); + LOG.debug("InvoiceLine Product:" + invoiceLine); invoiceLines.add(invoiceLine); } // Add delivery costs if (cartData.getDeliveryCost() != null) { - LineItem invoiceLine = new LineItem(); + final LineItem invoiceLine = new LineItem(); invoiceLine.setDescription("Delivery Costs"); - Amount deliveryAmount = Util.createAmount(cartData.getDeliveryCost().getValue().toString(), currency); - invoiceLine.setAmountExcludingTax(deliveryAmount.getValue()); - invoiceLine.setTaxAmount(new Long("0")); - invoiceLine.setTaxPercentage(new Long("0")); - invoiceLine.setTaxCategory(LineItem.TaxCategoryEnum.NONE); + + final Amount deliveryAmount = Util.createAmount(cartData.getDeliveryCost().getValue().toString(), currency); + + if (cartData.isNet()) { + final Double taxAmount = cartData.getEntries().stream() + .map(OrderEntryData::getTaxValues) + .flatMap(Collection::stream) + .map(TaxValue::getAppliedValue) + .collect(Collectors.toList()) + .stream() + .reduce(0.0, Double::sum); + invoiceLine.setAmountExcludingTax(deliveryAmount.getValue()); + invoiceLine.setTaxAmount(Util.createAmount(cartData.getTotalTax().getValue().subtract(new BigDecimal(taxAmount)), currency).getValue()); + } else { + invoiceLine.setAmountIncludingTax(deliveryAmount.getValue()); + } + + final Double percentage = cartData.getEntries().stream() + .findFirst() + .map(OrderEntryData::getTaxValues) + .stream() + .flatMap(Collection::stream) + .map(TaxValue::getValue) + .reduce(0.0, Double::sum) * 100; + + invoiceLine.setTaxPercentage(percentage.longValue()); invoiceLine.setQuantity(1L); - LOG.debug("InvoiceLine DeliveryCosts:" + invoiceLine.toString()); + LOG.debug("InvoiceLine DeliveryCosts:" + invoiceLine); invoiceLines.add(invoiceLine); } paymentsRequest.setLineItems(invoiceLines); } - private Name getAfterPayShopperName(CartData cartData) { - Name name = new Name(); - name.setFirstName(cartData.getAdyenFirstName()); - name.setLastName(cartData.getAdyenLastName()); - name.gender(Name.GenderEnum.valueOf(cartData.getAdyenShopperGender())); - return name; + private Name getAfterPayShopperName(final CartData cartData) { + return new Name() + .firstName(cartData.getAdyenFirstName()) + .lastName(cartData.getAdyenLastName()) + .gender(Name.GenderEnum.valueOf(cartData.getAdyenShopperGender())); } /** * Set Boleto payment request data */ - private void setBoletoData(PaymentsRequest paymentsRequest, CartData cartData) { - DefaultPaymentMethodDetails paymentMethodDetails = (DefaultPaymentMethodDetails) (paymentsRequest.getPaymentMethod()); - if (paymentMethodDetails == null) { - paymentMethodDetails = new DefaultPaymentMethodDetails(); - } - paymentMethodDetails.setType(PAYMENT_METHOD_BOLETO_SANTANDER); - paymentsRequest.setPaymentMethod(paymentMethodDetails); + private void setBoletoData(final PaymentsRequest paymentsRequest, final CartData cartData) { + paymentsRequest.setPaymentMethod(adyenPaymentMethodDetailsBuilderExecutor.createPaymentMethodDetails(cartData)); paymentsRequest.setSocialSecurityNumber(cartData.getAdyenSocialSecurityNumber()); - Name shopperName = new Name(); - shopperName.setFirstName(cartData.getAdyenFirstName()); - shopperName.setLastName(cartData.getAdyenLastName()); + final Name shopperName = new Name() + .firstName(cartData.getAdyenFirstName()) + .lastName(cartData.getAdyenLastName()); + paymentsRequest.setShopperName(shopperName); if (paymentsRequest.getBillingAddress() != null) { String stateOrProvinceBilling = paymentsRequest.getBillingAddress().getStateOrProvince(); - if (! StringUtils.isEmpty(stateOrProvinceBilling) && stateOrProvinceBilling.length() > 2) { + if (!StringUtils.isEmpty(stateOrProvinceBilling) && stateOrProvinceBilling.length() > 2) { String shortStateOrProvince = stateOrProvinceBilling.substring(stateOrProvinceBilling.length() - 2); paymentsRequest.getBillingAddress().setStateOrProvince(shortStateOrProvince); } } if (paymentsRequest.getDeliveryAddress() != null) { String stateOrProvinceDelivery = paymentsRequest.getDeliveryAddress().getStateOrProvince(); - if (! StringUtils.isEmpty(stateOrProvinceDelivery) && stateOrProvinceDelivery.length() > 2) { + if (!StringUtils.isEmpty(stateOrProvinceDelivery) && stateOrProvinceDelivery.length() > 2) { String shortStateOrProvince = stateOrProvinceDelivery.substring(stateOrProvinceDelivery.length() - 2); paymentsRequest.getDeliveryAddress().setStateOrProvince(shortStateOrProvince); } } } - private void setSepaDirectDebitData(PaymentsRequest paymentRequest, CartData cartData) { - DefaultPaymentMethodDetails paymentMethodDetails = new DefaultPaymentMethodDetails(); - paymentMethodDetails.setSepaOwnerName(cartData.getAdyenSepaOwnerName()); - paymentMethodDetails.setSepaIbanNumber(cartData.getAdyenSepaIbanNumber()); - paymentMethodDetails.setType(PAYMENT_METHOD_SEPA_DIRECTDEBIT); - paymentRequest.setPaymentMethod(paymentMethodDetails); - } - - private void setPixData(PaymentsRequest paymentsRequest, CartData cartData) { - Name shopperName = new Name(); - shopperName.setFirstName(cartData.getAdyenFirstName()); - shopperName.setLastName(cartData.getAdyenLastName()); - paymentsRequest.setShopperName(shopperName); - paymentsRequest.setSocialSecurityNumber(cartData.getAdyenSocialSecurityNumber()); - List invoiceLines = new ArrayList<>(); - for (OrderEntryData entry : cartData.getEntries()) { - if (entry.getQuantity() == 0L) { - // skip zero quantities - continue; - } + private void setPixData(final PaymentsRequest paymentsRequest, final CartData cartData) { + final List invoiceLines = cartData.getEntries().stream() + .filter(cartEntry -> cartEntry.getQuantity() > 0) + .map(cartEntry -> + new LineItem() + .amountIncludingTax(cartEntry.getBasePrice().getValue().longValue()) + .id(Optional.ofNullable(cartEntry.getProduct().getName()) + .filter(StringUtils::isNotEmpty) + .orElse("NA") + ) + ) + .collect(Collectors.toList()); - BigDecimal productAmountIncludingTax = entry.getBasePrice().getValue(); - String productName = "NA"; - if (entry.getProduct().getName() != null && !entry.getProduct().getName().isEmpty()) { - productName = entry.getProduct().getName(); - } - LineItem lineItem = new LineItem(); - lineItem.setAmountIncludingTax(productAmountIncludingTax.longValue()); - lineItem.setId(productName); - invoiceLines.add(lineItem); - } + paymentsRequest.setSocialSecurityNumber(cartData.getAdyenSocialSecurityNumber()); + paymentsRequest.setShopperName(new Name() + .firstName(cartData.getAdyenFirstName()) + .lastName(cartData.getAdyenLastName()) + ); paymentsRequest.setLineItems(invoiceLines); } @@ -995,20 +892,15 @@ private String getPlatformVersion() { } private Boolean is3DS2Allowed() { - - Configuration configuration = getConfigurationService().getConfiguration(); - boolean is3DS2AllowedValue = false; + final Configuration configuration = getConfigurationService().getConfiguration(); if (configuration.containsKey(IS_3DS2_ALLOWED_PROPERTY)) { - is3DS2AllowedValue = configuration.getBoolean(IS_3DS2_ALLOWED_PROPERTY); + return configuration.getBoolean(IS_3DS2_ALLOWED_PROPERTY); } - return is3DS2AllowedValue; + return false; } public ConfigurationService getConfigurationService() { return configurationService; } - public void setConfigurationService(ConfigurationService configurationService) { - this.configurationService = configurationService; - } } diff --git a/adyenv6core/src/com/adyen/v6/forms/AdyenPaymentForm.java b/adyenv6core/src/com/adyen/v6/forms/AdyenPaymentForm.java index eab1e1aa3..1b631cdeb 100644 --- a/adyenv6core/src/com/adyen/v6/forms/AdyenPaymentForm.java +++ b/adyenv6core/src/com/adyen/v6/forms/AdyenPaymentForm.java @@ -58,6 +58,7 @@ public class AdyenPaymentForm { //HPP private String issuerId; + private String upiVirtualAddress; //SEPA direct debit fields private String sepaOwnerName; @@ -132,6 +133,14 @@ public void setIssuerId(String issuerId) { this.issuerId = issuerId; } + public String getUpiVirtualAddress() { + return upiVirtualAddress; + } + + public void setUpiVirtualAddress(String upiVirtualAddress) { + this.upiVirtualAddress = upiVirtualAddress; + } + public boolean getRememberTheseDetails() { return this.rememberTheseDetails; } diff --git a/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategy.java b/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategy.java new file mode 100644 index 000000000..3633cc92a --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategy.java @@ -0,0 +1,43 @@ +package com.adyen.v6.ordercancel.denialstrategies.impl; + +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.security.PrincipalModel; +import de.hybris.platform.ordercancel.OrderCancelDenialReason; +import de.hybris.platform.ordercancel.OrderCancelDenialStrategy; +import de.hybris.platform.ordercancel.impl.denialstrategies.AbstractCancelDenialStrategy; +import de.hybris.platform.ordercancel.model.OrderCancelConfigModel; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import static de.hybris.platform.servicelayer.util.ServicesUtil.validateParameterNotNull; + +/** + * Implementation of a OrderCancelDenialStrategy considering the conditions of Adyen to do not allow a partial + * order cancel + */ +public class AdyenPartialOrderCancelDenialStrategy extends AbstractCancelDenialStrategy implements OrderCancelDenialStrategy { + + protected static final Logger LOG = LogManager.getLogger(AdyenPartialOrderCancelDenialStrategy.class); + + private static final String ORDER_CANCEL_CONFIG_CANNOT_BE_NULL = "Order cancel config cannot be null"; + private static final String ORDER_MODEL_CANNOT_BE_NULL = "OrderModel cannot be null"; + private static final String THE_PARTIAL_CANCEL_IS_NOT_ALLOWED = "The partial cancel is not allowed."; + + /** + * {@inheritDoc} + */ + @Override + public OrderCancelDenialReason getCancelDenialReason(final OrderCancelConfigModel orderCancelConfigModel, + final OrderModel orderModel, final PrincipalModel principalModel, + final boolean partialCancel, final boolean partialEntryCancel) { + validateParameterNotNull(orderCancelConfigModel, ORDER_CANCEL_CONFIG_CANNOT_BE_NULL); + validateParameterNotNull(orderModel, ORDER_MODEL_CANNOT_BE_NULL); + + if (partialCancel || partialEntryCancel) { + LOG.debug(THE_PARTIAL_CANCEL_IS_NOT_ALLOWED); + return getReason(); + } + + return null; + } +} diff --git a/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategy.java b/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategy.java new file mode 100644 index 000000000..b116c5f5b --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategy.java @@ -0,0 +1,77 @@ +package com.adyen.v6.ordercancel.denialstrategies.impl; + +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.security.PrincipalModel; +import de.hybris.platform.ordercancel.OrderCancelDenialReason; +import de.hybris.platform.ordercancel.OrderCancelDenialStrategy; +import de.hybris.platform.ordercancel.impl.denialstrategies.AbstractCancelDenialStrategy; +import de.hybris.platform.ordercancel.model.OrderCancelConfigModel; +import de.hybris.platform.payment.enums.PaymentTransactionType; +import de.hybris.platform.payment.model.PaymentTransactionEntryModel; +import de.hybris.platform.payment.model.PaymentTransactionModel; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.stream.Stream; + +import static de.hybris.platform.servicelayer.util.ServicesUtil.validateParameterNotNull; + +/** + * Implementation of a OrderCancelDenialStrategy considering the conditions of Adyen to do not allow a partial + * order cancel + */ +public class AdyenPaymentStatusOrderCancelDenialStrategy extends AbstractCancelDenialStrategy implements OrderCancelDenialStrategy { + + protected static final Logger LOG = LogManager.getLogger(AdyenPaymentStatusOrderCancelDenialStrategy.class); + + private static final String ORDER_CANCEL_CONFIG_CANNOT_BE_NULL = "Order cancel config cannot be null"; + private static final String ORDER_MODEL_CANNOT_BE_NULL = "OrderModel cannot be null"; + + /** + * {@inheritDoc} + */ + @Override + public OrderCancelDenialReason getCancelDenialReason(final OrderCancelConfigModel orderCancelConfigModel, + final OrderModel orderModel, final PrincipalModel principalModel, + final boolean partialCancel, final boolean partialEntryCancel) { + validateParameterNotNull(orderCancelConfigModel, ORDER_CANCEL_CONFIG_CANNOT_BE_NULL); + validateParameterNotNull(orderModel, ORDER_MODEL_CANNOT_BE_NULL); + + if (!hasAuthorizedTransactionType(orderModel) || !hasNoCaptureTransactionType(orderModel)) { + return getReason(); + } + + return null; + } + + /** + * Check is order has any {@link PaymentTransactionEntryModel} with status {@code AUTHORIZATION} + * + * @param orderModel + * @return true if there is any {@link PaymentTransactionEntryModel} with status {@code AUTHORIZATION} + */ + protected boolean hasAuthorizedTransactionType(final OrderModel orderModel) { + return orderModel.getPaymentTransactions().stream() + .flatMap(Stream::ofNullable) + .map(PaymentTransactionModel::getEntries) + .flatMap(Stream::ofNullable) + .flatMap(List::stream) + .anyMatch(entry -> PaymentTransactionType.AUTHORIZATION.equals(entry.getType())); + } + + /** + * Check is order has no {@link PaymentTransactionEntryModel} with status {@code AUTHORIZATION} + * + * @param orderModel + * @return true if there is not {@link PaymentTransactionEntryModel} with status {@code AUTHORIZATION} + */ + protected boolean hasNoCaptureTransactionType(final OrderModel orderModel) { + return orderModel.getPaymentTransactions().stream() + .flatMap(Stream::ofNullable) + .map(PaymentTransactionModel::getEntries) + .flatMap(Stream::ofNullable) + .flatMap(List::stream) + .noneMatch(entry -> PaymentTransactionType.CAPTURE.equals(entry.getType())); + } +} diff --git a/adyenv6core/src/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacade.java b/adyenv6core/src/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacade.java new file mode 100644 index 000000000..f055fddad --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacade.java @@ -0,0 +1,26 @@ +package com.adyen.v6.ordermanagement.impl; + +import de.hybris.platform.core.model.order.AbstractOrderEntryModel; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.ordermanagementfacades.cancellation.data.OrderCancelEntryData; +import de.hybris.platform.ordermanagementfacades.cancellation.data.OrderCancelRequestData; +import de.hybris.platform.ordermanagementfacades.order.OmsOrderFacade; +import de.hybris.platform.ordermanagementfacades.order.impl.DefaultOmsOrderFacade; + +import java.util.stream.Collectors; + +/** + * Extension of {@link DefaultOmsOrderFacade}. This has been extended to fix the ootb bug that set the order cancellation + * as partial by default. + */ +public class AdyenDefaultOmsOrderFacade extends DefaultOmsOrderFacade implements OmsOrderFacade { + + /** + * {@inheritDoc} + */ + @Override + protected Boolean isPartialCancel(final OrderCancelRequestData orderCancelRequestData, final OrderModel order) { + return !(orderCancelRequestData.getEntries().stream().map(OrderCancelEntryData::getOrderEntryNumber).collect(Collectors.toList())). + containsAll(order.getEntries().stream().map(AbstractOrderEntryModel::getEntryNumber).collect(Collectors.toList())); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/AdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/AdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..4cadd9085 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/AdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,39 @@ +package com.adyen.v6.paymentmethoddetails.builders; + +import com.adyen.model.checkout.PaymentMethodDetails; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.user.data.AddressData; + +public interface AdyenPaymentMethodDetailsBuilderStrategy { + + String SPACE = " "; + + /** + * Validates if the request qualifies to be applied. + * + * @param cartData The cart to use to perform the payment. + * @return True or false, subject to validations. + */ + boolean isApplicable(final S cartData); + + /** + * Build a PaymentMethodDetails based on the cartData information + * @param cartData + * @return + */ + PaymentMethodDetails buildPaymentMethodDetails(final S cartData); + + //Shopper name, phone number, and email address." + default String getPersonalDetails(final CartData cartData) { + final AddressData addressData = cartData.getDeliveryAddress(); + final StringBuilder personalDetails = new StringBuilder(); + + personalDetails.append(addressData.getFirstName() + SPACE); + personalDetails.append(addressData.getLastName() + SPACE); + personalDetails.append(cartData.getAdyenDob() + SPACE); + personalDetails.append(addressData.getPhone() + SPACE); + personalDetails.append(addressData.getEmail()); + + return personalDetails.toString(); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AffirmPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AffirmPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..fed9039d6 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AffirmPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class AffirmPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.AFFIRM.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(Adyenv6coreConstants.AFFIRM); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AfterpayAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AfterpayAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..b5b404a11 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AfterpayAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,36 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.AfterpayDetails; +import com.adyen.model.checkout.details.KlarnaDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class AfterpayAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + + return AfterpayDetails.AFTERPAY_DEFAULT.equals(cartPaymentMethod) || + AfterpayDetails.AFTERPAYTOUCH.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + + return new AfterpayDetails() + .type(cartData.getAdyenPaymentMethod()) + .personalDetails(getPersonalDetails(cartData)); + } + +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AmazonpayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AmazonpayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..96ed9ef6a --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/AmazonpayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; + +import com.adyen.model.checkout.details.AmazonPayDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +public class AmazonpayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + + return AmazonPayDetails.AMAZONPAY.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + + return new AmazonPayDetails(); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/BoletoBancarioSantanderAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/BoletoBancarioSantanderAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..d1fff7f9c --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/BoletoBancarioSantanderAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,31 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.constants.ApiConstants; +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class BoletoBancarioSantanderAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + return ApiConstants.SelectedBrand.BOLETO_SANTANDER.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails() + .type(ApiConstants.SelectedBrand.BOLETO_SANTANDER); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/ClearpayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/ClearpayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..321c6a133 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/ClearpayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class ClearpayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.CLEARPAY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(Adyenv6coreConstants.CLEARPAY); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/CreditCardAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/CreditCardAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..c730658a7 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/CreditCardAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,33 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class CreditCardAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + return Adyenv6coreConstants.PAYMENT_METHOD_CC.equals(cartPaymentMethod) || + CardDetails.CARD.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails() + .type(CardDetails.CARD) + .brand(cartData.getAdyenCardBrand()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/DotpayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/DotpayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..0d691b8c7 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/DotpayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class DotpayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_DOTPAY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/EPSAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/EPSAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..33bb931e9 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/EPSAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.GenericIssuerPaymentMethodDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class EPSAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_EPS.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new GenericIssuerPaymentMethodDetails().type(Adyenv6coreConstants.PAYMENT_METHOD_EPS).issuer(cartData.getAdyenIssuerId()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/FacilpayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/FacilpayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..153938a47 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/FacilpayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class FacilpayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_FACILPAY_PREFIX.indexOf(cartData.getAdyenPaymentMethod()) >= 0; + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiftcardPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiftcardPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..e4987842d --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiftcardPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,31 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +public class GiftcardPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + + return CardDetails.GIFTCARD.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + + return new CardDetails() + .type(CardDetails.GIFTCARD) + .brand(cartData.getAdyenGiftCardBrand()); + } + +} \ No newline at end of file diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiropayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiropayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..7d0f4189a --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/GiropayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,27 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.GiropayDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class GiropayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return GiropayDetails.GIROPAY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new GiropayDetails(); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/IdealAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/IdealAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..13bef8e9e --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/IdealAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.IdealDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class IdealAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_IDEAL.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new IdealDetails().issuer(cartData.getAdyenIssuerId()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/InteracPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/InteracPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..966eee34e --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/InteracPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class InteracPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_INTERAC.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/KlarnaAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/KlarnaAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..f218c442e --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/KlarnaAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,35 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.KlarnaDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class KlarnaAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + final String cartPaymentMethod = cartData.getAdyenPaymentMethod(); + + return KlarnaDetails.KLARNA.equals(cartPaymentMethod) || + KlarnaDetails.KLARNA_ACCOUNT.equals(cartPaymentMethod) || + KlarnaDetails.KLARNA_PAY_NOW.equals(cartPaymentMethod); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + + return new KlarnaDetails() + .type(cartData.getAdyenPaymentMethod()); + } + +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MolpayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MolpayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..45b32d1a1 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MolpayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,31 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.MolPayDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class MolpayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return MolPayDetails.EBANKING_TH.equals(cartData.getAdyenPaymentMethod()) || + MolPayDetails.EBANKING_MY.equals(cartData.getAdyenPaymentMethod()) || + MolPayDetails.EBANKING_VN.equals(cartData.getAdyenPaymentMethod()) || + MolPayDetails.EBANKING_FPX_MY.equals(cartData.getAdyenPaymentMethod()) || + MolPayDetails.EBANKING_DIRECT_MY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new MolPayDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MultibancoPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MultibancoPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..4e641125e --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/MultibancoPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class MultibancoPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_MULTIBANCO.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OneyPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OneyPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..456f416a6 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OneyPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class OneyPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return cartData.getAdyenPaymentMethod().startsWith(Adyenv6coreConstants.PAYMENT_METHOD_FACILPAY_PREFIX); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OnlineBankingPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OnlineBankingPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..a4211b772 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/OnlineBankingPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.GenericIssuerPaymentMethodDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class OnlineBankingPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return GenericIssuerPaymentMethodDetails.ONLINEBANKING_IN.equals(cartData.getAdyenPaymentMethod()) || Adyenv6coreConstants.PAYMENT_METHOD_ONLINEBANKING_PL.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new GenericIssuerPaymentMethodDetails().type(cartData.getAdyenPaymentMethod()).issuer(cartData.getAdyenIssuerId()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaybrightPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaybrightPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..e85fe15ed --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaybrightPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,30 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class PaybrightPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + //TODO Paybright has a missing PaymentMethodDetails + return Adyenv6coreConstants.PAYBRIGHT.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + //TODO Paybright has a missing PaymentMethodDetails + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..44cfef7c8 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,30 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.PayPalDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class PaypalAdyenPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return PayPalDetails.PAYPAL.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new PayPalDetails() + .subtype(PayPalDetails.SubtypeEnum.SDK) + .payerID(this.getPersonalDetails(cartData)); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaytmPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaytmPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..d048015c5 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/PaytmPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class PaytmPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_PAYTM.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..266ce780e --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class RatepayPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return cartData.getAdyenPaymentMethod().contains(Adyenv6coreConstants.RATEPAY); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..13d2405ef --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.SepaDirectDebitDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class SepaDirectDebitPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return SepaDirectDebitDetails.SEPADIRECTDEBIT.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new SepaDirectDebitDetails() + .ownerName(cartData.getAdyenSepaOwnerName()) + .iban(cartData.getAdyenSepaIbanNumber()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SofortPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SofortPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..a6a15a390 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/SofortPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class SofortPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_SOFORT.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/TrustyPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/TrustyPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..f618f4ad2 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/TrustyPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class TrustyPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_TRUSTLY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new CardDetails().type(Adyenv6coreConstants.PAYMENT_METHOD_TRUSTLY); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/UPIPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/UPIPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..a7af9082b --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/UPIPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.UpiCollectDetails; +import com.adyen.model.checkout.details.UpiDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class UPIPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return cartData.getAdyenPaymentMethod().contains(UpiDetails.UPI); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new UpiCollectDetails().virtualPaymentAddress(cartData.getAdyenUPIVirtualAddress()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WalletsIndiaPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WalletsIndiaPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..2afd2552a --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WalletsIndiaPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,28 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.GenericIssuerPaymentMethodDetails; +import com.adyen.model.checkout.details.PayUUpiDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class WalletsIndiaPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return GenericIssuerPaymentMethodDetails.WALLET_IN.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new GenericIssuerPaymentMethodDetails().type(cartData.getAdyenPaymentMethod()).issuer(cartData.getAdyenIssuerId()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WechatpayWebPaymentMethodDetailsBuilderStrategy.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WechatpayWebPaymentMethodDetailsBuilderStrategy.java new file mode 100644 index 000000000..75b9270e3 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/builders/impl/WechatpayWebPaymentMethodDetailsBuilderStrategy.java @@ -0,0 +1,29 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.model.checkout.details.WeChatPayDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import de.hybris.platform.commercefacades.order.data.CartData; + +/** + * {@inheritDoc} + */ +public class WechatpayWebPaymentMethodDetailsBuilderStrategy implements AdyenPaymentMethodDetailsBuilderStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isApplicable(final CartData cartData) { + return Adyenv6coreConstants.PAYMENT_METHOD_WECHATPAY.equals(cartData.getAdyenPaymentMethod()); + } + + /** + * {@inheritDoc} + */ + @Override + public PaymentMethodDetails buildPaymentMethodDetails(final CartData cartData) { + return new WeChatPayDetails().type(cartData.getAdyenPaymentMethod()); + } +} diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/AdyenPaymentMethodDetailsBuilderExecutor.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/AdyenPaymentMethodDetailsBuilderExecutor.java new file mode 100644 index 000000000..3ae79a6cc --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/AdyenPaymentMethodDetailsBuilderExecutor.java @@ -0,0 +1,16 @@ +package com.adyen.v6.paymentmethoddetails.executors; + +import com.adyen.model.checkout.PaymentMethodDetails; +import de.hybris.platform.commercefacades.order.data.CartData; + +public interface AdyenPaymentMethodDetailsBuilderExecutor { + + /** + * Validate if is applicable and create the PaymentMethodDetails + * + * @param source {@link CartData} + * @return The {@link PaymentMethodDetails}. + */ + T createPaymentMethodDetails(S source); +} + diff --git a/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/impl/AdyenPaymentMethodDetailsStrategyExecutorImpl.java b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/impl/AdyenPaymentMethodDetailsStrategyExecutorImpl.java new file mode 100644 index 000000000..f625e1387 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/paymentmethoddetails/executors/impl/AdyenPaymentMethodDetailsStrategyExecutorImpl.java @@ -0,0 +1,26 @@ +package com.adyen.v6.paymentmethoddetails.executors.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.v6.paymentmethoddetails.builders.AdyenPaymentMethodDetailsBuilderStrategy; +import com.adyen.v6.paymentmethoddetails.executors.AdyenPaymentMethodDetailsBuilderExecutor; +import de.hybris.platform.commercefacades.order.data.CartData; + +import java.util.List; + +public class AdyenPaymentMethodDetailsStrategyExecutorImpl implements AdyenPaymentMethodDetailsBuilderExecutor { + + protected final List> strategies; + + public AdyenPaymentMethodDetailsStrategyExecutorImpl(final List> strategies) { + this.strategies = strategies; + } + + @Override + public PaymentMethodDetails createPaymentMethodDetails(final CartData cartData) { + return strategies.stream() + .filter(strategy -> strategy.isApplicable(cartData)) + .findAny() + .map(strategy -> strategy.buildPaymentMethodDetails(cartData)) + .orElseThrow(() -> new RuntimeException("Not strategies were found for command request with payment type: [" + cartData.getAdyenPaymentMethod() + "]")); + } +} diff --git a/adyenv6core/src/com/adyen/v6/populator/AdyenOrderCancelPopulator.java b/adyenv6core/src/com/adyen/v6/populator/AdyenOrderCancelPopulator.java new file mode 100644 index 000000000..c408f1b01 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/populator/AdyenOrderCancelPopulator.java @@ -0,0 +1,48 @@ +package com.adyen.v6.populator; + +import de.hybris.platform.commercefacades.order.data.OrderData; +import de.hybris.platform.core.model.order.AbstractOrderEntryModel; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.user.UserModel; +import de.hybris.platform.ordermanagementfacades.order.converters.populator.OrderCancelPopulator; +import de.hybris.platform.servicelayer.dto.converter.ConversionException; + +import java.util.Map; + +import static de.hybris.platform.servicelayer.util.ServicesUtil.validateParameterNotNull; + +public class AdyenOrderCancelPopulator extends OrderCancelPopulator { + + /** + * {@inheritDoc} + */ + @Override + public void populate(final OrderModel source, final OrderData target) throws ConversionException { + validateParameterNotNull(source, "Parameter source cannot be null."); + validateParameterNotNull(target, "Parameter target cannot be null."); + + final UserModel userModel = getUserService().getCurrentUser(); + final boolean isFullCancellationAllowed = getOrderCancelService() + .isCancelPossible(source, userModel, false, false).isAllowed(); + final boolean isPartialCancellationAllowed = getOrderCancelService() + .isCancelPossible(source, userModel, false, false).isAllowed(); + target.setCancellable(isFullCancellationAllowed || isPartialCancellationAllowed); + + final Map cancellableEntryQuantityMap = getCancelableEntriesStrategy() + .getAllCancelableEntries(source, userModel); + cancellableEntryQuantityMap.forEach((entry, qty) -> target.getEntries().forEach(orderEntryData -> { + // Case of MultiD product + if (isMultidimensionalEntry(orderEntryData)) { + orderEntryData.getEntries().stream() + .filter(nestedOrderEntry -> nestedOrderEntry.getEntryNumber().equals(entry.getEntryNumber())) + .forEach(nestedOrderEntryData -> nestedOrderEntryData.setCancellableQty(qty)); + } + // Case of non MultiD product + else { + if (orderEntryData.getEntryNumber().equals(entry.getEntryNumber())) { + orderEntryData.setCancellableQty(qty); + } + } + })); + } +} diff --git a/adyenv6core/src/com/adyen/v6/populator/CartPopulator.java b/adyenv6core/src/com/adyen/v6/populator/CartPopulator.java index f414fac37..f45fe81ef 100644 --- a/adyenv6core/src/com/adyen/v6/populator/CartPopulator.java +++ b/adyenv6core/src/com/adyen/v6/populator/CartPopulator.java @@ -39,6 +39,7 @@ public void populate(final CartModel source, final CartData target) throws Conve if (paymentInfo != null && isAdyenPaymentInfo(paymentInfo)) { target.setAdyenPaymentMethod(paymentInfo.getAdyenPaymentMethod()); target.setAdyenIssuerId(paymentInfo.getAdyenIssuerId()); + target.setAdyenUPIVirtualAddress(paymentInfo.getAdyenUPIVirtualAddress()); target.setAdyenRememberTheseDetails(paymentInfo.getAdyenRememberTheseDetails()); target.setAdyenSelectedReference(paymentInfo.getAdyenSelectedReference()); target.setAdyenDob(paymentInfo.getAdyenDob()); diff --git a/adyenv6core/src/com/adyen/v6/service/AdyenAmazonPayIntegratorService.java b/adyenv6core/src/com/adyen/v6/service/AdyenAmazonPayIntegratorService.java new file mode 100644 index 000000000..ab832d3fa --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/service/AdyenAmazonPayIntegratorService.java @@ -0,0 +1,15 @@ +package com.adyen.v6.service; + +/** + * Service which takes care of the interaction with amazonpay API + */ +public interface AdyenAmazonPayIntegratorService { + + /** + * Get the amazonpayToken from the amazon API reaching the checkoutSession endpoint + * + * @param checkoutSessionId The checkoutSessionId provided from Adyen + * @return the amazonPayToken associated to the given checkoutSessionId + */ + String getAmazonPayTokenByCheckoutSessionId(final String checkoutSessionId); +} diff --git a/adyenv6core/src/com/adyen/v6/service/AdyenPaymentService.java b/adyenv6core/src/com/adyen/v6/service/AdyenPaymentService.java index 95310af79..030907dd1 100644 --- a/adyenv6core/src/com/adyen/v6/service/AdyenPaymentService.java +++ b/adyenv6core/src/com/adyen/v6/service/AdyenPaymentService.java @@ -22,11 +22,7 @@ import com.adyen.httpclient.HTTPClientException; import com.adyen.model.PaymentResult; -import com.adyen.model.checkout.PaymentMethod; -import com.adyen.model.checkout.PaymentMethodDetails; -import com.adyen.model.checkout.PaymentMethodsResponse; -import com.adyen.model.checkout.PaymentsDetailsResponse; -import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.model.checkout.*; import com.adyen.model.modification.ModificationResult; import com.adyen.model.recurring.RecurringDetail; import com.adyen.model.terminal.ConnectedTerminalsResponse; @@ -34,6 +30,7 @@ import com.adyen.service.exception.ApiException; import com.adyen.v6.model.RequestInfo; import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.core.model.order.AbstractOrderModel; import de.hybris.platform.core.model.user.CustomerModel; import javax.servlet.http.HttpServletRequest; @@ -51,7 +48,7 @@ public interface AdyenPaymentService { */ PaymentResult authorise(CartData cartData, HttpServletRequest request, CustomerModel customerModel) throws Exception; - ConnectedTerminalsResponse getConnectedTerminals() throws IOException, ApiException ; + ConnectedTerminalsResponse getConnectedTerminals() throws IOException, ApiException; PaymentsResponse authorisePayment(CartData cartData, RequestInfo requestInfo, CustomerModel customerModel) throws Exception; @@ -85,10 +82,11 @@ public interface AdyenPaymentService { * @deprecated use getPaymentMethods including shopperReference instead {@link #getPaymentMethods(BigDecimal amount, String currency, String countryCode, String shopperLocale, String shopperReference) */ @Deprecated - List getPaymentMethods(BigDecimal amount, String currency, String countryCode, String shopperLocale) throws HTTPClientException, SignatureException, IOException; + List getPaymentMethods(BigDecimal amount, String currency, String countryCode, String shopperLocale) throws HTTPClientException, SignatureException, IOException; /** * Retrieve stored cards from recurring contracts via Adyen API + * * @deprecated use getPaymentMethodsResponse instead {@link #getPaymentMethodsResponse(BigDecimal amount, String currency, String countryCode, String shopperLocale, String shopperReference)} () */ @Deprecated @@ -107,7 +105,7 @@ public interface AdyenPaymentService { /** * Retrieves payment response from /payments/details */ - PaymentsDetailsResponse getPaymentDetailsFromPayload( HashMap details) throws Exception; + PaymentsDetailsResponse getPaymentDetailsFromPayload(HashMap details) throws Exception; /** * Returns the Device Fingerprint url @@ -118,8 +116,28 @@ public interface AdyenPaymentService { * Send POS Payment Request using Adyen Terminal API */ TerminalAPIResponse sendSyncPosPaymentRequest(CartData cartData, CustomerModel customer, String serviceId) throws Exception; + /** * Send POS Status Request using Adyen Terminal API */ TerminalAPIResponse sendSyncPosStatusRequest(CartData cartData, String serviceId) throws Exception; + + /** + * Performs Refund request via new Adyen API + */ + PaymentRefundResource refunds(final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) throws Exception; + + /** + * Performs Capture request via new Adyen API + */ + PaymentCaptureResource captures(final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) throws Exception; + + /** + * Performs Cancel or Refunds request via new Adyen API + */ + PaymentReversalResource cancelOrRefunds(final String authReference, final String merchantReference) throws Exception; + + BigDecimal calculateAmountWithTaxes(final AbstractOrderModel abstractOrderModel); + + CreateCheckoutSessionResponse getPaymentSessionData(final CartData cartData) throws IOException, ApiException; } diff --git a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorService.java b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorService.java new file mode 100644 index 000000000..d811fef97 --- /dev/null +++ b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorService.java @@ -0,0 +1,85 @@ +package com.adyen.v6.service; + +import com.adyen.v6.enums.AmazonpayEnvironment; +import com.adyen.v6.enums.AmazonpayRegion; +import com.amazon.pay.api.AmazonPayResponse; +import com.amazon.pay.api.PayConfiguration; +import com.amazon.pay.api.WebstoreClient; +import com.amazon.pay.api.exceptions.AmazonPayClientException; +import com.amazon.pay.api.types.Environment; +import com.amazon.pay.api.types.Region; +import de.hybris.platform.store.BaseStoreModel; +import de.hybris.platform.store.services.BaseStoreService; +import org.apache.log4j.Logger; +import org.apache.logging.log4j.util.Strings; +import org.json.JSONException; +import org.json.JSONObject; +import org.springframework.util.Assert; +import org.springframework.util.ResourceUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; + + +/** + * {@inheritDoc} + */ +public class DefaultAdyenAmazonPayIntegratorService implements AdyenAmazonPayIntegratorService { + + private static final Logger LOGGER = Logger.getLogger(DefaultAdyenAmazonPayIntegratorService.class); + + protected final BaseStoreService baseStoreService; + + public DefaultAdyenAmazonPayIntegratorService(final BaseStoreService baseStoreService) { + this.baseStoreService = baseStoreService; + } + + /** + * {@inheritDoc} + */ + @Override + public String getAmazonPayTokenByCheckoutSessionId(final String checkoutSessionId) { + Assert.hasText(checkoutSessionId,"Amazonpaytoken cannot be retrieved since the checkoutSessionId is null"); + + final BaseStoreModel currentBaseStore = baseStoreService.getCurrentBaseStore(); + Assert.notNull(currentBaseStore,"Amazonpaytoken cannot be retrieved since the current baseStore is null"); + + final AmazonpayEnvironment amazonpayEnvironment = currentBaseStore.getAmazonpayEnvironment(); + final AmazonpayRegion amazonpayRegion = currentBaseStore.getAmazonpayRegion(); + final String amazonpayPublicKey = currentBaseStore.getAmazonpayPublicKey(); + + Assert.hasText(amazonpayPublicKey,"Amazonpaytoken cannot be retrieved since the amazonpay public key configuration is not set on the current baseStore"); + Assert.notNull(amazonpayRegion,"Amazonpaytoken cannot be retrieved since the amazonpay region configuration is not set on the current baseStore"); + Assert.notNull(amazonpayEnvironment,"Amazonpaytoken cannot be retrieved since the amazonpay environment configuration is not set on the current baseStore"); + + final PayConfiguration payConfiguration; + try { + payConfiguration = new PayConfiguration() + .setPublicKeyId(amazonpayPublicKey) + .setRegion(Region.valueOf(amazonpayRegion.getCode())) + .setPrivateKey(new String(Files.readAllBytes(ResourceUtils.getFile("classpath:certificates/amazonpay/DummyCertificate.pem").toPath())).toCharArray()) + .setEnvironment(Environment.valueOf(amazonpayEnvironment.getCode())); + } catch (AmazonPayClientException e) { + LOGGER.error("The AmazonPayConfiguration cannot be created, please, review the amazonpay configuration set on the baseStore as well as the private key",e); + return Strings.EMPTY; + } catch (FileNotFoundException e) { + LOGGER.error("The AmazonPayCertificate.pem file cannot be found under /resources/certificates/amazonpay/AmazonPayCertificate.pm path",e); + return Strings.EMPTY; + } catch (IOException e) { + LOGGER.error("The AmazonPayCertificate.pem file cannot be readed, please provide a valid private key under /resources/certificates/amazonpay/AmazonPayCertificate.pm path",e); + return Strings.EMPTY; + } + try { + final WebstoreClient webstoreClient = new WebstoreClient(payConfiguration); + final AmazonPayResponse amazonPayResponse = webstoreClient.getCheckoutSession(checkoutSessionId); + final JSONObject response = amazonPayResponse.getResponse(); + return (String) response.get("amazonPayToken"); + } catch (AmazonPayClientException e) { + LOGGER.error("The AmazonPayToken cannot be found given the " + checkoutSessionId + "there were an error during the API Call to get the checkoutSession data" ,e); + } catch (JSONException e) { + LOGGER.error("The amazonPayToken is not on the given session",e); + } + return Strings.EMPTY; + } +} diff --git a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenOrderService.java b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenOrderService.java index 444ada896..890062b69 100644 --- a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenOrderService.java +++ b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenOrderService.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; import com.adyen.util.DateUtil; import org.apache.log4j.Logger; @@ -47,6 +48,7 @@ public class DefaultAdyenOrderService implements AdyenOrderService { private static final Logger LOG = Logger.getLogger(DefaultAdyenOrderService.class); + private static final String ADDITIONAL_DATA_CARD_TYPE = "checkout.cardAddedBrand"; private ModelService modelService; private PaymentsResponseConverter paymentsResponseConverter; @@ -132,8 +134,11 @@ public void updateOrderFromPaymentsResponse(OrderModel order, PaymentsResponse p PaymentInfoModel paymentInfo = order.getPaymentInfo(); - if(paymentsResponse.getPaymentMethod()!=null && !paymentsResponse.getPaymentMethod().isEmpty()) { - paymentInfo.setAdyenPaymentMethod(paymentsResponse.getPaymentMethod()); + if(Objects.nonNull(paymentsResponse.getAdditionalData()) && paymentsResponse.getAdditionalData().containsKey(ADDITIONAL_DATA_CARD_TYPE)){ + paymentInfo.setAdyenPaymentMethod(paymentsResponse.getAdditionalData().get(ADDITIONAL_DATA_CARD_TYPE)); + } + else if(paymentsResponse.getPaymentMethod()!=null) { + paymentInfo.setAdyenPaymentMethod(paymentsResponse.getPaymentMethod().getType()); } //Card specific data diff --git a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenPaymentService.java b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenPaymentService.java index 66c600e9f..4c7aeaa2e 100644 --- a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenPaymentService.java +++ b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenPaymentService.java @@ -23,68 +23,53 @@ import com.adyen.Client; import com.adyen.Config; import com.adyen.enums.Environment; -import com.adyen.httpclient.HTTPClientException; import com.adyen.model.PaymentRequest; import com.adyen.model.PaymentResult; -import com.adyen.model.checkout.PaymentMethod; -import com.adyen.model.checkout.PaymentMethodDetails; -import com.adyen.model.checkout.PaymentMethodsRequest; -import com.adyen.model.checkout.PaymentMethodsResponse; -import com.adyen.model.checkout.PaymentsDetailsRequest; -import com.adyen.model.checkout.PaymentsDetailsResponse; -import com.adyen.model.checkout.PaymentsRequest; -import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.model.checkout.*; import com.adyen.model.modification.CancelOrRefundRequest; import com.adyen.model.modification.CaptureRequest; import com.adyen.model.modification.ModificationResult; import com.adyen.model.modification.RefundRequest; -import com.adyen.model.recurring.DisableRequest; -import com.adyen.model.recurring.DisableResult; import com.adyen.model.recurring.RecurringDetail; -import com.adyen.model.recurring.RecurringDetailsRequest; -import com.adyen.model.recurring.RecurringDetailsResult; +import com.adyen.model.recurring.*; import com.adyen.model.terminal.ConnectedTerminalsRequest; import com.adyen.model.terminal.ConnectedTerminalsResponse; import com.adyen.model.terminal.TerminalAPIRequest; import com.adyen.model.terminal.TerminalAPIResponse; -import com.adyen.service.Checkout; -import com.adyen.service.Modification; -import com.adyen.service.Payment; -import com.adyen.service.PosPayment; -import com.adyen.service.TerminalCloudAPI; +import com.adyen.service.*; import com.adyen.service.exception.ApiException; import com.adyen.terminal.serialization.TerminalAPIGsonBuilder; import com.adyen.util.Util; -import com.adyen.v6.converters.PaymentMethodConverter; +import com.adyen.v6.enums.AdyenRegions; import com.adyen.v6.enums.RecurringContractMode; import com.adyen.v6.factory.AdyenRequestFactory; import com.adyen.v6.model.RequestInfo; import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.product.data.PriceData; +import de.hybris.platform.core.model.order.AbstractOrderModel; import de.hybris.platform.core.model.user.CustomerModel; import de.hybris.platform.store.BaseStoreModel; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; -import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; -import java.security.SignatureException; +import java.math.RoundingMode; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Currency; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import static com.adyen.v6.constants.Adyenv6coreConstants.PLUGIN_NAME; import static com.adyen.v6.constants.Adyenv6coreConstants.PLUGIN_VERSION; public class DefaultAdyenPaymentService implements AdyenPaymentService { + + private static final Logger LOG = Logger.getLogger(DefaultAdyenPaymentService.class); + private static final int POS_REQUEST_TIMEOUT = 25000; + private static final String CHECKOUT_ENDPOINT_LIVE_IN_SUFFIX = "-checkout-live-in.adyenpayments.com/checkout"; + private BaseStoreModel baseStore; private AdyenRequestFactory adyenRequestFactory; private Config config; @@ -92,12 +77,6 @@ public class DefaultAdyenPaymentService implements AdyenPaymentService { private Config posConfig; private Client posClient; - private PaymentMethodConverter paymentMethodConverter; - - private static final int POS_REQUEST_TIMEOUT = 25000; - - private static final Logger LOG = Logger.getLogger(DefaultAdyenPaymentService.class); - /** * Prevent initialization without base store */ @@ -107,40 +86,45 @@ private DefaultAdyenPaymentService() { public DefaultAdyenPaymentService(final BaseStoreModel baseStore) { this.baseStore = baseStore; - String apiKey = baseStore.getAdyenAPIKey(); - String merchantAccount = baseStore.getAdyenMerchantAccount(); - String apiEndpointPrefix = baseStore.getAdyenAPIEndpointPrefix(); - boolean isTestMode = baseStore.getAdyenTestMode(); - boolean isPosEnabled = baseStore.getAdyenPosEnabled(); - if (isPosEnabled) { - String posApiKey = baseStore.getAdyenPosApiKey(); - String posMerchantAccount = baseStore.getAdyenPosMerchantAccount(); + if (Boolean.TRUE.equals(baseStore.getAdyenPosEnabled())) { posConfig = new Config(); - posConfig.setApiKey(posApiKey); - posConfig.setMerchantAccount(posMerchantAccount); + posConfig.setApiKey(baseStore.getAdyenPosApiKey()); + posConfig.setMerchantAccount(baseStore.getAdyenPosMerchantAccount()); posConfig.setReadTimeoutMillis(POS_REQUEST_TIMEOUT); posConfig.setApplicationName(PLUGIN_NAME + " v" + PLUGIN_VERSION); posClient = new Client(posConfig); - if (isTestMode) { + if (Boolean.TRUE.equals(baseStore.getAdyenTestMode())) { posClient.setEnvironment(Environment.TEST, null); } else { posClient.setEnvironment(Environment.LIVE, null); } } - Assert.notNull(merchantAccount); config = new Config(); - config.setApiKey(apiKey); - config.setMerchantAccount(merchantAccount); + config.setApiKey(baseStore.getAdyenAPIKey()); + config.setMerchantAccount(baseStore.getAdyenMerchantAccount()); config.setApplicationName(PLUGIN_NAME + " v" + PLUGIN_VERSION); client = new Client(config); - if (isTestMode) { + if (Boolean.TRUE.equals(baseStore.getAdyenTestMode())) { client.setEnvironment(Environment.TEST, null); } else { - client.setEnvironment(Environment.LIVE, apiEndpointPrefix); + createLiveEnvironment(baseStore); } + + } + + private void createLiveEnvironment(final BaseStoreModel baseStore) { + + this.config.setEnvironment(Environment.LIVE); + this.config.setMarketPayEndpoint(Client.MARKETPAY_ENDPOINT_LIVE); + this.config.setHppEndpoint(Client.HPP_LIVE); + this.config.setCheckoutEndpoint(Client.ENDPOINT_PROTOCOL + baseStore.getAdyenAPIEndpointPrefix() + Client.CHECKOUT_ENDPOINT_LIVE_SUFFIX); + this.config.setEndpoint(Client.ENDPOINT_PROTOCOL + baseStore.getAdyenAPIEndpointPrefix() + Client.ENDPOINT_LIVE_SUFFIX); + this.config.setTerminalApiCloudEndpoint(Client.TERMINAL_API_ENDPOINT_LIVE); + this.config.setPosTerminalManagementApiEndpoint(Client.POS_TERMINAL_MANAGEMENT_ENDPOINT_LIVE); + this.config.setDataProtectionEndpoint(Client.DATA_PROTECTION_ENDPOINT_LIVE); } @Override @@ -148,10 +132,10 @@ public PaymentResult authorise(final CartData cartData, final HttpServletRequest Payment payment = new Payment(client); PaymentRequest paymentRequest = getAdyenRequestFactory().createAuthorizationRequest(client.getConfig().getMerchantAccount(), - cartData, - request, - customerModel, - baseStore.getAdyenRecurringContractMode()); + cartData, + request, + customerModel, + baseStore.getAdyenRecurringContractMode()); LOG.debug(paymentRequest); @@ -162,7 +146,7 @@ public PaymentResult authorise(final CartData cartData, final HttpServletRequest } @Override - public ConnectedTerminalsResponse getConnectedTerminals() throws IOException, ApiException { + public ConnectedTerminalsResponse getConnectedTerminals() throws IOException, ApiException { PosPayment posPayment = new PosPayment(posClient); ConnectedTerminalsRequest connectedTerminalsRequest = new ConnectedTerminalsRequest(); connectedTerminalsRequest.setMerchantAccount(posConfig.getMerchantAccount()); @@ -181,11 +165,11 @@ public PaymentsResponse authorisePayment(final CartData cartData, final RequestI Checkout checkout = new Checkout(client); PaymentsRequest paymentsRequest = getAdyenRequestFactory().createPaymentsRequest(client.getConfig().getMerchantAccount(), - cartData, - requestInfo, - customerModel, - baseStore.getAdyenRecurringContractMode(), - baseStore.getAdyenGuestUserTokenization()); + cartData, + requestInfo, + customerModel, + baseStore.getAdyenRecurringContractMode(), + baseStore.getAdyenGuestUserTokenization()); LOG.debug(paymentsRequest); PaymentsResponse paymentsResponse = checkout.payments(paymentsRequest); @@ -236,6 +220,22 @@ public ModificationResult capture(final BigDecimal amount, final Currency curren return modificationResult; } + @Override + public PaymentCaptureResource captures(final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) throws Exception { + final Checkout checkout = new Checkout(client); + + final CreatePaymentCaptureRequest captureRequest = new CreatePaymentCaptureRequest(); + captureRequest.setAmount(Util.createAmount(amount, currency.getCurrencyCode())); + captureRequest.setReference(merchantReference); + captureRequest.setMerchantAccount(client.getConfig().getMerchantAccount()); + + LOG.debug(captureRequest); + final PaymentCaptureResource paymentCaptureResource = checkout.paymentsCaptures(authReference, captureRequest); + LOG.debug(paymentCaptureResource); + + return paymentCaptureResource; + } + @Override public ModificationResult cancelOrRefund(final String authReference, final String merchantReference) throws Exception { Modification modification = new Modification(client); @@ -249,6 +249,21 @@ public ModificationResult cancelOrRefund(final String authReference, final Strin return modificationResult; } + @Override + public PaymentReversalResource cancelOrRefunds(final String authReference, final String merchantReference) throws Exception { + final Checkout checkout = new Checkout(client); + + final CreatePaymentReversalRequest reversalRequest = new CreatePaymentReversalRequest(); + reversalRequest.setReference(merchantReference); + reversalRequest.setMerchantAccount(client.getConfig().getMerchantAccount()); + + LOG.debug(reversalRequest); + final PaymentReversalResource paymentReversalResource = checkout.paymentsReversals(authReference, reversalRequest); + LOG.debug(paymentReversalResource); + + return paymentReversalResource; + } + @Override public ModificationResult refund(final BigDecimal amount, final Currency currency, final String authReference, final String merchantReference) throws Exception { Modification modification = new Modification(client); @@ -262,6 +277,23 @@ public ModificationResult refund(final BigDecimal amount, final Currency currenc return modificationResult; } + @Override + public PaymentRefundResource refunds(final BigDecimal amount, final Currency currency, final String pspReference, final String reference) throws Exception { + final Checkout checkout = new Checkout(client); + + final CreatePaymentRefundRequest refundRequest = new CreatePaymentRefundRequest(); + refundRequest.setAmount(Util.createAmount(amount, currency.getCurrencyCode())); + refundRequest.setMerchantAccount(client.getConfig().getMerchantAccount()); + refundRequest.setReference(reference); + + LOG.debug(refundRequest); + final PaymentRefundResource paymentRefundResource = checkout.paymentsRefunds(pspReference, refundRequest); + LOG.debug(paymentRefundResource); + + return paymentRefundResource; + } + + @Override public List getPaymentMethods(final BigDecimal amount, final String currency, @@ -269,30 +301,30 @@ public List getPaymentMethods(final BigDecimal amount, final String shopperLocale, final String shopperReference) throws IOException, ApiException { - PaymentMethodsResponse response =getPaymentMethodsResponse(amount,currency, countryCode, shopperLocale, shopperReference); + final PaymentMethodsResponse response = getPaymentMethodsResponse(amount, currency, countryCode, shopperLocale, shopperReference); return response.getPaymentMethods(); } @Override public PaymentMethodsResponse getPaymentMethodsResponse(final BigDecimal amount, - final String currency, - final String countryCode, - final String shopperLocale, - final String shopperReference) throws IOException, ApiException { + final String currency, + final String countryCode, + final String shopperLocale, + final String shopperReference) throws IOException, ApiException { Checkout checkout = new Checkout(client); PaymentMethodsRequest request = new PaymentMethodsRequest(); request.merchantAccount(client.getConfig().getMerchantAccount()).amount(Util.createAmount(amount, currency)).countryCode(countryCode); - if (! StringUtils.isEmpty(shopperLocale)) { + if (!StringUtils.isEmpty(shopperLocale)) { request.setShopperLocale(shopperLocale); } - if (! StringUtils.isEmpty(shopperReference)) { + if (!StringUtils.isEmpty(shopperReference)) { request.setShopperReference(shopperReference); } LOG.debug(request); - PaymentMethodsResponse response = checkout.paymentMethods(request); + final PaymentMethodsResponse response = checkout.paymentMethods(request); LOG.debug(response); return response; @@ -300,13 +332,12 @@ public PaymentMethodsResponse getPaymentMethodsResponse(final BigDecimal amount, @Override @Deprecated - public List getPaymentMethods(final BigDecimal amount, - final String currency, - final String countryCode, - final String shopperLocale) throws HTTPClientException, SignatureException, IOException { + public List getPaymentMethods(final BigDecimal amount, + final String currency, + final String countryCode, + final String shopperLocale) throws IOException { try { - List checkoutPaymentMethods = getPaymentMethods(amount, currency, countryCode, shopperLocale, null); - return checkoutPaymentMethods.stream().map(paymentMethodConverter::convert).collect(Collectors.toList()); + return getPaymentMethods(amount, currency, countryCode, shopperLocale, null); } catch (ApiException e) { LOG.error(e); } @@ -330,9 +361,9 @@ public List getStoredCards(final String customerId) throws IOEx //Return only cards List storedCards = result.getRecurringDetails() - .stream() - .filter(detail -> (detail.getCard() != null && detail.getRecurringDetailReference() != null)) - .collect(Collectors.toList()); + .stream() + .filter(detail -> (detail.getCard() != null && detail.getRecurringDetailReference() != null)) + .collect(Collectors.toList()); return storedCards; } @@ -378,6 +409,22 @@ public PaymentsDetailsResponse getPaymentDetailsFromPayload(Map return paymentsResponse; } + + @Override + public CreateCheckoutSessionResponse getPaymentSessionData(final CartData cartData) throws IOException, ApiException { + final Checkout checkout = new Checkout(client); + final PriceData totalPriceWithTax = cartData.getTotalPriceWithTax(); + + final CreateCheckoutSessionRequest createCheckoutSessionRequest = new CreateCheckoutSessionRequest(); + createCheckoutSessionRequest.amount(Util.createAmount(totalPriceWithTax.getValue(), totalPriceWithTax.getCurrencyIso())); + createCheckoutSessionRequest.merchantAccount(getBaseStore().getAdyenMerchantAccount()); + createCheckoutSessionRequest.countryCode(cartData.getDeliveryAddress().getCountry().getIsocode()); + createCheckoutSessionRequest.returnUrl(Optional.ofNullable(cartData.getAdyenReturnUrl()).orElse("returnUrl")); + createCheckoutSessionRequest.reference(cartData.getCode()); + + return checkout.sessions(createCheckoutSessionRequest); + } + @Override public String getDeviceFingerprintUrl() { DateFormat df = new SimpleDateFormat("yyyyMMdd"); @@ -418,6 +465,16 @@ public TerminalAPIResponse sendSyncPosStatusRequest(CartData cartData, String or return terminalApiResponse; } + @Override + public BigDecimal calculateAmountWithTaxes(final AbstractOrderModel abstractOrderModel) { + final Double totalPrice = abstractOrderModel.getTotalPrice(); + final Double totalTax = Boolean.TRUE.equals(abstractOrderModel.getNet()) ? abstractOrderModel.getTotalTax() : Double.valueOf(0d); + final BigDecimal totalPriceWithoutTaxBD = BigDecimal.valueOf(totalPrice == null ? 0d : totalPrice).setScale(2, + RoundingMode.HALF_EVEN); + return BigDecimal.valueOf(totalTax == null ? 0d : totalTax) + .setScale(2, RoundingMode.HALF_EVEN).add(totalPriceWithoutTaxBD); + } + public AdyenRequestFactory getAdyenRequestFactory() { return adyenRequestFactory; } @@ -450,11 +507,4 @@ public Config getConfig() { return config; } - public PaymentMethodConverter getPaymentMethodConverter() { - return paymentMethodConverter; - } - - public void setPaymentMethodConverter(PaymentMethodConverter paymentMethodConverter) { - this.paymentMethodConverter = paymentMethodConverter; - } } diff --git a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenTransactionService.java b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenTransactionService.java index f2da595c3..fe1d87d73 100644 --- a/adyenv6core/src/com/adyen/v6/service/DefaultAdyenTransactionService.java +++ b/adyenv6core/src/com/adyen/v6/service/DefaultAdyenTransactionService.java @@ -21,6 +21,7 @@ package com.adyen.v6.service; import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.model.NotificationItemModel; import de.hybris.platform.core.model.c2l.CurrencyModel; import de.hybris.platform.core.model.order.AbstractOrderModel; @@ -31,6 +32,7 @@ import de.hybris.platform.payment.model.PaymentTransactionModel; import de.hybris.platform.servicelayer.i18n.CommonI18NService; import de.hybris.platform.servicelayer.model.ModelService; +import de.hybris.platform.store.services.BaseStoreService; import org.apache.log4j.Logger; import org.joda.time.DateTime; @@ -45,13 +47,12 @@ public class DefaultAdyenTransactionService implements AdyenTransactionService { private ModelService modelService; private CommonI18NService commonI18NService; + private AdyenPaymentServiceFactory adyenPaymentServiceFactory; + private BaseStoreService baseStoreService; @Override public PaymentTransactionEntryModel createCapturedTransactionFromNotification(final PaymentTransactionModel paymentTransaction, final NotificationItemModel notificationItemModel) { - final PaymentTransactionEntryModel transactionEntryModel = createFromModificationNotification( - paymentTransaction, - notificationItemModel - ); + final PaymentTransactionEntryModel transactionEntryModel = createFromModificationNotification(paymentTransaction, notificationItemModel); transactionEntryModel.setType(PaymentTransactionType.CAPTURE); @@ -60,19 +61,14 @@ public PaymentTransactionEntryModel createCapturedTransactionFromNotification(fi @Override public PaymentTransactionEntryModel createRefundedTransactionFromNotification(final PaymentTransactionModel paymentTransaction, final NotificationItemModel notificationItemModel) { - final PaymentTransactionEntryModel transactionEntryModel = createFromModificationNotification( - paymentTransaction, - notificationItemModel - ); + final PaymentTransactionEntryModel transactionEntryModel = createFromModificationNotification(paymentTransaction, notificationItemModel); transactionEntryModel.setType(PaymentTransactionType.REFUND_FOLLOW_ON); return transactionEntryModel; } - private PaymentTransactionEntryModel createFromModificationNotification( - final PaymentTransactionModel paymentTransaction, - final NotificationItemModel notificationItemModel) { + private PaymentTransactionEntryModel createFromModificationNotification(final PaymentTransactionModel paymentTransaction, final NotificationItemModel notificationItemModel) { final PaymentTransactionEntryModel transactionEntryModel = modelService.create(PaymentTransactionEntryModel.class); String code = paymentTransaction.getRequestId() + "_" + paymentTransaction.getEntries().size(); @@ -102,18 +98,11 @@ private PaymentTransactionEntryModel createFromModificationNotification( @Override public PaymentTransactionModel authorizeOrderModel(final AbstractOrderModel abstractOrderModel, final String merchantTransactionCode, final String pspReference) { //First save the transactions to the CartModel < AbstractOrderModel - final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction( - merchantTransactionCode, - pspReference, - abstractOrderModel); + final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction(merchantTransactionCode, pspReference, abstractOrderModel); modelService.save(paymentTransactionModel); - PaymentTransactionEntryModel authorisedTransaction = createAuthorizationPaymentTransactionEntryModel( - paymentTransactionModel, - merchantTransactionCode, - abstractOrderModel - ); + PaymentTransactionEntryModel authorisedTransaction = createAuthorizationPaymentTransactionEntryModel(paymentTransactionModel, merchantTransactionCode, abstractOrderModel); LOG.info("Saving AUTH transaction entry with psp reference: " + pspReference); modelService.save(authorisedTransaction); @@ -126,20 +115,11 @@ public PaymentTransactionModel authorizeOrderModel(final AbstractOrderModel abst @Override public PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference, BigDecimal paymentAmount) { //First save the transactions to the CartModel < AbstractOrderModel - final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction( - merchantTransactionCode, - pspReference, - abstractOrderModel, - paymentAmount); + final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction(merchantTransactionCode, pspReference, abstractOrderModel, paymentAmount); modelService.save(paymentTransactionModel); - PaymentTransactionEntryModel authorisedTransaction = createAuthorizationPaymentTransactionEntryModel( - paymentTransactionModel, - merchantTransactionCode, - abstractOrderModel, - paymentAmount - ); + PaymentTransactionEntryModel authorisedTransaction = createAuthorizationPaymentTransactionEntryModel(paymentTransactionModel, merchantTransactionCode, abstractOrderModel, paymentAmount); LOG.info("Saving AUTH transaction entry with psp reference: " + pspReference); modelService.save(authorisedTransaction); @@ -150,39 +130,24 @@ public PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOr } @Override - public PaymentTransactionModel storeFailedAuthorizationFromNotification(NotificationItemModel notificationItemModel, - AbstractOrderModel abstractOrderModel) { + public PaymentTransactionModel storeFailedAuthorizationFromNotification(NotificationItemModel notificationItemModel, AbstractOrderModel abstractOrderModel) { boolean partialPayment = isPartialPayment(notificationItemModel, abstractOrderModel); //First save the transactions to the CartModel < AbstractOrderModel final PaymentTransactionModel paymentTransactionModel; if (partialPayment) { - paymentTransactionModel = createPaymentTransaction( - notificationItemModel.getMerchantReference(), - notificationItemModel.getPspReference(), - abstractOrderModel, - notificationItemModel.getAmountValue()); + paymentTransactionModel = createPaymentTransaction(notificationItemModel.getMerchantReference(), notificationItemModel.getPspReference(), abstractOrderModel, notificationItemModel.getAmountValue()); } else { - paymentTransactionModel = createPaymentTransaction( - notificationItemModel.getMerchantReference(), - notificationItemModel.getPspReference(), - abstractOrderModel); + paymentTransactionModel = createPaymentTransaction(notificationItemModel.getMerchantReference(), notificationItemModel.getPspReference(), abstractOrderModel); } modelService.save(paymentTransactionModel); final PaymentTransactionEntryModel authorisedTransaction; if (partialPayment) { - authorisedTransaction = createAuthorizationPaymentTransactionEntryModel( - paymentTransactionModel, - notificationItemModel.getMerchantReference(), - abstractOrderModel, - notificationItemModel.getAmountValue()); + authorisedTransaction = createAuthorizationPaymentTransactionEntryModel(paymentTransactionModel, notificationItemModel.getMerchantReference(), abstractOrderModel, notificationItemModel.getAmountValue()); } else { - authorisedTransaction = createAuthorizationPaymentTransactionEntryModel( - paymentTransactionModel, - notificationItemModel.getMerchantReference(), - abstractOrderModel); + authorisedTransaction = createAuthorizationPaymentTransactionEntryModel(paymentTransactionModel, notificationItemModel.getMerchantReference(), abstractOrderModel); } authorisedTransaction.setTransactionStatus(TransactionStatus.REJECTED.name()); @@ -194,7 +159,7 @@ public PaymentTransactionModel storeFailedAuthorizationFromNotification(Notifica return paymentTransactionModel; } - + /** * Map notification item reason to transactionStatusDetails item */ @@ -213,10 +178,7 @@ private TransactionStatusDetails getTransactionStatusDetailsFromReason(String re return transactionStatusDetails; } - private PaymentTransactionEntryModel createAuthorizationPaymentTransactionEntryModel( - final PaymentTransactionModel paymentTransaction, - final String merchantCode, - final AbstractOrderModel abstractOrderModel) { + private PaymentTransactionEntryModel createAuthorizationPaymentTransactionEntryModel(final PaymentTransactionModel paymentTransaction, final String merchantCode, final AbstractOrderModel abstractOrderModel) { final PaymentTransactionEntryModel transactionEntryModel = modelService.create(PaymentTransactionEntryModel.class); String code = paymentTransaction.getRequestId() + "_" + paymentTransaction.getEntries().size(); @@ -229,26 +191,19 @@ private PaymentTransactionEntryModel createAuthorizationPaymentTransactionEntryM transactionEntryModel.setTime(DateTime.now().toDate()); transactionEntryModel.setTransactionStatus(TransactionStatus.ACCEPTED.name()); transactionEntryModel.setTransactionStatusDetails(TransactionStatusDetails.SUCCESFULL.name()); - transactionEntryModel.setAmount(BigDecimal.valueOf(abstractOrderModel.getTotalPrice())); + transactionEntryModel.setAmount(getAdyenPaymentService().calculateAmountWithTaxes(abstractOrderModel)); transactionEntryModel.setCurrency(abstractOrderModel.getCurrency()); return transactionEntryModel; } - private PaymentTransactionEntryModel createAuthorizationPaymentTransactionEntryModel( - final PaymentTransactionModel paymentTransaction, - final String merchantCode, - final AbstractOrderModel abstractOrderModel, - final BigDecimal paymentAmount) { + private PaymentTransactionEntryModel createAuthorizationPaymentTransactionEntryModel(final PaymentTransactionModel paymentTransaction, final String merchantCode, final AbstractOrderModel abstractOrderModel, final BigDecimal paymentAmount) { final PaymentTransactionEntryModel transactionEntryModel = createAuthorizationPaymentTransactionEntryModel(paymentTransaction, merchantCode, abstractOrderModel); transactionEntryModel.setAmount(paymentAmount); return transactionEntryModel; } - private PaymentTransactionModel createPaymentTransaction( - final String merchantCode, - final String pspReference, - final AbstractOrderModel abstractOrderModel) { + private PaymentTransactionModel createPaymentTransaction(final String merchantCode, final String pspReference, final AbstractOrderModel abstractOrderModel) { final PaymentTransactionModel paymentTransactionModel = modelService.create(PaymentTransactionModel.class); paymentTransactionModel.setCode(pspReference); paymentTransactionModel.setRequestId(pspReference); @@ -257,16 +212,12 @@ private PaymentTransactionModel createPaymentTransaction( paymentTransactionModel.setOrder(abstractOrderModel); paymentTransactionModel.setCurrency(abstractOrderModel.getCurrency()); paymentTransactionModel.setInfo(abstractOrderModel.getPaymentInfo()); - paymentTransactionModel.setPlannedAmount(BigDecimal.valueOf(abstractOrderModel.getTotalPrice())); + paymentTransactionModel.setPlannedAmount(getAdyenPaymentService().calculateAmountWithTaxes(abstractOrderModel)); return paymentTransactionModel; } - private PaymentTransactionModel createPaymentTransaction( - final String merchantCode, - final String pspReference, - final AbstractOrderModel abstractOrderModel, - final BigDecimal paymentAmount) { + private PaymentTransactionModel createPaymentTransaction(final String merchantCode, final String pspReference, final AbstractOrderModel abstractOrderModel, final BigDecimal paymentAmount) { final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction(merchantCode, pspReference, abstractOrderModel); paymentTransactionModel.setPlannedAmount(paymentAmount); return paymentTransactionModel; @@ -293,23 +244,12 @@ public PaymentTransactionEntryModel createCancellationTransaction(final PaymentT } @Override - public PaymentTransactionModel createPaymentTransactionFromResultCode(final AbstractOrderModel abstractOrderModel, - final String merchantTransactionCode, - final String pspReference, - final PaymentsResponse.ResultCodeEnum resultCodeEnum) { - final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction( - merchantTransactionCode, - pspReference, - abstractOrderModel); + public PaymentTransactionModel createPaymentTransactionFromResultCode(final AbstractOrderModel abstractOrderModel, final String merchantTransactionCode, final String pspReference, final PaymentsResponse.ResultCodeEnum resultCodeEnum) { + final PaymentTransactionModel paymentTransactionModel = createPaymentTransaction(merchantTransactionCode, pspReference, abstractOrderModel); modelService.save(paymentTransactionModel); - PaymentTransactionEntryModel paymentTransactionEntryModel = createPaymentTransactionEntryModelFromResultCode( - paymentTransactionModel, - merchantTransactionCode, - abstractOrderModel, - resultCodeEnum - ); + PaymentTransactionEntryModel paymentTransactionEntryModel = createPaymentTransactionEntryModelFromResultCode(paymentTransactionModel, merchantTransactionCode, abstractOrderModel, resultCodeEnum); LOG.info("Saving transaction entry for resultCode " + resultCodeEnum + " with psp reference:" + pspReference); modelService.save(paymentTransactionEntryModel); @@ -322,11 +262,7 @@ public PaymentTransactionModel createPaymentTransactionFromResultCode(final Abst return paymentTransactionModel; } - private PaymentTransactionEntryModel createPaymentTransactionEntryModelFromResultCode( - final PaymentTransactionModel paymentTransaction, - final String merchantCode, - final AbstractOrderModel abstractOrderModel, - final PaymentsResponse.ResultCodeEnum resultCode) { + private PaymentTransactionEntryModel createPaymentTransactionEntryModelFromResultCode(final PaymentTransactionModel paymentTransaction, final String merchantCode, final AbstractOrderModel abstractOrderModel, final PaymentsResponse.ResultCodeEnum resultCode) { final PaymentTransactionEntryModel transactionEntryModel = modelService.create(PaymentTransactionEntryModel.class); String code = paymentTransaction.getRequestId() + "_" + paymentTransaction.getEntries().size(); @@ -339,7 +275,7 @@ private PaymentTransactionEntryModel createPaymentTransactionEntryModelFromResul transactionEntryModel.setTime(DateTime.now().toDate()); transactionEntryModel.setTransactionStatus(getTransactionStatusForResultCode(resultCode)); transactionEntryModel.setTransactionStatusDetails("ResultCode: " + resultCode.getValue()); - transactionEntryModel.setAmount(BigDecimal.valueOf(abstractOrderModel.getTotalPrice())); + transactionEntryModel.setAmount(getAdyenPaymentService().calculateAmountWithTaxes(abstractOrderModel)); transactionEntryModel.setCurrency(abstractOrderModel.getCurrency()); return transactionEntryModel; @@ -362,14 +298,18 @@ private String getTransactionStatusForResultCode(PaymentsResponse.ResultCodeEnum } private boolean isPartialPayment(NotificationItemModel notificationItemModel, AbstractOrderModel abstractOrderModel) { - BigDecimal totalOrderAmount = BigDecimal.valueOf(abstractOrderModel.getTotalPrice()); + BigDecimal totalOrderAmount = getAdyenPaymentService().calculateAmountWithTaxes(abstractOrderModel); BigDecimal notificationAmount = notificationItemModel.getAmountValue(); - if(notificationAmount == null) { + if (notificationAmount == null) { return false; } return totalOrderAmount.compareTo(notificationAmount) > 0; } + public AdyenPaymentService getAdyenPaymentService() { + return adyenPaymentServiceFactory.createFromBaseStore(baseStoreService.getCurrentBaseStore()); + } + public ModelService getModelService() { return modelService; } @@ -385,4 +325,20 @@ public CommonI18NService getCommonI18NService() { public void setCommonI18NService(CommonI18NService commonI18NService) { this.commonI18NService = commonI18NService; } + + public AdyenPaymentServiceFactory getAdyenPaymentServiceFactory() { + return adyenPaymentServiceFactory; + } + + public void setAdyenPaymentServiceFactory(AdyenPaymentServiceFactory adyenPaymentServiceFactory) { + this.adyenPaymentServiceFactory = adyenPaymentServiceFactory; + } + + public BaseStoreService getBaseStoreService() { + return baseStoreService; + } + + public void setBaseStoreService(BaseStoreService baseStoreService) { + this.baseStoreService = baseStoreService; + } } diff --git a/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckAuthorizationActionTest.java b/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckAuthorizationActionTest.java index 4729384ce..3d660154b 100644 --- a/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckAuthorizationActionTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckAuthorizationActionTest.java @@ -20,19 +20,25 @@ */ package com.adyen.v6.actions.order; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; +import com.adyen.v6.service.AdyenPaymentService; import de.hybris.bootstrap.annotations.UnitTest; import de.hybris.platform.core.model.order.OrderModel; import de.hybris.platform.core.model.order.payment.PaymentInfoModel; import de.hybris.platform.orderprocessing.model.OrderProcessModel; import de.hybris.platform.payment.model.PaymentTransactionModel; import de.hybris.platform.servicelayer.model.ModelService; +import de.hybris.platform.store.BaseStoreModel; +import de.hybris.platform.store.services.BaseStoreService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -45,18 +51,25 @@ @UnitTest @RunWith(MockitoJUnitRunner.class) public class AdyenCheckAuthorizationActionTest extends AbstractActionTest { + @Mock private OrderProcessModel orderProcessModelMock; - @Mock private OrderModel orderModelMock; - @Mock private PaymentInfoModel paymentInfoModelMock; - @Mock private ModelService modelServiceMock; + @Mock + private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock; + @Mock + private BaseStoreService baseStoreServiceMock; + @Mock + private BaseStoreModel baseStoreModelMock; + @Mock + private AdyenPaymentService adyenPaymentServiceMock; + @InjectMocks private AdyenCheckAuthorizationAction adyenCheckAuthorizationAction; @Before @@ -68,8 +81,13 @@ public void setUp() { when(orderProcessModelMock.getCode()).thenReturn("1234"); when(orderProcessModelMock.getOrder()).thenReturn(orderModelMock); - adyenCheckAuthorizationAction = new AdyenCheckAuthorizationAction(); + adyenCheckAuthorizationAction = new AdyenCheckAuthorizationAction(adyenPaymentServiceFactoryMock, baseStoreServiceMock); adyenCheckAuthorizationAction.setModelService(modelServiceMock); + when(adyenCheckAuthorizationAction.getAdyenPaymentService(orderModelMock)).thenReturn(adyenPaymentServiceMock); + + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(adyenPaymentServiceFactoryMock.createFromBaseStore(baseStoreModelMock)).thenReturn(adyenPaymentServiceMock); + when(adyenPaymentServiceMock.calculateAmountWithTaxes(orderModelMock)).thenReturn(new BigDecimal(10)); } @After @@ -99,9 +117,9 @@ public void testAlreadyAuthorized() { List transactions = new ArrayList<>(); PaymentTransactionModel authorizedTransaction = createAdyenTransaction(); - transactions.add(authorizedTransaction); - + authorizedTransaction.setPlannedAmount(new BigDecimal(10)); authorizedTransaction.getEntries().add(createAuthorizedEntry()); + transactions.add(authorizedTransaction); when(orderModelMock.getPaymentTransactions()).thenReturn(transactions); diff --git a/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckCaptureActionTest.java b/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckCaptureActionTest.java index 63193b33b..b80bff688 100644 --- a/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckCaptureActionTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/actions/order/AdyenCheckCaptureActionTest.java @@ -20,6 +20,8 @@ */ package com.adyen.v6.actions.order; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; +import com.adyen.v6.service.AdyenPaymentService; import de.hybris.bootstrap.annotations.UnitTest; import de.hybris.platform.core.enums.OrderStatus; import de.hybris.platform.core.model.order.OrderModel; @@ -28,13 +30,17 @@ import de.hybris.platform.payment.model.PaymentTransactionEntryModel; import de.hybris.platform.payment.model.PaymentTransactionModel; import de.hybris.platform.servicelayer.model.ModelService; +import de.hybris.platform.store.BaseStoreModel; +import de.hybris.platform.store.services.BaseStoreService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -50,18 +56,25 @@ public class AdyenCheckCaptureActionTest extends AbstractActionTest { @Mock private OrderProcessModel orderProcessModelMock; - @Mock private OrderModel orderModelMock; - @Mock private PaymentInfoModel paymentInfoModelMock; - @Mock private ModelService modelServiceMock; + @Mock + private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock; + @Mock + private BaseStoreService baseStoreServiceMock; + @Mock + private BaseStoreModel baseStoreModelMock; + @Mock + private AdyenPaymentService adyenPaymentServiceMock; + @InjectMocks private AdyenCheckCaptureAction adyenCheckCaptureAction; + @Before public void setUp() { when(paymentInfoModelMock.getAdyenPaymentMethod()).thenReturn("visa"); @@ -72,8 +85,13 @@ public void setUp() { when(orderProcessModelMock.getCode()).thenReturn("1234"); when(orderProcessModelMock.getOrder()).thenReturn(orderModelMock); - adyenCheckCaptureAction = new AdyenCheckCaptureAction(); + adyenCheckCaptureAction = new AdyenCheckCaptureAction(adyenPaymentServiceFactoryMock, baseStoreServiceMock); adyenCheckCaptureAction.setModelService(modelServiceMock); + when(adyenCheckCaptureAction.getAdyenPaymentService(orderModelMock)).thenReturn(adyenPaymentServiceMock); + + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(adyenPaymentServiceFactoryMock.createFromBaseStore(baseStoreModelMock)).thenReturn(adyenPaymentServiceMock); + when(adyenPaymentServiceMock.calculateAmountWithTaxes(orderModelMock)).thenReturn(new BigDecimal(10)); } @After diff --git a/adyenv6core/testsrc/com/adyen/v6/commands/AdyenCaptureCommandTest.java b/adyenv6core/testsrc/com/adyen/v6/commands/AdyenCaptureCommandTest.java index 09198aef7..b80946da7 100644 --- a/adyenv6core/testsrc/com/adyen/v6/commands/AdyenCaptureCommandTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/commands/AdyenCaptureCommandTest.java @@ -20,16 +20,7 @@ */ package com.adyen.v6.commands; -import java.math.BigDecimal; -import java.util.Currency; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; -import com.adyen.model.modification.ModificationResult; +import com.adyen.model.checkout.PaymentCaptureResource; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.repository.OrderRepository; import com.adyen.v6.service.DefaultAdyenPaymentService; @@ -41,6 +32,17 @@ import de.hybris.platform.payment.dto.TransactionStatus; import de.hybris.platform.payment.dto.TransactionStatusDetails; import de.hybris.platform.store.BaseStoreModel; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import java.math.BigDecimal; +import java.util.Currency; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -98,12 +100,12 @@ public void tearDown() { */ @Test public void testManualCaptureSuccess() throws Exception { - ModificationResult modificationResult = new ModificationResult(); - modificationResult.setPspReference("1235"); - modificationResult.setResponse("[capture-received]"); + PaymentCaptureResource paymentCaptureResult = new PaymentCaptureResource(); + paymentCaptureResult.setPspReference("1235"); + paymentCaptureResult.setStatus(PaymentCaptureResource.StatusEnum.RECEIVED); - when(adyenPaymentServiceMock.capture(captureRequest.getTotalAmount(), captureRequest.getCurrency(), captureRequest.getRequestId(), captureRequest.getRequestToken())).thenReturn( - modificationResult); + when(adyenPaymentServiceMock.captures(captureRequest.getTotalAmount(), captureRequest.getCurrency(), captureRequest.getRequestId(), captureRequest.getRequestToken())).thenReturn( + paymentCaptureResult); CaptureResult result = adyenCaptureCommand.perform(captureRequest); assertEquals(TransactionStatus.ACCEPTED, result.getTransactionStatus()); diff --git a/adyenv6core/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java b/adyenv6core/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java index ffe957161..43f6d0b7e 100644 --- a/adyenv6core/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/facades/AdyenCheckoutFacadeTest.java @@ -42,9 +42,11 @@ import com.adyen.model.terminal.TerminalAPIResponse; import com.adyen.service.exception.ApiException; import com.adyen.v6.constants.Adyenv6coreConstants; +import com.adyen.v6.converters.PaymentsDetailsResponseConverter; import com.adyen.v6.converters.PosPaymentResponseConverter; import com.adyen.v6.enums.RecurringContractMode; import com.adyen.v6.exceptions.AdyenNonAuthorizedPaymentException; +import com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade; import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.repository.OrderRepository; import com.adyen.v6.service.AdyenBusinessProcessService; @@ -74,6 +76,7 @@ import de.hybris.platform.order.CartService; import de.hybris.platform.order.InvalidCartException; import de.hybris.platform.payment.model.PaymentTransactionModel; +import de.hybris.platform.servicelayer.config.ConfigurationService; import de.hybris.platform.servicelayer.dto.converter.ConversionException; import de.hybris.platform.servicelayer.dto.converter.Converter; import de.hybris.platform.servicelayer.i18n.CommonI18NService; @@ -81,18 +84,19 @@ import de.hybris.platform.servicelayer.session.SessionService; import de.hybris.platform.store.BaseStoreModel; import de.hybris.platform.store.services.BaseStoreService; +import org.apache.commons.configuration.Configuration; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; -import java.security.SignatureException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -102,9 +106,9 @@ import static com.adyen.constants.ApiConstants.ThreeDS2Property.CHALLENGE_RESULT; import static com.adyen.constants.ApiConstants.ThreeDS2Property.FINGERPRINT_RESULT; import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_EPS; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_ISSUER_LISTS; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.MODEL_SELECTED_PAYMENT_METHOD; -import static com.adyen.v6.facades.DefaultAdyenCheckoutFacade.SESSION_PENDING_ORDER_CODE; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.MODEL_ISSUER_LISTS; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.MODEL_SELECTED_PAYMENT_METHOD; +import static com.adyen.v6.facades.impl.DefaultAdyenCheckoutFacade.SESSION_PENDING_ORDER_CODE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -112,12 +116,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @UnitTest @RunWith(MockitoJUnitRunner.class) @@ -131,7 +130,9 @@ public class AdyenCheckoutFacadeTest { private static final String RESULT = "result"; private static final String SERVICE_ID = "serviceId"; private static final String URL = "url"; + private static final String ORDER_CODE = "orderCode"; + @Spy @InjectMocks DefaultAdyenCheckoutFacade adyenCheckoutFacade = new DefaultAdyenCheckoutFacade(); @@ -173,6 +174,18 @@ public class AdyenCheckoutFacadeTest { AddressPopulator addressPopulator; @Mock AdyenBusinessProcessService adyenBusinessProcessService; + @Mock + private PaymentsDetailsResponseConverter getPaymentsDetailsResponseConverterMock; + @Mock + private ConfigurationService configurationServiceMock; + @Mock + private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock; + @Mock + private BaseStoreService baseStoreServiceMock; + @Mock + private BaseStoreModel baseStoreModelMock; + @Mock + private AdyenPaymentService adyenPaymentServiceMock; @Mock HttpServletRequest request; @@ -206,7 +219,6 @@ public class AdyenCheckoutFacadeTest { UserModel userModel; @Mock BaseStoreModel storeModel; - @Mock TerminalAPIResponse terminalApiResponse; @Mock @@ -236,6 +248,8 @@ public class AdyenCheckoutFacadeTest { OutputText textJustName; @Mock OutputText textJustValue; + @Mock + Configuration configurationMock; @Before public void setUp() { @@ -244,13 +258,18 @@ public void setUp() { when(request.getAttribute("originalServiceId")).thenReturn(SERVICE_ID); when(baseStoreService.getCurrentBaseStore()).thenReturn(baseStore); when(adyenPaymentServiceFactory.createFromBaseStore(any())).thenReturn(adyenPaymentService); + when(getPaymentsDetailsResponseConverterMock.convert(paymentsDetailsResponse)).thenReturn(paymentsResponse); + when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(adyenPaymentServiceFactoryMock.createFromBaseStore(baseStoreModelMock)).thenReturn(adyenPaymentServiceMock); + when(adyenPaymentServiceMock.calculateAmountWithTaxes(orderModel)).thenReturn(new BigDecimal(10)); } @Test public void testInitializeEpsCheckoutData() throws Exception { when(checkoutFacade.getCheckoutCart()).thenReturn(cartData); when(baseStore.getAdyenPosEnabled()).thenReturn(false); - when(cartData.getTotalPrice()).thenReturn(priceData); + when(cartData.getTotalPriceWithTax()).thenReturn(priceData); when(priceData.getValue()).thenReturn(BigDecimal.TEN); when(priceData.getCurrencyIso()).thenReturn("EUR"); when(cartData.getDeliveryAddress()).thenReturn(addressData); @@ -282,7 +301,7 @@ private PaymentMethodsResponse createEpsPaymentMethodsResponse() { item.setId(UUID.randomUUID().toString()); item.setName("FakeIssuer"); detail.addItemsItem(item); - paymentMethod.addDetailsItem(detail); + paymentMethod.addInputDetailsItem(detail); PaymentMethodsResponse response = new PaymentMethodsResponse(); response.setPaymentMethods(Collections.singletonList(paymentMethod)); @@ -411,13 +430,12 @@ public void testCheckPosPaymentStatusTimeout() throws Exception { when(request.getAttribute("paymentStartTime")).thenReturn(processStartTime); when(request.getAttribute("totalTimeout")).thenReturn(10); - AdyenCheckoutFacade adyenCheckoutFacadeSpy = spy(adyenCheckoutFacade); try { - adyenCheckoutFacadeSpy.checkPosPaymentStatus(request, cartData); + adyenCheckoutFacade.checkPosPaymentStatus(request, cartData); fail("Expected AdyenNonAuthorizedPaymentException"); } catch (AdyenNonAuthorizedPaymentException e) { assertEquals(terminalApiResponse, e.getTerminalApiResponse()); - verify(adyenCheckoutFacadeSpy, atLeast(2)).checkPosPaymentStatus(request, cartData); + verify(adyenCheckoutFacade, atLeast(2)).checkPosPaymentStatus(request, cartData); } } @@ -496,14 +514,17 @@ public void testHandle3DResponseAuthorised() throws Exception { when(adyenTransactionService.createPaymentTransactionFromResultCode(any(), any(), any(), any())).thenReturn(new PaymentTransactionModel()); doNothing().when(adyenOrderService).updateOrderFromPaymentsResponse(any(), any()); when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); + when(paymentsDetailsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); doNothing().when(modelService).save(any()); when(orderConverter.convert(any())).thenReturn(orderData); doNothing().when(adyenBusinessProcessService).triggerOrderProcessEvent(any(), any()); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); OrderData orderDataResult = adyenCheckoutFacade.handle3DSResponse(details); assertEquals(orderData, orderDataResult); verify(adyenPaymentService).authorise3DSPayment(anyMap()); - verify(orderRepository).getOrderModel(MERCHANT_REFERENCE); + verify(orderRepository).getOrderModel(ORDER_CODE); verify(orderConverter).convert(orderModel); } @@ -534,13 +555,15 @@ public void testHandle3DResponseError() throws Exception { when(cartModel.getUser()).thenReturn(userModel); when(orderModel.getStore()).thenReturn(storeModel); when(cartModel.getStore()).thenReturn(storeModel); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); + when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.CHALLENGESHOPPER); + when(orderRepository.getOrderModel(ORDER_CODE)).thenReturn(orderModel); try { adyenCheckoutFacade.handle3DSResponse(details); fail("Expected AdyenNonAuthorizedPaymentException"); } catch (AdyenNonAuthorizedPaymentException e) { verify(adyenPaymentService).authorise3DSPayment(anyMap()); - verify(orderRepository, times(2)).getOrderModel(MERCHANT_REFERENCE); verify(cartFactory).createCart(); verify(cartService).setSessionCart(cartModel); verify(calculationService).calculate(cartModel); @@ -585,16 +608,6 @@ public void testHandle3DResponseThrowsApiException() throws Exception { } } - @Test - public void testHandle3DResponseWrongSignature() throws Exception { - try { - adyenCheckoutFacade.handle3DSResponse(details); - fail("Expected SignatureException"); - } catch (SignatureException e) { - assertEquals("MD does not match!", e.getMessage()); - } - } - @Test public void testHandle3DS2ResponseAuthorised() throws Exception { when(request.getParameter(FINGERPRINT_RESULT)).thenReturn(null); @@ -605,15 +618,17 @@ public void testHandle3DS2ResponseAuthorised() throws Exception { doNothing().when(sessionService).removeAttribute(any()); when(adyenTransactionService.createPaymentTransactionFromResultCode(any(), any(), any(), any())).thenReturn(new PaymentTransactionModel()); doNothing().when(adyenOrderService).updateOrderFromPaymentsResponse(any(), any()); + when(paymentsDetailsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); doNothing().when(modelService).save(any()); when(orderConverter.convert(any())).thenReturn(orderData); doNothing().when(adyenBusinessProcessService).triggerOrderProcessEvent(any(), any()); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); OrderData orderDataResult = adyenCheckoutFacade.handle3DSResponse(details); assertEquals(orderData, orderDataResult); verify(adyenPaymentService).authorise3DSPayment(anyMap()); - verify(orderRepository).getOrderModel(MERCHANT_REFERENCE); verify(orderConverter).convert(orderModel); } @@ -622,15 +637,17 @@ public void testHandle3DS2ResponseChallengeShopper() throws Exception { when(request.getParameter(FINGERPRINT_RESULT)).thenReturn(RESULT); when(request.getParameter(CHALLENGE_RESULT)).thenReturn(null); when(adyenPaymentService.authorise3DSPayment(anyMap())).thenReturn(paymentsDetailsResponse); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.CHALLENGESHOPPER); + when(orderRepository.getOrderModel(ORDER_CODE)).thenReturn(orderModel); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); try { adyenCheckoutFacade.handle3DSResponse(details); fail("Expected AdyenNonAuthorizedPaymentException"); } catch (AdyenNonAuthorizedPaymentException e) { verify(adyenPaymentService).authorise3DSPayment(anyMap()); - assertNotNull(e.getPaymentsResponse()); - assertEquals(PaymentsResponse.ResultCodeEnum.CHALLENGESHOPPER, e.getPaymentsResponse().getResultCode()); + assertNotNull(e.getPaymentsDetailsResponse()); } } @@ -663,13 +680,14 @@ public void testHandle3DS2ResponseError() throws Exception { when(cartModel.getUser()).thenReturn(userModel); when(orderModel.getStore()).thenReturn(storeModel); when(cartModel.getStore()).thenReturn(storeModel); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); try { adyenCheckoutFacade.handle3DSResponse(details); fail("Expected AdyenNonAuthorizedPaymentException"); } catch (AdyenNonAuthorizedPaymentException e) { verify(adyenPaymentService).authorise3DSPayment(anyMap()); - verify(orderRepository, times(2)).getOrderModel(MERCHANT_REFERENCE); verify(cartFactory).createCart(); verify(cartService).setSessionCart(cartModel); verify(calculationService).calculate(cartModel); @@ -720,20 +738,24 @@ public void testHandle3DS2ResponseThrowsApiException() throws Exception { public void testHandleRedirectPayloadAuthorised() throws Exception { when(sessionService.getAttribute(Adyenv6coreConstants.PAYMENT_METHOD)).thenReturn(PAYMENT_METHOD); when(adyenPaymentService.getPaymentDetailsFromPayload(any())).thenReturn(paymentsDetailsResponse); + when(adyenPaymentService.authorise3DSPayment(any())).thenReturn(paymentsDetailsResponse); when(paymentsResponse.getMerchantReference()).thenReturn(MERCHANT_REFERENCE); when(orderRepository.getOrderModel(any())).thenReturn(orderModel); doNothing().when(sessionService).removeAttribute(any()); when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); + when(paymentsDetailsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.AUTHORISED); when(adyenTransactionService.createPaymentTransactionFromResultCode(any(), any(), any(), any())).thenReturn(new PaymentTransactionModel()); doNothing().when(adyenOrderService).updateOrderFromPaymentsResponse(any(), any()); doNothing().when(adyenBusinessProcessService).triggerOrderProcessEvent(any(), any()); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); HashMap details = new HashMap<>(); PaymentsDetailsResponse paymentsDetailsResponseReturned = adyenCheckoutFacade.handleRedirectPayload(details); assertEquals(paymentsDetailsResponseReturned, paymentsDetailsResponse); assertEquals(PaymentsResponse.ResultCodeEnum.AUTHORISED, paymentsDetailsResponseReturned.getResultCode()); verify(adyenPaymentService).getPaymentDetailsFromPayload(details); - verify(orderRepository).getOrderModel(MERCHANT_REFERENCE); + verify(orderRepository).getOrderModel(ORDER_CODE); } @Test @@ -744,6 +766,7 @@ public void testHandleRedirectPayloadNotAuthorised() throws Exception { when(orderRepository.getOrderModel(any())).thenReturn(orderModel); doNothing().when(sessionService).removeAttribute(any()); when(paymentsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.REFUSED); + when(paymentsDetailsResponse.getResultCode()).thenReturn(PaymentsResponse.ResultCodeEnum.REFUSED); doNothing().when(modelService).save(any()); when(cartFactory.createCart()).thenReturn(cartModel); doNothing().when(cartService).setSessionCart(any()); @@ -764,13 +787,15 @@ public void testHandleRedirectPayloadNotAuthorised() throws Exception { when(cartModel.getUser()).thenReturn(userModel); when(orderModel.getStore()).thenReturn(storeModel); when(cartModel.getStore()).thenReturn(storeModel); + when(orderRepository.getOrderModel(ORDER_CODE)).thenReturn(orderModel); + when(orderModel.getEntries()).thenReturn(Collections.emptyList()); + when(paymentsDetailsResponse.getMerchantReference()).thenReturn(ORDER_CODE); HashMap details = new HashMap<>(); PaymentsDetailsResponse paymentsDetailsResponseReturned = adyenCheckoutFacade.handleRedirectPayload(details); assertEquals(paymentsDetailsResponseReturned, paymentsDetailsResponse); assertEquals(PaymentsResponse.ResultCodeEnum.REFUSED, paymentsDetailsResponseReturned.getResultCode()); verify(adyenPaymentService).getPaymentDetailsFromPayload(details); - verify(orderRepository, times(2)).getOrderModel(MERCHANT_REFERENCE); verify(cartFactory).createCart(); verify(cartService).setSessionCart(cartModel); verify(calculationService).calculate(cartModel); diff --git a/adyenv6core/testsrc/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacadeTest.java b/adyenv6core/testsrc/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacadeTest.java new file mode 100644 index 000000000..b29ef58b2 --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/facades/impl/DefaultAdyenAmazonPayFacadeTest.java @@ -0,0 +1,55 @@ +package com.adyen.v6.facades.impl; + +import com.adyen.v6.service.AdyenAmazonPayIntegratorService; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService; +import de.hybris.platform.basecommerce.model.site.BaseSiteModel; +import de.hybris.platform.site.BaseSiteService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class DefaultAdyenAmazonPayFacadeTest { + private static final String AMAZON_PAY_TOKEN = "amazonPayToken"; + private static final String RELATIVE_URL = "relativeUrl"; + private static final String ABSOLUTE_URL = "absoluteUrl"; + private final String AMAZONPAY_CHECKOUT_SESSION_ID = "amazonpayCheckoutSessionId"; + + @InjectMocks + private DefaultAdyenAmazonPayFacade testObj; + @Mock + private AdyenAmazonPayIntegratorService adyenAmazonPayIntegratorServiceMock; + @Mock + private BaseSiteService baseSiteServiceMock; + @Mock + private SiteBaseUrlResolutionService siteBaseUrlResolutionServiceMock; + + @Mock + private BaseSiteModel baseSiteModelMock; + + @Test + public void getAmazonPayToken_shouldReturnTheAmazonPayToken() { + when(adyenAmazonPayIntegratorServiceMock.getAmazonPayTokenByCheckoutSessionId(AMAZONPAY_CHECKOUT_SESSION_ID)).thenReturn(AMAZON_PAY_TOKEN); + + final String result = testObj.getAmazonPayToken(AMAZONPAY_CHECKOUT_SESSION_ID); + + assertThat(result).isEqualTo(result); + } + + @Test + public void getReturnUrl_shouldReturnUrl() { + when(baseSiteServiceMock.getCurrentBaseSite()).thenReturn(baseSiteModelMock); + when(siteBaseUrlResolutionServiceMock.getWebsiteUrlForSite(baseSiteModelMock, true, RELATIVE_URL)).thenReturn(ABSOLUTE_URL); + + final String result = testObj.getReturnUrl(RELATIVE_URL); + + assertThat(result).isEqualTo(ABSOLUTE_URL); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/factory/AdyenRequestFactoryTest.java b/adyenv6core/testsrc/com/adyen/v6/factory/AdyenRequestFactoryTest.java index 8a7a120e4..ef5c09c3e 100644 --- a/adyenv6core/testsrc/com/adyen/v6/factory/AdyenRequestFactoryTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/factory/AdyenRequestFactoryTest.java @@ -20,29 +20,19 @@ */ package com.adyen.v6.factory; -import java.math.BigDecimal; - import com.adyen.model.Name; -import com.adyen.model.nexo.AmountsReq; -import com.adyen.model.nexo.MessageCategoryType; -import com.adyen.model.nexo.MessageHeader; -import com.adyen.model.nexo.SaleData; -import com.adyen.model.nexo.TransactionStatusRequest; -import com.adyen.model.terminal.SaleToAcquirerData; -import com.adyen.model.terminal.TerminalAPIRequest; -import org.apache.commons.configuration.BaseConfiguration; -import org.apache.commons.configuration.Configuration; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import com.adyen.model.PaymentRequest; -import com.adyen.model.checkout.DefaultPaymentMethodDetails; +import com.adyen.model.checkout.PaymentDetails; import com.adyen.model.checkout.PaymentsRequest; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.model.checkout.details.GenericIssuerPaymentMethodDetails; +import com.adyen.model.nexo.*; import com.adyen.model.recurring.Recurring; +import com.adyen.model.terminal.SaleToAcquirerData; +import com.adyen.model.terminal.TerminalAPIRequest; import com.adyen.v6.enums.RecurringContractMode; import com.adyen.v6.model.RequestInfo; +import com.adyen.v6.paymentmethoddetails.executors.AdyenPaymentMethodDetailsBuilderExecutor; import de.hybris.bootstrap.annotations.UnitTest; import de.hybris.platform.commercefacades.order.data.CCPaymentInfoData; import de.hybris.platform.commercefacades.order.data.CartData; @@ -51,15 +41,19 @@ import de.hybris.platform.commercefacades.user.data.CountryData; import de.hybris.platform.core.model.user.CustomerModel; import de.hybris.platform.servicelayer.config.ConfigurationService; +import org.apache.commons.configuration.BaseConfiguration; +import org.apache.commons.configuration.Configuration; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_CC; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_EPS; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_ONECLICK; -import static com.adyen.v6.constants.Adyenv6coreConstants.PAYMENT_METHOD_PAYPAL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import java.math.BigDecimal; + +import static com.adyen.v6.constants.Adyenv6coreConstants.*; +import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -90,49 +84,55 @@ public class AdyenRequestFactoryTest { private static final String REMOTE_ADDRESS = "1.2.3.4"; private static final String REQUEST_URL = "https://localhost:9002/electronics/en/checkout/multi/adyen/summary/placeOrder"; private static final String REQUEST_URI = "/electronics/en/checkout/multi/adyen/summary/placeOrder"; - private static final String RETURN_URL ="https://localhost:9002/electronics/en/checkout/multi/adyen/summary/checkout-adyen-response"; + private static final String RETURN_URL = "https://localhost:9002/electronics/en/checkout/multi/adyen/summary/checkout-adyen-response"; //POS private static final String SERVICE_ID = "serviceId"; private static final String TERMINAL_ID = "V400m-123456789"; + @InjectMocks private AdyenRequestFactory adyenRequestFactory; @Mock - CartData cartDataMock; + private ConfigurationService configurationServiceMock; + + @Mock + private AdyenPaymentMethodDetailsBuilderExecutor adyenPaymentMethodDetailsStrategyExecutor; @Mock - javax.servlet.http.HttpServletRequest requestMock; + private CartData cartDataMock; @Mock - CustomerModel customerModelMock; + private javax.servlet.http.HttpServletRequest requestMock; @Mock - AddressData deliveryAddressMock; + private CustomerModel customerModelMock; @Mock - AddressData billingAddressMock; + private AddressData deliveryAddressMock; @Mock - CCPaymentInfoData paymentInfoMock; + private AddressData billingAddressMock; @Mock - CountryData deliveryCountryDataMock; + private CCPaymentInfoData paymentInfoMock; @Mock - CountryData billingCountryDataMock; + private CountryData deliveryCountryDataMock; @Mock - ConfigurationService configurationServiceMock; + private CountryData billingCountryDataMock; + @Mock + private PaymentDetails paymentDetailsMock; @Before public void setUp() { - adyenRequestFactory = new AdyenRequestFactory(); + adyenRequestFactory = new AdyenRequestFactory(configurationServiceMock, adyenPaymentMethodDetailsStrategyExecutor); PriceData priceData = new PriceData(); priceData.setValue(new BigDecimal(AMOUNT)); priceData.setCurrencyIso(CURRENCY); - when(cartDataMock.getTotalPrice()).thenReturn(priceData); + when(cartDataMock.getTotalPriceWithTax()).thenReturn(priceData); when(cartDataMock.getCode()).thenReturn(CART_CODE); when(cartDataMock.getDeliveryAddress()).thenReturn(deliveryAddressMock); when(cartDataMock.getPaymentInfo()).thenReturn(paymentInfoMock); @@ -160,17 +160,15 @@ public void setUp() { Configuration configurationMock = mock(BaseConfiguration.class); when(configurationMock.getString(any(String.class))).thenReturn("dummy"); when(configurationServiceMock.getConfiguration()).thenReturn(configurationMock); - - adyenRequestFactory.setConfigurationService(configurationServiceMock); } @Test - public void testAuthorise() throws Exception { + public void testAuthorise() { when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_CC); PaymentsRequest paymentsRequest; - //Test anonymous - paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), null, RecurringContractMode.NONE, false); + + paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, RecurringContractMode.RECURRING, false); //use delivery/billing address from cart assertEquals(DELIVERY_TOWN, paymentsRequest.getDeliveryAddress().getCity()); @@ -178,7 +176,7 @@ public void testAuthorise() throws Exception { assertEquals(BILLING_TOWN, paymentsRequest.getBillingAddress().getCity()); assertEquals(BILLING_COUNTRY, paymentsRequest.getBillingAddress().getCountry()); - assertNull(paymentsRequest.getShopperReference()); + assertNotNull(paymentsRequest.getShopperReference()); assertEquals(USER_AGENT_HEADER, paymentsRequest.getBrowserInfo().getUserAgent()); assertEquals(ACCEPT_HEADER, paymentsRequest.getBrowserInfo().getAcceptHeader()); @@ -189,16 +187,16 @@ public void testAuthorise() throws Exception { testRecurringOption(null, null); testRecurringOption(RecurringContractMode.NONE, null); testRecurringOption(RecurringContractMode.ONECLICK, null); - testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING); - testRecurringOption(RecurringContractMode.ONECLICK_RECURRING, Recurring.ContractEnum.RECURRING); + //testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING); + //testRecurringOption(RecurringContractMode.ONECLICK_RECURRING, Recurring.ContractEnum.RECURRING); //Test recurring contract when remember-me is set when(cartDataMock.getAdyenRememberTheseDetails()).thenReturn(true); testRecurringOption(null, null); testRecurringOption(RecurringContractMode.NONE, null); - testRecurringOption(RecurringContractMode.ONECLICK, Recurring.ContractEnum.ONECLICK); - testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING); - testRecurringOption(RecurringContractMode.ONECLICK_RECURRING, Recurring.ContractEnum.ONECLICK_RECURRING); + //testRecurringOption(RecurringContractMode.ONECLICK, Recurring.ContractEnum.ONECLICK); + //testRecurringOption(RecurringContractMode.RECURRING, Recurring.ContractEnum.RECURRING); + //testRecurringOption(RecurringContractMode.ONECLICK_RECURRING, Recurring.ContractEnum.ONECLICK_RECURRING); //When a store card is selected, send the reference and include the recurring contract when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_ONECLICK); @@ -206,7 +204,7 @@ public void testAuthorise() throws Exception { when(cartDataMock.getAdyenRememberTheseDetails()).thenReturn(false); paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, null, false); - DefaultPaymentMethodDetails paymentMethodDetails = (DefaultPaymentMethodDetails) paymentsRequest.getPaymentMethod(); + final CardDetails paymentMethodDetails = (CardDetails) paymentsRequest.getPaymentMethod(); assertEquals(RECURRING_REFERENCE, paymentMethodDetails.getRecurringDetailReference()); } @@ -228,15 +226,17 @@ private void testRecurringOption(final RecurringContractMode recurringContractMo public void testEpsPaymentRequest() throws Exception { when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PAYMENT_METHOD_EPS); when(cartDataMock.getAdyenReturnUrl()).thenReturn(RETURN_URL); + final GenericIssuerPaymentMethodDetails type = new GenericIssuerPaymentMethodDetails().type(PAYMENT_METHOD_EPS).issuer(ISSUER_ID); when(cartDataMock.getAdyenIssuerId()).thenReturn(ISSUER_ID); + when(adyenPaymentMethodDetailsStrategyExecutor.createPaymentMethodDetails(cartDataMock)).thenReturn(type); - PaymentsRequest paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, null, false); + final PaymentsRequest paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, null, false); assertNotNull(paymentsRequest); assertEquals(RETURN_URL, paymentsRequest.getReturnUrl()); assertNotNull(paymentsRequest.getPaymentMethod()); assertEquals(PAYMENT_METHOD_EPS, paymentsRequest.getPaymentMethod().getType()); - assertEquals(ISSUER_ID, ((DefaultPaymentMethodDetails) paymentsRequest.getPaymentMethod()).getIssuer()); + assertEquals(ISSUER_ID, type.getIssuer()); } @Test @@ -246,8 +246,10 @@ public void testPaypalPaymentRequest() throws Exception { when(deliveryAddressMock.getFirstName()).thenReturn(FIRST_NAME); when(deliveryAddressMock.getLastName()).thenReturn(LAST_NAME); when(deliveryAddressMock.getTitleCode()).thenReturn(TITLE_CODE); + final GenericIssuerPaymentMethodDetails type = new GenericIssuerPaymentMethodDetails().type(PAYMENT_METHOD_PAYPAL).issuer(ISSUER_ID); + when(adyenPaymentMethodDetailsStrategyExecutor.createPaymentMethodDetails(cartDataMock)).thenReturn(type); - PaymentsRequest paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, null, false); + final PaymentsRequest paymentsRequest = adyenRequestFactory.createPaymentsRequest(MERCHANT_ACCOUNT, cartDataMock, new RequestInfo(requestMock), customerModelMock, null, false); assertNotNull(paymentsRequest); assertEquals(RETURN_URL, paymentsRequest.getReturnUrl()); @@ -275,7 +277,7 @@ public void testTerminalApiPaymentRequestWithRecurring() throws Exception { assertNotNull(terminalApiRequest.getSaleToPOIRequest().getPaymentRequest().getSaleData().getSaleToAcquirerData()); SaleToAcquirerData saleToAcquirerData = terminalApiRequest.getSaleToPOIRequest().getPaymentRequest().getSaleData().getSaleToAcquirerData(); - assertTrue(saleToAcquirerData.getRecurringContract().equals( Recurring.ContractEnum.ONECLICK_RECURRING.toString())); + assertTrue(saleToAcquirerData.getRecurringContract().equals(Recurring.ContractEnum.ONECLICK_RECURRING.toString())); assertTrue(saleToAcquirerData.getShopperEmail().equals(CUSTOMER_EMAIL)); assertTrue(saleToAcquirerData.getShopperReference().equals(CUSTOMER_ID)); } diff --git a/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategyTest.java b/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategyTest.java new file mode 100644 index 000000000..343d0a2ca --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPartialOrderCancelDenialStrategyTest.java @@ -0,0 +1,59 @@ +package com.adyen.v6.ordercancel.denialstrategies.impl; + +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.security.PrincipalModel; +import de.hybris.platform.ordercancel.DefaultOrderCancelDenialReason; +import de.hybris.platform.ordercancel.OrderCancelDenialReason; +import de.hybris.platform.ordercancel.model.OrderCancelConfigModel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenPartialOrderCancelDenialStrategyTest { + + @Spy + @InjectMocks + private AdyenPartialOrderCancelDenialStrategy testObj; + + @Mock + private OrderCancelConfigModel orderCancelConfigModelMock; + @Mock + private OrderModel orderModelMock; + @Mock + private PrincipalModel principalModelMock; + + @Test(expected = IllegalArgumentException.class) + public void getCancelDenialReason_WhenOrderIsNull_ShouldThrowException() { + testObj.getCancelDenialReason(orderCancelConfigModelMock, null, principalModelMock, false, false); + } + + @Test(expected = IllegalArgumentException.class) + public void getCancelDenialReason_WhenOrderCancelConfigIsNull_ShouldThrowException() { + testObj.getCancelDenialReason(null, orderModelMock, principalModelMock, false, false); + } + + @Test + public void getCancelDenialReason_WhenPartialFlagsFalse_ShouldReturnNull() { + final OrderCancelDenialReason result = testObj.getCancelDenialReason(orderCancelConfigModelMock, orderModelMock, principalModelMock, false, false); + + assertNull(result); + } + + @Test + public void getCancelDenialReason_WhenPartialFlagsTrue_ShouldReturnTheDecision() { + when(testObj.getReason()).thenReturn(new DefaultOrderCancelDenialReason()); + + final OrderCancelDenialReason result = testObj.getCancelDenialReason(orderCancelConfigModelMock, orderModelMock, principalModelMock, true, true); + + assertNotNull(result); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategyTest.java b/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategyTest.java new file mode 100644 index 000000000..6fddc915c --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/ordercancel/denialstrategies/impl/AdyenPaymentStatusOrderCancelDenialStrategyTest.java @@ -0,0 +1,60 @@ +package com.adyen.v6.ordercancel.denialstrategies.impl; + +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.security.PrincipalModel; +import de.hybris.platform.ordercancel.DefaultOrderCancelDenialReason; +import de.hybris.platform.ordercancel.OrderCancelDenialReason; +import de.hybris.platform.ordercancel.model.OrderCancelConfigModel; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenPaymentStatusOrderCancelDenialStrategyTest { + + @Spy + @InjectMocks + private AdyenPartialOrderCancelDenialStrategy testObj; + + @Mock + private OrderCancelConfigModel orderCancelConfigModelMock; + @Mock + private OrderModel orderModelMock; + @Mock + private PrincipalModel principalModelMock; + + @Test(expected = IllegalArgumentException.class) + public void getCancelDenialReason_WhenOrderIsNull_ShouldThrowException() { + testObj.getCancelDenialReason(orderCancelConfigModelMock, null, principalModelMock, false, false); + } + + @Test(expected = IllegalArgumentException.class) + public void getCancelDenialReason_WhenOrderCancelConfigIsNull_ShouldThrowException() { + testObj.getCancelDenialReason(null, orderModelMock, principalModelMock, false, false); + } + + @Test + public void getCancelDenialReason_WhenPartialFlagsFalse_ShouldReturnNull() { + final OrderCancelDenialReason result = testObj.getCancelDenialReason(orderCancelConfigModelMock, orderModelMock, principalModelMock, false, false); + + assertNull(result); + } + + @Test + public void getCancelDenialReason_WhenPartialFlagsTrue_ShouldReturnTheDecision() { + when(testObj.getReason()).thenReturn(new DefaultOrderCancelDenialReason()); + + final OrderCancelDenialReason result = testObj.getCancelDenialReason(orderCancelConfigModelMock, orderModelMock, principalModelMock, true, true); + + assertNotNull(result); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacadeTest.java b/adyenv6core/testsrc/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacadeTest.java new file mode 100644 index 000000000..4482e5fd4 --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/ordermanagement/impl/AdyenDefaultOmsOrderFacadeTest.java @@ -0,0 +1,55 @@ +package com.adyen.v6.ordermanagement.impl; + +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.core.model.order.AbstractOrderEntryModel; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.ordermanagementfacades.cancellation.data.OrderCancelEntryData; +import de.hybris.platform.ordermanagementfacades.cancellation.data.OrderCancelRequestData; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenDefaultOmsOrderFacadeTest { + @InjectMocks + private AdyenDefaultOmsOrderFacade testObj; + + @Mock + private OrderCancelRequestData orderCancelRequestDataMock; + @Mock + private OrderModel orderModelMock; + @Mock + private OrderCancelEntryData orderCancelEntryDataMock; + @Mock + private AbstractOrderEntryModel entryModelMock1, entryModelMock2; + + @Test + public void isPartialCancel_WhenEntriesMatch_ShouldReturnFalse() { + when(orderCancelRequestDataMock.getEntries()).thenReturn(singletonList(orderCancelEntryDataMock)); + when(orderCancelEntryDataMock.getOrderEntryNumber()).thenReturn(1); + when(orderModelMock.getEntries()).thenReturn(singletonList(entryModelMock1)); + when(entryModelMock1.getEntryNumber()).thenReturn(1); + + assertFalse(testObj.isPartialCancel(orderCancelRequestDataMock, orderModelMock)); + } + + @Test + public void isPartialCancel_WhenEntriesDoNotMatch_ShouldReturnTrue() { + when(orderCancelRequestDataMock.getEntries()).thenReturn(singletonList(orderCancelEntryDataMock)); + when(orderCancelEntryDataMock.getOrderEntryNumber()).thenReturn(1); + when(orderModelMock.getEntries()).thenReturn(asList(entryModelMock1, entryModelMock2)); + when(entryModelMock1.getEntryNumber()).thenReturn(1); + when(entryModelMock2.getEntryNumber()).thenReturn(2); + + assertTrue(testObj.isPartialCancel(orderCancelRequestDataMock, orderModelMock)); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategyTest.java b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategyTest.java new file mode 100644 index 000000000..cdfbeb564 --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/PaypalAdyenPaymentMethodDetailsBuilderStrategyTest.java @@ -0,0 +1,71 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.PayPalDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.commercefacades.order.data.CartData; +import de.hybris.platform.commercefacades.user.data.AddressData; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class PaypalAdyenPaymentMethodDetailsBuilderStrategyTest { + + private static String personalDetails = "firstName lastName "; + private static String contactDetails = " 666666666 test@test.com"; + + @InjectMocks + private PaypalAdyenPaymentMethodDetailsBuilderStrategy testObj; + + @Mock + private CartData cartDataMock; + @Mock + private AddressData addressDataMock; + + @Before + public void setUp() throws Exception { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(PayPalDetails.PAYPAL); + when(cartDataMock.getDeliveryAddress()).thenReturn(addressDataMock); + when(cartDataMock.getAdyenDob()).thenReturn(new Date(0)); + when(addressDataMock.getFirstName()).thenReturn("firstName"); + when(addressDataMock.getLastName()).thenReturn("lastName"); + when(addressDataMock.getPhone()).thenReturn("666666666"); + when(addressDataMock.getEmail()).thenReturn("test@test.com"); + } + + @Test + public void isApplicable_returnTrue_whenIsPaypalPaymentMethod() { + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isTrue(); + } + + @Test + public void isApplicable_returnFalse_whenIsNotPaypalPaymentMethod() { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(Adyenv6coreConstants.PAYBRIGHT); + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isFalse(); + } + + @Test + public void buildPaymentMethodDetails_returnPaypalDetailsCorrectlyFilled() { + final PaymentMethodDetails result = testObj.buildPaymentMethodDetails(cartDataMock); + + assertThat(result).isInstanceOfAny(PayPalDetails.class); + assertThat(((PayPalDetails) result).getSubtype()).isEqualTo(PayPalDetails.SubtypeEnum.SDK); + assertThat(((PayPalDetails) result).getPayerID()).isEqualTo(personalDetails + new Date(0) + contactDetails); + } + +} \ No newline at end of file diff --git a/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategyTest.java b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategyTest.java new file mode 100644 index 000000000..dfd35e332 --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/RatepayPaymentMethodDetailsBuilderStrategyTest.java @@ -0,0 +1,57 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.CardDetails; +import com.adyen.model.checkout.details.SepaDirectDebitDetails; +import com.adyen.v6.constants.Adyenv6coreConstants; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.commercefacades.order.data.CartData; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class RatepayPaymentMethodDetailsBuilderStrategyTest { + + @InjectMocks + private RatepayPaymentMethodDetailsBuilderStrategy testObj; + + @Mock + private CartData cartDataMock; + + @Before + public void setUp() throws Exception { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(Adyenv6coreConstants.RATEPAY); + } + + @Test + public void isApplicable_returnTrue_whenIsSepaDirectDebitPaymentMethod() { + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isTrue(); + } + + @Test + public void isApplicable_returnFalse_whenIsNotSepaDirectDebitPaymentMethod() { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(Adyenv6coreConstants.PAYBRIGHT); + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isFalse(); + } + + @Test + public void buildPaymentMethodDetails_returnSepaDiredtDebitDetailsCorrectlyFilled() { + final PaymentMethodDetails result = testObj.buildPaymentMethodDetails(cartDataMock); + + assertThat(result).isInstanceOfAny(CardDetails.class); + assertThat(result.getType()).isEqualTo(Adyenv6coreConstants.RATEPAY); + } +} \ No newline at end of file diff --git a/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategyTest.java b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategyTest.java new file mode 100644 index 000000000..69c7a7caa --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/paymentmethoddetails/builders/impl/SepaDirectDebitPaymentMethodDetailsBuilderStrategyTest.java @@ -0,0 +1,60 @@ +package com.adyen.v6.paymentmethoddetails.builders.impl; + +import com.adyen.model.checkout.PaymentMethodDetails; +import com.adyen.model.checkout.details.SepaDirectDebitDetails; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.commercefacades.order.data.CartData; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class SepaDirectDebitPaymentMethodDetailsBuilderStrategyTest { + protected static final String ADYEN_SEPA_OWNER_NAME = "adyenSepaOwnerName"; + protected static final String ADYEN_SEPA_IBAN_NUMBER = "adyenSepaIbanNumber"; + + @InjectMocks + private SepaDirectDebitPaymentMethodDetailsBuilderStrategy testObj; + + @Mock + private CartData cartDataMock; + + @Before + public void setUp() throws Exception { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(SepaDirectDebitDetails.SEPADIRECTDEBIT); + when(cartDataMock.getAdyenSepaOwnerName()).thenReturn(ADYEN_SEPA_OWNER_NAME); + when(cartDataMock.getAdyenSepaIbanNumber()).thenReturn(ADYEN_SEPA_IBAN_NUMBER); + } + + @Test + public void isApplicable_returnTrue_whenIsSepaDirectDebitPaymentMethod() { + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isTrue(); + } + + @Test + public void isApplicable_returnFalse_whenIsNotSepaDirectDebitPaymentMethod() { + when(cartDataMock.getAdyenPaymentMethod()).thenReturn(SepaDirectDebitDetails.SEPADIRECTDEBIT_AMAZONPAY); + + final boolean result = testObj.isApplicable(cartDataMock); + + assertThat(result).isFalse(); + } + + @Test + public void buildPaymentMethodDetails_returnSepaDiredtDebitDetailsCorrectlyFilled() { + final PaymentMethodDetails result = testObj.buildPaymentMethodDetails(cartDataMock); + + assertThat(result).isInstanceOfAny(SepaDirectDebitDetails.class); + assertThat(((SepaDirectDebitDetails) result).getIban()).isEqualTo(ADYEN_SEPA_IBAN_NUMBER); + assertThat(((SepaDirectDebitDetails) result).getOwnerName()).isEqualTo(ADYEN_SEPA_OWNER_NAME); + } +} \ No newline at end of file diff --git a/adyenv6core/testsrc/com/adyen/v6/populator/AdyenOrderCancelPopulatorTest.java b/adyenv6core/testsrc/com/adyen/v6/populator/AdyenOrderCancelPopulatorTest.java new file mode 100644 index 000000000..019a5b9d0 --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/populator/AdyenOrderCancelPopulatorTest.java @@ -0,0 +1,99 @@ +package com.adyen.v6.populator; + +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.commercefacades.order.data.OrderData; +import de.hybris.platform.commercefacades.order.data.OrderEntryData; +import de.hybris.platform.commercefacades.product.data.ProductData; +import de.hybris.platform.core.model.order.AbstractOrderEntryModel; +import de.hybris.platform.core.model.order.OrderModel; +import de.hybris.platform.core.model.user.UserModel; +import de.hybris.platform.ordercancel.CancelDecision; +import de.hybris.platform.ordercancel.OrderCancelCancelableEntriesStrategy; +import de.hybris.platform.ordercancel.OrderCancelService; +import de.hybris.platform.servicelayer.user.UserService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class AdyenOrderCancelPopulatorTest { + @Spy + @InjectMocks + private AdyenOrderCancelPopulator testObj; + + @Mock + private OrderCancelService orderCancelServiceMock; + @Mock + private UserService userServiceMock; + @Mock + private OrderCancelCancelableEntriesStrategy orderCancelCancelableEntriesStrategy; + + @Mock + private OrderModel orderModelMock; + @Mock + private UserModel userModelMock; + @Mock + private CancelDecision fullCancelDecisionMock; + @Mock + private CancelDecision partialCancelDecisionMock; + + private OrderData orderDataStub = new OrderData(); + private AbstractOrderEntryModel abstractOrderEntryModelStubOne, abstractOrderEntryModelStubTwo; + private OrderEntryData orderEntryDataStubOne, orderEntryDataStubTwo; + private ProductData productDataStubOne, productDataStubTwo; + + @Before + public void setUp() throws Exception { + abstractOrderEntryModelStubOne = new AbstractOrderEntryModel(); + abstractOrderEntryModelStubTwo = new AbstractOrderEntryModel(); + orderEntryDataStubOne = new OrderEntryData(); + orderEntryDataStubTwo = new OrderEntryData(); + productDataStubOne = new ProductData(); + productDataStubTwo = new ProductData(); + orderDataStub.setEntries(List.of(orderEntryDataStubOne, orderEntryDataStubTwo)); + orderEntryDataStubOne.setProduct(productDataStubOne); + orderEntryDataStubTwo.setProduct(productDataStubTwo); + orderEntryDataStubOne.setEntries(Collections.singletonList(orderEntryDataStubTwo)); + orderEntryDataStubTwo.setEntries(Collections.singletonList(orderEntryDataStubOne)); + orderEntryDataStubTwo.setEntryNumber(1); + orderEntryDataStubOne.setEntryNumber(0); + productDataStubOne.setMultidimensional(Boolean.TRUE); + productDataStubTwo.setMultidimensional(Boolean.FALSE); + when(userServiceMock.getCurrentUser()).thenReturn(userModelMock); + when(orderCancelCancelableEntriesStrategy.getAllCancelableEntries(orderModelMock, userModelMock)).thenReturn(Map.of(abstractOrderEntryModelStubOne, 0L, abstractOrderEntryModelStubTwo, 1L)); + } + + @Test + public void populate_shouldPopulateOrderCancellableFalse() { + when(orderCancelServiceMock.isCancelPossible(orderModelMock, userModelMock, false, false)).thenReturn(partialCancelDecisionMock); + when(partialCancelDecisionMock.isAllowed()).thenReturn(Boolean.FALSE); + when(orderCancelServiceMock.isCancelPossible(orderModelMock, userModelMock, false, false)).thenReturn(fullCancelDecisionMock); + when(fullCancelDecisionMock.isAllowed()).thenReturn(Boolean.FALSE); + + testObj.populate(orderModelMock, orderDataStub); + + assertThat(orderDataStub.isCancellable()).isFalse(); + } + + @Test(expected = IllegalArgumentException.class) + public void populate_ShouldThrowException_whenOrderModelIsNull() { + testObj.populate(null, orderDataStub); + } + + @Test(expected = IllegalArgumentException.class) + public void populate_ShouldThrowException_whenOrderDataIsNull() { + testObj.populate(orderModelMock, null); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/service/AdyenNotificationServiceTest.java b/adyenv6core/testsrc/com/adyen/v6/service/AdyenNotificationServiceTest.java index 6d680a711..ded259594 100644 --- a/adyenv6core/testsrc/com/adyen/v6/service/AdyenNotificationServiceTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/service/AdyenNotificationServiceTest.java @@ -20,6 +20,7 @@ */ package com.adyen.v6.service; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -128,6 +129,7 @@ public void testCaptureNotification() throws Exception { public void testAuthorisationNotification() throws Exception { String pspReference = "123"; String merchantReference = "001"; + final BigDecimal amount = new BigDecimal(2); OrderModel orderModel = createDummyOrderModel(); @@ -136,6 +138,7 @@ public void testAuthorisationNotification() throws Exception { notificationItemModel.setEventCode(EVENT_CODE_AUTHORISATION); notificationItemModel.setMerchantReference(merchantReference); notificationItemModel.setSuccess(true); + notificationItemModel.setAmountValue(amount); when(paymentTransactionRepositoryMock.getTransactionModel(Mockito.any(String.class))).thenReturn(null); @@ -144,10 +147,10 @@ public void testAuthorisationNotification() throws Exception { adyenNotificationService.processNotification(notificationItemModel); //Verify that we emmit the event of Capture to the order processes - verify(businessProcessServiceMock).triggerEvent("order_process_code_AdyenAuthorized"); + verify(businessProcessServiceMock).triggerEvent("order_process_code_AdyenPaymentResult"); //Verify that the authorizeOrderModel is called - verify(adyenTransactionServiceMock).authorizeOrderModel(orderModel, merchantReference, pspReference); + verify(adyenTransactionServiceMock).authorizeOrderModel(orderModel, merchantReference, pspReference, amount); } /** @@ -173,7 +176,7 @@ public void testFailedAuthorisationNotification() { adyenNotificationService.processNotification(notificationItemModel); //Verify that we emmit the event of Capture to the order processes - verify(businessProcessServiceMock).triggerEvent("order_process_code_AdyenAuthorized"); + verify(businessProcessServiceMock).triggerEvent("order_process_code_AdyenPaymentResult"); //Verify that the authorizeOrderModel is called verify(adyenTransactionServiceMock).storeFailedAuthorizationFromNotification(notificationItemModel, orderModel); diff --git a/adyenv6core/testsrc/com/adyen/v6/service/AdyenTransactionServiceTest.java b/adyenv6core/testsrc/com/adyen/v6/service/AdyenTransactionServiceTest.java index abffb902f..3a9adcecc 100644 --- a/adyenv6core/testsrc/com/adyen/v6/service/AdyenTransactionServiceTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/service/AdyenTransactionServiceTest.java @@ -21,25 +21,31 @@ package com.adyen.v6.service; import com.adyen.model.checkout.PaymentsResponse; +import com.adyen.v6.factory.AdyenPaymentServiceFactory; import com.adyen.v6.model.NotificationItemModel; import de.hybris.bootstrap.annotations.UnitTest; import de.hybris.platform.core.model.c2l.CurrencyModel; import de.hybris.platform.core.model.order.OrderModel; import de.hybris.platform.core.model.order.payment.PaymentInfoModel; import de.hybris.platform.orderprocessing.model.OrderProcessModel; -import de.hybris.platform.payment.dto.TransactionStatus; import de.hybris.platform.payment.model.PaymentTransactionEntryModel; import de.hybris.platform.payment.model.PaymentTransactionModel; import de.hybris.platform.servicelayer.i18n.CommonI18NService; import de.hybris.platform.servicelayer.model.ModelService; +import de.hybris.platform.store.BaseStoreModel; +import de.hybris.platform.store.services.BaseStoreService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import static com.adyen.model.notification.NotificationRequestItem.EVENT_CODE_AUTHORISATION; import static com.adyen.model.notification.NotificationRequestItem.EVENT_CODE_CAPTURE; @@ -57,28 +63,44 @@ public class AdyenTransactionServiceTest { private static final String MERCHANT_REFERENCE = "merchantReference"; private static final String PSP_REFERENCE = "pspReference"; + @Spy + @InjectMocks + private DefaultAdyenTransactionService adyenTransactionService; + @Mock private ModelService modelServiceMock; - @Mock private CommonI18NService commonI18NServiceMock; + @Mock + private AdyenPaymentService adyenPaymentServiceMock; + @Mock + private AdyenPaymentServiceFactory adyenPaymentServiceFactoryMock; + @Mock + private BaseStoreService baseStoreServiceMock; - private DefaultAdyenTransactionService adyenTransactionService; + @Mock + private BaseStoreModel baseStoreModelMock; + @Mock + private PaymentTransactionModel paymentTransactionModel; + @Mock + private PaymentTransactionEntryModel paymentTransactionEntryModel; @Before public void setUp() { - when(modelServiceMock.create(PaymentTransactionEntryModel.class)) - .thenReturn(new PaymentTransactionEntryModel()); - - PaymentTransactionModel paymentTransactionModel = new PaymentTransactionModel(); - paymentTransactionModel.setEntries(new ArrayList<>()); - when(modelServiceMock.create(PaymentTransactionModel.class)) - .thenReturn(paymentTransactionModel); + when(modelServiceMock.create(PaymentTransactionEntryModel.class)).thenReturn(new PaymentTransactionEntryModel()); + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(adyenPaymentServiceFactoryMock.createFromBaseStore(baseStoreModelMock)).thenReturn(adyenPaymentServiceMock); + when(adyenTransactionService.getAdyenPaymentService()).thenReturn(adyenPaymentServiceMock); + when(paymentTransactionModel.getEntries()).thenReturn(new ArrayList<>()); + when(modelServiceMock.create(PaymentTransactionModel.class)).thenReturn(paymentTransactionModel); adyenTransactionService = new DefaultAdyenTransactionService(); adyenTransactionService.setModelService(modelServiceMock); adyenTransactionService.setCommonI18NService(commonI18NServiceMock); + adyenTransactionService.setAdyenPaymentServiceFactory(adyenPaymentServiceFactoryMock); + adyenTransactionService.setBaseStoreService(baseStoreServiceMock); + } @Test @@ -113,9 +135,9 @@ public void testCreateCapturedTransactionFromNotification() { @Test public void testAuthorizeOrderModel() { OrderModel orderModel = createDummyOrderModel(); + when(adyenPaymentServiceMock.calculateAmountWithTaxes(orderModel)).thenReturn(new BigDecimal(10)); - PaymentTransactionModel paymentTransactionModel = adyenTransactionService - .authorizeOrderModel(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE); + PaymentTransactionModel paymentTransactionModel = adyenTransactionService.authorizeOrderModel(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE); //Verify that the payment transaction is saved verify(modelServiceMock).save(paymentTransactionModel); @@ -131,8 +153,7 @@ public void testStoreFailedAuthorizationFromNotification() { OrderModel orderModel = createDummyOrderModel(); - PaymentTransactionModel paymentTransactionModel = adyenTransactionService - .storeFailedAuthorizationFromNotification(notificationItemModel, orderModel); + PaymentTransactionModel paymentTransactionModel = adyenTransactionService.storeFailedAuthorizationFromNotification(notificationItemModel, orderModel); //Verify that the payment transaction is saved verify(modelServiceMock).save(paymentTransactionModel); @@ -141,9 +162,11 @@ public void testStoreFailedAuthorizationFromNotification() { @Test public void testCreatePaymentTransactionFromAuthorisedResultCode() { OrderModel orderModel = createDummyOrderModel(); + when(modelServiceMock.create(PaymentTransactionEntryModel.class)).thenReturn(paymentTransactionEntryModel); + when(paymentTransactionModel.getEntries()).thenReturn(Collections.singletonList(paymentTransactionEntryModel)); + when(paymentTransactionEntryModel.getTransactionStatus()).thenReturn(ACCEPTED.name()); - PaymentTransactionModel paymentTransactionModel = adyenTransactionService - .createPaymentTransactionFromResultCode(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE, PaymentsResponse.ResultCodeEnum.AUTHORISED); + PaymentTransactionModel paymentTransactionModel = adyenTransactionService.createPaymentTransactionFromResultCode(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE, PaymentsResponse.ResultCodeEnum.AUTHORISED); //Verify that the payment transaction is saved verify(modelServiceMock).save(paymentTransactionModel); @@ -155,9 +178,11 @@ public void testCreatePaymentTransactionFromAuthorisedResultCode() { @Test public void testCreatePaymentTransactionFromRefusedResultCode() { OrderModel orderModel = createDummyOrderModel(); + when(modelServiceMock.create(PaymentTransactionEntryModel.class)).thenReturn(paymentTransactionEntryModel); + when(paymentTransactionModel.getEntries()).thenReturn(Collections.singletonList(paymentTransactionEntryModel)); + when(paymentTransactionEntryModel.getTransactionStatus()).thenReturn(REJECTED.name()); - PaymentTransactionModel paymentTransactionModel = adyenTransactionService - .createPaymentTransactionFromResultCode(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE, PaymentsResponse.ResultCodeEnum.REFUSED); + PaymentTransactionModel paymentTransactionModel = adyenTransactionService.createPaymentTransactionFromResultCode(orderModel, MERCHANT_REFERENCE, PSP_REFERENCE, PaymentsResponse.ResultCodeEnum.REFUSED); //Verify that the payment transaction is saved verify(modelServiceMock).save(paymentTransactionModel); diff --git a/adyenv6core/testsrc/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorServiceTest.java b/adyenv6core/testsrc/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorServiceTest.java new file mode 100644 index 000000000..f9bf239db --- /dev/null +++ b/adyenv6core/testsrc/com/adyen/v6/service/DefaultAdyenAmazonPayIntegratorServiceTest.java @@ -0,0 +1,94 @@ +package com.adyen.v6.service; + +import com.adyen.v6.enums.AmazonpayEnvironment; +import com.adyen.v6.enums.AmazonpayRegion; +import de.hybris.bootstrap.annotations.UnitTest; +import de.hybris.platform.store.BaseStoreModel; +import de.hybris.platform.store.services.BaseStoreService; +import org.apache.commons.lang.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + + +@UnitTest +@RunWith(MockitoJUnitRunner.class) +public class DefaultAdyenAmazonPayIntegratorServiceTest { + + private static final String FAKE_PUBLIC_KEY = "publicKey"; + private static final String CHECKOUT_SESSION_ID = "checkoutSessionId"; + @InjectMocks + private DefaultAdyenAmazonPayIntegratorService testObj; + @Mock + private BaseStoreService baseStoreServiceMock; + @Mock + private BaseStoreModel baseStoreModelMock; + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenCheckoutSessionIdIsNull() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayEnvironment()).thenReturn(AmazonpayEnvironment.SANDBOX); + when(baseStoreModelMock.getAmazonpayPublicKey()).thenReturn(FAKE_PUBLIC_KEY); + when(baseStoreModelMock.getAmazonpayRegion()).thenReturn(AmazonpayRegion.EU); + + testObj.getAmazonPayTokenByCheckoutSessionId(null); + } + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenCheckoutSessionIdIsEmpty() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayEnvironment()).thenReturn(AmazonpayEnvironment.SANDBOX); + when(baseStoreModelMock.getAmazonpayPublicKey()).thenReturn(FAKE_PUBLIC_KEY); + when(baseStoreModelMock.getAmazonpayRegion()).thenReturn(AmazonpayRegion.EU); + + testObj.getAmazonPayTokenByCheckoutSessionId(StringUtils.EMPTY); + } + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenCurrentBaseStoreIsNotSet() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(null); + + testObj.getAmazonPayTokenByCheckoutSessionId(StringUtils.EMPTY); + } + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenAmazonEnvironmentIsNotSet() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayEnvironment()).thenReturn(null); + + testObj.getAmazonPayTokenByCheckoutSessionId(StringUtils.EMPTY); + } + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenAmazonPublicKeyIsNotSet() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayPublicKey()).thenReturn(null); + + testObj.getAmazonPayTokenByCheckoutSessionId(StringUtils.EMPTY); + } + + @Test(expected = IllegalArgumentException.class) + public void getAmazonPayTokenByCheckoutSessionId_shouldThrownLillegalArgumentException_whenAmazonRegionIsNotSet() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayRegion()).thenReturn(null); + + testObj.getAmazonPayTokenByCheckoutSessionId(StringUtils.EMPTY); + } + + @Test + public void getAmazonPayTokenByCheckoutSessionId_shouldReturnAnEmptyString_whenCheckoutSessionIdIsEmpty() { + when(baseStoreServiceMock.getCurrentBaseStore()).thenReturn(baseStoreModelMock); + when(baseStoreModelMock.getAmazonpayEnvironment()).thenReturn(AmazonpayEnvironment.SANDBOX); + when(baseStoreModelMock.getAmazonpayPublicKey()).thenReturn(FAKE_PUBLIC_KEY); + when(baseStoreModelMock.getAmazonpayRegion()).thenReturn(AmazonpayRegion.EU); + + final String result = testObj.getAmazonPayTokenByCheckoutSessionId(CHECKOUT_SESSION_ID); + + assertThat(result).isEmpty(); + } +} diff --git a/adyenv6core/testsrc/com/adyen/v6/util/TerminalAPIUtilTest.java b/adyenv6core/testsrc/com/adyen/v6/util/TerminalAPIUtilTest.java index 402580492..dde3d0f8a 100644 --- a/adyenv6core/testsrc/com/adyen/v6/util/TerminalAPIUtilTest.java +++ b/adyenv6core/testsrc/com/adyen/v6/util/TerminalAPIUtilTest.java @@ -1,9 +1,14 @@ package com.adyen.v6.util; +import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; + +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; @@ -22,7 +27,7 @@ @RunWith(MockitoJUnitRunner.class) public class TerminalAPIUtilTest { - public static String TEST_RESPONSE_DIR ="resources/test/"; + public static String TEST_RESPONSE_DIR ="test/"; @Test public void testGetPaymentResultFromStatusOrPaymentResponseSuccess() throws IOException { TerminalAPIResponse terminalAPIResponse = createResponseFromFile(TEST_RESPONSE_DIR+"SaleToPOIResponse.json"); @@ -112,8 +117,9 @@ public void testGetErrorMessageForNonAuthorizedPosPayment() throws IOException { assertEquals("checkout.error.authorization.payment.cancelled", errorMessage); } - private static TerminalAPIResponse createResponseFromFile(String fileName) throws IOException { - String json = new String(Files.readAllBytes(Paths.get(fileName)), StandardCharsets.UTF_8); + private TerminalAPIResponse createResponseFromFile(String fileName) throws IOException { + URL resource = getClass().getClassLoader().getResource(fileName); + String json = Files.readString(Path.of(resource.getPath()), StandardCharsets.UTF_8); return TerminalAPIGsonBuilder.create().fromJson(json, new TypeToken() { }.getType()); } diff --git a/adyenv6core/unmanaged-dependencies.txt b/adyenv6core/unmanaged-dependencies.txt new file mode 100644 index 000000000..41c709bd8 --- /dev/null +++ b/adyenv6core/unmanaged-dependencies.txt @@ -0,0 +1 @@ +adyen-java-api-library \ No newline at end of file diff --git a/adyenv6fulfilmentprocess/.classpath b/adyenv6fulfilmentprocess/.classpath deleted file mode 100644 index b6f3c37af..000000000 --- a/adyenv6fulfilmentprocess/.classpath +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6fulfilmentprocess/extensioninfo.xsd b/adyenv6fulfilmentprocess/extensioninfo.xsd new file mode 100644 index 000000000..7b0f1b274 --- /dev/null +++ b/adyenv6fulfilmentprocess/extensioninfo.xsd @@ -0,0 +1,237 @@ + + + + + + + Configures the available modules of the extension. + + + + Configures the available modules of the extension. + + + + + + + + + + Configures the available modules of the extension. + + + + + Configures the set of extensions required by the extension at compile time. If you set 'autoload=true' in the localextensions.xml file, you will not need to reference any core extensions here. + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + + Configures a web module for the extension. Required directory: /web. + + + + + Configures an hMC module for the extension. Required directory: /hmc. + + + + + Configures metadata. + + + + + + + Name of the extension. Do not use special characters or spaces. + + + + + Optionally defines the version of this extension. If not defined the build process assumes it being the same version as the platform. + + + + + Prefix used for generated extension classes, such as the classes for Constants. Default is "[extensionname]". + + + + + Prefix for generated Java classes, such as the abstract classes for getter and setter methods. Default is "Generated". + + + + + Deprecated. Default is "false". + + + + + If 'true' this extension is treated like platform/ext core extensions and is automtically added to all other extension dependencies. + + + + + Class name of the manager class. Default is "[classprefix]Manager" + + + + + Class name of the manager's superclass. Default is de.hybris.platform.jalo.extension.Extension. + + + + + Short description of this extension. Is used by the hybris package manager. + + + + + If 'true' uses maven and external-dependencies.xml file for fetching required libraries into \lib and \web\webroot\WEB-INF\lib. + + + + + If 'true' types introduced by this extension are SLD safe by default and contains no JALO logic. + + + + + + + Configures the set of extensions required by the extension at compile time. + + + + Name of an extension which is required at compile time. + + + + + Allowed range of versions of the required extension. Is used by the hybris package manager. + + + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + Deprecated. Not used anymore. + + + + + Package root where extension and item classes will be generated to. + + + + + Fully qualified Java class name of the extension's manager. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'src' directory is available + + + + + If "true", item and extension classes will be generated. Only needed in case of "sourceavailable=true". Default is "false". + + + + + Deprecated. Will always be evaluated to 'true'. Generated item and extension classes will use java generics and annotations. + + + + + If "true", the generated item and extension classes will use the partOf handler, so partOf references will be removed if the holding item is removed. Default is "true". + + + + + + + Configures an hMC module for the extension. Required directory: /web. + + + + Webroot where the web application will be available at. + + + + + Deprecated. Not used anymore. + + + + + If "true", JSP files will be pre-compiled as part of the build process. If "false", JSP files will be compiled when first used by the application server. Default is "true". + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'web/src' directory is available + + + + + + + Configures an hmc module for the extension. Required directory: /hmc. + + + + Deprecated. Not used anymore. + + + + + Name of the extension's HMCExtension class. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'hmc/src' directory is available + + + + + + + Configures metadata. + + + + Metadata key. + + + + + Metadata value. + + + + + + + A class name including full package name. + + + + + diff --git a/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/adyenv6fulfilmentprocess-testclasses.xml b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/adyenv6fulfilmentprocess-testclasses.xml new file mode 100644 index 000000000..38e6c65f2 --- /dev/null +++ b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/adyenv6fulfilmentprocess-testclasses.xml @@ -0,0 +1 @@ +com.adyen.v6.jalo.Adyenv6fulfilmentprocessTest \ No newline at end of file diff --git a/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process-spring.xml b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process-spring.xml index b17bff021..fbfa3f814 100644 --- a/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process-spring.xml +++ b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process-spring.xml @@ -34,7 +34,10 @@ - + + + + diff --git a/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process.xml b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process.xml new file mode 100644 index 000000000..e89464714 --- /dev/null +++ b/adyenv6fulfilmentprocess/resources/adyenv6fulfilmentprocess/process/order-process.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + ${process.order.code}_ReviewDecision + + + + + + + + + + + + + + ${process.code}_CSAOrderVerified + + + + + + + + + + + + + + ${process.code}_CleanUpEvent + + + + + + + + + + + + + + + + + + + + + + + + + + ${process.code}_AdyenCaptured + + + + + + + + + + + + + + + + + + + + + + + + + ${process.code}_ConsignmentSubprocessEnd + + + + + + + + + + + + All went wrong. + Order not placed. + Order placed. + + \ No newline at end of file diff --git a/adyenv6fulfilmentprocess/resources/beans.xsd b/adyenv6fulfilmentprocess/resources/beans.xsd new file mode 100644 index 000000000..8c08411ae --- /dev/null +++ b/adyenv6fulfilmentprocess/resources/beans.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the type of bean. Allowed are 'bean' or 'event'. + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Marks property as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + + + + + + + + Marks bean as deprecated. Allows defining a message. + + + + + Marks bean as deprecated. Sets the deprecatedSince attribute. + + + + + + + \ No newline at end of file diff --git a/adyenv6fulfilmentprocess/resources/items.xsd b/adyenv6fulfilmentprocess/resources/items.xsd new file mode 100644 index 000000000..8aa3c6bb9 --- /dev/null +++ b/adyenv6fulfilmentprocess/resources/items.xsd @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + Corresponding Java class in the hybris Suite; will also be used as the code of the atomic type. + + + + + If 'true', the AtomicType will be created during initialization. + + + + + Deprecated. Has no effect for atomic types. Default is 'true'. + + + + + Defines the class which will be extended. Default is 'java.lang.Object'. + + + + + + + + Defines a list of atomic types. + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + + + + + A CollectionType defines a collection of typed elements. Attention: If using a collection type for persistent attributes (not jalo) you can not search on that attribute and you are limited in size of collection. Consider to use a relation instead. + + + + The code (that is, qualifier) of the CollectionType. + + + + + The type of elements of this CollectionType. + + + + + If 'true', the CollectionType will be created during initialization. + + + + + Deprecated. Has no effect for collection types. Default is 'true'. + + + + + Configures the type of this collection: 'set', 'list', 'collection'. The getter / setter methods will use corresponding Java collection interfaces. Default is 'collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + + + Defines a list of collection types. + + + + + + A CollectionType defines a collection of typed elements. + + + + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + The mapped database table. Must be globally unique. + + + + + The mapped item type code. Must be globally unique + + + + + The mapped dump property database table to be used for this item. Default is 'props'. + + + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Configures deployment information for this relation (table name and typecode). + + + + + Configures the generated attribute at source relation end + + + + + Configures the generated attribute at target relation end + + + + + + The typecode. + + + + + A localized n-m relation can have a link between two items for each language. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', the item will be created during initialization. + + + + + Deprecated. Will have no effect for relations. + + + + + + + + Defines a list of relation types. + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + + + + Configures the generated attribute at one relation end. + + + + + Documents this relation attribute. Will be cited at javadoc of generated getters/setters. + + + + + Defines properties for the attribute. + + + + + Allows to configure model generation for this relation attribute used at servicelayer. + + + + + Allows to configure custom properties for the relation attribute. + + + + + + Type of attribute which will be generated at type configured for opposite relation end. + + + + + Qualifier of attribute which will be generated at type configured for opposite relation end. If navigable is not set to false the qualifier is mandatory. Default is empty. + + + + + The (meta)type which describes the attributes type. Must be type extending RelationDescriptor. Default is 'RelationDescriptor'. + + + + + The cardinality of this relation end. Choose 'one' for 'one' part of a 1:n relation or 'many' when part of a n:m relation. A 1:1 relation is not supported. Default is 'many'. + + + + + + The element is the 'one' part of a 1:n relation + + + + + The element is part of a n:m relation + + + + + + + + Is the relation navigable from this side. Can only be disabled for one side of many to many relation. If disabled, no qualifier as well as modifiers can be defined. Default is 'true'. + + + + + Configures the type of this collection if element has cardinality 'many'. Related attribute getter / setter will use corresponding java collection interfaces. Default is 'Collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + If 'true' an additional ordering attribute will be generated for maintaining ordering. Default is 'false'. + + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Allows changing enum model settings. + + + + + Configures one value of this Enumeration. + + + + + + The unique code of this Enumeration. + + + + + If 'true', the item will be created during initialization. + + + + + If 'false' no constants will be generated at constant class of extension as well as at corresponding servicelayer enum class. Default is 'true'. + + + + + Specifies the name of the associated jalo class. The specified class must extend de.hybris.platform.jalo.enumeration.EnumerationValue and will not be generated. By specifying a jalo class you can change the implementation to use for the values of this enumeration. By default EnumerationValue class is used. + + + + + Whether it is possible to add new values by runtime. Also results in different types of enums: 'true' results in 'classic' hybris enums, 'false' results in Java enums. Default is false. Both kinds of enums are API compatible, and switching between enum types is possible by running a system update. + + + + + Marks enum as deprecated since specified version. + + + + + + + Defines a list of enumeration types. + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + + + + Configures a database index for enclosing type. + + + + + Configures a single index key. + + + + + Configures a single index include column. + + + + + + The name prefix of the index. + + + + + If 'true' this index will be ommitted while in initialization process even if there were precendent declarations.This attribute has effect only if replace = true. + + + + + If 'true' this index is a replacement/redeclaration for already existing index. + + + + + If 'true', the value of this attribute has to be unique within all instances of this index. Attributes with persistence type set to 'jalo' can not be unique. Default is 'false'. + + + + + Determines index creation mode. + + + + + + Create index on all supported databases (default) + + + + + Force creation on Database which by default prevents index creation by external configuration + + + + + Create index only on SAP Hana database + + + + + Create index only on MySQL database + + + + + Create index only on Oracle database + + + + + Create index only on MSSQL Server database + + + + + Create index only on HSQL database + + + + + Create index only on PostgreSQL database + + + + + + + + + + Configures a single index key. + + + + Type attribute to be indexed. + + + + + Elements will be indexed case-insensitive. Default is 'false'. + + + + + + + Configures a single index include column. + + + + Type attribute to be indexed. + + + + + + + Defines an attribute of a type. + + + + + Configures a default value for this attribute used if no value is provided. The default value is calculated by initialization and will not be re-calculated by runtime. + + + + + Gives a description for this attribute only used for the javadoc of generated attribute methods. + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + Configures advanced settings for this attribute definition. + + + + + Allows to configure custom properties for this attribute. + + + + + Allows to configure model generation settings for this attribute. Models are used by the hybris ServiceLayer. + + + + + + Lets you re-define the attribute definition from an inherited type. In essence, you can use a different type of attribute as well as different modifier combinations than on the supertype. Default is 'false'. + + + + + Qualifier of this attribute. Attribute qualifiers must be unique across a single type. + + + + + The type of the attribute, such as 'Product', 'int' or 'java.lang.String'. Primitive java types will be mapped to the corresponding atomic type. For example: 'int' will be mapped to the atomic type 'java.lang.Integer' with implicit default value. + + + + + Advanced setting. Specifies the metatype for the attributes definition. Must be a type extending AttributeDescriptor. Default is 'AttributeDescriptor'. + + + + + If 'true', the attribute descriptor will be created during initialization. Default is 'true'. + + + + + If 'true', getter and setter methods for this attribute will be generated during a hybris Suite build. Default is 'true'. + + + + + References an attribute of the same type. Only values of the referenced attribute can be selected as values for this attribute. Typical example: the default delivery address of a customer must be one of the addresses set for the customer. Default is 'false'. + + + + + + + Allows to configure model generation for this attribute used at servicelayer. + + + + + + Allows to configure alternative getter methods at generated model. + + + + + + + Allows to configure alternative setter methods at generated model. + + + + + + + Whether getter and setter methods for the model representation of the attribute will be generated. Default is 'true'. + + + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + Allows to configure model constructor signatures. + + + + + + + Whether a model for the type and models for subtypes will be generated. Default is 'true'. + + + + + + + Allows to configure model constructor signatures. + + + + Add here, as comma separated list, the attribute qualifiers for the constructor signature in the model. + + + + + + + Allows to configure alternative methods at generated model. + + + + + + + + Name of the alternative getter method. + + + + + + + Will the method be marked deprecated? Default is + false. + + + + + + + Version since when this method is marked as deprecated. Settting deprecatedSince attribute automatically + sets deprecated attribute to true. + + + + + + Will this method be the default method and replace the original one instead of adding it additional? Default is false. + + + + + + + Defines custom properties. + + + + + Defines a custom property. + + + + + + + + Defines a custom property. + + + + + The value of the custom property. + + + + + + The name of the custom property. + + + + + + + Configures a list of attributes. + + + + + Defines a single attribute. + + + + + + + + Configures a list of indexes. + + + + + Configures a single index. + + + + + + + + Specifies a specific ComposedType. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + + Defines a list of custom properties for this type. + + + + + Defines the list of item attributes. + + + + + Defines the database indexes for this type. + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + The unique code of this type. + + + + + Defines the class, which will be extended. Default is 'GenericItem'. + + + + + Specifies the name of the associated jalo class. Default is [extension-root-package].jalo.[type-code] which will be generated if not existent. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', type gets marked as singleton which will be evaluated by some modules like hmc or impex, with that allowing only one instance per system. Default is 'false'. + + + + + DEPRECATED. Use 'implements JaloOnlyItem' in your bean. If 'true', the item will only exists in the jalo layer and isn't backed by an entity bean. Default is 'false'. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + If 'true', the sourcecode for this item will be created. Default is 'true'. + + + + + Marks type and jalo class as abstract. If 'true', the type can not be instantiated. Default is 'false'. + + + + + The (meta)type which describes the assigned type. Must be a type extensing ComposedType. Default is 'ComposedType'. + + + + + Marks item as deprecated since specified version. + + + + + + + Defines a grouping of item types. + + + + + Specifies a specific ComposedType. + + + + + Specifies a group of ComposedTypes to allow better structuring within the items.xml file. + + + + + + + + + + Specifies a specific ComposedType. + + + + + + Defines the name of this group. Only for structural purpose, will have no effect on runtime. Default is empty. + + + + + + + Defines the types of your extension. + + + + + + Defines the list of AtomicType's for your extension. + + + + + Defines the list of CollectionType's for your extension. + + + + + Defines the list of EnumerationType's for your extension. + + + + + Defines the list of MapType's for your extension. + + + + + Defines the list of RelationType's for your extension. + + + + + Defines the list of ComposedType's for your extension. + + + + + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + The unique code of the map. + + + + + The type of the key attributes. + + + + + The type of the value attributes. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'false'. + + + + + + + Specifies a list of map types. + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + + + + + Specifies further properties of an attribute which can be redeclared at other extensions. + + + + Defines if this attribute is readable (that is, if a getter method will be generated). Default is 'true'. The visibility of the getter depends on the value of the private attribute. + + + + + Defines if this attribute is writable (that is, if a setter method will be generated). Default is 'true'. The visibility of the setter depends on the value of the private attribute. + + + + + Defines if this attribute is searchable by a FlexibleSearch. Default is 'true'. Attributes with persistence type set to 'jalo' can not be searchable. + + + + + Defines if this attribute is mandatory or optional. Default is 'true' for optional. Set to 'false' for mandatory. + + + + + Defines the Java visibility of the generated getter and setter methods for this attribute. If 'true', the visibility modifier of generated methods is set to 'protected'; if 'false', the visibility modifier is 'public'. Default is 'false' for 'public' generated methods. Also, you will have no generated methods in the ServiceLayer if 'true'. + + + + + If 'true', the attribute will only be writable during the item creation. Setting this to 'true' is only useful in combination with write='false'. Default is 'false'. + + + + + Defines if this attribute is removable. Default is 'true'. + + + + + Defines if the assigned attribute value only belongs to the current instance of this type. Default is 'false'. + + + + + If 'true', the value of this attribute has to be unique within all instances of this type. If there are multiple attributes marked as unique, then their combined values must be unique. Will not be evaluated at jalo layer, if you want to manage the attribute directly using jalo layer you have to ensure uniqueness manually. Default is 'false'. + + + + + If 'true' the attribute value will be stored in the 'global' property table, otherwise a separate column (inside the table of the associated type)will be created for storing its values. Default is 'false'. + + + + + If 'true', the attribute value will be stored in an encrypted way. Default is 'false'. + + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent), and 'property' (persistent). + + + + + Configures a persistence definition for a specific database used at create statement. + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + + Attribte will be stored persistent. + + + + + Attribte will be stored non-persistent (deprecated, please use dynamic instead). + + + + + Deprecated. + + + + + Defines that attribute dynamic. + + + + + + + + Deprecated. Only usable in relation with 'cmp' and 'property'(compatibility reasons) persistence type. Default is empty. + + + + + Spring bean id that handles dynamic attributes implementation. + + + + + + + Configures a persistence definition for a specific database. + + + + + The attribute type used in the create statement of the database table, such as 'varchar2(4000)'. + + + + + + + + + The database the given definition will be used for. One of 'oracle', 'mysql', 'sqlserver' or 'hsql'. Default is empty which configures fallback for non specified databases. + + + + + + + Defines a default value text. + + + + + + + Configures a single element. + + + + The unique code of this element. + + + + + + + Configures a single enum model pojo. + + + + Defines the package for the actual enum model pojo. + + + + + + + Configures a single enum value. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + + The unique code of this element. + + + + + + + Configures the code of an enumeration value element. Must start with a letter or underscore. + + + + + + + + + Configures the code of an element. + + + + + + + Deprecated. Defines a reference to a deployment definition. + + + + + + + Configures the class to use for enclosing element. + + + + diff --git a/adyenv6fulfilmentprocess/ruleset.xml b/adyenv6fulfilmentprocess/ruleset.xml deleted file mode 100644 index 73c9d8bfb..000000000 --- a/adyenv6fulfilmentprocess/ruleset.xml +++ /dev/null @@ -1,755 +0,0 @@ - - - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - Java PMD ruleset for hybris - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6notification/resources/adyenv6notification/adyenv6notification-webtestclasses.xml b/adyenv6notification/resources/adyenv6notification/adyenv6notification-webtestclasses.xml new file mode 100644 index 000000000..67101ada4 --- /dev/null +++ b/adyenv6notification/resources/adyenv6notification/adyenv6notification-webtestclasses.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/adyenv6notification/ruleset.xml b/adyenv6notification/ruleset.xml deleted file mode 100644 index 6cd1d06b6..000000000 --- a/adyenv6notification/ruleset.xml +++ /dev/null @@ -1,765 +0,0 @@ - - - - - Java PMD ruleset for hybris - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6ordermanagement/.classpath b/adyenv6ordermanagement/.classpath deleted file mode 100644 index 9914e8a9e..000000000 --- a/adyenv6ordermanagement/.classpath +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adyenv6ordermanagement/.project b/adyenv6ordermanagement/.project deleted file mode 100644 index 0b0d390ed..000000000 --- a/adyenv6ordermanagement/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - adyenv6ordermanagement - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/adyenv6ordermanagement/extensioninfo.xsd b/adyenv6ordermanagement/extensioninfo.xsd new file mode 100644 index 000000000..7b0f1b274 --- /dev/null +++ b/adyenv6ordermanagement/extensioninfo.xsd @@ -0,0 +1,237 @@ + + + + + + + Configures the available modules of the extension. + + + + Configures the available modules of the extension. + + + + + + + + + + Configures the available modules of the extension. + + + + + Configures the set of extensions required by the extension at compile time. If you set 'autoload=true' in the localextensions.xml file, you will not need to reference any core extensions here. + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + + Configures a web module for the extension. Required directory: /web. + + + + + Configures an hMC module for the extension. Required directory: /hmc. + + + + + Configures metadata. + + + + + + + Name of the extension. Do not use special characters or spaces. + + + + + Optionally defines the version of this extension. If not defined the build process assumes it being the same version as the platform. + + + + + Prefix used for generated extension classes, such as the classes for Constants. Default is "[extensionname]". + + + + + Prefix for generated Java classes, such as the abstract classes for getter and setter methods. Default is "Generated". + + + + + Deprecated. Default is "false". + + + + + If 'true' this extension is treated like platform/ext core extensions and is automtically added to all other extension dependencies. + + + + + Class name of the manager class. Default is "[classprefix]Manager" + + + + + Class name of the manager's superclass. Default is de.hybris.platform.jalo.extension.Extension. + + + + + Short description of this extension. Is used by the hybris package manager. + + + + + If 'true' uses maven and external-dependencies.xml file for fetching required libraries into \lib and \web\webroot\WEB-INF\lib. + + + + + If 'true' types introduced by this extension are SLD safe by default and contains no JALO logic. + + + + + + + Configures the set of extensions required by the extension at compile time. + + + + Name of an extension which is required at compile time. + + + + + Allowed range of versions of the required extension. Is used by the hybris package manager. + + + + + + + Configures a core module for the extension. A core module consists of an items.xml file (and therefore allows to add new types to the system), a manager class, classes for the JaLo Layer and the ServiceLayer and JUnit test classes. The following directories are required: /src, /resources, /testsrc. + + + + Deprecated. Not used anymore. + + + + + Package root where extension and item classes will be generated to. + + + + + Fully qualified Java class name of the extension's manager. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'src' directory is available + + + + + If "true", item and extension classes will be generated. Only needed in case of "sourceavailable=true". Default is "false". + + + + + Deprecated. Will always be evaluated to 'true'. Generated item and extension classes will use java generics and annotations. + + + + + If "true", the generated item and extension classes will use the partOf handler, so partOf references will be removed if the holding item is removed. Default is "true". + + + + + + + Configures an hMC module for the extension. Required directory: /web. + + + + Webroot where the web application will be available at. + + + + + Deprecated. Not used anymore. + + + + + If "true", JSP files will be pre-compiled as part of the build process. If "false", JSP files will be compiled when first used by the application server. Default is "true". + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'web/src' directory is available + + + + + + + Configures an hmc module for the extension. Required directory: /hmc. + + + + Deprecated. Not used anymore. + + + + + Name of the extension's HMCExtension class. + + + + + Deprecated. Has no effect and will be evaluated always to 'true' if a 'hmc/src' directory is available + + + + + + + Configures metadata. + + + + Metadata key. + + + + + Metadata value. + + + + + + + A class name including full package name. + + + + + diff --git a/adyenv6ordermanagement/resources/adyenv6ordermanagement/adyenv6ordermanagement-testclasses.xml b/adyenv6ordermanagement/resources/adyenv6ordermanagement/adyenv6ordermanagement-testclasses.xml new file mode 100644 index 000000000..295d4bb15 --- /dev/null +++ b/adyenv6ordermanagement/resources/adyenv6ordermanagement/adyenv6ordermanagement-testclasses.xml @@ -0,0 +1 @@ +com.adyen.v6.actions.returns.AdyenCaptureRefundActionTest \ No newline at end of file diff --git a/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process-spring.xml b/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process-spring.xml index bbc6b270a..744eec19c 100644 --- a/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process-spring.xml +++ b/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process-spring.xml @@ -17,7 +17,10 @@ - + + + + diff --git a/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process.xml b/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process.xml new file mode 100755 index 000000000..78f637573 --- /dev/null +++ b/adyenv6ordermanagement/resources/adyenv6ordermanagement/process/order-process.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSAOrderVerified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AdyenCaptured + + + + + + + + + + + Order process error. + Order process failed. + Order process completed. + + diff --git a/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-process-order.impex b/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-process-order.impex new file mode 100644 index 000000000..d85c25bcc --- /dev/null +++ b/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-process-order.impex @@ -0,0 +1,175 @@ +# ###### +# ###### +# ############ ####( ###### #####. ###### ############ ############ +# ############# #####( ###### #####. ###### ############# ############# +# ###### #####( ###### #####. ###### ##### ###### ##### ###### +# ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### +# ###### ###### #####( ###### #####. ###### ##### ##### ###### +# ############# ############# ############# ############# ##### ###### +# ############ ############ ############# ############ ##### ###### +# ###### +# ############# +# ############ +# +# Adyen Hybris Extension +# +# Copyright (c) 2017 Adyen B.V. +# This file is open source and available under the MIT license. +# See the LICENSE file for more info. + +INSERT_UPDATE DynamicProcessDefinition;code[unique=true];active[unique=true];content +;adyen-order-process;true;" + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + + + + + AdyenPaymentResult + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSAOrderVerified + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AdyenCaptured + + + + + + + + + + +Order process error. +Order process failed. +Order process completed. + +" + +$storeUid=electronics +$orderProcessCode=adyen-order-process + +UPDATE BaseStore;uid[unique=true];submitOrderProcessCode +;$storeUid;$orderProcessCode diff --git a/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-return-order.impex b/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-return-order.impex new file mode 100644 index 000000000..b9c919429 --- /dev/null +++ b/adyenv6ordermanagement/resources/impex/projectdata-dynamic-business-return-order.impex @@ -0,0 +1,120 @@ +# ###### +# ###### +# ############ ####( ###### #####. ###### ############ ############ +# ############# #####( ###### #####. ###### ############# ############# +# ###### #####( ###### #####. ###### ##### ###### ##### ###### +# ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### +# ###### ###### #####( ###### #####. ###### ##### ##### ###### +# ############# ############# ############# ############# ##### ###### +# ############ ############ ############# ############ ##### ###### +# ###### +# ############# +# ############ +# +# Adyen Hybris Extension +# +# Copyright (c) 2017 Adyen B.V. +# This file is open source and available under the MIT license. +# See the LICENSE file for more info. + +INSERT_UPDATE DynamicProcessDefinition;code[unique=true];active[unique=true];content +;adyen-return-process;true;" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AdyenRefunded + + + + + + + + + + + + + + + + + + + + FailTaxReverseEvent + + + + + + + + + + + + + + +Return issue detected. +Return process ended as expected. +" + +$storeUid=electronics +$orderReturnCode=adyen-return-process + +UPDATE BaseStore;uid[unique=true];createReturnProcessCode +;$storeUid;$orderReturnCode diff --git a/adyenv6ordermanagement/resources/items.xsd b/adyenv6ordermanagement/resources/items.xsd new file mode 100644 index 000000000..8aa3c6bb9 --- /dev/null +++ b/adyenv6ordermanagement/resources/items.xsd @@ -0,0 +1,1136 @@ + + + + + + + + + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + Corresponding Java class in the hybris Suite; will also be used as the code of the atomic type. + + + + + If 'true', the AtomicType will be created during initialization. + + + + + Deprecated. Has no effect for atomic types. Default is 'true'. + + + + + Defines the class which will be extended. Default is 'java.lang.Object'. + + + + + + + + Defines a list of atomic types. + + + + + + An AtomicType represents a simple java object. (The name 'atomic' just means 'non-composed' objects.) + + + + + + + + A CollectionType defines a collection of typed elements. Attention: If using a collection type for persistent attributes (not jalo) you can not search on that attribute and you are limited in size of collection. Consider to use a relation instead. + + + + The code (that is, qualifier) of the CollectionType. + + + + + The type of elements of this CollectionType. + + + + + If 'true', the CollectionType will be created during initialization. + + + + + Deprecated. Has no effect for collection types. Default is 'true'. + + + + + Configures the type of this collection: 'set', 'list', 'collection'. The getter / setter methods will use corresponding Java collection interfaces. Default is 'collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + + + Defines a list of collection types. + + + + + + A CollectionType defines a collection of typed elements. + + + + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + The mapped database table. Must be globally unique. + + + + + The mapped item type code. Must be globally unique + + + + + The mapped dump property database table to be used for this item. Default is 'props'. + + + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Configures deployment information for this relation (table name and typecode). + + + + + Configures the generated attribute at source relation end + + + + + Configures the generated attribute at target relation end + + + + + + The typecode. + + + + + A localized n-m relation can have a link between two items for each language. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', the item will be created during initialization. + + + + + Deprecated. Will have no effect for relations. + + + + + + + + Defines a list of relation types. + + + + + + A RelationType defines a n-m or 1-n relation between types. + + + + + + + + Configures the generated attribute at one relation end. + + + + + Documents this relation attribute. Will be cited at javadoc of generated getters/setters. + + + + + Defines properties for the attribute. + + + + + Allows to configure model generation for this relation attribute used at servicelayer. + + + + + Allows to configure custom properties for the relation attribute. + + + + + + Type of attribute which will be generated at type configured for opposite relation end. + + + + + Qualifier of attribute which will be generated at type configured for opposite relation end. If navigable is not set to false the qualifier is mandatory. Default is empty. + + + + + The (meta)type which describes the attributes type. Must be type extending RelationDescriptor. Default is 'RelationDescriptor'. + + + + + The cardinality of this relation end. Choose 'one' for 'one' part of a 1:n relation or 'many' when part of a n:m relation. A 1:1 relation is not supported. Default is 'many'. + + + + + + The element is the 'one' part of a 1:n relation + + + + + The element is part of a n:m relation + + + + + + + + Is the relation navigable from this side. Can only be disabled for one side of many to many relation. If disabled, no qualifier as well as modifiers can be defined. Default is 'true'. + + + + + Configures the type of this collection if element has cardinality 'many'. Related attribute getter / setter will use corresponding java collection interfaces. Default is 'Collection'. + + + + + + A collection that contains no duplicate elements. + + + + + An ordered collection. + + + + + A collection. + + + + + + + + If 'true' an additional ordering attribute will be generated for maintaining ordering. Default is 'false'. + + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + Allows changing enum model settings. + + + + + Configures one value of this Enumeration. + + + + + + The unique code of this Enumeration. + + + + + If 'true', the item will be created during initialization. + + + + + If 'false' no constants will be generated at constant class of extension as well as at corresponding servicelayer enum class. Default is 'true'. + + + + + Specifies the name of the associated jalo class. The specified class must extend de.hybris.platform.jalo.enumeration.EnumerationValue and will not be generated. By specifying a jalo class you can change the implementation to use for the values of this enumeration. By default EnumerationValue class is used. + + + + + Whether it is possible to add new values by runtime. Also results in different types of enums: 'true' results in 'classic' hybris enums, 'false' results in Java enums. Default is false. Both kinds of enums are API compatible, and switching between enum types is possible by running a system update. + + + + + Marks enum as deprecated since specified version. + + + + + + + Defines a list of enumeration types. + + + + + + An EnumerationType defines fixed value types. (The typesystem provides item enumeration only) + + + + + + + + Configures a database index for enclosing type. + + + + + Configures a single index key. + + + + + Configures a single index include column. + + + + + + The name prefix of the index. + + + + + If 'true' this index will be ommitted while in initialization process even if there were precendent declarations.This attribute has effect only if replace = true. + + + + + If 'true' this index is a replacement/redeclaration for already existing index. + + + + + If 'true', the value of this attribute has to be unique within all instances of this index. Attributes with persistence type set to 'jalo' can not be unique. Default is 'false'. + + + + + Determines index creation mode. + + + + + + Create index on all supported databases (default) + + + + + Force creation on Database which by default prevents index creation by external configuration + + + + + Create index only on SAP Hana database + + + + + Create index only on MySQL database + + + + + Create index only on Oracle database + + + + + Create index only on MSSQL Server database + + + + + Create index only on HSQL database + + + + + Create index only on PostgreSQL database + + + + + + + + + + Configures a single index key. + + + + Type attribute to be indexed. + + + + + Elements will be indexed case-insensitive. Default is 'false'. + + + + + + + Configures a single index include column. + + + + Type attribute to be indexed. + + + + + + + Defines an attribute of a type. + + + + + Configures a default value for this attribute used if no value is provided. The default value is calculated by initialization and will not be re-calculated by runtime. + + + + + Gives a description for this attribute only used for the javadoc of generated attribute methods. + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + Configures advanced settings for this attribute definition. + + + + + Allows to configure custom properties for this attribute. + + + + + Allows to configure model generation settings for this attribute. Models are used by the hybris ServiceLayer. + + + + + + Lets you re-define the attribute definition from an inherited type. In essence, you can use a different type of attribute as well as different modifier combinations than on the supertype. Default is 'false'. + + + + + Qualifier of this attribute. Attribute qualifiers must be unique across a single type. + + + + + The type of the attribute, such as 'Product', 'int' or 'java.lang.String'. Primitive java types will be mapped to the corresponding atomic type. For example: 'int' will be mapped to the atomic type 'java.lang.Integer' with implicit default value. + + + + + Advanced setting. Specifies the metatype for the attributes definition. Must be a type extending AttributeDescriptor. Default is 'AttributeDescriptor'. + + + + + If 'true', the attribute descriptor will be created during initialization. Default is 'true'. + + + + + If 'true', getter and setter methods for this attribute will be generated during a hybris Suite build. Default is 'true'. + + + + + References an attribute of the same type. Only values of the referenced attribute can be selected as values for this attribute. Typical example: the default delivery address of a customer must be one of the addresses set for the customer. Default is 'false'. + + + + + + + Allows to configure model generation for this attribute used at servicelayer. + + + + + + Allows to configure alternative getter methods at generated model. + + + + + + + Allows to configure alternative setter methods at generated model. + + + + + + + Whether getter and setter methods for the model representation of the attribute will be generated. Default is 'true'. + + + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + Allows to configure model constructor signatures. + + + + + + + Whether a model for the type and models for subtypes will be generated. Default is 'true'. + + + + + + + Allows to configure model constructor signatures. + + + + Add here, as comma separated list, the attribute qualifiers for the constructor signature in the model. + + + + + + + Allows to configure alternative methods at generated model. + + + + + + + + Name of the alternative getter method. + + + + + + + Will the method be marked deprecated? Default is + false. + + + + + + + Version since when this method is marked as deprecated. Settting deprecatedSince attribute automatically + sets deprecated attribute to true. + + + + + + Will this method be the default method and replace the original one instead of adding it additional? Default is false. + + + + + + + Defines custom properties. + + + + + Defines a custom property. + + + + + + + + Defines a custom property. + + + + + The value of the custom property. + + + + + + The name of the custom property. + + + + + + + Configures a list of attributes. + + + + + Defines a single attribute. + + + + + + + + Configures a list of indexes. + + + + + Configures a single index. + + + + + + + + Specifies a specific ComposedType. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + A deployment defines how a (generic) item or relation is mapped onto the database. + + + + + Defines a list of custom properties for this type. + + + + + Defines the list of item attributes. + + + + + Defines the database indexes for this type. + + + + + Allows to configure model generation for this item used at servicelayer. + + + + + + The unique code of this type. + + + + + Defines the class, which will be extended. Default is 'GenericItem'. + + + + + Specifies the name of the associated jalo class. Default is [extension-root-package].jalo.[type-code] which will be generated if not existent. + + + + + Deprecated, please use separate deployment sub tag. All instances of this type will be stored in a separated database table. The value of this attribute represents a reference to the specified deployment in the corresponding 'advanced-deployment.xml'. Default is empty. + + + + + If 'true', type gets marked as singleton which will be evaluated by some modules like hmc or impex, with that allowing only one instance per system. Default is 'false'. + + + + + DEPRECATED. Use 'implements JaloOnlyItem' in your bean. If 'true', the item will only exists in the jalo layer and isn't backed by an entity bean. Default is 'false'. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + If 'true', the sourcecode for this item will be created. Default is 'true'. + + + + + Marks type and jalo class as abstract. If 'true', the type can not be instantiated. Default is 'false'. + + + + + The (meta)type which describes the assigned type. Must be a type extensing ComposedType. Default is 'ComposedType'. + + + + + Marks item as deprecated since specified version. + + + + + + + Defines a grouping of item types. + + + + + Specifies a specific ComposedType. + + + + + Specifies a group of ComposedTypes to allow better structuring within the items.xml file. + + + + + + + + + + Specifies a specific ComposedType. + + + + + + Defines the name of this group. Only for structural purpose, will have no effect on runtime. Default is empty. + + + + + + + Defines the types of your extension. + + + + + + Defines the list of AtomicType's for your extension. + + + + + Defines the list of CollectionType's for your extension. + + + + + Defines the list of EnumerationType's for your extension. + + + + + Defines the list of MapType's for your extension. + + + + + Defines the list of RelationType's for your extension. + + + + + Defines the list of ComposedType's for your extension. + + + + + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + The unique code of the map. + + + + + The type of the key attributes. + + + + + The type of the value attributes. + + + + + If 'true', the item will be created during initialization. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'true'. + + + + + Deprecated. Has no effect for map types. Default is 'false'. + + + + + + + Specifies a list of map types. + + + + + Like the java collection framework, a type, which defines map objects. Attention: When used as type for an attribute, the attribute will not be searchable and the access performance is not effective. Consider to use a relation. + + + + + + + + Specifies further properties of an attribute which can be redeclared at other extensions. + + + + Defines if this attribute is readable (that is, if a getter method will be generated). Default is 'true'. The visibility of the getter depends on the value of the private attribute. + + + + + Defines if this attribute is writable (that is, if a setter method will be generated). Default is 'true'. The visibility of the setter depends on the value of the private attribute. + + + + + Defines if this attribute is searchable by a FlexibleSearch. Default is 'true'. Attributes with persistence type set to 'jalo' can not be searchable. + + + + + Defines if this attribute is mandatory or optional. Default is 'true' for optional. Set to 'false' for mandatory. + + + + + Defines the Java visibility of the generated getter and setter methods for this attribute. If 'true', the visibility modifier of generated methods is set to 'protected'; if 'false', the visibility modifier is 'public'. Default is 'false' for 'public' generated methods. Also, you will have no generated methods in the ServiceLayer if 'true'. + + + + + If 'true', the attribute will only be writable during the item creation. Setting this to 'true' is only useful in combination with write='false'. Default is 'false'. + + + + + Defines if this attribute is removable. Default is 'true'. + + + + + Defines if the assigned attribute value only belongs to the current instance of this type. Default is 'false'. + + + + + If 'true', the value of this attribute has to be unique within all instances of this type. If there are multiple attributes marked as unique, then their combined values must be unique. Will not be evaluated at jalo layer, if you want to manage the attribute directly using jalo layer you have to ensure uniqueness manually. Default is 'false'. + + + + + If 'true' the attribute value will be stored in the 'global' property table, otherwise a separate column (inside the table of the associated type)will be created for storing its values. Default is 'false'. + + + + + If 'true', the attribute value will be stored in an encrypted way. Default is 'false'. + + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent), and 'property' (persistent). + + + + + Configures a persistence definition for a specific database used at create statement. + + + + + + Defines how the values of the attribute will be stored. Possible values: 'cmp' (deprecated), 'jalo' (not persistent, deprecated), 'property' (persistent), 'dynamic' (not persisted). + + + + + + Attribte will be stored persistent. + + + + + Attribte will be stored non-persistent (deprecated, please use dynamic instead). + + + + + Deprecated. + + + + + Defines that attribute dynamic. + + + + + + + + Deprecated. Only usable in relation with 'cmp' and 'property'(compatibility reasons) persistence type. Default is empty. + + + + + Spring bean id that handles dynamic attributes implementation. + + + + + + + Configures a persistence definition for a specific database. + + + + + The attribute type used in the create statement of the database table, such as 'varchar2(4000)'. + + + + + + + + + The database the given definition will be used for. One of 'oracle', 'mysql', 'sqlserver' or 'hsql'. Default is empty which configures fallback for non specified databases. + + + + + + + Defines a default value text. + + + + + + + Configures a single element. + + + + The unique code of this element. + + + + + + + Configures a single enum model pojo. + + + + Defines the package for the actual enum model pojo. + + + + + + + Configures a single enum value. + + + + + Provides possibility to add meaningfull description phrase for a generated model class. + + + + + + The unique code of this element. + + + + + + + Configures the code of an enumeration value element. Must start with a letter or underscore. + + + + + + + + + Configures the code of an element. + + + + + + + Deprecated. Defines a reference to a deployment definition. + + + + + + + Configures the class to use for enclosing element. + + + + diff --git a/adyenv6ordermanagement/ruleset.xml b/adyenv6ordermanagement/ruleset.xml deleted file mode 100644 index 73c9d8bfb..000000000 --- a/adyenv6ordermanagement/ruleset.xml +++ /dev/null @@ -1,755 +0,0 @@ - - - - .*/generated-sources/.* - .*/Generated/.* - .*/gensrc/.* - .*/jsp/.* - .*_jsp.java - .*/jax-doclets/.* - - Java PMD ruleset for hybris - - - 2 - - - - - - 1 - - - - - 2 - - - - 1 - - - - 1 - - - - - - - - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - - - - 2 - - - - - - - 3 - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - 4 - - - - - - - - - - - 4 - - - - - $maxmethods - ] - ]]> - - - - - - - 4 - - - 2 - - - - - 4 - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - 2 - - - - 2 - - - - 4 - - - - - 2 - - - - - 2 - - - - - 2 - - - - 2 - - - - - 5 - - - - 4 - - - - - - - - - - - - - - - - 4 - - - - 2 - - - - 2 - - - - 4 - - - - - - 1 - - - - 2 - - - - - 3 - - - - -By explicitly commenting empty blocks -it is easier to distinguish between intentional (commented) and unintentional -empty block. - - 3 - - - - - - - - - - - - - - -All instance and class variables must be private. Class constants (which are static and final) can have other scopes. - - 2 - - - - - - - - - - - - - - 2 - - - - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - -You must not import from a child package. It usually indicates coupling to a specific implementation rather than referencing the interface of the implementation. - - 3 - - - - - - - - - - - Do not use import wildcards. Keep your code explicit. - 3 - - - - - - - - - - - - - - - 4 - - - - - - - - - - - - - - - - 2 - - - - - - 2 - - - - - - 4 - - - - - - - - - - - - - - - 5 - - - - - - - - - - - 5 - - - - - - - - 5 - - - - 3 - - - - 1 - - - - 2 - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - 2 - - - - 5 - - - - - - - - - - - - - - 1 - - - - 2 - - - - - - - - - 2 - - - - - - - 2 - - - - - 2 - - - - - - - 2 - - - - - - - - 4 - - - - 4 - - - - - 2 - - - - 2 - - - - - - - - - 2 - - - - - - 2 - - - - 2 - - - - 2 - - - - - 2 - - - - 2 - - - - 2 - - - - - - - - - - - - - - - - - - - \ No newline at end of file