diff --git a/.gitignore b/.gitignore index 2fba55ec..a994a257 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ /vendor/ /node_modules/ /composer.lock +/phpspec.yml /etc/build/* !/etc/build/.gitkeep +!/etc/build/.gitignore /tests/Application/yarn.lock diff --git a/README.md b/README.md index f3517209..859b584f 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,15 @@ Symfony Flex, it's much quicker! :) 2. Paste the following content to the `src/Repository/CustomerRepository.php`: ```php words[1].toUpperCase()); +}; + +$.fn.extend({ + addressBook() { + const element = this; + const select = element.parents('.js-address-container').prev().find('> *:first-child'); + + const findByName = function findByName(name) { + return element.find(`[name*="[${parseKey(name)}]"]`); + }; + + select.dropdown({ + forceSelection: false, + + onChange(name, text, choice) { + const { provinceCode, provinceName } = choice.data(); + const provinceContainer = select.parent().find('.province-container').get(0); + + element.find('input:not([type="radio"]):not([type="checkbox"]), select').each((index, input) => { + $(input).val(''); + }); + + Object.entries(choice.data()).forEach(([property, value]) => { + const field = findByName(property); + + if (property.indexOf('countryCode') !== -1) { + field.val(value).change(); + + const exists = setInterval(() => { + const provinceCodeField = findByName('provinceCode'); + const provinceNameField = findByName('provinceName'); + + const provinceIsLoading = $(provinceContainer).attr('data-loading'); + + if (!(typeof provinceIsLoading !== 'undefinded' && provinceIsLoading !== false)) { + if (provinceCodeField.length !== 0 && (provinceCode !== '' || provinceCode != undefined)) { + provinceCodeField.val(provinceCode); + + clearInterval(exists); + } else if (provinceNameField.length !== 0 && (provinceName !== '' || provinceName != undefined)) { + provinceNameField.val(provinceName); + + clearInterval(exists); + } + } + }, 100); + } else if (field.is('[type="radio"]') || field.is('[type="checkbox"]')) { + field.prop('checked', false); + field.filter(`[value="${value}"]`).prop('checked', true); + } else { + field.val(value); + } + }); + }, + }); + }, +}); + +export default () => { + $('#sylius_admin_order_creation_new_order_shippingAddress').addressBook(); + $('#sylius_admin_order_creation_new_order_billingAddress').addressBook(); +}; diff --git a/src/Resources/assets/admin/js/index.js b/src/Resources/assets/admin/js/index.js new file mode 100644 index 00000000..cf72cca5 --- /dev/null +++ b/src/Resources/assets/admin/js/index.js @@ -0,0 +1,5 @@ + import OrderCreateAddressSelect from './OrderCreateAddressSelect'; + +$(function() { + OrderCreateAddressSelect(); +}); diff --git a/src/Resources/assets/admin/scss/main.scss b/src/Resources/assets/admin/scss/main.scss new file mode 100644 index 00000000..d1c22213 --- /dev/null +++ b/src/Resources/assets/admin/scss/main.scss @@ -0,0 +1 @@ +@import './pages/main'; diff --git a/src/Resources/assets/admin/scss/pages/main.scss b/src/Resources/assets/admin/scss/pages/main.scss new file mode 100644 index 00000000..f0b2cf48 --- /dev/null +++ b/src/Resources/assets/admin/scss/pages/main.scss @@ -0,0 +1 @@ +@import './order-creation/main'; diff --git a/src/Resources/assets/admin/scss/pages/order-creation/_addressSelect.scss b/src/Resources/assets/admin/scss/pages/order-creation/_addressSelect.scss new file mode 100644 index 00000000..fd561168 --- /dev/null +++ b/src/Resources/assets/admin/scss/pages/order-creation/_addressSelect.scss @@ -0,0 +1,7 @@ +.custom-address-select { + margin-bottom: 16px; +} +.custom-address-select .dropdown, +.custom-address-select .ui.search.dropdown > input.search { + cursor: pointer; +} diff --git a/src/Resources/assets/admin/scss/pages/order-creation/main.scss b/src/Resources/assets/admin/scss/pages/order-creation/main.scss new file mode 100644 index 00000000..bac0f8f0 --- /dev/null +++ b/src/Resources/assets/admin/scss/pages/order-creation/main.scss @@ -0,0 +1 @@ +@import './addressSelect'; diff --git a/src/Resources/assets/shop/entry.js b/src/Resources/assets/shop/entry.js new file mode 100644 index 00000000..01733d44 --- /dev/null +++ b/src/Resources/assets/shop/entry.js @@ -0,0 +1,2 @@ +import './scss/main.scss' +import './js' diff --git a/src/Resources/assets/shop/js/index.js b/src/Resources/assets/shop/js/index.js new file mode 100644 index 00000000..e69de29b diff --git a/src/Resources/assets/shop/scss/main.scss b/src/Resources/assets/shop/scss/main.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/Resources/config/app/config.yml b/src/Resources/config/app/config.yml index 8964c6e1..72291219 100644 --- a/src/Resources/config/app/config.yml +++ b/src/Resources/config/app/config.yml @@ -30,3 +30,14 @@ sylius_mailer: order_created_in_admin_panel: subject: 'sylius_admin_order_creation.email.order_created.subject' template: '@SyliusAdminOrderCreationPlugin/Emails/orderCreated.html.twig' + +sylius_ui: + events: + sylius.admin.layout.stylesheets: + blocks: + sylius_admin_order_creation: + template: '@SyliusAdminOrderCreationPlugin/Event/Admin/_styles.html.twig' + sylius.admin.layout.javascripts: + blocks: + sylius_admin_order_creation: + template: '@SyliusAdminOrderCreationPlugin/Event/Admin/_scripts.html.twig' \ No newline at end of file diff --git a/src/Resources/views/Event/Admin/_scripts.html.twig b/src/Resources/views/Event/Admin/_scripts.html.twig new file mode 100644 index 00000000..17f074cd --- /dev/null +++ b/src/Resources/views/Event/Admin/_scripts.html.twig @@ -0,0 +1 @@ +{{ encore_entry_script_tags('sylius-order-creation-admin', null, 'admin') }} \ No newline at end of file diff --git a/src/Resources/views/Event/Admin/_styles.html.twig b/src/Resources/views/Event/Admin/_styles.html.twig new file mode 100644 index 00000000..334b02bd --- /dev/null +++ b/src/Resources/views/Event/Admin/_styles.html.twig @@ -0,0 +1 @@ +{{ encore_entry_link_tags('sylius-order-creation-admin', null, 'admin') }} diff --git a/src/Resources/views/Order/Create/_addressBookSelect.html.twig b/src/Resources/views/Order/Create/_addressBookSelect.html.twig new file mode 100644 index 00000000..8dbf6524 --- /dev/null +++ b/src/Resources/views/Order/Create/_addressBookSelect.html.twig @@ -0,0 +1,23 @@ + diff --git a/src/Resources/views/Order/Create/_form.html.twig b/src/Resources/views/Order/Create/_form.html.twig index 82515cbb..f163f2a2 100644 --- a/src/Resources/views/Order/Create/_form.html.twig +++ b/src/Resources/views/Order/Create/_form.html.twig @@ -12,10 +12,34 @@
{{ 'sylius.ui.shipping_address'|trans }} & {{ 'sylius.ui.billing_address'|trans }}
+ {% set customer = form.vars.value.customer %}
-
-
{{ form_row(form.shippingAddress) }}
-
{{ form_row(form.billingAddress) }}
+
+
+
+ {% if customer is not empty and customer.user is not empty and customer.addresses|length > 0 %} +
+ {% include '@SyliusAdminOrderCreationPlugin/Order/Create/_addressBookSelect.html.twig' %} +
+ {% endif %} +
+ {{ form_row(form.shippingAddress) }} +
+
+
+ +
+
+ {% if customer is not empty and customer.user is not empty and customer.addresses|length > 0 %} +
+ {% include '@SyliusAdminOrderCreationPlugin/Order/Create/_addressBookSelect.html.twig' %} +
+ {% endif %} +
+ {{ form_row(form.billingAddress) }} +
+
+
diff --git a/tests/Application/.gitignore b/tests/Application/.gitignore index 8ad1225e..bc600a8c 100644 --- a/tests/Application/.gitignore +++ b/tests/Application/.gitignore @@ -1,4 +1,5 @@ /public/assets +/public/build /public/css /public/js /public/media/* diff --git a/tests/Application/assets/admin/entry.js b/tests/Application/assets/admin/entry.js new file mode 100644 index 00000000..635f5acc --- /dev/null +++ b/tests/Application/assets/admin/entry.js @@ -0,0 +1 @@ +import 'sylius/bundle/AdminBundle/Resources/private/entry'; diff --git a/tests/Application/assets/shop/entry.js b/tests/Application/assets/shop/entry.js new file mode 100644 index 00000000..aadc3174 --- /dev/null +++ b/tests/Application/assets/shop/entry.js @@ -0,0 +1 @@ +import 'sylius/bundle/ShopBundle/Resources/private/entry'; diff --git a/tests/Application/config/bundles.php b/tests/Application/config/bundles.php index 9669540b..e9bb0231 100644 --- a/tests/Application/config/bundles.php +++ b/tests/Application/config/bundles.php @@ -1,5 +1,7 @@ ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], @@ -56,4 +58,5 @@ SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true], BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true], + Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], ]; diff --git a/tests/Application/config/packages/assets.yaml b/tests/Application/config/packages/assets.yaml new file mode 100644 index 00000000..421ebb3d --- /dev/null +++ b/tests/Application/config/packages/assets.yaml @@ -0,0 +1,11 @@ +framework: + assets: + packages: + shop: + json_manifest_path: '%kernel.project_dir%/public/build/shop/manifest.json' + admin: + json_manifest_path: '%kernel.project_dir%/public/build/admin/manifest.json' + orderCreation_shop: + json_manifest_path: '%kernel.project_dir%/public/build/sylius/orderCreation/shop/manifest.json' + orderCreation_admin: + json_manifest_path: '%kernel.project_dir%/public/build/sylius/orderCreation/admin/manifest.json' diff --git a/tests/Application/config/packages/webpack_encore.yaml b/tests/Application/config/packages/webpack_encore.yaml new file mode 100644 index 00000000..91abbc37 --- /dev/null +++ b/tests/Application/config/packages/webpack_encore.yaml @@ -0,0 +1,7 @@ +webpack_encore: + output_path: '%kernel.project_dir%/public/build/default' + builds: + shop: '%kernel.project_dir%/public/build/shop' + admin: '%kernel.project_dir%/public/build/admin' + orderCreation_shop: '%kernel.project_dir%/public/build/sylius/orderCreation/shop' + orderCreation_admin: '%kernel.project_dir%/public/build/sylius/orderCreation/admin' diff --git a/tests/Application/package.json b/tests/Application/package.json index 9271063f..b94f6f25 100644 --- a/tests/Application/package.json +++ b/tests/Application/package.json @@ -2,13 +2,14 @@ "dependencies": { "babel-polyfill": "^6.26.0", "chart.js": "^2.9.3", - "jquery": "^3.2.0", + "jquery": "^3.5.0", + "jquery.dirtyforms": "^2.0.0", "lightbox2": "^2.9.0", "semantic-ui-css": "^2.2.0", "slick-carousel": "^1.8.1" }, "devDependencies": { - "@symfony/webpack-encore": "^0.28.0", + "@symfony/webpack-encore": "^1.6.1", "babel-core": "^6.26.3", "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-module-resolver": "^3.1.1", @@ -19,32 +20,15 @@ "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-import-resolver-babel-module": "^4.0.0", - "eslint-plugin-import": "^2.12.0", - "fast-async": "^6.3.7", - "gulp": "^4.0.0", - "gulp-chug": "^0.5", - "gulp-concat": "^2.6.0", - "gulp-debug": "^2.1.2", - "gulp-if": "^2.0.0", - "gulp-livereload": "^3.8.1", - "gulp-order": "^1.1.1", - "gulp-sass": "^4.0.1", - "gulp-sourcemaps": "^1.6.0", - "gulp-uglifycss": "^1.0.5", + "eslint-plugin-import": "^2.11.0", "merge-stream": "^1.0.0", - "rollup": "^0.60.7", - "rollup-plugin-babel": "^3.0.4", - "rollup-plugin-commonjs": "^9.1.3", - "rollup-plugin-inject": "^2.0.0", - "rollup-plugin-node-resolve": "^3.3.0", - "rollup-plugin-uglify": "^4.0.0", - "sass-loader": "^7.0.1", - "upath": "^1.1.0", - "yargs": "^6.4.0" + "sass": "^1.39.2", + "sass-loader": "^12.1.0" }, "scripts": { - "build": "gulp build", - "gulp": "gulp build", + "dev": "yarn encore dev", + "watch": "yarn encore dev --watch", + "prod": "yarn encore prod", "lint": "yarn lint:js", "lint:js": "eslint gulpfile.babel.js" }, diff --git a/tests/Application/webpack.config.js b/tests/Application/webpack.config.js new file mode 100644 index 00000000..af481486 --- /dev/null +++ b/tests/Application/webpack.config.js @@ -0,0 +1,47 @@ +const path = require('path'); +const Encore = require('@symfony/webpack-encore'); + +const [syliusOrderCreationShop, syliusOrderCreationAdmin] = require('../../webpack.config.js'); + +const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/'); +const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/'); +const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/private/'); + +// Shop config +Encore.setOutputPath('public/build/shop/') + .setPublicPath('/build/shop') + .addEntry('shop-entry', './assets/shop/entry.js') + .disableSingleRuntimeChunk() + .cleanupOutputBeforeBuild() + .enableSourceMaps(!Encore.isProduction()) + .enableVersioning(Encore.isProduction()) + .enableSassLoader(); + +const shopConfig = Encore.getWebpackConfig(); + +shopConfig.resolve.alias['sylius/ui'] = uiBundleScripts; +shopConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources; +shopConfig.resolve.alias['sylius/bundle'] = syliusBundles; +shopConfig.name = 'shop'; + +Encore.reset(); + +// Admin config +Encore.setOutputPath('public/build/admin/') + .setPublicPath('/build/admin') + .addEntry('admin-entry', './assets/admin/entry.js') + .disableSingleRuntimeChunk() + .cleanupOutputBeforeBuild() + .enableSourceMaps(!Encore.isProduction()) + .enableVersioning(Encore.isProduction()) + .enableSassLoader(); + +const adminConfig = Encore.getWebpackConfig(); + +adminConfig.resolve.alias['sylius/ui'] = uiBundleScripts; +adminConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources; +adminConfig.resolve.alias['sylius/bundle'] = syliusBundles; +adminConfig.externals = Object.assign({}, adminConfig.externals, {window: 'window', document: 'document'}); +adminConfig.name = 'admin'; + +module.exports = [shopConfig, adminConfig, syliusOrderCreationShop, syliusOrderCreationAdmin]; diff --git a/tests/Behat/Context/Admin/ManagingOrdersContext.php b/tests/Behat/Context/Admin/ManagingOrdersContext.php index b3a0b4a0..c437506e 100644 --- a/tests/Behat/Context/Admin/ManagingOrdersContext.php +++ b/tests/Behat/Context/Admin/ManagingOrdersContext.php @@ -14,6 +14,7 @@ use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Core\Test\Services\EmailCheckerInterface; use Tests\Sylius\AdminOrderCreationPlugin\Behat\Element\Admin\OrderCreateFormElementInterface; +use Tests\Sylius\AdminOrderCreationPlugin\Behat\Page\Admin\NewOrderCreatePageInterface; use Tests\Sylius\AdminOrderCreationPlugin\Behat\Page\Admin\NewOrderCustomerPageInterface; use Tests\Sylius\AdminOrderCreationPlugin\Behat\Page\Admin\OrderIndexPageInterface; use Tests\Sylius\AdminOrderCreationPlugin\Behat\Page\Admin\OrderPreviewPageInterface; @@ -49,6 +50,9 @@ final class ManagingOrdersContext implements Context /** @var AddressComparatorInterface */ private $addressComparator; + + /** @var NewOrderCreatePageInterface */ + private $newOrderCreatePage; public function __construct( OrderIndexPageInterface $orderIndexPage, @@ -59,7 +63,8 @@ public function __construct( OrderCreateFormElementInterface $orderCreateFormElement, NotificationCheckerInterface $notificationChecker, EmailCheckerInterface $emailChecker, - AddressComparatorInterface $addressComparator + AddressComparatorInterface $addressComparator, + NewOrderCreatePageInterface $newOrderCreatePage ) { $this->orderIndexPage = $orderIndexPage; $this->newOrderCustomerPage = $newOrderCustomerPage; @@ -70,6 +75,7 @@ public function __construct( $this->notificationChecker = $notificationChecker; $this->emailChecker = $emailChecker; $this->addressComparator = $addressComparator; + $this->newOrderCreatePage = $newOrderCreatePage; } /** @@ -583,4 +589,54 @@ public function discountShouldBe(string $itemName, string $discount): void { Assert::eq($this->orderShowPage->getItemDiscount($itemName), $discount); } + + /** + * @Given /^I see the address book billing address select$/ + */ + public function iSeeTheAddressBookBillingAddressSelect(): void + { + Assert::true($this->newOrderCreatePage->isBillingAddressAutocompleteField()); + } + + /** + * @Given /^I see the address book shipping address select$/ + */ + public function iSeeTheAddressBookShippingAddressSelect(): void + { + Assert::true($this->newOrderCreatePage->isShippingAddressAutocompleteField()); + } + + /** + * @Given /^I select first address in shipping address book with name "([^"]*)"$/ + */ + public function iSelectFirstAddressInShippingAddressBookWithName(string $name): void + { + $name = explode(' ',$name); + $this->newOrderCreatePage->selectShippingAddress($name); + } + + /** + * @Given /^I select first address in billing address book with name "([^"]*)"$/ + */ + public function iSelectFirstAddressInBillingAddressBookWith(string $name): void + { + $name = explode(' ',$name); + $this->newOrderCreatePage->selectBillingAddress($name); + } + + /** + * @Given /^I should not see the address book shipping address select$/ + */ + public function iShouldNotSeeTheAddressBookShippingAddressSelect(): void + { + Assert::false($this->newOrderCreatePage->isShippingAddressAutocompleteField()); + } + + /** + * @Given /^I should not see the address book billing address select$/ + */ + public function iShouldNotSeeTheAddressBookBillingAddressSelect(): void + { + Assert::false($this->newOrderCreatePage->isBillingAddressAutocompleteField()); + } } diff --git a/tests/Behat/Page/Admin/NewOrderCreatePage.php b/tests/Behat/Page/Admin/NewOrderCreatePage.php new file mode 100644 index 00000000..5f8ecb85 --- /dev/null +++ b/tests/Behat/Page/Admin/NewOrderCreatePage.php @@ -0,0 +1,42 @@ +getDocument()->find('css','.shipping-address-book'); + + return null !== $shippingAddressBook; + } + + public function isBillingAddressAutocompleteField(): bool + { + + $billingAddressBook = $this->getDocument()->find('css','.billing-address-book'); + + return null !== $billingAddressBook; + } + + public function selectShippingAddress(array $name): void + { + $shippingAddressBook = $this->getDocument()->find('css','.shipping-address-book'); + $shippingAddressBook->find('css', sprintf('[data-first-name="%s"]', $name[0]))->click(); + } + + public function selectBillingAddress(array $name): void + { + $billingAddressBook = $this->getDocument()->find('css','.billing-address-book'); + $billingAddressBook->find('css', sprintf('[data-first-name="%s"]', $name[0]))->click(); + } +} diff --git a/tests/Behat/Page/Admin/NewOrderCreatePageInterface.php b/tests/Behat/Page/Admin/NewOrderCreatePageInterface.php new file mode 100644 index 00000000..b2c7491a --- /dev/null +++ b/tests/Behat/Page/Admin/NewOrderCreatePageInterface.php @@ -0,0 +1,16 @@ + + @@ -34,5 +35,7 @@ + + diff --git a/tests/Behat/Resources/suites/managing_orders.yml b/tests/Behat/Resources/suites/managing_orders.yml index 04061b6b..73377a9b 100644 --- a/tests/Behat/Resources/suites/managing_orders.yml +++ b/tests/Behat/Resources/suites/managing_orders.yml @@ -7,6 +7,7 @@ default: - sylius.behat.context.setup.admin_security - sylius.behat.context.setup.admin_user + - sylius.behat.context.setup.address - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency - sylius.behat.context.setup.customer diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..0c3809d0 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const Encore = require('@symfony/webpack-encore'); +const pluginName = 'orderCreation'; + +const getConfig = (pluginName, type) => { + Encore.reset(); + + Encore + .setOutputPath(`public/build/sylius/${pluginName}/${type}/`) + .setPublicPath(`/build/sylius/${pluginName}/${type}/`) + .addEntry(`sylius-${pluginName}-${type}`, path.resolve(__dirname, `./src/Resources/assets/${type}/entry.js`)) + .disableSingleRuntimeChunk() + .cleanupOutputBeforeBuild() + .enableSourceMaps(!Encore.isProduction()) + .enableSassLoader(); + + const config = Encore.getWebpackConfig(); + config.name = `sylius-${pluginName}-${type}`; + + return config; +} + +Encore + .setOutputPath(`src/Resources/public/`) + .setPublicPath(`/public/`) + .addEntry(`sylius-${pluginName}-shop`, path.resolve(__dirname, `./src/Resources/assets/shop/entry.js`)) + .addEntry(`sylius-${pluginName}-admin`, path.resolve(__dirname, `./src/Resources/assets/admin/entry.js`)) + .cleanupOutputBeforeBuild() + .disableSingleRuntimeChunk() + .enableSassLoader(); + +const distConfig = Encore.getWebpackConfig(); +distConfig.name = `sylius-plugin-dist`; + +Encore.reset(); + +const shopConfig = getConfig(pluginName, 'shop') +const adminConfig = getConfig(pluginName, 'admin') + +module.exports = [shopConfig, adminConfig, distConfig];