diff --git a/.gitignore b/.gitignore index 3017e8d48..865c3f6a1 100755 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,8 @@ templates/* !templates/email/ !templates/frontOffice/ !templates/pdf/ + +#Ignore CodeKit +codekit-config.json +config.codekit +.codekit-cache diff --git a/.travis.yml b/.travis.yml index 56524f1a5..8516ac373 100755 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ env: - DB_USER=root before_script: + - sudo apt-get update -qq + - sudo apt-get install -y language-pack-fr language-pack-fr-base - phpenv config-add travis.php.ini - composer self-update - composer install --prefer-dist --dev diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f06f77c0..a707ba34b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ +#2.0.3 +- New coupon type: Free product if selected products are in the cart. + #2.0.2 +- Coupon UI has been redesigned. +- New coupon types: + - Constant discount on selected products + - Constant discount on products of selected categories + - Percentage discount on selected products + - Percentage discount on products of selected categories - New coupon conditions : - Start date - Billing country @@ -12,7 +21,15 @@ - class event : Thelia\Core\Event\SessionEvent - example : Thelia\Core\EventListener\SessionListener - Creation of Thelia\Core\TheliakernelEvents class for referencing kernel event - +- Add new command line that refresh modules list `Thelia module:refresh` +- Coupon internals have been simplified and improved. +- Error messages are displayed in install process +- Add pagination on catalog page in Back-Office +- Add Hong Kong to country list +- Fixed issue #452 when installing Thelia on database with special characters +- implement search on content, folder and category loop. +- all form are documented +- template exists for managing google sitemap : sitemap.html #2.0.1 - possibility to apply a permanent discount on a customer diff --git a/composer.json b/composer.json index 37f3a0b15..8788db05d 100644 --- a/composer.json +++ b/composer.json @@ -33,13 +33,14 @@ "simplepie/simplepie": "dev-master", "imagine/imagine": "0.*", "symfony/icu": "1.0", - "swiftmailer/swiftmailer": "5.0.*", + "swiftmailer/swiftmailer": "5.2.*", "symfony/serializer": "2.3.*", "ensepar/html2pdf": "1.0.1", - "symfony/finder": "~2.2" + "symfony/finder": "~2.2", + "symfony/browser-kit": "2.3.*" }, "require-dev": { - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "4.1.*", "fzaninotto/faker": "dev-master", "maximebf/debugbar": "dev-master" }, diff --git a/composer.lock b/composer.lock index d7da926ba..2f1e713a0 100644 --- a/composer.lock +++ b/composer.lock @@ -1,9 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" ], - "hash": "d1e1c31ed8e38f2282ab431898cf8b08", + "hash": "4606e1d72b13b6b8fa84dca5f7bac16b", "packages": [ { "name": "doctrine/cache", @@ -607,25 +608,28 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v5.0.2", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379" + "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/f3917ecef35a4e4d98b303eb9fee463bc983f379", - "reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/2b9af56cc676c338d52fca4c657e5bdff73bb7af", + "reference": "2b9af56cc676c338d52fca4c657e5bdff73bb7af", "shasum": "" }, "require": { "php": ">=5.2.4" }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "5.2-dev" } }, "autoload": { @@ -640,7 +644,9 @@ "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { "name": "Chris Corbyn" @@ -652,7 +658,7 @@ "mail", "mailer" ], - "time": "2013-08-30 12:35:21" + "time": "2014-06-13 11:44:54" }, { "name": "symfony-cmf/routing", @@ -703,6 +709,63 @@ ], "time": "2013-03-25 15:02:40" }, + { + "name": "symfony/browser-kit", + "version": "v2.3.13", + "target-dir": "Symfony/Component/BrowserKit", + "source": { + "type": "git", + "url": "https://github.com/symfony/BrowserKit.git", + "reference": "97563874c24b65ea8d31b82fe051a161caf83e10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/97563874c24b65ea8d31b82fe051a161caf83e10", + "reference": "97563874c24b65ea8d31b82fe051a161caf83e10", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/dom-crawler": "~2.0" + }, + "require-dev": { + "symfony/css-selector": "~2.0", + "symfony/process": "~2.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\BrowserKit\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "http://symfony.com", + "time": "2014-04-18 20:35:25" + }, { "name": "symfony/class-loader", "version": "v2.2.6", @@ -902,6 +965,61 @@ "homepage": "http://symfony.com", "time": "2013-07-21 09:38:59" }, + { + "name": "symfony/dom-crawler", + "version": "v2.4.4", + "target-dir": "Symfony/Component/DomCrawler", + "source": { + "type": "git", + "url": "https://github.com/symfony/DomCrawler.git", + "reference": "e94b29c7cac964e58c406408d238ceeaa3604e78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/e94b29c7cac964e58c406408d238ceeaa3604e78", + "reference": "e94b29c7cac964e58c406408d238ceeaa3604e78", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/css-selector": "~2.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\DomCrawler\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "http://symfony.com", + "time": "2014-04-18 20:37:09" + }, { "name": "symfony/event-dispatcher", "version": "v2.2.6", @@ -1959,40 +2077,44 @@ }, { "name": "phpunit/php-code-coverage", - "version": "1.2.12", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.12" + "reference": "58401826c8cfc8fd689b60026e91c337df374bca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.12", - "reference": "1.2.12", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/58401826c8cfc8fd689b60026e91c337df374bca", + "reference": "58401826c8cfc8fd689b60026e91c337df374bca", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.1.1@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2.0", + "phpunit/php-token-stream": "~1.2.2", + "sebastian/environment": "~1.0.0", + "sebastian/version": "~1.0.3" }, "require-dev": { - "phpunit/phpunit": "3.7.*@dev" + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4.0.14" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.0.5" + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ - "PHP/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2016,20 +2138,20 @@ "testing", "xunit" ], - "time": "2013-07-06 06:26:16" + "time": "2014-05-26 14:55:24" }, { "name": "phpunit/php-file-iterator", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "1.3.3" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", - "reference": "1.3.3", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", "shasum": "" }, "require": { @@ -2056,25 +2178,25 @@ } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], - "time": "2012-10-11 04:44:38" + "time": "2013-10-10 15:34:57" }, { "name": "phpunit/php-text-template", - "version": "1.1.4", + "version": "1.2.0", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-text-template.git", - "reference": "1.1.4" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", - "reference": "1.1.4", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", "shasum": "" }, "require": { @@ -2105,7 +2227,7 @@ "keywords": [ "template" ], - "time": "2012-10-31 11:15:28" + "time": "2014-01-30 17:20:04" }, { "name": "phpunit/php-timer", @@ -2153,16 +2275,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.2.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1.2.0" + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1.2.0", - "reference": "1.2.0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", "shasum": "" }, "require": { @@ -2199,56 +2321,56 @@ "keywords": [ "tokenizer" ], - "time": "2013-08-04 05:57:48" + "time": "2014-03-03 05:10:30" }, { "name": "phpunit/phpunit", - "version": "3.7.24", + "version": "4.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.24" + "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.24", - "reference": "3.7.24", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/939cb801b3b2aa253aedd0b279f40bb8f35cec91", + "reference": "939cb801b3b2aa253aedd0b279f40bb8f35cec91", "shasum": "" }, "require": { "ext-dom": "*", + "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", - "phpunit/php-code-coverage": "~1.2.1", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-timer": ">=1.0.4", - "phpunit/phpunit-mock-objects": "~1.2.0", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.1", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.1", + "sebastian/comparator": "~1.0", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.0", + "sebastian/exporter": "~1.0", + "sebastian/version": "~1.0", "symfony/yaml": "~2.0" }, - "require-dev": { - "pear-pear/pear": "1.9.4" - }, "suggest": { - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "phpunit/php-invoker": ">=1.1.0,<1.2.0" + "phpunit/php-invoker": "~1.1" }, "bin": [ - "composer/bin/phpunit" + "phpunit" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.7.x-dev" + "dev-master": "4.1.x-dev" } }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2273,33 +2395,41 @@ "testing", "xunit" ], - "time": "2013-08-09 06:58:24" + "time": "2014-06-11 14:15:47" }, { "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", + "version": "2.1.4", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "1.2.3" + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", - "reference": "1.2.3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", + "reference": "1a894a16b6c15fcdc5ef2b110f0e6233952c9b0f", "shasum": "" }, "require": { "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" }, "suggest": { "ext-soap": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, "autoload": { "classmap": [ - "PHPUnit/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2322,7 +2452,275 @@ "mock", "xunit" ], - "time": "2013-01-13 10:24:48" + "time": "2014-06-07 16:22:57" + }, + { + "name": "sebastian/comparator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.1", + "sebastian/exporter": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2014-05-02 07:05:58" + }, + { + "name": "sebastian/diff", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2013-08-03 16:46:33" + }, + { + "name": "sebastian/environment", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-02-18 16:17:19" + }, + { + "name": "sebastian/exporter", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "4.0.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net", + "role": "Lead" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2014-02-16 08:26:31" + }, + { + "name": "sebastian/version", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-03-07 15:35:33" } ], "aliases": [ diff --git a/core/bootstrap.php b/core/bootstrap.php index 87cbb2907..8c6042711 100644 --- a/core/bootstrap.php +++ b/core/bootstrap.php @@ -32,6 +32,5 @@ if (!file_exists(THELIA_CONF_DIR . 'database.yml') && !defined('THELIA_INSTALL_M } else { $request = \Thelia\Core\HttpFoundation\Request::createFromGlobals(); header('Location: '.$request->getUriForPath('/install')); - exit; } } diff --git a/core/lib/Thelia/Action/Address.php b/core/lib/Thelia/Action/Address.php index e6e9b9f65..17ae95cc8 100644 --- a/core/lib/Thelia/Action/Address.php +++ b/core/lib/Thelia/Action/Address.php @@ -79,7 +79,7 @@ class Address extends BaseAction implements EventSubscriberInterface ->save() ; - if ($event->getIsDefault()) { + if ($event->getIsDefault() && !$addressModel->getIsDefault()) { $addressModel->makeItDefault(); } diff --git a/core/lib/Thelia/Action/Coupon.php b/core/lib/Thelia/Action/Coupon.php index b8e2a7553..4dc708394 100644 --- a/core/lib/Thelia/Action/Coupon.php +++ b/core/lib/Thelia/Action/Coupon.php @@ -109,6 +109,17 @@ class Coupon extends BaseAction implements EventSubscriberInterface $this->createOrUpdateCondition($modelCoupon, $event); } + /** + * Clear all coupons in session. + */ + public function clearAllCoupons() + { + // Tell coupons to clear any data they may have stored + $this->couponManager->clear(); + + $this->request->getSession()->setConsumedCoupons(array()); + } + /** * Occurring when a Coupon condition is about to be consumed * @@ -139,21 +150,22 @@ class Coupon extends BaseAction implements EventSubscriberInterface $consumedCoupons[$event->getCode()] = $event->getCode(); $this->request->getSession()->setConsumedCoupons($consumedCoupons); - - $totalDiscount = $this->couponManager->getDiscount(); - - $this->request - ->getSession() - ->getCart() - ->setDiscount($totalDiscount) - ->save(); - $this->request - ->getSession() - ->getOrder() - ->setDiscount($totalDiscount) - ; } - } + + $totalDiscount = $this->couponManager->getDiscount(); + + $this->request + ->getSession() + ->getCart() + ->setDiscount($totalDiscount) + ->save(); + + $this->request + ->getSession() + ->getOrder() + ->setDiscount($totalDiscount) + ; + } } $event->setIsValid($isValid); @@ -339,7 +351,8 @@ class Coupon extends BaseAction implements EventSubscriberInterface } } - $this->request->getSession()->setConsumedCoupons(array()); + // Clear all coupons. + $event->getDispatcher()->dispatch(TheliaEvents::COUPON_CLEAR_ALL); } /** @@ -368,6 +381,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface TheliaEvents::COUPON_CREATE => array("create", 128), TheliaEvents::COUPON_UPDATE => array("update", 128), TheliaEvents::COUPON_CONSUME => array("consume", 128), + TheliaEvents::COUPON_CLEAR_ALL => array("clearAllCoupons", 128), TheliaEvents::COUPON_CONDITION_UPDATE => array("updateCondition", 128), TheliaEvents::ORDER_SET_POSTAGE => array("testFreePostage", 132), TheliaEvents::ORDER_BEFORE_PAYMENT => array("afterOrder", 128), diff --git a/core/lib/Thelia/Command/ModuleRefreshCommand.php b/core/lib/Thelia/Command/ModuleRefreshCommand.php new file mode 100644 index 000000000..318542939 --- /dev/null +++ b/core/lib/Thelia/Command/ModuleRefreshCommand.php @@ -0,0 +1,54 @@ + + */ +class ModuleRefreshCommand extends ContainerAwareCommand +{ + protected function configure() + { + $this + ->setName('module:refresh') + ->setDescription('Refresh modules list'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $moduleManagement = new ModuleManagement; + $moduleManagement->updateModules(); + } catch (\Exception $e) { + throw new \RuntimeException(sprintf('Refresh modules list fail with Exception : [%d] %s', $e->getCode(), $e->getMessage())); + } + + if (method_exists($output, 'renderBlock')) { + $output->renderBlock([ + '', + 'Modules list successfully refreshed', + '' + ], + 'bg=green;fg=black' + ); + } + } +} diff --git a/core/lib/Thelia/Condition/Implementation/StartDate.php b/core/lib/Thelia/Condition/Implementation/StartDate.php index 251ba395b..d086fb39a 100644 --- a/core/lib/Thelia/Condition/Implementation/StartDate.php +++ b/core/lib/Thelia/Condition/Implementation/StartDate.php @@ -55,6 +55,8 @@ class StartDate extends ConditionAbstract */ public function setValidatorsFromForm(array $operators, array $values) { + $this->checkComparisonOperatorValue($operators, self::START_DATE); + if (! isset($values[self::START_DATE])) { $values[self::START_DATE] = time(); } @@ -125,10 +127,6 @@ class StartDate extends ConditionAbstract */ public function getSummary() { - $i18nOperator = Operators::getI18n( - $this->translator, $this->operators[self::START_DATE] - ); - $date = new \DateTime(); $date->setTimestamp($this->values[self::START_DATE]); $strDate = $date->format($this->getDateFormat()); diff --git a/core/lib/Thelia/Config/I18n/en_US.php b/core/lib/Thelia/Config/I18n/en_US.php index ea9d3ff9e..6b92a7fb6 100644 --- a/core/lib/Thelia/Config/I18n/en_US.php +++ b/core/lib/Thelia/Config/I18n/en_US.php @@ -50,6 +50,7 @@ return array( 'Cart item count is' => 'Cart item count is', 'Cart total amount' => 'Cart total amount', 'Cart total amount is' => 'Cart total amount is', + 'Catalog' => 'Catalog', 'Category title *' => 'Category title *', 'Cellphone' => 'Cellphone', 'Chapo' => 'Chapo', @@ -85,7 +86,6 @@ return array( 'Description' => 'Description', 'Detailed description' => 'Detailed description', 'Disabled' => 'Disabled', - 'Discount amount' => 'Discount amount', 'Document deleted successfully' => 'Document deleted successfully', 'Document position updated' => 'Document position updated', 'EAN Code' => 'EAN Code', @@ -112,13 +112,18 @@ return array( 'First Name' => 'First Name', 'Firstname' => 'Firstname', 'Fixed Amount Discount' => 'Fixed Amount Discount', - 'Fixed amount discount on selected categories' => 'Fixed amount discount on selected categories', + 'Fixed amount discount for selected attribute values' => 'Fixed amount discount for selected attribute values', + 'Fixed amount discount for selected categories' => 'Fixed amount discount for selected categories', + 'Fixed amount discount for selected products' => 'Fixed amount discount for selected products', + 'Folder' => 'Folder', 'Folder title *' => 'Folder title *', 'For one ore more customers' => 'For one ore more customers', + 'Free product when buying one or more selected products' => 'Free product when buying one or more selected products', 'Full Name' => 'Full Name', 'Greater than' => 'Greater than', 'Greater than or equals' => 'Greater than or equals', 'HTML Message' => 'HTML Message', + 'Home' => 'Home', 'Host' => 'Host', 'I would like to receive the newsletter or the latest news.' => 'I would like to receive the newsletter or the latest news.', 'ISO 4217 code *' => 'ISO 4217 code *', @@ -190,13 +195,22 @@ return array( 'Password *' => 'Password *', 'Password confirmation' => 'Password confirmation', 'Per customer' => 'Per customer', - 'Percent Discount' => 'Percent Discount', + 'Percentage discount for selected attribute values' => 'Percentage discount for selected attribute values', + 'Percentage discount for selected categories' => 'Percentage discount for selected categories', + 'Percentage discount for selected products' => 'Percentage discount for selected products', 'Percentage of the product price' => 'Percentage of the product price', 'Phone' => 'Phone', 'Please accept the Terms and conditions in order to register.' => 'Please accept the Terms and conditions in order to register.', 'Please check your input: %error' => 'Please check your input: %error', 'Please enter your email address' => 'Please enter your email address', 'Please enter your password' => 'Please enter your password', + 'Please select a category' => 'Please select a category', + 'Please select an attribute' => 'Please select an attribute', + 'Please select at least one attribute value' => 'Please select at least one attribute value', + 'Please select at least one category' => 'Please select at least one category', + 'Please select at least one product' => 'Please select at least one product', + 'Please select the category of the offred product' => 'Please select the category of the offred product', + 'Please select the offered product' => 'Please select the offered product', 'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Please specify either \'path\' or \'file\' parameter in {url} function.', 'Port' => 'Port', 'Post Scriptum' => 'Post Scriptum', @@ -284,8 +298,14 @@ return array( 'This category is online.' => 'This category is online.', 'This condition is always true' => 'This condition is always true', 'This content is online.' => 'This content is online.', + 'This coupon adds a free product to the cart if one of the selected products is in the cart.' => 'This coupon adds a free product to the cart if one of the selected products is in the cart.', 'This coupon does not exists' => 'This coupon does not exists', - 'This coupon subtracts the specified amount from the order total for each product of the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each product of the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + 'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', 'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', 'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', 'This email already exists.' => 'This email already exists.', @@ -316,6 +336,8 @@ return array( 'Username *' => 'Username *', 'Valid only from %date% to the coupon expiration date' => 'Valide à partir du %date% jusqu\'à la date d\'expiration', 'Value' => 'Value', + 'Value %val for Discount Amount is invalid. Please enter a positive value.' => 'Value %val for Discount Amount is invalid. Please enter a positive value.', + 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.' => 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.', 'Value *' => 'Value *', 'Warnings' => 'Warnings', 'Weight' => 'Weight', diff --git a/core/lib/Thelia/Config/I18n/fr_FR.php b/core/lib/Thelia/Config/I18n/fr_FR.php index 388b3d684..bd789a0ad 100644 --- a/core/lib/Thelia/Config/I18n/fr_FR.php +++ b/core/lib/Thelia/Config/I18n/fr_FR.php @@ -50,6 +50,7 @@ return array( 'Cart item count is' => 'Le nombre d\'articles dans le panier est', 'Cart total amount' => 'Montant total du panier', 'Cart total amount is' => 'Le total du panier est', + 'Catalog' => 'Catalogue', 'Category title *' => 'Titre de la catégorie *', 'Cellphone' => 'Numéro de portable', 'Chapo' => 'Chapeau', @@ -85,7 +86,6 @@ return array( 'Description' => 'Description', 'Detailed description' => 'Description détaillée', 'Disabled' => 'Désactivé', - 'Discount amount' => 'Montant de la remise', 'Document deleted successfully' => 'Le document a été supprimé.', 'Document position updated' => 'La position du document a été modfiée', 'EAN Code' => 'Code EAN', @@ -112,12 +112,18 @@ return array( 'First Name' => 'Prénom', 'Firstname' => 'Prénom', 'Fixed Amount Discount' => 'Remise d\'un montant fixe', + 'Fixed amount discount for selected attribute values' => 'Remise constante pour certaines valeurs de déclinaison', + 'Fixed amount discount for selected categories' => 'Remise fixe pour certaines catégories', + 'Fixed amount discount for selected products' => 'Remise fixe pour certains produits', + 'Folder' => 'Dossier', 'Folder title *' => 'Titre du dossier *', 'For one ore more customers' => 'Valable pour un ou plusieurs clients', + 'Free product when buying one or more selected products' => 'Un produit offert pour l\'achat d\'un ou plusieurs produits', 'Full Name' => 'Nom complet', 'Greater than' => 'Supérieur à', 'Greater than or equals' => 'Supérieur ou égal à', 'HTML Message' => 'Message au format HTML', + 'Home' => 'Accueil', 'Host' => 'Nom de l\'hôte', 'I would like to receive the newsletter or the latest news.' => 'Je souhaite recevoir la lettre d\'information ou les dernières actualités.', 'ISO 4217 code *' => 'Code ISO 4217 *', @@ -189,19 +195,28 @@ return array( 'Password *' => 'Mot de passe *', 'Password confirmation' => 'Confirmation du mot de passe.', 'Per customer' => 'Par client', - 'Percent Discount' => 'Remise en pourcentage de la commande', + 'Percentage discount for selected attribute values' => 'Remise en pourcentage pour certaines valeurs de déclinaison', + 'Percentage discount for selected categories' => 'Remise en pourcentage pour certaines catégories', + 'Percentage discount for selected products' => 'Remise en pourcentage pour certains produits', 'Percentage of the product price' => 'Pourcentage du prix du produit', 'Phone' => 'Téléphone', 'Please accept the Terms and conditions in order to register.' => 'Veuillez accepter les termes et conditions pour vous inscrire.', 'Please check your input: %error' => 'Merci de vérifier votre saisie: %error', 'Please enter your email address' => 'Renseignez votre adresse mail', 'Please enter your password' => 'Entrez votre mot de passe.', + 'Please select a category' => 'Merci de choisir une catégorie', + 'Please select an attribute' => 'Merci de choisir une déclinaison', + 'Please select at least one attribute value' => 'Merci de choisir au moins une valeur de déclinaison', + 'Please select at least one category' => 'Merci de choisir au moins une catégorie.', + 'Please select at least one product' => 'Merci de choisir au moins un produit', + 'Please select the category of the offred product' => 'Merci de choisir la catégorie du produit offert', + 'Please select the offered product' => 'Merci de choisir le produit offert', 'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Veuillez spécifier soit le paramètre \'chemin\' ou \'fichier\' dans la fonction {url}', 'Port' => 'Port', 'Post Scriptum' => 'Post-scriptum', 'Postage' => 'Frais de livraison', 'Preferred locale' => 'locale souhaitée', - 'Prevent mailing template modification or deletion, except for super-admin' => 'Prévenir la suppression ou la modification ds templates de mail, excepté pour les super-administrateurs.', + 'Prevent mailing template modification or deletion, except for super-admin' => 'Prévenir la suppression ou la modification des templates de mail, excepté pour les super-administrateurs.', 'Prevent variable modification or deletion, except for super-admin' => 'Prévenir la suppression ou la modification de variables, excepté pour les super-administrateurs.', 'Price currency *' => 'Devise *', 'Processing cancelation of payment for order ref. %ref' => 'Traitement de l\'annulation du paiement de la commande %ref, ID %id', @@ -254,7 +269,7 @@ return array( 'Store configuration failed.' => 'Erreur de configuration du magasin.', 'Store email address' => 'Adresse mail du magasin', 'Store logs into text file' => 'Conserver les logs dans des fichiers texte', - 'Store logs into text file, up to a certian size, then a new file is created' => 'Sauvegarder les logs dans un fichier texte. A partir d\'une certaine taille un nouveau fichier est crée', + 'Store logs into text file, up to a certian size, then a new file is created' => 'Sauvegarder les logs dans un fichier texte. A partir d\'une certaine taille un nouveau fichier est créé', 'Store name' => 'Nom du magasin', 'Street Address' => 'Adresse', 'Street Address ' => 'Rue', @@ -283,7 +298,14 @@ return array( 'This category is online.' => 'Cette catégorie est en ligne.', 'This condition is always true' => 'Cette condition est troujours vérifiée', 'This content is online.' => 'Ce contenu est en ligne.', + 'This coupon adds a free product to the cart if one of the selected products is in the cart.' => 'Ce coupon ajoute un produit gratuit (sous forme de remise) au panier, si un des produits indiqués est présent dans le panier.', 'This coupon does not exists' => 'Ce code promo n\'existe pas', + 'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits appartenant aux catégories sélectionnées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', + 'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits ayant au moins une des valeurs de déclinaisons indiquées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', + 'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits sélectionnés. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', + 'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits appartenant aux catégories sélectionnées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', + 'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits ayant au moins une des valeurs de déclinaisons indiquées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', + 'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits sélectionnés. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.', 'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le pourcentage indiqué du total de la commande, hors frais de port et taxes. Si la remise est supérieur au total de la commande, seul le port sera facturé, à moins que le code promo n\'offre aussi les frais port.', 'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande, hors frais de port et taxes. Si la remise est supérieur au total de la commande, seul le port sera facturé, à moins que le code promo n\'offre aussi les frais port.', 'This email already exists.' => 'Cette adresse email existe déjà', @@ -314,6 +336,8 @@ return array( 'Username *' => 'Nom d\'utilisateur *', 'Valid only from %date% to the coupon expiration date' => 'Valide à partir de %date% jusqu\'à la date d\'expoiration', 'Value' => 'Valeur', + 'Value %val for Discount Amount is invalid. Please enter a positive value.' => 'La valeur %val pour le montant de la remise est invalide. Merci d\'indiquer une valeur positive.', + 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.' => 'La valeur %val pour le pourcentage de remise est invalide. Merci d\'indiquer un nombre entre 1 et 100', 'Value *' => 'Valeur *', 'Warnings' => 'Avertissements', 'Weight' => 'Poids', diff --git a/core/lib/Thelia/Config/Resources/command.xml b/core/lib/Thelia/Config/Resources/command.xml index 8b61f40e7..313904c40 100644 --- a/core/lib/Thelia/Config/Resources/command.xml +++ b/core/lib/Thelia/Config/Resources/command.xml @@ -11,6 +11,7 @@ + diff --git a/core/lib/Thelia/Config/Resources/coupon.xml b/core/lib/Thelia/Config/Resources/coupon.xml index 68486c969..06e8f7bb6 100644 --- a/core/lib/Thelia/Config/Resources/coupon.xml +++ b/core/lib/Thelia/Config/Resources/coupon.xml @@ -36,6 +36,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 348c1d7ec..6b5622ff8 100644 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -16,7 +16,7 @@ Thelia\Controller\Admin\HomeController::defaultAction - + Thelia\Controller\Admin\HomeController::getLatestTheliaVersion @@ -466,7 +466,7 @@ Thelia\Controller\Admin\ContentController::createAction - + Thelia\Controller\Admin\ContentController::updateAction \d+ @@ -1165,7 +1165,7 @@ - Thelia\Controller\Admin\CustomerExportController::NewsletterExportAction + Thelia\Controller\Admin\CustomerExportController::newsletterExportAction diff --git a/core/lib/Thelia/Config/Resources/test.xml b/core/lib/Thelia/Config/Resources/test.xml new file mode 100644 index 000000000..b1190195e --- /dev/null +++ b/core/lib/Thelia/Config/Resources/test.xml @@ -0,0 +1,28 @@ + + + + + + Thelia\Core\HttpKernel\Client + + Symfony\Component\BrowserKit\History + Symfony\Component\BrowserKit\CookieJar + + + + + + %test.client.parameters% + + + + + + + + + + + diff --git a/core/lib/Thelia/Controller/Admin/BaseAdminController.php b/core/lib/Thelia/Controller/Admin/BaseAdminController.php index deba32d56..27bf724cc 100644 --- a/core/lib/Thelia/Controller/Admin/BaseAdminController.php +++ b/core/lib/Thelia/Controller/Admin/BaseAdminController.php @@ -23,7 +23,6 @@ use Thelia\Model\ConfigQuery; use Symfony\Component\HttpKernel\HttpKernelInterface; use Thelia\Core\Security\Exception\AuthenticationException; use Thelia\Tools\URL; -use Thelia\Tools\Redirect; use Thelia\Model\AdminLog; use Thelia\Model\LangQuery; diff --git a/core/lib/Thelia/Controller/Admin/CategoryController.php b/core/lib/Thelia/Controller/Admin/CategoryController.php index ad5b2bd36..c4604c990 100644 --- a/core/lib/Thelia/Controller/Admin/CategoryController.php +++ b/core/lib/Thelia/Controller/Admin/CategoryController.php @@ -169,7 +169,8 @@ class CategoryController extends AbstractSeoCrudController return array( 'category_id' => $this->getRequest()->get('category_id', 0), 'folder_id' => $this->getRequest()->get('folder_id', 0), - 'current_tab' => $this->getRequest()->get('current_tab', 'general') + 'current_tab' => $this->getRequest()->get('current_tab', 'general'), + 'page' => $this->getRequest()->get('page', 1) ); } @@ -182,14 +183,17 @@ class CategoryController extends AbstractSeoCrudController array( 'category_order' => $currentOrder, 'product_order' => $product_order, - 'category_id' => $this->getRequest()->get('category_id', 0) + 'category_id' => $this->getRequest()->get('category_id', 0), + 'page' => $this->getRequest()->get('page', 1) )); } protected function redirectToListTemplate() { - $category_id = $this->getRequest()->get('category_id', 0); - $this->redirectToListTemplateWithId($category_id); + $this->redirectToRoute('admin.categories', array( + 'category_id' => $this->getRequest()->get('category_id', 0), + 'page' => $this->getRequest()->get('page', 1)) + ); } protected function redirectToListTemplateWithId($category_id) diff --git a/core/lib/Thelia/Controller/Admin/CountryController.php b/core/lib/Thelia/Controller/Admin/CountryController.php index 888e8943a..bdd76bc82 100644 --- a/core/lib/Thelia/Controller/Admin/CountryController.php +++ b/core/lib/Thelia/Controller/Admin/CountryController.php @@ -20,6 +20,7 @@ use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Security\AccessManager; use Thelia\Form\CountryCreationForm; use Thelia\Form\CountryModificationForm; +use Thelia\Log\Tlog; use Thelia\Model\CountryQuery; /** @@ -228,7 +229,7 @@ class CountryController extends AbstractCrudController public function toggleDefaultAction() { if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) return $response; - $content = null; + if (null !== $country_id = $this->getRequest()->get('country_id')) { $toogleDefaultEvent = new CountryToggleDefaultEvent($country_id); try { @@ -238,7 +239,7 @@ class CountryController extends AbstractCrudController return $this->nullResponse(); } } catch (\Exception $ex) { - $content = $ex->getMessage(); + Tlog::getInstance()->error($ex->getMessage()); } } diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php index 11abe29a3..370b504c1 100644 --- a/core/lib/Thelia/Controller/Admin/CouponController.php +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -13,7 +13,7 @@ namespace Thelia\Controller\Admin; use Symfony\Component\Form\Form; -use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Router; use Thelia\Condition\ConditionFactory; @@ -25,9 +25,7 @@ use Thelia\Core\Security\AccessManager; use Thelia\Coupon\CouponFactory; use Thelia\Coupon\CouponManager; use Thelia\Condition\ConditionCollection; -use Thelia\Coupon\Type\CouponAbstract; use Thelia\Coupon\Type\CouponInterface; -use Thelia\Coupon\Type\RemoveXPercent; use Thelia\Form\CouponCreationForm; use Thelia\Form\Exception\FormValidationException; use Thelia\Log\Tlog; @@ -37,6 +35,7 @@ use Thelia\Model\CouponModule; use Thelia\Model\CouponQuery; use Thelia\Model\LangQuery; use Thelia\Tools\Rest\ResponseRest; +use Thelia\Tools\URL; /** * Control View and Action (Model) via Events @@ -80,11 +79,13 @@ class CouponController extends BaseAdminController $eventToDispatch = TheliaEvents::COUPON_CREATE; if ($this->getRequest()->isMethod('POST')) { - $this->validateCreateOrUpdateForm( + if(null !== $response = $this->validateCreateOrUpdateForm( $eventToDispatch, 'created', 'creation' - ); + )){ + return $response; + } } else { // If no input for expirationDate, now + 2 months $defaultDate = new \DateTime(); @@ -139,12 +140,14 @@ class CouponController extends BaseAdminController // Update if ($this->getRequest()->isMethod('POST')) { - $this->validateCreateOrUpdateForm( + if (null !== $response = $this->validateCreateOrUpdateForm( $eventToDispatch, 'updated', 'update', $coupon - ); + )) { + return $response; + } } else { // Display // Prepare the data that will hydrate the form @@ -199,6 +202,7 @@ class CouponController extends BaseAdminController } $args['couponCode'] = $coupon->getCode(); + $args['couponType'] = $coupon->getType(); $args['availableCoupons'] = $this->getAvailableCoupons(); $args['couponInputsHtml'] = $couponManager->drawBackOfficeInputs(); $args['urlAjaxAdminCouponDrawInputs'] = $this->getRoute( @@ -475,7 +479,7 @@ class CouponController extends BaseAdminController { // Create the form from the request $couponForm = new CouponCreationForm($this->getRequest()); - + $response = null; $message = false; try { // Check the form against conditions violations @@ -499,20 +503,19 @@ class CouponController extends BaseAdminController ); if ($this->getRequest()->get('save_mode') == 'stay') { - $this->redirect( - str_replace( - '{id}', - $couponEvent->getCouponModel()->getId(), - $couponForm->getSuccessUrl() - ) + $response = RedirectResponse::create(str_replace( + '{id}', + $couponEvent->getCouponModel()->getId(), + $couponForm->getSuccessUrl() + )); + + } else { + // Redirect to the success URL + $response = RedirectResponse::create( + URL::getInstance()->absoluteUrl($this->getRoute('admin.coupon.list')) ); - - exit(); } - // Redirect to the success URL - $this->redirectToRoute('admin.coupon.list'); - } catch (FormValidationException $ex) { // Invalid data entered $message = $this->createStandardFormValidationErrorMessage($ex); @@ -534,7 +537,7 @@ class CouponController extends BaseAdminController ->setGeneralError($message); } - return $this; + return $response; } /** @@ -577,7 +580,7 @@ class CouponController extends BaseAdminController $condition['serviceId'] = $availableCoupon->getServiceId(); $condition['name'] = $availableCoupon->getName(); $condition['toolTip'] = $availableCoupon->getToolTip(); - // $condition['inputName'] = $availableCoupon->getInputName(); + $cleanedCoupons[] = $condition; } @@ -624,17 +627,23 @@ class CouponController extends BaseAdminController return $response; } - $this->checkXmlHttpRequest(); + if (! empty($couponServiceId)) { + $this->checkXmlHttpRequest(); - /** @var CouponInterface $coupon */ - $couponManager = $this->container->get($couponServiceId); + /** @var CouponInterface $coupon */ + $couponManager = $this->container->get($couponServiceId); - if (!$couponManager instanceof CouponInterface) { - $this->pageNotFound(); + if (!$couponManager instanceof CouponInterface) { + $this->pageNotFound(); + } + + $response = new ResponseRest($couponManager->drawBackOfficeInputs()); + } else { + // Return an empty response if the service ID is not defined + // Typically, when the user chooses "Please select a coupon type" + $response = new ResponseRest(''); } - $response = new ResponseRest($couponManager->drawBackOfficeInputs()); - return $response; } @@ -676,35 +685,6 @@ class CouponController extends BaseAdminController } - /** - * Add percentage logic if found in the Coupon post data - * - * @param array $effects Effect parameters to populate - * @param array $extendedInputNames Extended Inputs to manage - * - * @return array Populated effect with percentage - */ - protected function addExtendedLogic(array $effects, array $extendedInputNames) - { - /** @var Request $request */ - $request = $this->container->get('request'); - $postData = $request->request; - // Validate quantity input - - if ($postData->has(RemoveXPercent::INPUT_EXTENDED__NAME)) { - $extentedPostData = $postData->get(RemoveXPercent::INPUT_EXTENDED__NAME); - - foreach ($extendedInputNames as $extendedInputName) { - if (isset($extentedPostData[$extendedInputName])) { - $inputValue = $extentedPostData[$extendedInputName]; - $effects[$extendedInputName] = $inputValue; - } - } - } - - return $effects; - } - /** * Feed the Coupon Create or Update event with the User inputs * @@ -718,16 +698,15 @@ class CouponController extends BaseAdminController // Get the form field values $data = $form->getData(); $serviceId = $data['type']; - /** @var CouponInterface $couponManager */ - $couponManager = $this->container->get($serviceId); - $effects = [CouponAbstract::INPUT_AMOUNT_NAME => $data[CouponAbstract::INPUT_AMOUNT_NAME]]; - $effects = $this->addExtendedLogic($effects, $couponManager->getExtendedInputs()); + + /** @var CouponInterface $coupon */ + $coupon = $this->container->get($serviceId); $couponEvent = new CouponCreateOrUpdateEvent( $data['code'], $serviceId, $data['title'], - $effects, + $coupon->getEffects($data), $data['shortDescription'], $data['description'], $data['isEnabled'], diff --git a/core/lib/Thelia/Controller/Admin/CustomerExportController.php b/core/lib/Thelia/Controller/Admin/CustomerExportController.php index 5e9900dba..0036f2d53 100644 --- a/core/lib/Thelia/Controller/Admin/CustomerExportController.php +++ b/core/lib/Thelia/Controller/Admin/CustomerExportController.php @@ -25,7 +25,7 @@ use Thelia\Model\NewsletterQuery; class CustomerExportController extends BaseAdminController { - public function NewsletterExportAction() + public function newsletterExportAction() { if (null !== $response = $this->checkAuth([AdminResources::EXPORT_CUSTOMER_NEWSLETTER], [], [AccessManager::VIEW])) { return $response; diff --git a/core/lib/Thelia/Controller/Admin/FileController.php b/core/lib/Thelia/Controller/Admin/FileController.php index 8494d833a..3b8bd0507 100644 --- a/core/lib/Thelia/Controller/Admin/FileController.php +++ b/core/lib/Thelia/Controller/Admin/FileController.php @@ -31,10 +31,12 @@ use Thelia\Model\ContentDocument; use Thelia\Model\ContentImage; use Thelia\Model\FolderDocument; use Thelia\Model\FolderImage; +use Thelia\Model\Lang; use Thelia\Model\ProductDocument; use Thelia\Model\ProductImage; use Thelia\Tools\FileManager; use Thelia\Tools\Rest\ResponseRest; +use Thelia\Tools\URL; /** * Created by JetBrains PhpStorm. @@ -182,6 +184,7 @@ class FileController extends BaseAdminController } $documentModel->setParentId($parentId); + $documentModel->setLocale(Lang::getDefaultLanguage()->getLocale()); $documentModel->setTitle($fileBeingUploaded->getClientOriginalName()); $documentCreateOrUpdateEvent = new DocumentCreateOrUpdateEvent( @@ -309,7 +312,8 @@ class FileController extends BaseAdminController 'imageId' => $imageId, 'imageType' => $parentType, 'redirectUrl' => $redirectUrl, - 'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES) + 'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES), + 'breadcrumb' => $image->getBreadcrumb($this->getRouter($this->getCurrentRouter()), $this->container, 'images') )); } catch (\Exception $e) { $this->pageNotFound(); @@ -338,7 +342,8 @@ class FileController extends BaseAdminController 'documentId' => $documentId, 'documentType' => $parentType, 'redirectUrl' => $redirectUrl, - 'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS) + 'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS), + 'breadcrumb' => $document->getBreadcrumb($this->getRouter($this->getCurrentRouter()), $this->container, 'documents') )); } catch (\Exception $e) { $this->pageNotFound(); @@ -389,7 +394,7 @@ class FileController extends BaseAdminController $this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId())); if ($this->getRequest()->get('save_mode') == 'close') { - $this->redirectToRoute('admin.images'); + $this->redirect(URL::getInstance()->absoluteUrl($fileManager->getRedirectionUrl($parentType, $image->getParentId(), FileManager::FILE_TYPE_IMAGES))); } else { $this->redirectSuccess($imageModification); } @@ -466,7 +471,7 @@ class FileController extends BaseAdminController $this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Document with Ref %s (ID %d) modified', $documentUpdated->getTitle(), $documentUpdated->getId())); if ($this->getRequest()->get('save_mode') == 'close') { - $this->redirectToRoute('admin.documents'); + $this->redirect(URL::getInstance()->absoluteUrl($fileManager->getRedirectionUrl($parentType, $document->getParentId(), FileManager::FILE_TYPE_DOCUMENTS))); } else { $this->redirectSuccess($documentModification); } diff --git a/core/lib/Thelia/Controller/Admin/ProductController.php b/core/lib/Thelia/Controller/Admin/ProductController.php index f4bfb095f..4cbfbad42 100644 --- a/core/lib/Thelia/Controller/Admin/ProductController.php +++ b/core/lib/Thelia/Controller/Admin/ProductController.php @@ -361,7 +361,8 @@ class ProductController extends AbstractSeoCrudController 'product_id' => $this->getRequest()->get('product_id', 0), 'folder_id' => $this->getRequest()->get('folder_id', 0), 'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0), - 'current_tab' => $this->getRequest()->get('current_tab', 'general') + 'current_tab' => $this->getRequest()->get('current_tab', 'general'), + 'page' => $this->getRequest()->get('page', 1) ); } @@ -386,7 +387,8 @@ class ProductController extends AbstractSeoCrudController return $this->render('categories', array( 'product_order' => $currentOrder, - 'category_id' => $this->getCategoryId() + 'category_id' => $this->getCategoryId(), + 'page' => $this->getRequest()->get('page', 1) )); } @@ -394,7 +396,10 @@ class ProductController extends AbstractSeoCrudController { $this->redirectToRoute( 'admin.products.default', - array('category_id' => $this->getCategoryId()) + array( + 'category_id' => $this->getCategoryId(), + 'page' => $this->getRequest()->get('page', 1) + ) ); } @@ -438,18 +443,6 @@ class ProductController extends AbstractSeoCrudController ); } - protected function performAdditionalUpdateAction($updateEvent) - { - if ($this->getRequest()->get('save_mode') != 'stay') { - - // Redirect to parent product list - $this->redirectToRoute( - 'admin.categories.default', - array('category_id' => $this->getCategoryId()) - ); - } - } - protected function performAdditionalUpdatePositionAction($positionEvent) { // Redirect to parent product list diff --git a/core/lib/Thelia/Controller/Admin/TranslationsController.php b/core/lib/Thelia/Controller/Admin/TranslationsController.php index 93aab31cb..6c2aed749 100644 --- a/core/lib/Thelia/Controller/Admin/TranslationsController.php +++ b/core/lib/Thelia/Controller/Admin/TranslationsController.php @@ -181,13 +181,6 @@ class TranslationsController extends BaseAdminController case 'ma' : $template = new TemplateDefinition($item_name, TemplateDefinition::EMAIL); break; - - default: - /* - throw new \InvalidArgumentException( - $this->getTranslator()->trans("Undefined translation type: %item", ['%item' => $item_to_translate]) - ); - */ } if ($template) { diff --git a/core/lib/Thelia/Controller/BaseController.php b/core/lib/Thelia/Controller/BaseController.php index 162b5a814..41fa50067 100644 --- a/core/lib/Thelia/Controller/BaseController.php +++ b/core/lib/Thelia/Controller/BaseController.php @@ -291,7 +291,7 @@ abstract class BaseController extends ContainerAware protected function getRouteFromRouter($routerName, $routeId, $parameters = array(), $referenceType = Router::ABSOLUTE_URL) { /** @var Router $router */ - $router = $this->container->get($routerName); + $router = $this->getRouter($routerName); if ($router == null) { throw new \InvalidArgumentException(sprintf("Router '%s' does not exists.", $routerName)); @@ -300,6 +300,15 @@ abstract class BaseController extends ContainerAware return $router->generate($routeId, $parameters, $referenceType); } + /** + * @param $routerName + * @return Router + */ + protected function getRouter($routerName) + { + return $this->container->get($routerName); + } + /** * Return a 404 error * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException diff --git a/core/lib/Thelia/Core/Event/Cart/CartEvent.php b/core/lib/Thelia/Core/Event/Cart/CartEvent.php index 1c719c0ae..d6a100c16 100644 --- a/core/lib/Thelia/Core/Event/Cart/CartEvent.php +++ b/core/lib/Thelia/Core/Event/Cart/CartEvent.php @@ -14,6 +14,7 @@ namespace Thelia\Core\Event\Cart; use Thelia\Core\Event\ActionEvent; use Thelia\Model\Cart; +use Thelia\Model\CartItem; class CartEvent extends ActionEvent { @@ -31,7 +32,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $append + * @param bool $append + * @return CartEvent */ public function setAppend($append) { @@ -41,7 +43,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return bool */ public function getAppend() { @@ -49,7 +51,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $cartItem + * @param CartItem $cartItem + * @return CartEvent */ public function setCartItem($cartItem) { @@ -59,7 +62,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return CartItem */ public function getCartItem() { @@ -67,7 +70,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $newness + * @param bool $newness + * @return CartEvent */ public function setNewness($newness) { @@ -77,7 +81,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return bool */ public function getNewness() { @@ -85,7 +89,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $product + * @param int $product the product ID + * @return CartEvent */ public function setProduct($product) { @@ -95,7 +100,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return int the product ID */ public function getProduct() { @@ -103,7 +108,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $productSaleElementsId + * @param int $productSaleElementsId + * @return CartEvent */ public function setProductSaleElementsId($productSaleElementsId) { @@ -113,7 +119,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return int */ public function getProductSaleElementsId() { @@ -121,7 +127,8 @@ class CartEvent extends ActionEvent } /** - * @param mixed $quantity + * @param int $quantity + * @return CartEvent */ public function setQuantity($quantity) { @@ -131,7 +138,7 @@ class CartEvent extends ActionEvent } /** - * @return mixed + * @return int */ public function getQuantity() { diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php index 755dbe9f7..9b3a979da 100644 --- a/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php +++ b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php @@ -14,7 +14,6 @@ namespace Thelia\Core\Event\Coupon; use Thelia\Core\Event\ActionEvent; use Thelia\Condition\ConditionCollection; use Thelia\Model\Coupon; -use Thelia\Model\Exception\InvalidArgumentException; /** * Occurring when a Coupon is created or updated @@ -327,10 +326,9 @@ class CouponCreateOrUpdateEvent extends ActionEvent */ public function setEffects(array $effects) { - if (null === $effects['amount']) { - throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect ready to be serialized array'); - } - $this->amount = $effects['amount']; + // Amount is now optionnal. + $this->amount = isset($effects['amount']) ? $effects['amount'] : 0; + $this->effects = $effects; } diff --git a/core/lib/Thelia/Core/Event/SessionEvent.php b/core/lib/Thelia/Core/Event/SessionEvent.php index 6def3ac01..8503495cc 100644 --- a/core/lib/Thelia/Core/Event/SessionEvent.php +++ b/core/lib/Thelia/Core/Event/SessionEvent.php @@ -14,7 +14,6 @@ namespace Thelia\Core\Event; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; - /** * Class SessionEvent * @package Thelia\Core\Event @@ -71,5 +70,4 @@ class SessionEvent extends ActionEvent return $this->session; } - -} \ No newline at end of file +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 69c12fb73..571604b69 100644 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -464,6 +464,11 @@ final class TheliaEvents */ const COUPON_CONSUME = "action.consume_coupon"; + /** + * Sent when all coupons in the current session should be cleared + */ + const COUPON_CLEAR_ALL = "action.clear_all_coupon"; + /** * Sent just before an attempt to use a Coupon */ diff --git a/core/lib/Thelia/Core/EventListener/SessionListener.php b/core/lib/Thelia/Core/EventListener/SessionListener.php index f8d1f809d..aafcc53ca 100644 --- a/core/lib/Thelia/Core/EventListener/SessionListener.php +++ b/core/lib/Thelia/Core/EventListener/SessionListener.php @@ -21,7 +21,6 @@ use Thelia\Core\HttpFoundation\Session\Session; use Thelia\Core\TheliaKernelEvents; use Thelia\Model\ConfigQuery; - /** * Class SessionListener * @package Thelia\Core\EventListener @@ -79,4 +78,4 @@ class SessionListener implements EventSubscriberInterface ] ]; } -} \ No newline at end of file +} diff --git a/core/lib/Thelia/Core/EventListener/ViewListener.php b/core/lib/Thelia/Core/EventListener/ViewListener.php index b0ed5ce2f..c30ed9acb 100644 --- a/core/lib/Thelia/Core/EventListener/ViewListener.php +++ b/core/lib/Thelia/Core/EventListener/ViewListener.php @@ -25,7 +25,6 @@ use Thelia\Core\Template\Exception\ResourceNotFoundException; use Thelia\Core\Template\TemplateHelper; use Thelia\Exception\OrderException; -use Thelia\Tools\Redirect; use Thelia\Core\Security\Exception\AuthenticationException; diff --git a/core/lib/Thelia/Core/HttpKernel/Client.php b/core/lib/Thelia/Core/HttpKernel/Client.php new file mode 100644 index 000000000..fca5066d5 --- /dev/null +++ b/core/lib/Thelia/Core/HttpKernel/Client.php @@ -0,0 +1,43 @@ + + */ +class Client extends BaseClient +{ + + /** + * Converts the BrowserKit request to a HttpKernel request. + * + * @param DomRequest $request A Request instance + * + * @return Request A Request instance + */ + protected function filterRequest(DomRequest $request) + { + $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent()); + + $httpRequest->files->replace($this->filterFiles($httpRequest->files->all())); + + return $httpRequest; + } + +} diff --git a/core/lib/Thelia/Core/Template/Loop/Cart.php b/core/lib/Thelia/Core/Template/Loop/Cart.php index 4f635ddeb..91c22a7b4 100644 --- a/core/lib/Thelia/Core/Template/Loop/Cart.php +++ b/core/lib/Thelia/Core/Template/Loop/Cart.php @@ -82,9 +82,9 @@ class Cart extends BaseLoop implements ArraySearchLoopInterface public function parseResults(LoopResult $loopResult) { $taxCountry = $this->container->get('thelia.taxEngine')->getDeliveryCountry(); - + $locale = $this->request->getSession()->getLang()->getLocale(); foreach ($loopResult->getResultDataCollection() as $cartItem) { - $product = $cartItem->getProduct(); + $product = $cartItem->getProduct(null, $locale); $productSaleElement = $cartItem->getProductSaleElements(); $loopResultRow = new LoopResultRow(); diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 9dbb3ea2a..9ecee9182 100644 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Element\PropelSearchLoopInterface; +use Thelia\Core\Template\Element\SearchLoopInterface; use Thelia\Core\Template\Loop\Argument\ArgumentCollection; use Thelia\Core\Template\Loop\Argument\Argument; @@ -51,7 +52,7 @@ use Thelia\Model\ProductQuery; * @author Manuel Raynaud * @author Etienne Roudeix */ -class Category extends BaseI18nLoop implements PropelSearchLoopInterface +class Category extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface { protected $timestampable = true; protected $versionable = true; @@ -83,6 +84,23 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface ); } + /** + * @return array of available field to search in + */ + public function getSearchIn() + { + return [ + "title" + ]; + } + + public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria) + { + $search->_and(); + + $search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR); + } + public function buildModelCriteria() { $search = CategoryQuery::create(); @@ -172,9 +190,6 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface } } - /* @todo */ - $notEmpty = $this->getNot_empty(); - return $search; } diff --git a/core/lib/Thelia/Core/Template/Loop/Content.php b/core/lib/Thelia/Core/Template/Loop/Content.php index df0f18aff..5bae9f739 100644 --- a/core/lib/Thelia/Core/Template/Loop/Content.php +++ b/core/lib/Thelia/Core/Template/Loop/Content.php @@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Element\PropelSearchLoopInterface; +use Thelia\Core\Template\Element\SearchLoopInterface; use Thelia\Core\Template\Loop\Argument\ArgumentCollection; use Thelia\Core\Template\Loop\Argument\Argument; @@ -37,7 +38,7 @@ use Thelia\Type\BooleanOrBothType; * @package Thelia\Core\Template\Loop * @author Etienne Roudeix */ -class Content extends BaseI18nLoop implements PropelSearchLoopInterface +class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface { protected $timestampable = true; protected $versionable = true; @@ -60,7 +61,20 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface new Argument( 'order', new TypeCollection( - new Type\EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual_reverse', 'random', 'given_id', 'created', 'created_reverse', 'updated', 'updated_reverse')) + new Type\EnumListType( + array( + 'alpha', + 'alpha-reverse', + 'manual', + 'manual_reverse', + 'random', + 'given_id', + 'created', + 'created_reverse', + 'updated', + 'updated_reverse' + ) + ) ), 'alpha' ), @@ -69,6 +83,23 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface ); } + /** + * @return array of available field to search in + */ + public function getSearchIn() + { + return [ + "title" + ]; + } + + public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria) + { + $search->_and(); + + $search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR); + } + public function buildModelCriteria() { diff --git a/core/lib/Thelia/Core/Template/Loop/Coupon.php b/core/lib/Thelia/Core/Template/Loop/Coupon.php index 14444726d..310a760e2 100644 --- a/core/lib/Thelia/Core/Template/Loop/Coupon.php +++ b/core/lib/Thelia/Core/Template/Loop/Coupon.php @@ -152,11 +152,6 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface /** @var ConditionFactory $conditionFactory */ $conditionFactory = $this->container->get('thelia.condition.factory'); - /** @var Request $request */ - $request = $this->container->get('request'); - /** @var Lang $lang */ - $lang = $request->getSession()->getLang(); - /** @var MCoupon $coupon */ foreach ($loopResult->getResultDataCollection() as $coupon) { diff --git a/core/lib/Thelia/Core/Template/Loop/Document.php b/core/lib/Thelia/Core/Template/Loop/Document.php index 3e4063d7b..77a38587e 100644 --- a/core/lib/Thelia/Core/Template/Loop/Document.php +++ b/core/lib/Thelia/Core/Template/Loop/Document.php @@ -237,7 +237,7 @@ class Document extends BaseI18nLoop implements PropelSearchLoopInterface $loopResultRow ->set("ID" , $result->getId()) ->set("LOCALE" , $this->locale) - ->set("DOCUMENT_URL" , $event->getFileUrl()) + ->set("DOCUMENT_URL" , $event->getDocumentUrl()) ->set("DOCUMENT_PATH" , $event->getDocumentPath()) ->set("ORIGINAL_DOCUMENT_PATH", $source_filepath) ->set("TITLE" , $result->getVirtualColumn('i18n_TITLE')) diff --git a/core/lib/Thelia/Core/Template/Loop/Folder.php b/core/lib/Thelia/Core/Template/Loop/Folder.php index 7b6906e32..ee4e0cbbe 100644 --- a/core/lib/Thelia/Core/Template/Loop/Folder.php +++ b/core/lib/Thelia/Core/Template/Loop/Folder.php @@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Element\PropelSearchLoopInterface; +use Thelia\Core\Template\Element\SearchLoopInterface; use Thelia\Core\Template\Loop\Argument\ArgumentCollection; use Thelia\Core\Template\Loop\Argument\Argument; @@ -33,7 +34,7 @@ use Thelia\Type\BooleanOrBothType; * @package Thelia\Core\Template\Loop * @author Etienne Roudeix */ -class Folder extends BaseI18nLoop implements PropelSearchLoopInterface +class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface { protected $timestampable = true; protected $versionable = true; @@ -62,6 +63,23 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface ); } + /** + * @return array of available field to search in + */ + public function getSearchIn() + { + return [ + "title" + ]; + } + + public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria) + { + $search->_and(); + + $search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR); + } + public function buildModelCriteria() { $search = FolderQuery::create(); @@ -139,9 +157,6 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface } } - /* @todo */ - $notEmpty = $this->getNot_empty(); - return $search; } diff --git a/core/lib/Thelia/Core/Template/Loop/OrderProduct.php b/core/lib/Thelia/Core/Template/Loop/OrderProduct.php index 83397a9cb..c66d6e1ea 100644 --- a/core/lib/Thelia/Core/Template/Loop/OrderProduct.php +++ b/core/lib/Thelia/Core/Template/Loop/OrderProduct.php @@ -41,7 +41,8 @@ class OrderProduct extends BaseLoop implements PropelSearchLoopInterface protected function getArgDefinitions() { return new ArgumentCollection( - Argument::createIntTypeArgument('order', null, true) + Argument::createIntTypeArgument('order', null, true), + Argument::createIntListTypeArgument('id') ); } @@ -58,6 +59,10 @@ class OrderProduct extends BaseLoop implements PropelSearchLoopInterface $search->filterByOrderId($order, Criteria::EQUAL); + if (null !== $this->getId()) { + $search->filterById($this->getId(), Criteria::IN); + } + $search->orderById(Criteria::ASC); return $search; diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Assets.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Assets.php index bc2107f8d..74d8d82b5 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Assets.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Assets.php @@ -43,18 +43,7 @@ class Assets extends AbstractSmartyPlugin public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat) { - try { - return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat); - } catch (\Exception $e) { - $catchException = $this->getNormalizedParam($params, array('catchException')); - if ($catchException == "true") { - $repeat = false; - - return null; - } else { - throw $e; - } - } + return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat); } public function blockImages($params, $content, \Smarty_Internal_Template $template, &$repeat) diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php index 588cbe76d..f9f8725bd 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php @@ -402,7 +402,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin return $noGetterData[$keyAttribute]; } - $getter = sprintf("get%s", ucfirst($attribute)); + $getter = sprintf("get%s", $this->underscoreToCamelcase($attribute)); if (method_exists($data, $getter)) { $return = $data->$getter(); @@ -427,6 +427,27 @@ class DataAccessFunctions extends AbstractSmartyPlugin return ''; } + /** + * Transcode an underscored string into a camel-cased string, eg. default_folder into DefaultFolder + * + * @param string $str the string to convert from underscore to camel-case + * + * @return string the camel cased string. + */ + private function underscoreToCamelcase($str) + { + // Split string in words. + $words = explode('_', strtolower($str)); + + $return = ''; + + foreach ($words as $word) { + $return .= ucfirst(trim($word)); + } + + return $return; + } + /** * Define the various smarty plugins hendled by this class * diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php index 372f74d3f..26cd8b1d8 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php @@ -50,6 +50,7 @@ class Format extends AbstractSmartyPlugin * * ex : * {format_date date=$dateTimeObject format="Y-m-d H:i:s"} will output the format with specific format + * {format_date date=$dateTimeObject format="%e %B %Y" locale="fr_FR"} will output the format with specific format (see strftime() function) * {format_date date=$dateTimeObject output="date"} will output the date using the default date system format * {format_date date=$dateTimeObject} will output with the default datetime system format * @@ -86,7 +87,32 @@ class Format extends AbstractSmartyPlugin $format = DateTimeFormat::getInstance($this->request)->getFormat($this->getParam($params, "output", null)); } - return $date->format($format); + $locale = $this->getParam($params,'locale', false); + + if (false === $locale) { + $value = $date->format($format); + } else { + $value = $this->formatDateWithLocale($date, $locale, $format); + } + + return $value; + } + + private function formatDateWithLocale(\DateTime $date, $locale, $format) + { + if (function_exists('setlocale')) { + // Save the current locale + $systemLocale = setlocale('LC_TIME', 0); + setlocale('LC_TIME', $locale); + $localizedDate = strftime($format, $date->getTimestamp()); + // Restore the locale + setlocale('LC_TIME', $systemLocale); + + return $localizedDate; + } else { + // setlocale() function not available => error + throw new SmartyPluginException("The setlocale() function is not available on your system."); + } } /** diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php index aa66c114f..22ba0d14f 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php @@ -47,20 +47,26 @@ class Translation extends AbstractSmartyPlugin */ public function translate($params, &$smarty) { - // All parameters other than 'l' and 'd' are supposed to be variables. Build an array of var => value pairs + // All parameters other than 'l' and 'd' and 'js' are supposed to be variables. Build an array of var => value pairs // and pass it to the translator $vars = array(); foreach ($params as $name => $value) { - if ($name != 'l' && $name != 'd') $vars["%$name"] = $value; + if ($name != 'l' && $name != 'd' && $name != 'js') $vars["%$name"] = $value; } - return $this->translator->trans( + $str = $this->translator->trans( $this->getParam($params, 'l'), $vars, $this->getParam($params, 'd', $this->defaultTranslationDomain) ); -} + + if ($this->getParam($params, 'js', 0)) { + $str = preg_replace("/(['\"])/", "\\\\$1", $str); + } + + return $str; + } /** * Define the various smarty plugins handled by this class diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php index 03d605358..332c3fbaf 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php @@ -152,9 +152,9 @@ class UrlGenerator extends AbstractSmartyPlugin protected function getNavigateToValues() { return array( - "current" => "getCurrentUrl", - "return_to" => "getReturnToUrl", - "index" => "getIndexUrl", + "current" => "getCurrentUrl", + "previous" => "getPreviousUrl", + "index" => "getIndexUrl", ); } @@ -167,7 +167,7 @@ class UrlGenerator extends AbstractSmartyPlugin $navigateToValues = $this->getNavigateToValues(); if (!array_key_exists($to, $navigateToValues)) { - throw new \InvalidArgumentException("Incorrect value for parameter `to` in `navigate` substitution."); + throw new \InvalidArgumentException(sprintf("Incorrect value `%s` for parameter `to` in `navigate` substitution.", $to)); } return $navigateToValues[$to]; @@ -178,7 +178,7 @@ class UrlGenerator extends AbstractSmartyPlugin return $this->request->getUri(); } - protected function getReturnToUrl() + protected function getPreviousUrl() { return URL::getInstance()->absoluteUrl($this->request->getSession()->getReturnToUrl()); } diff --git a/core/lib/Thelia/Core/Template/TemplateHelper.php b/core/lib/Thelia/Core/Template/TemplateHelper.php index ef6737890..c7c7c1163 100644 --- a/core/lib/Thelia/Core/Template/TemplateHelper.php +++ b/core/lib/Thelia/Core/Template/TemplateHelper.php @@ -60,13 +60,13 @@ class TemplateHelper $tplVar = 'active-front-template'; break; case TemplateDefinition::BACK_OFFICE: - $tplVar = 'active-front-template'; + $tplVar = 'active-admin-template'; break; case TemplateDefinition::PDF: - $tplVar = 'active-front-template'; + $tplVar = 'active-pdf-template'; break; case TemplateDefinition::EMAIL: - $tplVar = 'active-front-template'; + $tplVar = 'active-mail-template'; break; } diff --git a/core/lib/Thelia/Core/Thelia.php b/core/lib/Thelia/Core/Thelia.php index fb750c534..20b57e088 100644 --- a/core/lib/Thelia/Core/Thelia.php +++ b/core/lib/Thelia/Core/Thelia.php @@ -21,35 +21,33 @@ namespace Thelia\Core; * @author Manuel Raynaud */ +use Propel\Runtime\Connection\ConnectionManagerSingle; use Propel\Runtime\Connection\ConnectionWrapper; +use Propel\Runtime\Propel; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Finder\Finder; use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Yaml\Yaml; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; - -use Thelia\Core\Event\TheliaEvents; use Thelia\Config\DatabaseConfiguration; use Thelia\Config\DefinePropel; +use Thelia\Core\DependencyInjection\Loader\XmlFileLoader; +use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Template\ParserInterface; use Thelia\Core\Template\TemplateDefinition; - -use Thelia\Core\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\Config\FileLocator; - -use Propel\Runtime\Propel; -use Propel\Runtime\Connection\ConnectionManagerSingle; use Thelia\Core\Template\TemplateHelper; use Thelia\Log\Tlog; use Thelia\Model\Module; +use Thelia\Model\ModuleQuery; class Thelia extends Kernel { - const THELIA_VERSION = '2.0.1'; + const THELIA_VERSION = '2.0.2'; public function init() { @@ -143,7 +141,7 @@ class Thelia extends Kernel } } } catch (\UnexpectedValueException $ex) { - // The directory does not exists, ignore it. + // The directory does not exists, ignore it. } } @@ -162,12 +160,13 @@ class Thelia extends Kernel ->depth(0) ->in(THELIA_ROOT . "/core/lib/Thelia/Config/Resources"); + /** @var \SplFileInfo $file */ foreach ($finder as $file) { $loader->load($file->getBaseName()); } if (defined("THELIA_INSTALL_MODE") === false) { - $modules = \Thelia\Model\ModuleQuery::getActivated(); + $modules = ModuleQuery::getActivated(); $translationDirs = array(); @@ -233,12 +232,16 @@ class Thelia extends Kernel $translationDirs[$module->getFrontOfficeTemplateTranslationDomain($template->getName())] = $module->getAbsoluteFrontOfficeI18nTemplatePath($template->getName()); } + $this->addStandardModuleTemplatesToParserEnvironment($parser, $module); } catch (\InvalidArgumentException $e) { + Tlog::getInstance()->addError( sprintf("Failed to load module %s: %s", $module->getCode(), $e->getMessage()), $e ); + + throw $e; } } diff --git a/core/lib/Thelia/Core/TheliaHttpKernel.php b/core/lib/Thelia/Core/TheliaHttpKernel.php index 2bf5a0004..a17e90484 100644 --- a/core/lib/Thelia/Core/TheliaHttpKernel.php +++ b/core/lib/Thelia/Core/TheliaHttpKernel.php @@ -20,7 +20,6 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Session; use Thelia\Core\Event\Currency\CurrencyChangeEvent; use Thelia\Core\Event\SessionEvent; diff --git a/core/lib/Thelia/Core/TheliaKernelEvents.php b/core/lib/Thelia/Core/TheliaKernelEvents.php index d1d3fe276..2348d55d9 100644 --- a/core/lib/Thelia/Core/TheliaKernelEvents.php +++ b/core/lib/Thelia/Core/TheliaKernelEvents.php @@ -12,7 +12,6 @@ namespace Thelia\Core; - /** * Class TheliaKernelEvents * @package Thelia\Core @@ -23,4 +22,4 @@ final class TheliaKernelEvents const SESSION = "thelia_kernel.session"; -} \ No newline at end of file +} diff --git a/core/lib/Thelia/Core/Translation/Translator.php b/core/lib/Thelia/Core/Translation/Translator.php index bad4d4d99..28f370c1c 100644 --- a/core/lib/Thelia/Core/Translation/Translator.php +++ b/core/lib/Thelia/Core/Translation/Translator.php @@ -14,7 +14,6 @@ namespace Thelia\Core\Translation; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Translation\Translator as BaseTranslator; -use Thelia\Log\Tlog; class Translator extends BaseTranslator { @@ -74,14 +73,9 @@ class Translator extends BaseTranslator $this->loadCatalogue($locale); } - if (! $this->catalogues[$locale]->has((string) $id, $domain)) { - - } - if ($this->catalogues[$locale]->has((string) $id, $domain)) { return parent::trans($id, $parameters, $domain, $locale); } else { - //Tlog::getInstance()->addWarning("Undefined translation: locale: $locale, domain: $domain, ID: $id"); if ($return_default_if_not_available) return strtr($id, $parameters); diff --git a/core/lib/Thelia/Coupon/BaseFacade.php b/core/lib/Thelia/Coupon/BaseFacade.php index 0fdf0c36b..25a177996 100644 --- a/core/lib/Thelia/Coupon/BaseFacade.php +++ b/core/lib/Thelia/Coupon/BaseFacade.php @@ -21,6 +21,7 @@ use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Template\ParserInterface; use Thelia\Core\Template\TemplateHelper; use Thelia\Model\AddressQuery; +use Thelia\Model\Country; use Thelia\Model\Coupon; use Thelia\Model\CouponQuery; use Thelia\Cart\CartTrait; @@ -118,17 +119,43 @@ class BaseFacade implements FacadeInterface * * @return float */ - public function getCartTotalPrice() + public function getCartTotalPrice($withItemsInPromo = true) { - return $this->getRequest()->getSession()->getCart()->getTotalAmount(); + $total = 0; + $cartItems = $this->getRequest()->getSession()->getCart()->getCartItems(); + + foreach ($cartItems as $cartItem) { + if ($withItemsInPromo || ! $cartItem->getPromo()) { + $total += $cartItem->getRealPrice() * $cartItem->getQuantity(); + } + } + + return $total; } - public function getCartTotalTaxPrice() + public function getCartTotalTaxPrice($withItemsInPromo = true) { $taxCountry = $this->getContainer()->get('thelia.taxEngine')->getDeliveryCountry(); + $cartItems = $this->getRequest()->getSession()->getCart()->getCartItems(); - return $this->getCart()->getTaxedAmount($taxCountry, false); + $total = 0; + + foreach ($cartItems as $cartItem) { + if ($withItemsInPromo || ! $cartItem->getPromo()) { + $total += $cartItem->getRealTaxedPrice($taxCountry) * $cartItem->getQuantity(); + } + } + + return $total; + } + + /** + * @return Country the delivery country + */ + public function getDeliveryCountry() + { + return $this->getContainer()->get('thelia.taxEngine')->getDeliveryCountry(); } /** diff --git a/core/lib/Thelia/Coupon/CouponFactory.php b/core/lib/Thelia/Coupon/CouponFactory.php index 40a4f0483..f1b87ae19 100644 --- a/core/lib/Thelia/Coupon/CouponFactory.php +++ b/core/lib/Thelia/Coupon/CouponFactory.php @@ -69,7 +69,7 @@ class CouponFactory } // Check coupon usage count - if ($couponModel->getUsagesLeft($this->facade->getCustomer()->getId()) <= 0) { + if (! $couponModel->isUsageUnlimited() && $couponModel->getUsagesLeft($this->facade->getCustomer()->getId()) <= 0) { throw new CouponNoUsageLeftException($couponCode); } diff --git a/core/lib/Thelia/Coupon/CouponManager.php b/core/lib/Thelia/Coupon/CouponManager.php index ecb491673..e92aaaa86 100644 --- a/core/lib/Thelia/Coupon/CouponManager.php +++ b/core/lib/Thelia/Coupon/CouponManager.php @@ -58,14 +58,15 @@ class CouponManager /** * Get Discount for the given Coupons - * * @api * @return float checkout discount */ public function getDiscount() { $discount = 0.00; + $coupons = $this->facade->getCurrentCoupons(); + if (count($coupons) > 0) { $couponsKept = $this->sortCoupons($coupons); @@ -73,6 +74,7 @@ class CouponManager // Just In Case test $checkoutTotalPrice = $this->facade->getCartTotalTaxPrice(); + if ($discount >= $checkoutTotalPrice) { $discount = $checkoutTotalPrice; } @@ -83,6 +85,9 @@ class CouponManager /** * Check if there is a Coupon removing Postage + * + * @param Order $order the order for which we have to check if postage is free + * * @return bool */ public function isCouponRemovingPostage(Order $order) @@ -266,6 +271,19 @@ class CouponManager return $this->availableConditions; } + /** + * Clear all data kept by coupons + */ + public function clear() + { + $coupons = $this->facade->getCurrentCoupons(); + + /** @var CouponInterface $coupon */ + foreach ($coupons as $coupon) { + $coupon->clear(); + } + } + /** * Decrement this coupon quantity * @@ -278,57 +296,61 @@ class CouponManager */ public function decrementQuantity(Coupon $coupon, $customerId = null) { - $ret = false; + if ($coupon->isUsageUnlimited()) { + $ret = true; + } else { + $ret = false; - try { + try { - $usageLeft = $coupon->getUsagesLeft($customerId); + $usageLeft = $coupon->getUsagesLeft($customerId); - if ($usageLeft > 0) { + if ($usageLeft > 0) { - // If the coupon usage is per user, add an entry to coupon customer usage count table - if ($coupon->getPerCustomerUsageCount()) { + // If the coupon usage is per user, add an entry to coupon customer usage count table + if ($coupon->getPerCustomerUsageCount()) { - if (null == $customerId) { - throw new \LogicException("Customer should not be null at this time."); - } + if (null == $customerId) { + throw new \LogicException("Customer should not be null at this time."); + } - $ccc = CouponCustomerCountQuery::create() - ->filterByCouponId($coupon->getId()) - ->filterByCustomerId($customerId) - ->findOne() - ; + $ccc = CouponCustomerCountQuery::create() + ->filterByCouponId($coupon->getId()) + ->filterByCustomerId($customerId) + ->findOne() + ; - if ($ccc === null) { - $ccc = new CouponCustomerCount(); + if ($ccc === null) { + $ccc = new CouponCustomerCount(); + + $ccc + ->setCustomerId($customerId) + ->setCouponId($coupon->getId()) + ->setCount(0); + } + + $newCount = 1 + $ccc->getCount(); $ccc - ->setCustomerId($customerId) - ->setCouponId($coupon->getId()) - ->setCount(0); + ->setCount($newCount) + ->save() + ; + + $ret = $usageLeft - $newCount; + } else { + $usageLeft--; + + $coupon->setMaxUsage($usageLeft); + + $coupon->save(); + + $ret = $usageLeft; } - - $newCount = 1 + $ccc->getCount(); - - $ccc - ->setCount($newCount) - ->save() - ; - - $ret = $usageLeft - $newCount; - } else { - $usageLeft--; - - $coupon->setMaxUsage($usageLeft); - - $coupon->save(); - - $ret = $usageLeft; } + } catch (\Exception $ex) { + // Just log the problem. + Tlog::getInstance()->addError(sprintf("Failed to decrement coupon %s: %s", $coupon->getCode(), $ex->getMessage())); } - } catch (\Exception $ex) { - // Just log the problem. - Tlog::getInstance()->addError(sprintf("Failed to decrement coupon %s: %s", $coupon->getCode(), $ex->getMessage())); } return $ret; diff --git a/core/lib/Thelia/Coupon/FacadeInterface.php b/core/lib/Thelia/Coupon/FacadeInterface.php index 40e4e2948..2201dfb69 100644 --- a/core/lib/Thelia/Coupon/FacadeInterface.php +++ b/core/lib/Thelia/Coupon/FacadeInterface.php @@ -18,6 +18,7 @@ use Symfony\Component\Translation\TranslatorInterface; use Thelia\Condition\ConditionEvaluator; use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Template\ParserInterface; +use Thelia\Model\Country; use Thelia\Model\Coupon; /** @@ -51,6 +52,11 @@ interface FacadeInterface */ public function getDeliveryAddress(); + /** + * @return Country the delivery country + */ + public function getDeliveryCountry(); + /** * Return an Customer a CouponManager can process * @@ -68,17 +74,19 @@ interface FacadeInterface /** * Return Products total price * CartTotalPrice = Checkout total - discount - postage + * @param bool $withItemsInPromo true (default) if item in promotion should be included in the total, false otherwise. * * @return float */ - public function getCartTotalPrice(); + public function getCartTotalPrice($withItemsInPromo = true); /** * Return Product total tax price + * @param bool $withItemsInPromo true (default) if item in promotion should be included in the total, false otherwise. * * @return float */ - public function getCartTotalTaxPrice(); + public function getCartTotalTaxPrice($withItemsInPromo = true); /** * Return the Checkout currency EUR|USD diff --git a/core/lib/Thelia/Coupon/Type/AbstractRemove.php b/core/lib/Thelia/Coupon/Type/AbstractRemove.php new file mode 100644 index 000000000..4cf89c3d6 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AbstractRemove.php @@ -0,0 +1,128 @@ + + */ +abstract class AbstractRemove extends CouponAbstract implements AmountAndPercentageCouponInterface +{ + /** + * Set the value of specific coupon fields. + * + * @param Array $effects the Coupon effects params + */ + abstract public function setFieldsValue($effects); + + /** + * Get the discount for a specific cart item. + * + * @param CartItem $cartItem the cart item + * @return float the discount value + */ + abstract public function getCartItemDiscount($cartItem); + + /** + * @inheritdoc + */ + public function set( + FacadeInterface $facade, + $code, + $title, + $shortDescription, + $description, + array $effects, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ) + { + parent::set( + $facade, $code, $title, $shortDescription, $description, $effects, + $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ); + + $this->setFieldsValue($effects); + + return $this; + } + /** + * @inheritdoc + */ + public function exec() + { + // This coupon subtracts the specified amount from the order total + // for each product of the selected categories. + $discount = 0; + + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) { + $categories = $cartItem->getProduct()->getCategories(); + + /** @var Category $category */ + foreach ($categories as $category) { + + if (in_array($category->getId(), $this->category_list)) { + $discount += $this->getCartItemDiscount($cartItem); + + break; + } + } + } + } + + return $discount; + } + + /** + * @inheritdoc + */ + public function drawBaseBackOfficeInputs($templateName, $otherFields) + { + return $this->facade->getParser()->render($templateName, $otherFields); + } + + /** + * @inheritdoc + */ + public function getBaseFieldList($otherFields) + { + return array_merge($otherFields); + } + + /** + * @inheritdoc + */ + public function checkBaseCouponFieldValue($fieldName, $fieldValue) + { + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/AbstractRemoveOnAttributeValues.php b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnAttributeValues.php new file mode 100644 index 000000000..3b54ce0e7 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnAttributeValues.php @@ -0,0 +1,180 @@ + + */ +abstract class AbstractRemoveOnAttributeValues extends CouponAbstract implements AmountAndPercentageCouponInterface +{ + const ATTRIBUTES_AV_LIST = 'attribute_avs'; + const ATTRIBUTE = 'attribute_id'; + + public $attributeAvList = array(); + public $attribute = 0; + + /** + * Set the value of specific coupon fields. + * @param Array $effects the Coupon effects params + */ + abstract public function setFieldsValue($effects); + + /** + * Get the discount for a specific cart item. + * + * @param CartItem $cartItem the cart item + * @return float the discount value + */ + abstract public function getCartItemDiscount($cartItem); + + /** + * @inheritdoc + */ + public function set( + FacadeInterface $facade, + $code, + $title, + $shortDescription, + $description, + array $effects, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ) + { + parent::set( + $facade, $code, $title, $shortDescription, $description, $effects, + $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ); + + $this->attributeAvList = isset($effects[self::ATTRIBUTES_AV_LIST]) ? $effects[self::ATTRIBUTES_AV_LIST] : array(); + + if (! is_array($this->attributeAvList)) $this->attributeAvList = array($this->attributeAvList); + + $this->attribute = isset($effects[self::ATTRIBUTE]) ? $effects[self::ATTRIBUTE] : 0; + + $this->setFieldsValue($effects); + + return $this; + } + + /** + * @inheritdoc + */ + public function exec() + { + // This coupon subtracts the specified amount from the order total + // for each product which uses the selected attributes + $discount = 0; + + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + + if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) { + $productSaleElements = $cartItem->getProductSaleElements(); + + $combinations = $productSaleElements->getAttributeCombinations(); + + /** @var AttributeCombination $combination */ + foreach ($combinations as $combination) { + + $attrValue = $combination->getAttributeAvId(); + + if (in_array($attrValue, $this->attributeAvList)) { + $discount += $this->getCartItemDiscount($cartItem); + + break; + } + } + } + } + + return $discount; + } + + /** + * Renders the template which implements coupon specific user-input, + * using the provided template file, and a list of specific input fields. + * + * @param string $templateName the path to the template + * @param array $otherFields the list of additional fields fields + * + * @return string the rendered template. + */ + public function drawBaseBackOfficeInputs($templateName, $otherFields) + { + return $this->facade->getParser()->render($templateName, array_merge($otherFields, [ + + // The attributes list field + 'attribute_field_name' => $this->makeCouponFieldName(self::ATTRIBUTE), + 'attribute_value' => $this->attribute, + + // The attributes list field + 'attribute_av_field_name' => $this->makeCouponFieldName(self::ATTRIBUTES_AV_LIST), + 'attribute_av_values' => $this->attributeAvList + ])); + } + + /** + * @inheritdoc + */ + public function getBaseFieldList($otherFields) + { + return array_merge($otherFields, [self::ATTRIBUTE, self::ATTRIBUTES_AV_LIST]); + } + + /** + * @inheritdoc + */ + public function checkBaseCouponFieldValue($fieldName, $fieldValue) + { + if ($fieldName === self::ATTRIBUTE) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select an attribute' + ) + ); + } + } elseif ($fieldName === self::ATTRIBUTES_AV_LIST) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select at least one attribute value' + ) + ); + } + } + + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/AbstractRemoveOnCategories.php b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnCategories.php new file mode 100644 index 000000000..355cf596a --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnCategories.php @@ -0,0 +1,152 @@ + + */ +abstract class AbstractRemoveOnCategories extends CouponAbstract implements AmountAndPercentageCouponInterface +{ + const CATEGORIES_LIST = 'categories'; + + protected $category_list = array(); + + /** + * Set the value of specific coupon fields. + * + * @param Array $effects the Coupon effects params + */ + abstract public function setFieldsValue($effects); + + /** + * Get the discount for a specific cart item. + * + * @param CartItem $cartItem the cart item + * @return float the discount value + */ + abstract public function getCartItemDiscount($cartItem); + + /** + * @inheritdoc + */ + public function set( + FacadeInterface $facade, + $code, + $title, + $shortDescription, + $description, + array $effects, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ) + { + parent::set( + $facade, $code, $title, $shortDescription, $description, $effects, + $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ); + + $this->category_list = isset($effects[self::CATEGORIES_LIST]) ? $effects[self::CATEGORIES_LIST] : array(); + + if (! is_array($this->category_list)) $this->category_list = array($this->category_list); + + $this->setFieldsValue($effects); + + return $this; + } + /** + * @inheritdoc + */ + public function exec() + { + // This coupon subtracts the specified amount from the order total + // for each product of the selected categories. + $discount = 0; + + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) { + $categories = $cartItem->getProduct()->getCategories(); + + /** @var Category $category */ + foreach ($categories as $category) { + + if (in_array($category->getId(), $this->category_list)) { + $discount += $this->getCartItemDiscount($cartItem); + + break; + } + } + } + } + + return $discount; + } + + /** + * @inheritdoc + */ + public function drawBaseBackOfficeInputs($templateName, $otherFields) + { + return $this->facade->getParser()->render($templateName, array_merge($otherFields, [ + + // The categories list field + 'categories_field_name' => $this->makeCouponFieldName(self::CATEGORIES_LIST), + 'categories_values' => $this->category_list + ])); + } + + /** + * @inheritdoc + */ + public function getBaseFieldList($otherFields) + { + return array_merge($otherFields, [self::CATEGORIES_LIST]); + } + + /** + * @inheritdoc + */ + public function checkBaseCouponFieldValue($fieldName, $fieldValue) + { + if ($fieldName === self::CATEGORIES_LIST) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select at least one category' + ) + ); + } + } + + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/AbstractRemoveOnProducts.php b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnProducts.php new file mode 100644 index 000000000..aa407041a --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AbstractRemoveOnProducts.php @@ -0,0 +1,162 @@ + + */ +abstract class AbstractRemoveOnProducts extends CouponAbstract implements AmountAndPercentageCouponInterface +{ + const CATEGORY_ID = 'category_id'; + const PRODUCTS_LIST = 'products'; + + public $category_id = 0; + public $product_list = array(); + + /** + * Set the value of specific coupon fields. + * + * @param Array $effects the Coupon effects params + */ + abstract public function setFieldsValue($effects); + + /** + * Get the discount for a specific cart item. + * + * @param CartItem $cartItem the cart item + * @return float the discount value + */ + abstract public function getCartItemDiscount($cartItem); + + /** + * @inheritdoc + */ + public function set( + FacadeInterface $facade, + $code, + $title, + $shortDescription, + $description, + array $effects, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ) + { + parent::set( + $facade, $code, $title, $shortDescription, $description, $effects, + $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate, + $freeShippingForCountries, + $freeShippingForModules, + $perCustomerUsageCount + ); + + $this->product_list = isset($effects[self::PRODUCTS_LIST]) ? $effects[self::PRODUCTS_LIST] : array(); + + if (! is_array($this->product_list)) $this->product_list = array($this->product_list); + + $this->category_id = isset($effects[self::CATEGORY_ID]) ? $effects[self::CATEGORY_ID] : 0; + + $this->setFieldsValue($effects); + + return $this; + } + + /** + * @inheritdoc + */ + public function exec() + { + // This coupon subtracts the specified amount from the order total + // for each product of the selected products. + $discount = 0; + + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + if (in_array($cartItem->getProduct()->getId(), $this->product_list)) { + if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) { + $discount += $this->getCartItemDiscount($cartItem); + } + } + } + + return $discount; + } + + /** + * @inheritdoc + */ + public function drawBaseBackOfficeInputs($templateName, $otherFields) + { + return $this->facade->getParser()->render($templateName, array_merge($otherFields, [ + + // The category ID field + 'category_id_field_name' => $this->makeCouponFieldName(self::CATEGORY_ID), + 'category_id_value' => $this->category_id, + + // The products list field + 'products_field_name' => $this->makeCouponFieldName(self::PRODUCTS_LIST), + 'products_values' => $this->product_list, + 'products_values_csv' => implode(', ', $this->product_list) + ])); + } + + /** + * @inheritdoc + */ + public function getBaseFieldList($otherFields) + { + return array_merge($otherFields, [self::CATEGORY_ID, self::PRODUCTS_LIST]); + } + + /** + * @inheritdoc + */ + public function checkBaseCouponFieldValue($fieldName, $fieldValue) + { + if ($fieldName === self::CATEGORY_ID) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select a category' + ) + ); + } + } elseif ($fieldName === self::PRODUCTS_LIST) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select at least one product' + ) + ); + } + } + + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/AmountAndPercentageCouponInterface.php b/core/lib/Thelia/Coupon/Type/AmountAndPercentageCouponInterface.php new file mode 100644 index 000000000..8fa76e5bb --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AmountAndPercentageCouponInterface.php @@ -0,0 +1,59 @@ + + * + */ +interface AmountAndPercentageCouponInterface +{ + + /** + * Set the value of specific coupon fields. + * @param Array $effects the Coupon effects params + */ + public function setFieldsValue($effects); + + /** + * Get the discount for a specific cart item. + * + * @param CartItem $cartItem the cart item + * @return float the discount value + */ + public function getCartItemDiscount($cartItem); + + /** + * Renders the template which implements coupon specific user-input, + * using the provided template file, and a list of specific input fields. + * + * @param string $templateName the path to the template + * @param array $otherFields the list of additional fields fields + * + * @return string the rendered template. + */ + public function drawBaseBackOfficeInputs($templateName, $otherFields); + + /** + * @inheritdoc + */ + public function getBaseFieldList($otherFields); + + /** + * + */ + public function checkBaseCouponFieldValue($fieldName, $fieldValue); +} diff --git a/core/lib/Thelia/Coupon/Type/AmountCouponTrait.php b/core/lib/Thelia/Coupon/Type/AmountCouponTrait.php new file mode 100644 index 000000000..86c3f65b1 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/AmountCouponTrait.php @@ -0,0 +1,93 @@ + + * @package Thelia\Coupon\Type + */ +Trait AmountCouponTrait { + + // The amount is already defined in CouponAbstract, and should not be redefined here. + // protected $amount = 0; + + /** + * Should return the amount field name, defined in the parent class. + * + * @return string the percentage field name + */ + abstract protected function getAmountFieldName(); + + /** + * @inheritdoc + */ + protected function setFieldsValue($effects) + { + $this->amount = $effects[$this->getAmountFieldName()]; + } + + /** + * @inheritdoc + */ + public function getCartItemDiscount($cartItem) + { + return $cartItem->getQuantity() * $this->amount; + } + + /** + * @inheritdoc + */ + public function callDrawBackOfficeInputs($templateName) + { + return $this->drawBaseBackOfficeInputs($templateName, [ + 'amount_field_name' => $this->makeCouponFieldName($this->getAmountFieldName()), + 'amount_value' => $this->amount + ]); + } + + /** + * @inheritdoc + */ + protected function getFieldList() + { + return $this->getBaseFieldList([$this->getAmountFieldName()]); + } + + /** + * @inheritdoc + */ + protected function checkCouponFieldValue($fieldName, $fieldValue) + { + $this->checkBaseCouponFieldValue($fieldName, $fieldValue); + + if ($fieldName === $this->getAmountFieldName()) { + + if (floatval($fieldValue) < 0) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Value %val for Discount Amount is invalid. Please enter a positive value.', + [ '%val' => $fieldValue] + ) + ); + } + } + + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/CouponAbstract.php b/core/lib/Thelia/Coupon/Type/CouponAbstract.php index 424de8323..9766b7fbe 100644 --- a/core/lib/Thelia/Coupon/Type/CouponAbstract.php +++ b/core/lib/Thelia/Coupon/Type/CouponAbstract.php @@ -17,6 +17,7 @@ use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionOrganizerInterface; use Thelia\Core\Translation\Translator; use Thelia\Coupon\FacadeInterface; +use Thelia\Form\CouponCreationForm; use Thelia\Model\CouponCountry; use Thelia\Model\CouponModule; @@ -29,12 +30,21 @@ use Thelia\Model\CouponModule; */ abstract class CouponAbstract implements CouponInterface { - const INPUT_EXTENDED__NAME = 'thelia_coupon_creation_extended'; + /** + * The dataset name for all coupon specific input fields, that do not appear in the CouPonCreationForm form. + * + * In the input form, these fields have to be created like: + * + * thelia_coupon_specific[my_field, thelia_coupon_creation_extended[my_other_field] + * + * use the makeCouponField() method to do that safely. + */ + const COUPON_DATASET_NAME = 'coupon_specific'; - const INPUT_AMOUNT_NAME = 'amount'; - - /** @var array Extended Inputs to manage */ - protected $extendedInputs = array(); + /** + * A standard 'amount' filed name, thant can be used in coupons which extends this class + */ + const AMOUNT_FIELD_NAME = 'amount'; /** @var FacadeInterface Provide necessary value from Thelia */ protected $facade = null; @@ -161,7 +171,8 @@ abstract class CouponAbstract implements CouponInterface $this->facade = $facade; $this->effects = $effects; - $this->amount = $effects[self::INPUT_AMOUNT_NAME]; + // Amount is now optional. + $this->amount = isset($effects[self::AMOUNT_FIELD_NAME]) ? $effects[self::AMOUNT_FIELD_NAME] : 0; $this->freeShippingForCountries = $freeShippingForCountries; $this->freeShippingForModules = $freeShippingForModules; @@ -267,10 +278,7 @@ abstract class CouponAbstract implements CouponInterface } /** - * Return effects generated by the coupon - * A negative value - * - * @return float Amount removed from the Total Checkout + * @inheritdoc */ public function exec() { @@ -383,6 +391,19 @@ abstract class CouponAbstract implements CouponInterface return $this->conditionEvaluator->isMatching($this->conditions); } + /** + * This is the field label than will be displayed in the form. + * This method should be overridden to be useful. + * + * For backward compatibility only. + * + * @return string + */ + public function getInputName() + { + return "Please override getInputName() method"; + } + /** * Draw the input displayed in the BackOffice * allowing Admin to set its Coupon effect @@ -394,19 +415,96 @@ abstract class CouponAbstract implements CouponInterface { return $this->facade->getParser()->render('coupon/type-fragments/remove-x.html', [ 'label' => $this->getInputName(), - 'fieldName' => self::INPUT_AMOUNT_NAME, + 'fieldId' => self::AMOUNT_FIELD_NAME, + 'fieldName' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME), 'value' => $this->amount ]); } /** - * Get all extended inputs name to manage + * This methods checks a field value. If the field has a correct value, this value is returned + * Otherwise, an InvalidArgumentException describing the problem should be thrown. * + * This method should be ovveriden to be useful. + * + * @param $fieldName + * @param $fieldValue * @return mixed + * @throws \InvalidArgumentException if the field valiue is not valid. */ - public function getExtendedInputs() + protected function checkCouponFieldValue($fieldName, $fieldValue) { - return $this->extendedInputs; + return $fieldValue; } + /** + * A helper to get the value of a standard field name + * + * @param string $fieldName the field name + * @param array $data the input form data (e.g. $form->getData()) + * @param mixed $defaultValue the default value if the field is not found. + * + * @return mixed the input value, or the default one + * + * @throws \InvalidArgumentException if the field is not found, and no default value has been defined. + */ + protected function getCouponFieldValue($fieldName, $data, $defaultValue = null) + { + if (isset($data[self::COUPON_DATASET_NAME][$fieldName])) { + return $this->checkCouponFieldValue( + $fieldName, + $data[self::COUPON_DATASET_NAME][$fieldName] + ); + } elseif (null !== $defaultValue) { + return $defaultValue; + } else { + throw new \InvalidArgumentException(sprintf("The coupon field name %s was not found in the coupon form", $fieldName)); + } + } + + /** + * A helper to create an standard field name that will be used in the coupon form + * + * @param string $fieldName the field name + * @return string the complete name, ready to be used in a form. + */ + protected function makeCouponFieldName($fieldName) + { + return sprintf("%s[%s][%s]", CouponCreationForm::COUPON_CREATION_FORM_NAME, self::COUPON_DATASET_NAME, $fieldName); + } + + /** + * Return a list of the fields name for this coupon. + * + * @return array + */ + protected function getFieldList() + { + return [self::AMOUNT_FIELD_NAME]; + } + + /** + * Create the effect array from the list of fields + * + * @param array $data the input form data (e.g. $form->getData()) + * @return array a filedName => fieldValue array + */ + public function getEffects($data) + { + $effects = []; + + foreach ($this->getFieldList() as $fieldName) { + $effects[$fieldName] = $this->getCouponFieldValue($fieldName, $data); + } + + return $effects; + } + + /** + * @inheritdoc + */ + public function clear() + { + // Does nothing. Override this function as needed. + } } diff --git a/core/lib/Thelia/Coupon/Type/CouponInterface.php b/core/lib/Thelia/Coupon/Type/CouponInterface.php index 69eca002a..d8190f3d7 100644 --- a/core/lib/Thelia/Coupon/Type/CouponInterface.php +++ b/core/lib/Thelia/Coupon/Type/CouponInterface.php @@ -220,13 +220,6 @@ interface CouponInterface */ public function drawBackOfficeInputs(); - /** - * Get all extended inputs name to manage - * - * @return mixed - */ - public function getExtendedInputs(); - /** * @return ObjectCollection list of country IDs for which shipping is free. All if empty */ @@ -236,4 +229,19 @@ interface CouponInterface * @return ObjectCollection list of module IDs for which shipping is free. All if empty */ public function getFreeShippingForModules(); + + /** + * Create the effect array from the list of fields + * + * @param array $data the input form data (e.g. $form->getData()) + * + * @return array a filedName => fieldValue array + */ + public function getEffects($data); + + /** + * Clear all the data the coupon may have stored, called after an order is completed. + */ + public function clear(); + } diff --git a/core/lib/Thelia/Coupon/Type/FreeProduct.php b/core/lib/Thelia/Coupon/Type/FreeProduct.php new file mode 100644 index 000000000..3032813a8 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/FreeProduct.php @@ -0,0 +1,338 @@ + + */ +class FreeProduct extends AbstractRemoveOnProducts +{ + const OFFERED_PRODUCT_ID = 'offered_product_id'; + const OFFERED_CATEGORY_ID = 'offered_category_id'; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.free_product'; + + protected $offeredProductId; + protected $offeredCategoryId; + + /** + * This constant is user to mark a free product as in the process of being added to the cart, + * but the CartItem ID is not yet been defined. + */ + const ADD_TO_CART_IN_PROCESS = -1; + + /** + * @inheritdoc + */ + public function setFieldsValue($effects) + { + $this->offeredProductId = $effects[self::OFFERED_PRODUCT_ID]; + $this->offeredCategoryId = $effects[self::OFFERED_CATEGORY_ID]; + } + + /** + * @inheritdoc + */ + public function getCartItemDiscount($cartItem) + { + // This method is not used, we use our own implementation of exec(); + return 0; + } + + /** + * @return string The session variable where the cart item IDs for the free products are stored + */ + protected function getSessionVarName() + { + return "coupon.free_product.cart_items." . $this->getCode(); + } + /** + * Return the cart item id which contains the free product related to a given product + * + * @param Product $product the product in the cart which triggered the discount + * + * @return bool|int|CartItem the cart item which contains the free product, or false if the product is no longer in the cart, or ADD_TO_CART_IN_PROCESS if the adding process is not finished + */ + protected function getRelatedCartItem($product) + { + $cartItemIdList = $this->facade->getRequest()->getSession()->get( + $this->getSessionVarName(), + array() + ); + + if (isset($cartItemIdList[$product->getId()])) { + + $cartItemId = $cartItemIdList[$product->getId()]; + + if ($cartItemId == self::ADD_TO_CART_IN_PROCESS) { + return self::ADD_TO_CART_IN_PROCESS; + } elseif (null !== $cartItem = CartItemQuery::create()->findPk($cartItemId)) { + return $cartItem; + } + } else { + // Maybe the product we're offering is already in the cart ? Search it. + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + if ($cartItem->getProduct()->getId() == $this->offeredProductId) { + + // We found the product. Store its cart item as the free product container. + $this->setRelatedCartItem($product, $cartItem->getId()); + + return $cartItem; + } + } + + } + + return false; + } + + /** + * Set the cart item id which contains the free product related to a given product + * + * @param Product $product the product in the cart which triggered the discount + * @param bool|int $cartItemId the cart item ID which contains the free product, or just true if the free product is not yet added. + */ + protected function setRelatedCartItem($product, $cartItemId) + { + $cartItemIdList = $this->facade->getRequest()->getSession()->get( + $this->getSessionVarName(), + array() + ); + + if (! is_array($cartItemIdList)) $cartItemIdList = array(); + + $cartItemIdList[$product->getId()] = $cartItemId; + + $this->facade->getRequest()->getSession()->set( + $this->getSessionVarName(), + $cartItemIdList + ); + } + + /** + * Get the product id / cart item id list. + * + * @return array an array where the free product ID is the key, and the related cart item id the value. + */ + protected function getFreeProductsCartItemIds() + { + return $this->facade->getRequest()->getSession()->get( + $this->getSessionVarName(), + array() + ); + } + + /** + * Clear the session variable. + */ + protected function clearFreeProductsCartItemIds() + { + return $this->facade->getRequest()->getSession()->remove($this->getSessionVarName()); + } + + /** + * We overload this method here to remove the free products when the + * coupons conditions are no longer met. + * + * @inheritdoc + */ + public function isMatching() + { + $match = parent::isMatching(); + + if (! $match) { + // Cancel coupon effect (but no not remove the product) + $this->clearFreeProductsCartItemIds(); + } + + return $match; + } + + /** + * @inheritdoc + */ + public function exec() + { + $discount = 0; + + $cartItems = $this->facade->getCart()->getCartItems(); + + /** @var Product $eligibleProduct */ + $eligibleProduct = null; + + /** @var CartItem $cartItem */ + foreach ($cartItems as $cartItem) { + if (in_array($cartItem->getProduct()->getId(), $this->product_list)) { + if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) { + $eligibleProduct = $cartItem; + break; + } + } + } + + if ($eligibleProduct !== null) { + + // Get the cart item for the eligible product + $freeProductCartItem = $this->getRelatedCartItem($eligibleProduct); + + // We add the free product it only if it not yet in the cart. + if ($freeProductCartItem === false) { + + if (null !== $freeProduct = ProductQuery::create()->findPk($this->offeredProductId)) { + + // Store in the session that the free product is added to the cart, + // so that we don't enter the following infinite loop : + // + // 1) exec() adds a product by firing a CART_ADDITEM event, + // 2) the event is processed by Action\Coupon::updateOrderDiscount(), + // 3) Action\Coupon::updateOrderDiscount() calls CouponManager::getDiscount() + // 4) CouponManager::getDiscount() calls exec() -> Infinite loop !! + + // Store a marker first, we do not have the cart item id yet. + $this->setRelatedCartItem($eligibleProduct, self::ADD_TO_CART_IN_PROCESS); + + $cartEvent = new CartEvent($this->facade->getCart()); + + $cartEvent->setNewness(true); + $cartEvent->setAppend(false); + $cartEvent->setQuantity(1); + $cartEvent->setProductSaleElementsId($freeProduct->getDefaultSaleElements()->getId()); + $cartEvent->setProduct($this->offeredProductId); + + $this->facade->getDispatcher()->dispatch(TheliaEvents::CART_ADDITEM, $cartEvent); + + // Store the final cart item ID. + $this->setRelatedCartItem($eligibleProduct, $cartEvent->getCartItem()->getId()); + + $freeProductCartItem = $cartEvent->getCartItem(); + } + } + + if ($freeProductCartItem instanceof CartItem) { + // The discount is the product price. + $discount = $freeProductCartItem->getPromo() ? + $freeProductCartItem->getPromoPrice() : $freeProductCartItem->getPrice(); + } + } + // No eligible product was found ! + else { + // Remove all free products for this coupon, but no not remove the product from the cart. + $this->clearFreeProductsCartItemIds(); + } + + return $discount; + } + + /** + * @inheritdoc + */ + protected function getFieldList() + { + return $this->getBaseFieldList([self::OFFERED_CATEGORY_ID, self::OFFERED_PRODUCT_ID]); + } + + /** + * @inheritdoc + */ + protected function checkCouponFieldValue($fieldName, $fieldValue) + { + $this->checkBaseCouponFieldValue($fieldName, $fieldValue); + + if ($fieldName === self::OFFERED_PRODUCT_ID) { + + if (floatval($fieldValue) < 0) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select the offered product' + ) + ); + } + } elseif ($fieldName === self::OFFERED_CATEGORY_ID) { + if (empty($fieldValue)) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Please select the category of the offred product' + ) + ); + } + } + + return $fieldValue; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Free product when buying one or more selected products', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon adds a free product to the cart if one of the selected products is in the cart.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->drawBaseBackOfficeInputs("coupon/type-fragments/free-product.html", [ + 'offered_category_field_name' => $this->makeCouponFieldName(self::OFFERED_CATEGORY_ID), + 'offered_category_value' => $this->offeredCategoryId, + + 'offered_product_field_name' => $this->makeCouponFieldName(self::OFFERED_PRODUCT_ID), + 'offered_product_value' => $this->offeredProductId + ]); + } + + /** + * @inheritdoc + */ + public function clear() + { + // Clear the session variable when the coupon is cleared. + $this->clearFreeProductsCartItemIds(); + } +} diff --git a/core/lib/Thelia/Coupon/Type/PercentageCouponTrait.php b/core/lib/Thelia/Coupon/Type/PercentageCouponTrait.php new file mode 100644 index 000000000..957114ffb --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/PercentageCouponTrait.php @@ -0,0 +1,93 @@ + + * @package Thelia\Coupon\Type + */ +Trait PercentageCouponTrait { + + public $percentage = 0; + + /** + * Should return the percentage field name, defined in the parent class. + * + * @return string the percentage field name + */ + abstract protected function getPercentageFieldName(); + + /** + * @inheritdoc + */ + protected function setFieldsValue($effects) + { + $this->percentage = $effects[$this->getPercentageFieldName()]; + } + + /** + * @inheritdoc + */ + public function getCartItemDiscount($cartItem) + { + return $cartItem->getQuantity() * $cartItem->getPrice() * ($this->percentage / 100); + } + + /** + * @inheritdoc + */ + public function callDrawBackOfficeInputs($templateName) + { + return $this->drawBaseBackOfficeInputs($templateName, [ + 'percentage_field_name' => $this->makeCouponFieldName($this->getPercentageFieldName()), + 'percentage_value' => $this->percentage, + ]); + } + + /** + * @inheritdoc + */ + protected function getFieldList() + { + return $this->getBaseFieldList([$this->getPercentageFieldName()]); + } + + /** + * @inheritdoc + */ + protected function checkCouponFieldValue($fieldName, $fieldValue) + { + $this->checkBaseCouponFieldValue($fieldName, $fieldValue); + + if ($fieldName === $this->getPercentageFieldName()) { + + $pcent = floatval($fieldValue); + + if ($pcent <= 0 || $pcent > 100) { + throw new \InvalidArgumentException( + Translator::getInstance()->trans( + 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.', + [ '%val' => $fieldValue] + ) + ); + } + } + + return $fieldValue; + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveAmountOnAttributeValues.php b/core/lib/Thelia/Coupon/Type/RemoveAmountOnAttributeValues.php new file mode 100644 index 000000000..625de5302 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveAmountOnAttributeValues.php @@ -0,0 +1,65 @@ + + */ +class RemoveAmountOnAttributeValues extends AbstractRemoveOnAttributeValues +{ + use AmountCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_amount_on_attribute_av'; + + protected function getAmountFieldName() + { + return self::AMOUNT_FIELD_NAME; + } + /** + * @inheritdoc + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Fixed amount discount for selected attribute values', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-attributes.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php b/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php new file mode 100644 index 000000000..54a0bcc17 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php @@ -0,0 +1,66 @@ + + */ +class RemoveAmountOnCategories extends AbstractRemoveOnCategories +{ + use AmountCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_amount_on_categories'; + + protected function getAmountFieldName() + { + return self::AMOUNT_FIELD_NAME; + } + + /** + * @inheritdoc + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Fixed amount discount for selected categories', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-categories.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveAmountOnProducts.php b/core/lib/Thelia/Coupon/Type/RemoveAmountOnProducts.php new file mode 100644 index 000000000..867f959aa --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveAmountOnProducts.php @@ -0,0 +1,70 @@ + + */ +class RemoveAmountOnProducts extends AbstractRemoveOnProducts +{ + use AmountCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_amount_on_products'; + + protected function getAmountFieldName() + { + return self::AMOUNT_FIELD_NAME; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Fixed amount discount for selected products', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-products.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemovePercentageOnAttributeValues.php b/core/lib/Thelia/Coupon/Type/RemovePercentageOnAttributeValues.php new file mode 100644 index 000000000..6d2dafebf --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemovePercentageOnAttributeValues.php @@ -0,0 +1,71 @@ + + */ +class RemovePercentageOnAttributeValues extends AbstractRemoveOnAttributeValues +{ + const PERCENTAGE = 'percentage'; + + use PercentageCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_percentage_on_attribute_av'; + + /** + * @inheritdoc + */ + protected function getPercentageFieldName() + { + return self::PERCENTAGE; + } + + /** + * @inheritdoc + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Percentage discount for selected attribute values', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-attributes.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemovePercentageOnCategories.php b/core/lib/Thelia/Coupon/Type/RemovePercentageOnCategories.php new file mode 100644 index 000000000..e2db763d4 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemovePercentageOnCategories.php @@ -0,0 +1,68 @@ + + */ +class RemovePercentageOnCategories extends AbstractRemoveOnCategories +{ + const PERCENTAGE = 'percentage'; + + use PercentageCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_percentage_on_categories'; + + /** + * @inheritdoc + */ + protected function getPercentageFieldName() + { + return self::PERCENTAGE; + } + + /** + * @inheritdoc + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Percentage discount for selected categories', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-categories.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemovePercentageOnProducts.php b/core/lib/Thelia/Coupon/Type/RemovePercentageOnProducts.php new file mode 100644 index 000000000..cab227442 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemovePercentageOnProducts.php @@ -0,0 +1,75 @@ + + */ +class RemovePercentageOnProducts extends AbstractRemoveOnProducts +{ + const PERCENTAGE = 'percentage'; + + use PercentageCouponTrait; + + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_percentage_on_products'; + + /** + * @inheritdoc + */ + protected function getPercentageFieldName() + { + return self::PERCENTAGE; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->facade + ->getTranslator() + ->trans('Percentage discount for selected products', array(), 'coupon'); + } + + /** + * @inheritdoc + */ + public function getToolTip() + { + $toolTip = $this->facade + ->getTranslator() + ->trans( + 'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.', + array(), + 'coupon' + ); + + return $toolTip; + } + + /** + * @inheritdoc + */ + public function drawBackOfficeInputs() + { + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-products.html'); + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveXAmount.php b/core/lib/Thelia/Coupon/Type/RemoveXAmount.php index c644706a2..c1ffb0675 100644 --- a/core/lib/Thelia/Coupon/Type/RemoveXAmount.php +++ b/core/lib/Thelia/Coupon/Type/RemoveXAmount.php @@ -16,18 +16,23 @@ namespace Thelia\Coupon\Type; * Allow to remove an amount from the checkout total * * @package Coupon - * @author Guillaume MOREL + * @author Guillaume MOREL , Franck Allimant * */ -class RemoveXAmount extends CouponAbstract +class RemoveXAmount extends AbstractRemove { + use AmountCouponTrait; + /** @var string Service Id */ protected $serviceId = 'thelia.coupon.type.remove_x_amount'; + protected function getAmountFieldName() + { + return self::AMOUNT_FIELD_NAME; + } + /** - * Get I18n name - * - * @return string + * @inheritdoc */ public function getName() { @@ -37,21 +42,7 @@ class RemoveXAmount extends CouponAbstract } /** - * Get I18n amount input name - * - * @return string - */ - public function getInputName() - { - return $this->facade - ->getTranslator() - ->trans('Discount amount', array(), 'coupon'); - } - - /** - * Get I18n tooltip - * - * @return string + * @inheritdoc */ public function getToolTip() { @@ -66,12 +57,19 @@ class RemoveXAmount extends CouponAbstract return $toolTip; } + /** + * @inheritdoc + */ + public function exec() + { + return $this->amount; + } + + /** + * @inheritdoc + */ public function drawBackOfficeInputs() { - return $this->facade->getParser()->render('coupon/type-fragments/remove-x-amount.html', [ - 'label' => $this->getInputName(), - 'fieldName' => self::INPUT_AMOUNT_NAME, - 'value' => $this->amount - ]); + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-amount.html'); } } diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercent.php b/core/lib/Thelia/Coupon/Type/RemoveXPercent.php index e5a98c5fb..623cb7078 100644 --- a/core/lib/Thelia/Coupon/Type/RemoveXPercent.php +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercent.php @@ -12,85 +12,30 @@ namespace Thelia\Coupon\Type; -use Thelia\Coupon\FacadeInterface; - /** * @package Coupon - * @author Guillaume MOREL + * @author Guillaume MOREL , Franck Allimant * */ -class RemoveXPercent extends CouponAbstract +class RemoveXPercent extends AbstractRemove { const INPUT_PERCENTAGE_NAME = 'percentage'; + use PercentageCouponTrait; + /** @var string Service Id */ protected $serviceId = 'thelia.coupon.type.remove_x_percent'; - /** @var float Percentage removed from the Cart */ - protected $percentage = 0; - - /** @var array Extended Inputs to manage */ - protected $extendedInputs = array( - self::INPUT_PERCENTAGE_NAME - ); - /** * @inheritdoc */ - public function set( - FacadeInterface $facade, - $code, - $title, - $shortDescription, - $description, - array $effects, - $isCumulative, - $isRemovingPostage, - $isAvailableOnSpecialOffers, - $isEnabled, - $maxUsage, - \DateTime $expirationDate, - $freeShippingForCountries, - $freeShippingForModules, - $perCustomerUsageCount - ) + protected function getPercentageFieldName() { - parent::set( - $facade, $code, $title, $shortDescription, $description, $effects, - $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate, - $freeShippingForCountries, - $freeShippingForModules, - $perCustomerUsageCount - ); - - $this->percentage = $effects[self::INPUT_PERCENTAGE_NAME]; - - return $this; + return self::INPUT_PERCENTAGE_NAME; } /** - * Return effects generated by the coupon - * A negative value - * - * @throws \Thelia\Exception\MissingFacadeException - * @throws \InvalidArgumentException - * @return float - */ - public function exec() - { - if ($this->percentage >= 100) { - throw new \InvalidArgumentException( - 'Percentage must be inferior to 100' - ); - } - - return round($this->facade->getCartTotalTaxPrice() * $this->percentage/100, 2); - } - - /** - * Get I18n name - * - * @return string + * @inheritdoc */ public function getName() { @@ -100,21 +45,7 @@ class RemoveXPercent extends CouponAbstract } /** - * Get I18n amount input name - * - * @return string - */ - public function getInputName() - { - return $this->facade - ->getTranslator() - ->trans('Percent Discount', array(), 'coupon'); - } - - /** - * Get I18n tooltip - * - * @return string + * @inheritdoc */ public function getToolTip() { @@ -130,19 +61,18 @@ class RemoveXPercent extends CouponAbstract } /** - * Draw the input displayed in the BackOffice - * allowing Admin to set its Coupon effect - * - * @return string HTML string + * @inheritdoc + */ + public function exec() + { + return round($this->facade->getCartTotalTaxPrice($this->isAvailableOnSpecialOffers()) * $this->percentage/100, 2); + } + + /** + * @inheritdoc */ public function drawBackOfficeInputs() { - return $this->facade->getParser()->render('coupon/type-fragments/remove-x-percent.html', [ - 'label' => $this->getInputName(), - 'typeKey' => self::INPUT_AMOUNT_NAME, - 'fieldId' => self::INPUT_PERCENTAGE_NAME, - 'fieldName' => self::INPUT_EXTENDED__NAME, - 'value' => $this->percentage - ]); + return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-percent.html'); } } diff --git a/core/lib/Thelia/Form/CouponCreationForm.php b/core/lib/Thelia/Form/CouponCreationForm.php index 688e8a6ba..acb16ce70 100644 --- a/core/lib/Thelia/Form/CouponCreationForm.php +++ b/core/lib/Thelia/Form/CouponCreationForm.php @@ -33,6 +33,8 @@ use Thelia\Module\BaseModule; */ class CouponCreationForm extends BaseForm { + const COUPON_CREATION_FORM_NAME = 'thelia_coupon_creation'; + /** * Build Coupon form * @@ -110,14 +112,6 @@ class CouponCreationForm extends BaseForm ) ) ) - ->add( - 'amount', - 'money', - array( - 'constraints' => array( - new NotBlank() - )) - ) ->add( 'isEnabled', 'text', @@ -198,7 +192,12 @@ class CouponCreationForm extends BaseForm new NotBlank() ) ) - ); + ) + ->add('coupon_specific', 'collection', array( + 'allow_add' => true, + 'allow_delete' => true, + )) + ; } /** @@ -226,6 +225,6 @@ class CouponCreationForm extends BaseForm */ public function getName() { - return 'thelia_coupon_creation'; + return self::COUPON_CREATION_FORM_NAME; } } diff --git a/core/lib/Thelia/Form/OrderDelivery.php b/core/lib/Thelia/Form/OrderDelivery.php index 74ad75f33..47d8bdfa8 100644 --- a/core/lib/Thelia/Form/OrderDelivery.php +++ b/core/lib/Thelia/Form/OrderDelivery.php @@ -66,19 +66,15 @@ class OrderDelivery extends BaseForm public function verifyDeliveryModule($value, ExecutionContextInterface $context) { $module = ModuleQuery::create() - ->filterByType(BaseModule::DELIVERY_MODULE_TYPE) - ->filterByActivate(1) - ->filterById($value) + ->filterActivatedByTypeAndId(BaseModule::DELIVERY_MODULE_TYPE, $value) ->findOne(); if (null === $module) { $context->addViolation(Translator::getInstance()->trans("Delivery module ID not found")); - } else { - if (! $module->isDeliveryModule()) { - $context->addViolation( - sprintf(Translator::getInstance()->trans("delivery module %s is not a Thelia\Module\DeliveryModuleInterface"), $module->getCode()) - ); - } + } elseif (! $module->isDeliveryModule()) { + $context->addViolation( + sprintf(Translator::getInstance()->trans("delivery module %s is not a Thelia\Module\DeliveryModuleInterface"), $module->getCode()) + ); } } diff --git a/core/lib/Thelia/Form/OrderPayment.php b/core/lib/Thelia/Form/OrderPayment.php index 9353eee37..6d1182a4a 100644 --- a/core/lib/Thelia/Form/OrderPayment.php +++ b/core/lib/Thelia/Form/OrderPayment.php @@ -66,16 +66,12 @@ class OrderPayment extends BaseForm public function verifyPaymentModule($value, ExecutionContextInterface $context) { $module = ModuleQuery::create() - ->filterByType(BaseModule::PAYMENT_MODULE_TYPE) - ->filterByActivate(1) - ->filterById($value) + ->filterActivatedByTypeAndId(BaseModule::PAYMENT_MODULE_TYPE, $value) ->findOne(); if (null === $module) { $context->addViolation("Payment module ID not found"); - } - - if (! $module->isPayementModule()) { + } elseif (! $module->isPayementModule()) { $context->addViolation( sprintf(Translator::getInstance()->trans("payment module %s is not a Thelia\Module\PaymentModuleInterface"), $module->getCode()) ); diff --git a/core/lib/Thelia/Install/CheckPermission.php b/core/lib/Thelia/Install/CheckPermission.php index 9cc1261f2..13c18f8dd 100644 --- a/core/lib/Thelia/Install/CheckPermission.php +++ b/core/lib/Thelia/Install/CheckPermission.php @@ -12,8 +12,6 @@ namespace Thelia\Install; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; use Symfony\Component\Translation\TranslatorInterface; use Thelia\Core\Translation\Translator; @@ -175,14 +173,6 @@ class CheckPermission extends BaseInstall */ protected function makeDirectoryWritable($directory) { - chmod($directory, 0777); - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($directory) - ); - foreach ($iterator as $item) { - chmod($item, 0777); - } - return (is_writable(THELIA_ROOT . $directory) === true); } diff --git a/core/lib/Thelia/Install/Database.php b/core/lib/Thelia/Install/Database.php index 9f45e9253..8b20995ff 100644 --- a/core/lib/Thelia/Install/Database.php +++ b/core/lib/Thelia/Install/Database.php @@ -65,7 +65,7 @@ class Database public function insertSql($dbName = null, array $extraSqlFiles = null) { if ($dbName) { - $this->connection->query(sprintf("use %s", $dbName)); + $this->connection->query(sprintf("use `%s`", $dbName)); } $sql = array(); @@ -146,7 +146,7 @@ class Database { $this->execute( sprintf( - "CREATE DATABASE IF NOT EXISTS %s CHARACTER SET utf8", + "CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET utf8", $dbName ) ); diff --git a/core/lib/Thelia/Install/Update.php b/core/lib/Thelia/Install/Update.php index 4deb768d2..306a1906b 100644 --- a/core/lib/Thelia/Install/Update.php +++ b/core/lib/Thelia/Install/Update.php @@ -33,6 +33,7 @@ class Update '4' => '2.0.0-RC1', '5' => '2.0.0', '6' => '2.0.1', + '7' => '2.0.2', ); protected function isLatestVersion($version) @@ -48,7 +49,6 @@ class Update $logger = Tlog::getInstance(); $logger->setLevel(Tlog::DEBUG); - $success = true; $updatedVersions = array(); $currentVersion = ConfigQuery::read('thelia_version'); diff --git a/core/lib/Thelia/Model/Admin.php b/core/lib/Thelia/Model/Admin.php index bba191cd1..fb6e05fcc 100644 --- a/core/lib/Thelia/Model/Admin.php +++ b/core/lib/Thelia/Model/Admin.php @@ -111,6 +111,7 @@ class Admin extends BaseAdmin implements UserInterface public function eraseCredentials() { parent::setPassword(null); + $this->resetModified(); } /** diff --git a/core/lib/Thelia/Model/Base/Order.php b/core/lib/Thelia/Model/Base/Order.php index 596829b3e..dae3d317b 100644 --- a/core/lib/Thelia/Model/Base/Order.php +++ b/core/lib/Thelia/Model/Base/Order.php @@ -35,7 +35,10 @@ use Thelia\Model\OrderProductQuery as ChildOrderProductQuery; use Thelia\Model\OrderQuery as ChildOrderQuery; use Thelia\Model\OrderStatus as ChildOrderStatus; use Thelia\Model\OrderStatusQuery as ChildOrderStatusQuery; +use Thelia\Model\OrderVersion as ChildOrderVersion; +use Thelia\Model\OrderVersionQuery as ChildOrderVersionQuery; use Thelia\Model\Map\OrderTableMap; +use Thelia\Model\Map\OrderVersionTableMap; abstract class Order implements ActiveRecordInterface { @@ -185,6 +188,25 @@ abstract class Order implements ActiveRecordInterface */ protected $updated_at; + /** + * The value for the version field. + * Note: this column has a database default value of: 0 + * @var int + */ + protected $version; + + /** + * The value for the version_created_at field. + * @var string + */ + protected $version_created_at; + + /** + * The value for the version_created_by field. + * @var string + */ + protected $version_created_by; + /** * @var Currency */ @@ -237,6 +259,12 @@ abstract class Order implements ActiveRecordInterface protected $collOrderCoupons; protected $collOrderCouponsPartial; + /** + * @var ObjectCollection|ChildOrderVersion[] Collection to store aggregation of ChildOrderVersion objects. + */ + protected $collOrderVersions; + protected $collOrderVersionsPartial; + /** * Flag to prevent endless save loop, if this object is referenced * by another object which falls in this transaction. @@ -245,6 +273,14 @@ abstract class Order implements ActiveRecordInterface */ protected $alreadyInSave = false; + // versionable behavior + + + /** + * @var bool + */ + protected $enforceVersion = false; + /** * An array of objects scheduled for deletion. * @var ObjectCollection @@ -257,11 +293,30 @@ abstract class Order implements ActiveRecordInterface */ protected $orderCouponsScheduledForDeletion = null; + /** + * An array of objects scheduled for deletion. + * @var ObjectCollection + */ + protected $orderVersionsScheduledForDeletion = null; + + /** + * Applies default values to this object. + * This method should be called from the object's constructor (or + * equivalent initialization method). + * @see __construct() + */ + public function applyDefaultValues() + { + $this->version = 0; + } + /** * Initializes internal state of Thelia\Model\Base\Order object. + * @see applyDefaults() */ public function __construct() { + $this->applyDefaultValues(); } /** @@ -751,6 +806,48 @@ abstract class Order implements ActiveRecordInterface } } + /** + * Get the [version] column value. + * + * @return int + */ + public function getVersion() + { + + return $this->version; + } + + /** + * Get the [optionally formatted] temporal [version_created_at] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw \DateTime object will be returned. + * + * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 + * + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getVersionCreatedAt($format = NULL) + { + if ($format === null) { + return $this->version_created_at; + } else { + return $this->version_created_at instanceof \DateTime ? $this->version_created_at->format($format) : null; + } + } + + /** + * Get the [version_created_by] column value. + * + * @return string + */ + public function getVersionCreatedBy() + { + + return $this->version_created_by; + } + /** * Set the value of [id] column. * @@ -1182,6 +1279,69 @@ abstract class Order implements ActiveRecordInterface return $this; } // setUpdatedAt() + /** + * Set the value of [version] column. + * + * @param int $v new value + * @return \Thelia\Model\Order The current object (for fluent API support) + */ + public function setVersion($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->version !== $v) { + $this->version = $v; + $this->modifiedColumns[OrderTableMap::VERSION] = true; + } + + + return $this; + } // setVersion() + + /** + * Sets the value of [version_created_at] column to a normalized version of the date/time value specified. + * + * @param mixed $v string, integer (timestamp), or \DateTime value. + * Empty strings are treated as NULL. + * @return \Thelia\Model\Order The current object (for fluent API support) + */ + public function setVersionCreatedAt($v) + { + $dt = PropelDateTime::newInstance($v, null, '\DateTime'); + if ($this->version_created_at !== null || $dt !== null) { + if ($dt !== $this->version_created_at) { + $this->version_created_at = $dt; + $this->modifiedColumns[OrderTableMap::VERSION_CREATED_AT] = true; + } + } // if either are not null + + + return $this; + } // setVersionCreatedAt() + + /** + * Set the value of [version_created_by] column. + * + * @param string $v new value + * @return \Thelia\Model\Order The current object (for fluent API support) + */ + public function setVersionCreatedBy($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->version_created_by !== $v) { + $this->version_created_by = $v; + $this->modifiedColumns[OrderTableMap::VERSION_CREATED_BY] = true; + } + + + return $this; + } // setVersionCreatedBy() + /** * Indicates whether the columns in this object are only set to default values. * @@ -1192,6 +1352,10 @@ abstract class Order implements ActiveRecordInterface */ public function hasOnlyDefaultValues() { + if ($this->version !== 0) { + return false; + } + // otherwise, everything was equal, so return TRUE return true; } // hasOnlyDefaultValues() @@ -1284,6 +1448,18 @@ abstract class Order implements ActiveRecordInterface $col = null; } $this->updated_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 19 + $startcol : OrderTableMap::translateFieldName('Version', TableMap::TYPE_PHPNAME, $indexType)]; + $this->version = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 20 + $startcol : OrderTableMap::translateFieldName('VersionCreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + if ($col === '0000-00-00 00:00:00') { + $col = null; + } + $this->version_created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 21 + $startcol : OrderTableMap::translateFieldName('VersionCreatedBy', TableMap::TYPE_PHPNAME, $indexType)]; + $this->version_created_by = (null !== $col) ? (string) $col : null; $this->resetModified(); $this->setNew(false); @@ -1292,7 +1468,7 @@ abstract class Order implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 19; // 19 = OrderTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 22; // 22 = OrderTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\Order object", 0, $e); @@ -1389,6 +1565,8 @@ abstract class Order implements ActiveRecordInterface $this->collOrderCoupons = null; + $this->collOrderVersions = null; + } // if (deep) } @@ -1457,6 +1635,14 @@ abstract class Order implements ActiveRecordInterface $isInsert = $this->isNew(); try { $ret = $this->preSave($con); + // versionable behavior + if ($this->isVersioningNecessary()) { + $this->setVersion($this->isNew() ? 1 : $this->getLastVersionNumber($con) + 1); + if (!$this->isColumnModified(OrderTableMap::VERSION_CREATED_AT)) { + $this->setVersionCreatedAt(time()); + } + $createVersion = true; // for postSave hook + } if ($isInsert) { $ret = $ret && $this->preInsert($con); // timestampable behavior @@ -1481,6 +1667,10 @@ abstract class Order implements ActiveRecordInterface $this->postUpdate($con); } $this->postSave($con); + // versionable behavior + if (isset($createVersion)) { + $this->addVersion($con); + } OrderTableMap::addInstanceToPool($this); } else { $affectedRows = 0; @@ -1617,6 +1807,23 @@ abstract class Order implements ActiveRecordInterface } } + if ($this->orderVersionsScheduledForDeletion !== null) { + if (!$this->orderVersionsScheduledForDeletion->isEmpty()) { + \Thelia\Model\OrderVersionQuery::create() + ->filterByPrimaryKeys($this->orderVersionsScheduledForDeletion->getPrimaryKeys(false)) + ->delete($con); + $this->orderVersionsScheduledForDeletion = null; + } + } + + if ($this->collOrderVersions !== null) { + foreach ($this->collOrderVersions as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + $this->alreadyInSave = false; } @@ -1700,6 +1907,15 @@ abstract class Order implements ActiveRecordInterface if ($this->isColumnModified(OrderTableMap::UPDATED_AT)) { $modifiedColumns[':p' . $index++] = '`UPDATED_AT`'; } + if ($this->isColumnModified(OrderTableMap::VERSION)) { + $modifiedColumns[':p' . $index++] = '`VERSION`'; + } + if ($this->isColumnModified(OrderTableMap::VERSION_CREATED_AT)) { + $modifiedColumns[':p' . $index++] = '`VERSION_CREATED_AT`'; + } + if ($this->isColumnModified(OrderTableMap::VERSION_CREATED_BY)) { + $modifiedColumns[':p' . $index++] = '`VERSION_CREATED_BY`'; + } $sql = sprintf( 'INSERT INTO `order` (%s) VALUES (%s)', @@ -1768,6 +1984,15 @@ abstract class Order implements ActiveRecordInterface case '`UPDATED_AT`': $stmt->bindValue($identifier, $this->updated_at ? $this->updated_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); break; + case '`VERSION`': + $stmt->bindValue($identifier, $this->version, PDO::PARAM_INT); + break; + case '`VERSION_CREATED_AT`': + $stmt->bindValue($identifier, $this->version_created_at ? $this->version_created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); + break; + case '`VERSION_CREATED_BY`': + $stmt->bindValue($identifier, $this->version_created_by, PDO::PARAM_STR); + break; } } $stmt->execute(); @@ -1887,6 +2112,15 @@ abstract class Order implements ActiveRecordInterface case 18: return $this->getUpdatedAt(); break; + case 19: + return $this->getVersion(); + break; + case 20: + return $this->getVersionCreatedAt(); + break; + case 21: + return $this->getVersionCreatedBy(); + break; default: return null; break; @@ -1935,6 +2169,9 @@ abstract class Order implements ActiveRecordInterface $keys[16] => $this->getLangId(), $keys[17] => $this->getCreatedAt(), $keys[18] => $this->getUpdatedAt(), + $keys[19] => $this->getVersion(), + $keys[20] => $this->getVersionCreatedAt(), + $keys[21] => $this->getVersionCreatedBy(), ); $virtualColumns = $this->virtualColumns; foreach ($virtualColumns as $key => $virtualColumn) { @@ -1972,6 +2209,9 @@ abstract class Order implements ActiveRecordInterface if (null !== $this->collOrderCoupons) { $result['OrderCoupons'] = $this->collOrderCoupons->toArray(null, true, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); } + if (null !== $this->collOrderVersions) { + $result['OrderVersions'] = $this->collOrderVersions->toArray(null, true, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } } return $result; @@ -2063,6 +2303,15 @@ abstract class Order implements ActiveRecordInterface case 18: $this->setUpdatedAt($value); break; + case 19: + $this->setVersion($value); + break; + case 20: + $this->setVersionCreatedAt($value); + break; + case 21: + $this->setVersionCreatedBy($value); + break; } // switch() } @@ -2106,6 +2355,9 @@ abstract class Order implements ActiveRecordInterface if (array_key_exists($keys[16], $arr)) $this->setLangId($arr[$keys[16]]); if (array_key_exists($keys[17], $arr)) $this->setCreatedAt($arr[$keys[17]]); if (array_key_exists($keys[18], $arr)) $this->setUpdatedAt($arr[$keys[18]]); + if (array_key_exists($keys[19], $arr)) $this->setVersion($arr[$keys[19]]); + if (array_key_exists($keys[20], $arr)) $this->setVersionCreatedAt($arr[$keys[20]]); + if (array_key_exists($keys[21], $arr)) $this->setVersionCreatedBy($arr[$keys[21]]); } /** @@ -2136,6 +2388,9 @@ abstract class Order implements ActiveRecordInterface if ($this->isColumnModified(OrderTableMap::LANG_ID)) $criteria->add(OrderTableMap::LANG_ID, $this->lang_id); if ($this->isColumnModified(OrderTableMap::CREATED_AT)) $criteria->add(OrderTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(OrderTableMap::UPDATED_AT)) $criteria->add(OrderTableMap::UPDATED_AT, $this->updated_at); + if ($this->isColumnModified(OrderTableMap::VERSION)) $criteria->add(OrderTableMap::VERSION, $this->version); + if ($this->isColumnModified(OrderTableMap::VERSION_CREATED_AT)) $criteria->add(OrderTableMap::VERSION_CREATED_AT, $this->version_created_at); + if ($this->isColumnModified(OrderTableMap::VERSION_CREATED_BY)) $criteria->add(OrderTableMap::VERSION_CREATED_BY, $this->version_created_by); return $criteria; } @@ -2217,6 +2472,9 @@ abstract class Order implements ActiveRecordInterface $copyObj->setLangId($this->getLangId()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); + $copyObj->setVersion($this->getVersion()); + $copyObj->setVersionCreatedAt($this->getVersionCreatedAt()); + $copyObj->setVersionCreatedBy($this->getVersionCreatedBy()); if ($deepCopy) { // important: temporarily setNew(false) because this affects the behavior of @@ -2235,6 +2493,12 @@ abstract class Order implements ActiveRecordInterface } } + foreach ($this->getOrderVersions() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addOrderVersion($relObj->copy($deepCopy)); + } + } + } // if ($deepCopy) if ($makeNew) { @@ -2690,6 +2954,9 @@ abstract class Order implements ActiveRecordInterface if ('OrderCoupon' == $relationName) { return $this->initOrderCoupons(); } + if ('OrderVersion' == $relationName) { + return $this->initOrderVersions(); + } } /** @@ -3128,6 +3395,227 @@ abstract class Order implements ActiveRecordInterface return $this; } + /** + * Clears out the collOrderVersions collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addOrderVersions() + */ + public function clearOrderVersions() + { + $this->collOrderVersions = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collOrderVersions collection loaded partially. + */ + public function resetPartialOrderVersions($v = true) + { + $this->collOrderVersionsPartial = $v; + } + + /** + * Initializes the collOrderVersions collection. + * + * By default this just sets the collOrderVersions collection to an empty array (like clearcollOrderVersions()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initOrderVersions($overrideExisting = true) + { + if (null !== $this->collOrderVersions && !$overrideExisting) { + return; + } + $this->collOrderVersions = new ObjectCollection(); + $this->collOrderVersions->setModel('\Thelia\Model\OrderVersion'); + } + + /** + * Gets an array of ChildOrderVersion objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildOrder is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return Collection|ChildOrderVersion[] List of ChildOrderVersion objects + * @throws PropelException + */ + public function getOrderVersions($criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collOrderVersionsPartial && !$this->isNew(); + if (null === $this->collOrderVersions || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collOrderVersions) { + // return empty collection + $this->initOrderVersions(); + } else { + $collOrderVersions = ChildOrderVersionQuery::create(null, $criteria) + ->filterByOrder($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collOrderVersionsPartial && count($collOrderVersions)) { + $this->initOrderVersions(false); + + foreach ($collOrderVersions as $obj) { + if (false == $this->collOrderVersions->contains($obj)) { + $this->collOrderVersions->append($obj); + } + } + + $this->collOrderVersionsPartial = true; + } + + reset($collOrderVersions); + + return $collOrderVersions; + } + + if ($partial && $this->collOrderVersions) { + foreach ($this->collOrderVersions as $obj) { + if ($obj->isNew()) { + $collOrderVersions[] = $obj; + } + } + } + + $this->collOrderVersions = $collOrderVersions; + $this->collOrderVersionsPartial = false; + } + } + + return $this->collOrderVersions; + } + + /** + * Sets a collection of OrderVersion objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $orderVersions A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return ChildOrder The current object (for fluent API support) + */ + public function setOrderVersions(Collection $orderVersions, ConnectionInterface $con = null) + { + $orderVersionsToDelete = $this->getOrderVersions(new Criteria(), $con)->diff($orderVersions); + + + //since at least one column in the foreign key is at the same time a PK + //we can not just set a PK to NULL in the lines below. We have to store + //a backup of all values, so we are able to manipulate these items based on the onDelete value later. + $this->orderVersionsScheduledForDeletion = clone $orderVersionsToDelete; + + foreach ($orderVersionsToDelete as $orderVersionRemoved) { + $orderVersionRemoved->setOrder(null); + } + + $this->collOrderVersions = null; + foreach ($orderVersions as $orderVersion) { + $this->addOrderVersion($orderVersion); + } + + $this->collOrderVersions = $orderVersions; + $this->collOrderVersionsPartial = false; + + return $this; + } + + /** + * Returns the number of related OrderVersion objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related OrderVersion objects. + * @throws PropelException + */ + public function countOrderVersions(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collOrderVersionsPartial && !$this->isNew(); + if (null === $this->collOrderVersions || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collOrderVersions) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getOrderVersions()); + } + + $query = ChildOrderVersionQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByOrder($this) + ->count($con); + } + + return count($this->collOrderVersions); + } + + /** + * Method called to associate a ChildOrderVersion object to this object + * through the ChildOrderVersion foreign key attribute. + * + * @param ChildOrderVersion $l ChildOrderVersion + * @return \Thelia\Model\Order The current object (for fluent API support) + */ + public function addOrderVersion(ChildOrderVersion $l) + { + if ($this->collOrderVersions === null) { + $this->initOrderVersions(); + $this->collOrderVersionsPartial = true; + } + + if (!in_array($l, $this->collOrderVersions->getArrayCopy(), true)) { // only add it if the **same** object is not already associated + $this->doAddOrderVersion($l); + } + + return $this; + } + + /** + * @param OrderVersion $orderVersion The orderVersion object to add. + */ + protected function doAddOrderVersion($orderVersion) + { + $this->collOrderVersions[]= $orderVersion; + $orderVersion->setOrder($this); + } + + /** + * @param OrderVersion $orderVersion The orderVersion object to remove. + * @return ChildOrder The current object (for fluent API support) + */ + public function removeOrderVersion($orderVersion) + { + if ($this->getOrderVersions()->contains($orderVersion)) { + $this->collOrderVersions->remove($this->collOrderVersions->search($orderVersion)); + if (null === $this->orderVersionsScheduledForDeletion) { + $this->orderVersionsScheduledForDeletion = clone $this->collOrderVersions; + $this->orderVersionsScheduledForDeletion->clear(); + } + $this->orderVersionsScheduledForDeletion[]= clone $orderVersion; + $orderVersion->setOrder(null); + } + + return $this; + } + /** * Clears the current object and sets all attributes to their default values */ @@ -3152,8 +3640,12 @@ abstract class Order implements ActiveRecordInterface $this->lang_id = null; $this->created_at = null; $this->updated_at = null; + $this->version = null; + $this->version_created_at = null; + $this->version_created_by = null; $this->alreadyInSave = false; $this->clearAllReferences(); + $this->applyDefaultValues(); $this->resetModified(); $this->setNew(true); $this->setDeleted(false); @@ -3181,10 +3673,16 @@ abstract class Order implements ActiveRecordInterface $o->clearAllReferences($deep); } } + if ($this->collOrderVersions) { + foreach ($this->collOrderVersions as $o) { + $o->clearAllReferences($deep); + } + } } // if ($deep) $this->collOrderProducts = null; $this->collOrderCoupons = null; + $this->collOrderVersions = null; $this->aCurrency = null; $this->aCustomer = null; $this->aOrderAddressRelatedByInvoiceOrderAddressId = null; @@ -3219,6 +3717,316 @@ abstract class Order implements ActiveRecordInterface return $this; } + // versionable behavior + + /** + * Enforce a new Version of this object upon next save. + * + * @return \Thelia\Model\Order + */ + public function enforceVersioning() + { + $this->enforceVersion = true; + + return $this; + } + + /** + * Checks whether the current state must be recorded as a version + * + * @return boolean + */ + public function isVersioningNecessary($con = null) + { + if ($this->alreadyInSave) { + return false; + } + + if ($this->enforceVersion) { + return true; + } + + if (ChildOrderQuery::isVersioningEnabled() && ($this->isNew() || $this->isModified()) || $this->isDeleted()) { + return true; + } + + return false; + } + + /** + * Creates a version of the current object and saves it. + * + * @param ConnectionInterface $con the connection to use + * + * @return ChildOrderVersion A version object + */ + public function addVersion($con = null) + { + $this->enforceVersion = false; + + $version = new ChildOrderVersion(); + $version->setId($this->getId()); + $version->setRef($this->getRef()); + $version->setCustomerId($this->getCustomerId()); + $version->setInvoiceOrderAddressId($this->getInvoiceOrderAddressId()); + $version->setDeliveryOrderAddressId($this->getDeliveryOrderAddressId()); + $version->setInvoiceDate($this->getInvoiceDate()); + $version->setCurrencyId($this->getCurrencyId()); + $version->setCurrencyRate($this->getCurrencyRate()); + $version->setTransactionRef($this->getTransactionRef()); + $version->setDeliveryRef($this->getDeliveryRef()); + $version->setInvoiceRef($this->getInvoiceRef()); + $version->setDiscount($this->getDiscount()); + $version->setPostage($this->getPostage()); + $version->setPaymentModuleId($this->getPaymentModuleId()); + $version->setDeliveryModuleId($this->getDeliveryModuleId()); + $version->setStatusId($this->getStatusId()); + $version->setLangId($this->getLangId()); + $version->setCreatedAt($this->getCreatedAt()); + $version->setUpdatedAt($this->getUpdatedAt()); + $version->setVersion($this->getVersion()); + $version->setVersionCreatedAt($this->getVersionCreatedAt()); + $version->setVersionCreatedBy($this->getVersionCreatedBy()); + $version->setOrder($this); + $version->save($con); + + return $version; + } + + /** + * Sets the properties of the current object to the value they had at a specific version + * + * @param integer $versionNumber The version number to read + * @param ConnectionInterface $con The connection to use + * + * @return ChildOrder The current object (for fluent API support) + */ + public function toVersion($versionNumber, $con = null) + { + $version = $this->getOneVersion($versionNumber, $con); + if (!$version) { + throw new PropelException(sprintf('No ChildOrder object found with version %d', $version)); + } + $this->populateFromVersion($version, $con); + + return $this; + } + + /** + * Sets the properties of the current object to the value they had at a specific version + * + * @param ChildOrderVersion $version The version object to use + * @param ConnectionInterface $con the connection to use + * @param array $loadedObjects objects that been loaded in a chain of populateFromVersion calls on referrer or fk objects. + * + * @return ChildOrder The current object (for fluent API support) + */ + public function populateFromVersion($version, $con = null, &$loadedObjects = array()) + { + $loadedObjects['ChildOrder'][$version->getId()][$version->getVersion()] = $this; + $this->setId($version->getId()); + $this->setRef($version->getRef()); + $this->setCustomerId($version->getCustomerId()); + $this->setInvoiceOrderAddressId($version->getInvoiceOrderAddressId()); + $this->setDeliveryOrderAddressId($version->getDeliveryOrderAddressId()); + $this->setInvoiceDate($version->getInvoiceDate()); + $this->setCurrencyId($version->getCurrencyId()); + $this->setCurrencyRate($version->getCurrencyRate()); + $this->setTransactionRef($version->getTransactionRef()); + $this->setDeliveryRef($version->getDeliveryRef()); + $this->setInvoiceRef($version->getInvoiceRef()); + $this->setDiscount($version->getDiscount()); + $this->setPostage($version->getPostage()); + $this->setPaymentModuleId($version->getPaymentModuleId()); + $this->setDeliveryModuleId($version->getDeliveryModuleId()); + $this->setStatusId($version->getStatusId()); + $this->setLangId($version->getLangId()); + $this->setCreatedAt($version->getCreatedAt()); + $this->setUpdatedAt($version->getUpdatedAt()); + $this->setVersion($version->getVersion()); + $this->setVersionCreatedAt($version->getVersionCreatedAt()); + $this->setVersionCreatedBy($version->getVersionCreatedBy()); + + return $this; + } + + /** + * Gets the latest persisted version number for the current object + * + * @param ConnectionInterface $con the connection to use + * + * @return integer + */ + public function getLastVersionNumber($con = null) + { + $v = ChildOrderVersionQuery::create() + ->filterByOrder($this) + ->orderByVersion('desc') + ->findOne($con); + if (!$v) { + return 0; + } + + return $v->getVersion(); + } + + /** + * Checks whether the current object is the latest one + * + * @param ConnectionInterface $con the connection to use + * + * @return Boolean + */ + public function isLastVersion($con = null) + { + return $this->getLastVersionNumber($con) == $this->getVersion(); + } + + /** + * Retrieves a version object for this entity and a version number + * + * @param integer $versionNumber The version number to read + * @param ConnectionInterface $con the connection to use + * + * @return ChildOrderVersion A version object + */ + public function getOneVersion($versionNumber, $con = null) + { + return ChildOrderVersionQuery::create() + ->filterByOrder($this) + ->filterByVersion($versionNumber) + ->findOne($con); + } + + /** + * Gets all the versions of this object, in incremental order + * + * @param ConnectionInterface $con the connection to use + * + * @return ObjectCollection A list of ChildOrderVersion objects + */ + public function getAllVersions($con = null) + { + $criteria = new Criteria(); + $criteria->addAscendingOrderByColumn(OrderVersionTableMap::VERSION); + + return $this->getOrderVersions($criteria, $con); + } + + /** + * Compares the current object with another of its version. + * + * print_r($book->compareVersion(1)); + * => array( + * '1' => array('Title' => 'Book title at version 1'), + * '2' => array('Title' => 'Book title at version 2') + * ); + * + * + * @param integer $versionNumber + * @param string $keys Main key used for the result diff (versions|columns) + * @param ConnectionInterface $con the connection to use + * @param array $ignoredColumns The columns to exclude from the diff. + * + * @return array A list of differences + */ + public function compareVersion($versionNumber, $keys = 'columns', $con = null, $ignoredColumns = array()) + { + $fromVersion = $this->toArray(); + $toVersion = $this->getOneVersion($versionNumber, $con)->toArray(); + + return $this->computeDiff($fromVersion, $toVersion, $keys, $ignoredColumns); + } + + /** + * Compares two versions of the current object. + * + * print_r($book->compareVersions(1, 2)); + * => array( + * '1' => array('Title' => 'Book title at version 1'), + * '2' => array('Title' => 'Book title at version 2') + * ); + * + * + * @param integer $fromVersionNumber + * @param integer $toVersionNumber + * @param string $keys Main key used for the result diff (versions|columns) + * @param ConnectionInterface $con the connection to use + * @param array $ignoredColumns The columns to exclude from the diff. + * + * @return array A list of differences + */ + public function compareVersions($fromVersionNumber, $toVersionNumber, $keys = 'columns', $con = null, $ignoredColumns = array()) + { + $fromVersion = $this->getOneVersion($fromVersionNumber, $con)->toArray(); + $toVersion = $this->getOneVersion($toVersionNumber, $con)->toArray(); + + return $this->computeDiff($fromVersion, $toVersion, $keys, $ignoredColumns); + } + + /** + * Computes the diff between two versions. + * + * print_r($book->computeDiff(1, 2)); + * => array( + * '1' => array('Title' => 'Book title at version 1'), + * '2' => array('Title' => 'Book title at version 2') + * ); + * + * + * @param array $fromVersion An array representing the original version. + * @param array $toVersion An array representing the destination version. + * @param string $keys Main key used for the result diff (versions|columns). + * @param array $ignoredColumns The columns to exclude from the diff. + * + * @return array A list of differences + */ + protected function computeDiff($fromVersion, $toVersion, $keys = 'columns', $ignoredColumns = array()) + { + $fromVersionNumber = $fromVersion['Version']; + $toVersionNumber = $toVersion['Version']; + $ignoredColumns = array_merge(array( + 'Version', + 'VersionCreatedAt', + 'VersionCreatedBy', + ), $ignoredColumns); + $diff = array(); + foreach ($fromVersion as $key => $value) { + if (in_array($key, $ignoredColumns)) { + continue; + } + if ($toVersion[$key] != $value) { + switch ($keys) { + case 'versions': + $diff[$fromVersionNumber][$key] = $value; + $diff[$toVersionNumber][$key] = $toVersion[$key]; + break; + default: + $diff[$key] = array( + $fromVersionNumber => $value, + $toVersionNumber => $toVersion[$key], + ); + break; + } + } + } + + return $diff; + } + /** + * retrieve the last $number versions. + * + * @param Integer $number the number of record to return. + * @return PropelCollection|array \Thelia\Model\OrderVersion[] List of \Thelia\Model\OrderVersion objects + */ + public function getLastVersions($number = 10, $criteria = null, $con = null) + { + $criteria = ChildOrderVersionQuery::create(null, $criteria); + $criteria->addDescendingOrderByColumn(OrderVersionTableMap::VERSION); + $criteria->limit($number); + + return $this->getOrderVersions($criteria, $con); + } /** * Code to be run before persisting the object * @param ConnectionInterface $con diff --git a/core/lib/Thelia/Model/Base/OrderQuery.php b/core/lib/Thelia/Model/Base/OrderQuery.php index 96aa3d30b..2db0f37e7 100644 --- a/core/lib/Thelia/Model/Base/OrderQuery.php +++ b/core/lib/Thelia/Model/Base/OrderQuery.php @@ -40,6 +40,9 @@ use Thelia\Model\Map\OrderTableMap; * @method ChildOrderQuery orderByLangId($order = Criteria::ASC) Order by the lang_id column * @method ChildOrderQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildOrderQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column + * @method ChildOrderQuery orderByVersion($order = Criteria::ASC) Order by the version column + * @method ChildOrderQuery orderByVersionCreatedAt($order = Criteria::ASC) Order by the version_created_at column + * @method ChildOrderQuery orderByVersionCreatedBy($order = Criteria::ASC) Order by the version_created_by column * * @method ChildOrderQuery groupById() Group by the id column * @method ChildOrderQuery groupByRef() Group by the ref column @@ -60,6 +63,9 @@ use Thelia\Model\Map\OrderTableMap; * @method ChildOrderQuery groupByLangId() Group by the lang_id column * @method ChildOrderQuery groupByCreatedAt() Group by the created_at column * @method ChildOrderQuery groupByUpdatedAt() Group by the updated_at column + * @method ChildOrderQuery groupByVersion() Group by the version column + * @method ChildOrderQuery groupByVersionCreatedAt() Group by the version_created_at column + * @method ChildOrderQuery groupByVersionCreatedBy() Group by the version_created_by column * * @method ChildOrderQuery leftJoin($relation) Adds a LEFT JOIN clause to the query * @method ChildOrderQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query @@ -105,6 +111,10 @@ use Thelia\Model\Map\OrderTableMap; * @method ChildOrderQuery rightJoinOrderCoupon($relationAlias = null) Adds a RIGHT JOIN clause to the query using the OrderCoupon relation * @method ChildOrderQuery innerJoinOrderCoupon($relationAlias = null) Adds a INNER JOIN clause to the query using the OrderCoupon relation * + * @method ChildOrderQuery leftJoinOrderVersion($relationAlias = null) Adds a LEFT JOIN clause to the query using the OrderVersion relation + * @method ChildOrderQuery rightJoinOrderVersion($relationAlias = null) Adds a RIGHT JOIN clause to the query using the OrderVersion relation + * @method ChildOrderQuery innerJoinOrderVersion($relationAlias = null) Adds a INNER JOIN clause to the query using the OrderVersion relation + * * @method ChildOrder findOne(ConnectionInterface $con = null) Return the first ChildOrder matching the query * @method ChildOrder findOneOrCreate(ConnectionInterface $con = null) Return the first ChildOrder matching the query, or a new ChildOrder object populated from the query conditions when no match is found * @@ -127,6 +137,9 @@ use Thelia\Model\Map\OrderTableMap; * @method ChildOrder findOneByLangId(int $lang_id) Return the first ChildOrder filtered by the lang_id column * @method ChildOrder findOneByCreatedAt(string $created_at) Return the first ChildOrder filtered by the created_at column * @method ChildOrder findOneByUpdatedAt(string $updated_at) Return the first ChildOrder filtered by the updated_at column + * @method ChildOrder findOneByVersion(int $version) Return the first ChildOrder filtered by the version column + * @method ChildOrder findOneByVersionCreatedAt(string $version_created_at) Return the first ChildOrder filtered by the version_created_at column + * @method ChildOrder findOneByVersionCreatedBy(string $version_created_by) Return the first ChildOrder filtered by the version_created_by column * * @method array findById(int $id) Return ChildOrder objects filtered by the id column * @method array findByRef(string $ref) Return ChildOrder objects filtered by the ref column @@ -147,11 +160,21 @@ use Thelia\Model\Map\OrderTableMap; * @method array findByLangId(int $lang_id) Return ChildOrder objects filtered by the lang_id column * @method array findByCreatedAt(string $created_at) Return ChildOrder objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildOrder objects filtered by the updated_at column + * @method array findByVersion(int $version) Return ChildOrder objects filtered by the version column + * @method array findByVersionCreatedAt(string $version_created_at) Return ChildOrder objects filtered by the version_created_at column + * @method array findByVersionCreatedBy(string $version_created_by) Return ChildOrder objects filtered by the version_created_by column * */ abstract class OrderQuery extends ModelCriteria { + // versionable behavior + + /** + * Whether the versioning is enabled + */ + static $isVersioningEnabled = true; + /** * Initializes internal state of \Thelia\Model\Base\OrderQuery object. * @@ -235,7 +258,7 @@ abstract class OrderQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT `ID`, `REF`, `CUSTOMER_ID`, `INVOICE_ORDER_ADDRESS_ID`, `DELIVERY_ORDER_ADDRESS_ID`, `INVOICE_DATE`, `CURRENCY_ID`, `CURRENCY_RATE`, `TRANSACTION_REF`, `DELIVERY_REF`, `INVOICE_REF`, `DISCOUNT`, `POSTAGE`, `PAYMENT_MODULE_ID`, `DELIVERY_MODULE_ID`, `STATUS_ID`, `LANG_ID`, `CREATED_AT`, `UPDATED_AT` FROM `order` WHERE `ID` = :p0'; + $sql = 'SELECT `ID`, `REF`, `CUSTOMER_ID`, `INVOICE_ORDER_ADDRESS_ID`, `DELIVERY_ORDER_ADDRESS_ID`, `INVOICE_DATE`, `CURRENCY_ID`, `CURRENCY_RATE`, `TRANSACTION_REF`, `DELIVERY_REF`, `INVOICE_REF`, `DISCOUNT`, `POSTAGE`, `PAYMENT_MODULE_ID`, `DELIVERY_MODULE_ID`, `STATUS_ID`, `LANG_ID`, `CREATED_AT`, `UPDATED_AT`, `VERSION`, `VERSION_CREATED_AT`, `VERSION_CREATED_BY` FROM `order` WHERE `ID` = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -1077,6 +1100,119 @@ abstract class OrderQuery extends ModelCriteria return $this->addUsingAlias(OrderTableMap::UPDATED_AT, $updatedAt, $comparison); } + /** + * Filter the query on the version column + * + * Example usage: + * + * $query->filterByVersion(1234); // WHERE version = 1234 + * $query->filterByVersion(array(12, 34)); // WHERE version IN (12, 34) + * $query->filterByVersion(array('min' => 12)); // WHERE version > 12 + * + * + * @param mixed $version The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderQuery The current query, for fluid interface + */ + public function filterByVersion($version = null, $comparison = null) + { + if (is_array($version)) { + $useMinMax = false; + if (isset($version['min'])) { + $this->addUsingAlias(OrderTableMap::VERSION, $version['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($version['max'])) { + $this->addUsingAlias(OrderTableMap::VERSION, $version['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderTableMap::VERSION, $version, $comparison); + } + + /** + * Filter the query on the version_created_at column + * + * Example usage: + * + * $query->filterByVersionCreatedAt('2011-03-14'); // WHERE version_created_at = '2011-03-14' + * $query->filterByVersionCreatedAt('now'); // WHERE version_created_at = '2011-03-14' + * $query->filterByVersionCreatedAt(array('max' => 'yesterday')); // WHERE version_created_at > '2011-03-13' + * + * + * @param mixed $versionCreatedAt The value to use as filter. + * Values can be integers (unix timestamps), DateTime objects, or strings. + * Empty strings are treated as NULL. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderQuery The current query, for fluid interface + */ + public function filterByVersionCreatedAt($versionCreatedAt = null, $comparison = null) + { + if (is_array($versionCreatedAt)) { + $useMinMax = false; + if (isset($versionCreatedAt['min'])) { + $this->addUsingAlias(OrderTableMap::VERSION_CREATED_AT, $versionCreatedAt['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($versionCreatedAt['max'])) { + $this->addUsingAlias(OrderTableMap::VERSION_CREATED_AT, $versionCreatedAt['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderTableMap::VERSION_CREATED_AT, $versionCreatedAt, $comparison); + } + + /** + * Filter the query on the version_created_by column + * + * Example usage: + * + * $query->filterByVersionCreatedBy('fooValue'); // WHERE version_created_by = 'fooValue' + * $query->filterByVersionCreatedBy('%fooValue%'); // WHERE version_created_by LIKE '%fooValue%' + * + * + * @param string $versionCreatedBy The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderQuery The current query, for fluid interface + */ + public function filterByVersionCreatedBy($versionCreatedBy = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($versionCreatedBy)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $versionCreatedBy)) { + $versionCreatedBy = str_replace('*', '%', $versionCreatedBy); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderTableMap::VERSION_CREATED_BY, $versionCreatedBy, $comparison); + } + /** * Filter the query by a related \Thelia\Model\Currency object * @@ -1823,6 +1959,79 @@ abstract class OrderQuery extends ModelCriteria ->useQuery($relationAlias ? $relationAlias : 'OrderCoupon', '\Thelia\Model\OrderCouponQuery'); } + /** + * Filter the query by a related \Thelia\Model\OrderVersion object + * + * @param \Thelia\Model\OrderVersion|ObjectCollection $orderVersion the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderQuery The current query, for fluid interface + */ + public function filterByOrderVersion($orderVersion, $comparison = null) + { + if ($orderVersion instanceof \Thelia\Model\OrderVersion) { + return $this + ->addUsingAlias(OrderTableMap::ID, $orderVersion->getId(), $comparison); + } elseif ($orderVersion instanceof ObjectCollection) { + return $this + ->useOrderVersionQuery() + ->filterByPrimaryKeys($orderVersion->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByOrderVersion() only accepts arguments of type \Thelia\Model\OrderVersion or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the OrderVersion relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return ChildOrderQuery The current query, for fluid interface + */ + public function joinOrderVersion($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('OrderVersion'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'OrderVersion'); + } + + return $this; + } + + /** + * Use the OrderVersion relation OrderVersion object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \Thelia\Model\OrderVersionQuery A secondary query class using the current class as primary query + */ + public function useOrderVersionQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinOrderVersion($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'OrderVersion', '\Thelia\Model\OrderVersionQuery'); + } + /** * Exclude object from result * @@ -1980,4 +2189,32 @@ abstract class OrderQuery extends ModelCriteria return $this->addAscendingOrderByColumn(OrderTableMap::CREATED_AT); } + // versionable behavior + + /** + * Checks whether versioning is enabled + * + * @return boolean + */ + static public function isVersioningEnabled() + { + return self::$isVersioningEnabled; + } + + /** + * Enables versioning + */ + static public function enableVersioning() + { + self::$isVersioningEnabled = true; + } + + /** + * Disables versioning + */ + static public function disableVersioning() + { + self::$isVersioningEnabled = false; + } + } // OrderQuery diff --git a/core/lib/Thelia/Model/Base/OrderVersion.php b/core/lib/Thelia/Model/Base/OrderVersion.php new file mode 100644 index 000000000..2baed9528 --- /dev/null +++ b/core/lib/Thelia/Model/Base/OrderVersion.php @@ -0,0 +1,2420 @@ +version = 0; + } + + /** + * Initializes internal state of Thelia\Model\Base\OrderVersion object. + * @see applyDefaults() + */ + public function __construct() + { + $this->applyDefaultValues(); + } + + /** + * Returns whether the object has been modified. + * + * @return boolean True if the object has been modified. + */ + public function isModified() + { + return !!$this->modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (Boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (Boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another OrderVersion instance. If + * obj is an instance of OrderVersion, delegates to + * equals(OrderVersion). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + $thisclazz = get_class($this); + if (!is_object($obj) || !($obj instanceof $thisclazz)) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() + || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + if (null !== $this->getPrimaryKey()) { + return crc32(serialize($this->getPrimaryKey())); + } + + return crc32(serialize(clone $this)); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return OrderVersion The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * + * @return OrderVersion The current object, for fluid interface + */ + public function importFrom($parser, $data) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), TableMap::TYPE_PHPNAME); + + return $this; + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + return array_keys(get_object_vars($this)); + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + + return $this->id; + } + + /** + * Get the [ref] column value. + * + * @return string + */ + public function getRef() + { + + return $this->ref; + } + + /** + * Get the [customer_id] column value. + * + * @return int + */ + public function getCustomerId() + { + + return $this->customer_id; + } + + /** + * Get the [invoice_order_address_id] column value. + * + * @return int + */ + public function getInvoiceOrderAddressId() + { + + return $this->invoice_order_address_id; + } + + /** + * Get the [delivery_order_address_id] column value. + * + * @return int + */ + public function getDeliveryOrderAddressId() + { + + return $this->delivery_order_address_id; + } + + /** + * Get the [optionally formatted] temporal [invoice_date] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw \DateTime object will be returned. + * + * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 + * + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getInvoiceDate($format = NULL) + { + if ($format === null) { + return $this->invoice_date; + } else { + return $this->invoice_date instanceof \DateTime ? $this->invoice_date->format($format) : null; + } + } + + /** + * Get the [currency_id] column value. + * + * @return int + */ + public function getCurrencyId() + { + + return $this->currency_id; + } + + /** + * Get the [currency_rate] column value. + * + * @return double + */ + public function getCurrencyRate() + { + + return $this->currency_rate; + } + + /** + * Get the [transaction_ref] column value. + * transaction reference - usually use to identify a transaction with banking modules + * @return string + */ + public function getTransactionRef() + { + + return $this->transaction_ref; + } + + /** + * Get the [delivery_ref] column value. + * delivery reference - usually use to identify a delivery progress on a distant delivery tracker website + * @return string + */ + public function getDeliveryRef() + { + + return $this->delivery_ref; + } + + /** + * Get the [invoice_ref] column value. + * the invoice reference + * @return string + */ + public function getInvoiceRef() + { + + return $this->invoice_ref; + } + + /** + * Get the [discount] column value. + * + * @return double + */ + public function getDiscount() + { + + return $this->discount; + } + + /** + * Get the [postage] column value. + * + * @return double + */ + public function getPostage() + { + + return $this->postage; + } + + /** + * Get the [payment_module_id] column value. + * + * @return int + */ + public function getPaymentModuleId() + { + + return $this->payment_module_id; + } + + /** + * Get the [delivery_module_id] column value. + * + * @return int + */ + public function getDeliveryModuleId() + { + + return $this->delivery_module_id; + } + + /** + * Get the [status_id] column value. + * + * @return int + */ + public function getStatusId() + { + + return $this->status_id; + } + + /** + * Get the [lang_id] column value. + * + * @return int + */ + public function getLangId() + { + + return $this->lang_id; + } + + /** + * Get the [optionally formatted] temporal [created_at] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw \DateTime object will be returned. + * + * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 + * + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getCreatedAt($format = NULL) + { + if ($format === null) { + return $this->created_at; + } else { + return $this->created_at instanceof \DateTime ? $this->created_at->format($format) : null; + } + } + + /** + * Get the [optionally formatted] temporal [updated_at] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw \DateTime object will be returned. + * + * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 + * + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getUpdatedAt($format = NULL) + { + if ($format === null) { + return $this->updated_at; + } else { + return $this->updated_at instanceof \DateTime ? $this->updated_at->format($format) : null; + } + } + + /** + * Get the [version] column value. + * + * @return int + */ + public function getVersion() + { + + return $this->version; + } + + /** + * Get the [optionally formatted] temporal [version_created_at] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw \DateTime object will be returned. + * + * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 + * + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getVersionCreatedAt($format = NULL) + { + if ($format === null) { + return $this->version_created_at; + } else { + return $this->version_created_at instanceof \DateTime ? $this->version_created_at->format($format) : null; + } + } + + /** + * Get the [version_created_by] column value. + * + * @return string + */ + public function getVersionCreatedBy() + { + + return $this->version_created_by; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[OrderVersionTableMap::ID] = true; + } + + if ($this->aOrder !== null && $this->aOrder->getId() !== $v) { + $this->aOrder = null; + } + + + return $this; + } // setId() + + /** + * Set the value of [ref] column. + * + * @param string $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setRef($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->ref !== $v) { + $this->ref = $v; + $this->modifiedColumns[OrderVersionTableMap::REF] = true; + } + + + return $this; + } // setRef() + + /** + * Set the value of [customer_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setCustomerId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->customer_id !== $v) { + $this->customer_id = $v; + $this->modifiedColumns[OrderVersionTableMap::CUSTOMER_ID] = true; + } + + + return $this; + } // setCustomerId() + + /** + * Set the value of [invoice_order_address_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setInvoiceOrderAddressId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->invoice_order_address_id !== $v) { + $this->invoice_order_address_id = $v; + $this->modifiedColumns[OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID] = true; + } + + + return $this; + } // setInvoiceOrderAddressId() + + /** + * Set the value of [delivery_order_address_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setDeliveryOrderAddressId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->delivery_order_address_id !== $v) { + $this->delivery_order_address_id = $v; + $this->modifiedColumns[OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID] = true; + } + + + return $this; + } // setDeliveryOrderAddressId() + + /** + * Sets the value of [invoice_date] column to a normalized version of the date/time value specified. + * + * @param mixed $v string, integer (timestamp), or \DateTime value. + * Empty strings are treated as NULL. + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setInvoiceDate($v) + { + $dt = PropelDateTime::newInstance($v, null, '\DateTime'); + if ($this->invoice_date !== null || $dt !== null) { + if ($dt !== $this->invoice_date) { + $this->invoice_date = $dt; + $this->modifiedColumns[OrderVersionTableMap::INVOICE_DATE] = true; + } + } // if either are not null + + + return $this; + } // setInvoiceDate() + + /** + * Set the value of [currency_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setCurrencyId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->currency_id !== $v) { + $this->currency_id = $v; + $this->modifiedColumns[OrderVersionTableMap::CURRENCY_ID] = true; + } + + + return $this; + } // setCurrencyId() + + /** + * Set the value of [currency_rate] column. + * + * @param double $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setCurrencyRate($v) + { + if ($v !== null) { + $v = (double) $v; + } + + if ($this->currency_rate !== $v) { + $this->currency_rate = $v; + $this->modifiedColumns[OrderVersionTableMap::CURRENCY_RATE] = true; + } + + + return $this; + } // setCurrencyRate() + + /** + * Set the value of [transaction_ref] column. + * transaction reference - usually use to identify a transaction with banking modules + * @param string $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setTransactionRef($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->transaction_ref !== $v) { + $this->transaction_ref = $v; + $this->modifiedColumns[OrderVersionTableMap::TRANSACTION_REF] = true; + } + + + return $this; + } // setTransactionRef() + + /** + * Set the value of [delivery_ref] column. + * delivery reference - usually use to identify a delivery progress on a distant delivery tracker website + * @param string $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setDeliveryRef($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->delivery_ref !== $v) { + $this->delivery_ref = $v; + $this->modifiedColumns[OrderVersionTableMap::DELIVERY_REF] = true; + } + + + return $this; + } // setDeliveryRef() + + /** + * Set the value of [invoice_ref] column. + * the invoice reference + * @param string $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setInvoiceRef($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->invoice_ref !== $v) { + $this->invoice_ref = $v; + $this->modifiedColumns[OrderVersionTableMap::INVOICE_REF] = true; + } + + + return $this; + } // setInvoiceRef() + + /** + * Set the value of [discount] column. + * + * @param double $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setDiscount($v) + { + if ($v !== null) { + $v = (double) $v; + } + + if ($this->discount !== $v) { + $this->discount = $v; + $this->modifiedColumns[OrderVersionTableMap::DISCOUNT] = true; + } + + + return $this; + } // setDiscount() + + /** + * Set the value of [postage] column. + * + * @param double $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setPostage($v) + { + if ($v !== null) { + $v = (double) $v; + } + + if ($this->postage !== $v) { + $this->postage = $v; + $this->modifiedColumns[OrderVersionTableMap::POSTAGE] = true; + } + + + return $this; + } // setPostage() + + /** + * Set the value of [payment_module_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setPaymentModuleId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->payment_module_id !== $v) { + $this->payment_module_id = $v; + $this->modifiedColumns[OrderVersionTableMap::PAYMENT_MODULE_ID] = true; + } + + + return $this; + } // setPaymentModuleId() + + /** + * Set the value of [delivery_module_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setDeliveryModuleId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->delivery_module_id !== $v) { + $this->delivery_module_id = $v; + $this->modifiedColumns[OrderVersionTableMap::DELIVERY_MODULE_ID] = true; + } + + + return $this; + } // setDeliveryModuleId() + + /** + * Set the value of [status_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setStatusId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->status_id !== $v) { + $this->status_id = $v; + $this->modifiedColumns[OrderVersionTableMap::STATUS_ID] = true; + } + + + return $this; + } // setStatusId() + + /** + * Set the value of [lang_id] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setLangId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->lang_id !== $v) { + $this->lang_id = $v; + $this->modifiedColumns[OrderVersionTableMap::LANG_ID] = true; + } + + + return $this; + } // setLangId() + + /** + * Sets the value of [created_at] column to a normalized version of the date/time value specified. + * + * @param mixed $v string, integer (timestamp), or \DateTime value. + * Empty strings are treated as NULL. + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setCreatedAt($v) + { + $dt = PropelDateTime::newInstance($v, null, '\DateTime'); + if ($this->created_at !== null || $dt !== null) { + if ($dt !== $this->created_at) { + $this->created_at = $dt; + $this->modifiedColumns[OrderVersionTableMap::CREATED_AT] = true; + } + } // if either are not null + + + return $this; + } // setCreatedAt() + + /** + * Sets the value of [updated_at] column to a normalized version of the date/time value specified. + * + * @param mixed $v string, integer (timestamp), or \DateTime value. + * Empty strings are treated as NULL. + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setUpdatedAt($v) + { + $dt = PropelDateTime::newInstance($v, null, '\DateTime'); + if ($this->updated_at !== null || $dt !== null) { + if ($dt !== $this->updated_at) { + $this->updated_at = $dt; + $this->modifiedColumns[OrderVersionTableMap::UPDATED_AT] = true; + } + } // if either are not null + + + return $this; + } // setUpdatedAt() + + /** + * Set the value of [version] column. + * + * @param int $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setVersion($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->version !== $v) { + $this->version = $v; + $this->modifiedColumns[OrderVersionTableMap::VERSION] = true; + } + + + return $this; + } // setVersion() + + /** + * Sets the value of [version_created_at] column to a normalized version of the date/time value specified. + * + * @param mixed $v string, integer (timestamp), or \DateTime value. + * Empty strings are treated as NULL. + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setVersionCreatedAt($v) + { + $dt = PropelDateTime::newInstance($v, null, '\DateTime'); + if ($this->version_created_at !== null || $dt !== null) { + if ($dt !== $this->version_created_at) { + $this->version_created_at = $dt; + $this->modifiedColumns[OrderVersionTableMap::VERSION_CREATED_AT] = true; + } + } // if either are not null + + + return $this; + } // setVersionCreatedAt() + + /** + * Set the value of [version_created_by] column. + * + * @param string $v new value + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + */ + public function setVersionCreatedBy($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->version_created_by !== $v) { + $this->version_created_by = $v; + $this->modifiedColumns[OrderVersionTableMap::VERSION_CREATED_BY] = true; + } + + + return $this; + } // setVersionCreatedBy() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + if ($this->version !== 0) { + return false; + } + + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : OrderVersionTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : OrderVersionTableMap::translateFieldName('Ref', TableMap::TYPE_PHPNAME, $indexType)]; + $this->ref = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : OrderVersionTableMap::translateFieldName('CustomerId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->customer_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : OrderVersionTableMap::translateFieldName('InvoiceOrderAddressId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->invoice_order_address_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : OrderVersionTableMap::translateFieldName('DeliveryOrderAddressId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->delivery_order_address_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : OrderVersionTableMap::translateFieldName('InvoiceDate', TableMap::TYPE_PHPNAME, $indexType)]; + if ($col === '0000-00-00') { + $col = null; + } + $this->invoice_date = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : OrderVersionTableMap::translateFieldName('CurrencyId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->currency_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : OrderVersionTableMap::translateFieldName('CurrencyRate', TableMap::TYPE_PHPNAME, $indexType)]; + $this->currency_rate = (null !== $col) ? (double) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : OrderVersionTableMap::translateFieldName('TransactionRef', TableMap::TYPE_PHPNAME, $indexType)]; + $this->transaction_ref = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : OrderVersionTableMap::translateFieldName('DeliveryRef', TableMap::TYPE_PHPNAME, $indexType)]; + $this->delivery_ref = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 10 + $startcol : OrderVersionTableMap::translateFieldName('InvoiceRef', TableMap::TYPE_PHPNAME, $indexType)]; + $this->invoice_ref = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 11 + $startcol : OrderVersionTableMap::translateFieldName('Discount', TableMap::TYPE_PHPNAME, $indexType)]; + $this->discount = (null !== $col) ? (double) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 12 + $startcol : OrderVersionTableMap::translateFieldName('Postage', TableMap::TYPE_PHPNAME, $indexType)]; + $this->postage = (null !== $col) ? (double) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 13 + $startcol : OrderVersionTableMap::translateFieldName('PaymentModuleId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->payment_module_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 14 + $startcol : OrderVersionTableMap::translateFieldName('DeliveryModuleId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->delivery_module_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 15 + $startcol : OrderVersionTableMap::translateFieldName('StatusId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->status_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 16 + $startcol : OrderVersionTableMap::translateFieldName('LangId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->lang_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 17 + $startcol : OrderVersionTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + if ($col === '0000-00-00 00:00:00') { + $col = null; + } + $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 18 + $startcol : OrderVersionTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + if ($col === '0000-00-00 00:00:00') { + $col = null; + } + $this->updated_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 19 + $startcol : OrderVersionTableMap::translateFieldName('Version', TableMap::TYPE_PHPNAME, $indexType)]; + $this->version = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 20 + $startcol : OrderVersionTableMap::translateFieldName('VersionCreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + if ($col === '0000-00-00 00:00:00') { + $col = null; + } + $this->version_created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 21 + $startcol : OrderVersionTableMap::translateFieldName('VersionCreatedBy', TableMap::TYPE_PHPNAME, $indexType)]; + $this->version_created_by = (null !== $col) ? (string) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 22; // 22 = OrderVersionTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException("Error populating \Thelia\Model\OrderVersion object", 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + if ($this->aOrder !== null && $this->id !== $this->aOrder->getId()) { + $this->aOrder = null; + } + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(OrderVersionTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildOrderVersionQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->aOrder = null; + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see OrderVersion::setDeleted() + * @see OrderVersion::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + + $con->beginTransaction(); + try { + $deleteQuery = ChildOrderVersionQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $con->commit(); + $this->setDeleted(true); + } else { + $con->commit(); + } + } catch (Exception $e) { + $con->rollBack(); + throw $e; + } + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + + $con->beginTransaction(); + $isInsert = $this->isNew(); + try { + $ret = $this->preSave($con); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + OrderVersionTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + $con->commit(); + + return $affectedRows; + } catch (Exception $e) { + $con->rollBack(); + throw $e; + } + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + // We call the save method on the following object(s) if they + // were passed to this object by their corresponding set + // method. This object relates to these object(s) by a + // foreign key reference. + + if ($this->aOrder !== null) { + if ($this->aOrder->isModified() || $this->aOrder->isNew()) { + $affectedRows += $this->aOrder->save($con); + } + $this->setOrder($this->aOrder); + } + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + } else { + $this->doUpdate($con); + } + $affectedRows += 1; + $this->resetModified(); + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(OrderVersionTableMap::ID)) { + $modifiedColumns[':p' . $index++] = '`ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::REF)) { + $modifiedColumns[':p' . $index++] = '`REF`'; + } + if ($this->isColumnModified(OrderVersionTableMap::CUSTOMER_ID)) { + $modifiedColumns[':p' . $index++] = '`CUSTOMER_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID)) { + $modifiedColumns[':p' . $index++] = '`INVOICE_ORDER_ADDRESS_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID)) { + $modifiedColumns[':p' . $index++] = '`DELIVERY_ORDER_ADDRESS_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_DATE)) { + $modifiedColumns[':p' . $index++] = '`INVOICE_DATE`'; + } + if ($this->isColumnModified(OrderVersionTableMap::CURRENCY_ID)) { + $modifiedColumns[':p' . $index++] = '`CURRENCY_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::CURRENCY_RATE)) { + $modifiedColumns[':p' . $index++] = '`CURRENCY_RATE`'; + } + if ($this->isColumnModified(OrderVersionTableMap::TRANSACTION_REF)) { + $modifiedColumns[':p' . $index++] = '`TRANSACTION_REF`'; + } + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_REF)) { + $modifiedColumns[':p' . $index++] = '`DELIVERY_REF`'; + } + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_REF)) { + $modifiedColumns[':p' . $index++] = '`INVOICE_REF`'; + } + if ($this->isColumnModified(OrderVersionTableMap::DISCOUNT)) { + $modifiedColumns[':p' . $index++] = '`DISCOUNT`'; + } + if ($this->isColumnModified(OrderVersionTableMap::POSTAGE)) { + $modifiedColumns[':p' . $index++] = '`POSTAGE`'; + } + if ($this->isColumnModified(OrderVersionTableMap::PAYMENT_MODULE_ID)) { + $modifiedColumns[':p' . $index++] = '`PAYMENT_MODULE_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_MODULE_ID)) { + $modifiedColumns[':p' . $index++] = '`DELIVERY_MODULE_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::STATUS_ID)) { + $modifiedColumns[':p' . $index++] = '`STATUS_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::LANG_ID)) { + $modifiedColumns[':p' . $index++] = '`LANG_ID`'; + } + if ($this->isColumnModified(OrderVersionTableMap::CREATED_AT)) { + $modifiedColumns[':p' . $index++] = '`CREATED_AT`'; + } + if ($this->isColumnModified(OrderVersionTableMap::UPDATED_AT)) { + $modifiedColumns[':p' . $index++] = '`UPDATED_AT`'; + } + if ($this->isColumnModified(OrderVersionTableMap::VERSION)) { + $modifiedColumns[':p' . $index++] = '`VERSION`'; + } + if ($this->isColumnModified(OrderVersionTableMap::VERSION_CREATED_AT)) { + $modifiedColumns[':p' . $index++] = '`VERSION_CREATED_AT`'; + } + if ($this->isColumnModified(OrderVersionTableMap::VERSION_CREATED_BY)) { + $modifiedColumns[':p' . $index++] = '`VERSION_CREATED_BY`'; + } + + $sql = sprintf( + 'INSERT INTO `order_version` (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case '`ID`': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case '`REF`': + $stmt->bindValue($identifier, $this->ref, PDO::PARAM_STR); + break; + case '`CUSTOMER_ID`': + $stmt->bindValue($identifier, $this->customer_id, PDO::PARAM_INT); + break; + case '`INVOICE_ORDER_ADDRESS_ID`': + $stmt->bindValue($identifier, $this->invoice_order_address_id, PDO::PARAM_INT); + break; + case '`DELIVERY_ORDER_ADDRESS_ID`': + $stmt->bindValue($identifier, $this->delivery_order_address_id, PDO::PARAM_INT); + break; + case '`INVOICE_DATE`': + $stmt->bindValue($identifier, $this->invoice_date ? $this->invoice_date->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); + break; + case '`CURRENCY_ID`': + $stmt->bindValue($identifier, $this->currency_id, PDO::PARAM_INT); + break; + case '`CURRENCY_RATE`': + $stmt->bindValue($identifier, $this->currency_rate, PDO::PARAM_STR); + break; + case '`TRANSACTION_REF`': + $stmt->bindValue($identifier, $this->transaction_ref, PDO::PARAM_STR); + break; + case '`DELIVERY_REF`': + $stmt->bindValue($identifier, $this->delivery_ref, PDO::PARAM_STR); + break; + case '`INVOICE_REF`': + $stmt->bindValue($identifier, $this->invoice_ref, PDO::PARAM_STR); + break; + case '`DISCOUNT`': + $stmt->bindValue($identifier, $this->discount, PDO::PARAM_STR); + break; + case '`POSTAGE`': + $stmt->bindValue($identifier, $this->postage, PDO::PARAM_STR); + break; + case '`PAYMENT_MODULE_ID`': + $stmt->bindValue($identifier, $this->payment_module_id, PDO::PARAM_INT); + break; + case '`DELIVERY_MODULE_ID`': + $stmt->bindValue($identifier, $this->delivery_module_id, PDO::PARAM_INT); + break; + case '`STATUS_ID`': + $stmt->bindValue($identifier, $this->status_id, PDO::PARAM_INT); + break; + case '`LANG_ID`': + $stmt->bindValue($identifier, $this->lang_id, PDO::PARAM_INT); + break; + case '`CREATED_AT`': + $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); + break; + case '`UPDATED_AT`': + $stmt->bindValue($identifier, $this->updated_at ? $this->updated_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); + break; + case '`VERSION`': + $stmt->bindValue($identifier, $this->version, PDO::PARAM_INT); + break; + case '`VERSION_CREATED_AT`': + $stmt->bindValue($identifier, $this->version_created_at ? $this->version_created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); + break; + case '`VERSION_CREATED_BY`': + $stmt->bindValue($identifier, $this->version_created_by, PDO::PARAM_STR); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = OrderVersionTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getRef(); + break; + case 2: + return $this->getCustomerId(); + break; + case 3: + return $this->getInvoiceOrderAddressId(); + break; + case 4: + return $this->getDeliveryOrderAddressId(); + break; + case 5: + return $this->getInvoiceDate(); + break; + case 6: + return $this->getCurrencyId(); + break; + case 7: + return $this->getCurrencyRate(); + break; + case 8: + return $this->getTransactionRef(); + break; + case 9: + return $this->getDeliveryRef(); + break; + case 10: + return $this->getInvoiceRef(); + break; + case 11: + return $this->getDiscount(); + break; + case 12: + return $this->getPostage(); + break; + case 13: + return $this->getPaymentModuleId(); + break; + case 14: + return $this->getDeliveryModuleId(); + break; + case 15: + return $this->getStatusId(); + break; + case 16: + return $this->getLangId(); + break; + case 17: + return $this->getCreatedAt(); + break; + case 18: + return $this->getUpdatedAt(); + break; + case 19: + return $this->getVersion(); + break; + case 20: + return $this->getVersionCreatedAt(); + break; + case 21: + return $this->getVersionCreatedBy(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + if (isset($alreadyDumpedObjects['OrderVersion'][serialize($this->getPrimaryKey())])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['OrderVersion'][serialize($this->getPrimaryKey())] = true; + $keys = OrderVersionTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getRef(), + $keys[2] => $this->getCustomerId(), + $keys[3] => $this->getInvoiceOrderAddressId(), + $keys[4] => $this->getDeliveryOrderAddressId(), + $keys[5] => $this->getInvoiceDate(), + $keys[6] => $this->getCurrencyId(), + $keys[7] => $this->getCurrencyRate(), + $keys[8] => $this->getTransactionRef(), + $keys[9] => $this->getDeliveryRef(), + $keys[10] => $this->getInvoiceRef(), + $keys[11] => $this->getDiscount(), + $keys[12] => $this->getPostage(), + $keys[13] => $this->getPaymentModuleId(), + $keys[14] => $this->getDeliveryModuleId(), + $keys[15] => $this->getStatusId(), + $keys[16] => $this->getLangId(), + $keys[17] => $this->getCreatedAt(), + $keys[18] => $this->getUpdatedAt(), + $keys[19] => $this->getVersion(), + $keys[20] => $this->getVersionCreatedAt(), + $keys[21] => $this->getVersionCreatedBy(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->aOrder) { + $result['Order'] = $this->aOrder->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return void + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = OrderVersionTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return void + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setRef($value); + break; + case 2: + $this->setCustomerId($value); + break; + case 3: + $this->setInvoiceOrderAddressId($value); + break; + case 4: + $this->setDeliveryOrderAddressId($value); + break; + case 5: + $this->setInvoiceDate($value); + break; + case 6: + $this->setCurrencyId($value); + break; + case 7: + $this->setCurrencyRate($value); + break; + case 8: + $this->setTransactionRef($value); + break; + case 9: + $this->setDeliveryRef($value); + break; + case 10: + $this->setInvoiceRef($value); + break; + case 11: + $this->setDiscount($value); + break; + case 12: + $this->setPostage($value); + break; + case 13: + $this->setPaymentModuleId($value); + break; + case 14: + $this->setDeliveryModuleId($value); + break; + case 15: + $this->setStatusId($value); + break; + case 16: + $this->setLangId($value); + break; + case 17: + $this->setCreatedAt($value); + break; + case 18: + $this->setUpdatedAt($value); + break; + case 19: + $this->setVersion($value); + break; + case 20: + $this->setVersionCreatedAt($value); + break; + case 21: + $this->setVersionCreatedBy($value); + break; + } // switch() + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = OrderVersionTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setRef($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setCustomerId($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setInvoiceOrderAddressId($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setDeliveryOrderAddressId($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setInvoiceDate($arr[$keys[5]]); + if (array_key_exists($keys[6], $arr)) $this->setCurrencyId($arr[$keys[6]]); + if (array_key_exists($keys[7], $arr)) $this->setCurrencyRate($arr[$keys[7]]); + if (array_key_exists($keys[8], $arr)) $this->setTransactionRef($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setDeliveryRef($arr[$keys[9]]); + if (array_key_exists($keys[10], $arr)) $this->setInvoiceRef($arr[$keys[10]]); + if (array_key_exists($keys[11], $arr)) $this->setDiscount($arr[$keys[11]]); + if (array_key_exists($keys[12], $arr)) $this->setPostage($arr[$keys[12]]); + if (array_key_exists($keys[13], $arr)) $this->setPaymentModuleId($arr[$keys[13]]); + if (array_key_exists($keys[14], $arr)) $this->setDeliveryModuleId($arr[$keys[14]]); + if (array_key_exists($keys[15], $arr)) $this->setStatusId($arr[$keys[15]]); + if (array_key_exists($keys[16], $arr)) $this->setLangId($arr[$keys[16]]); + if (array_key_exists($keys[17], $arr)) $this->setCreatedAt($arr[$keys[17]]); + if (array_key_exists($keys[18], $arr)) $this->setUpdatedAt($arr[$keys[18]]); + if (array_key_exists($keys[19], $arr)) $this->setVersion($arr[$keys[19]]); + if (array_key_exists($keys[20], $arr)) $this->setVersionCreatedAt($arr[$keys[20]]); + if (array_key_exists($keys[21], $arr)) $this->setVersionCreatedBy($arr[$keys[21]]); + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(OrderVersionTableMap::DATABASE_NAME); + + if ($this->isColumnModified(OrderVersionTableMap::ID)) $criteria->add(OrderVersionTableMap::ID, $this->id); + if ($this->isColumnModified(OrderVersionTableMap::REF)) $criteria->add(OrderVersionTableMap::REF, $this->ref); + if ($this->isColumnModified(OrderVersionTableMap::CUSTOMER_ID)) $criteria->add(OrderVersionTableMap::CUSTOMER_ID, $this->customer_id); + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID)) $criteria->add(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID, $this->invoice_order_address_id); + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID)) $criteria->add(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID, $this->delivery_order_address_id); + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_DATE)) $criteria->add(OrderVersionTableMap::INVOICE_DATE, $this->invoice_date); + if ($this->isColumnModified(OrderVersionTableMap::CURRENCY_ID)) $criteria->add(OrderVersionTableMap::CURRENCY_ID, $this->currency_id); + if ($this->isColumnModified(OrderVersionTableMap::CURRENCY_RATE)) $criteria->add(OrderVersionTableMap::CURRENCY_RATE, $this->currency_rate); + if ($this->isColumnModified(OrderVersionTableMap::TRANSACTION_REF)) $criteria->add(OrderVersionTableMap::TRANSACTION_REF, $this->transaction_ref); + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_REF)) $criteria->add(OrderVersionTableMap::DELIVERY_REF, $this->delivery_ref); + if ($this->isColumnModified(OrderVersionTableMap::INVOICE_REF)) $criteria->add(OrderVersionTableMap::INVOICE_REF, $this->invoice_ref); + if ($this->isColumnModified(OrderVersionTableMap::DISCOUNT)) $criteria->add(OrderVersionTableMap::DISCOUNT, $this->discount); + if ($this->isColumnModified(OrderVersionTableMap::POSTAGE)) $criteria->add(OrderVersionTableMap::POSTAGE, $this->postage); + if ($this->isColumnModified(OrderVersionTableMap::PAYMENT_MODULE_ID)) $criteria->add(OrderVersionTableMap::PAYMENT_MODULE_ID, $this->payment_module_id); + if ($this->isColumnModified(OrderVersionTableMap::DELIVERY_MODULE_ID)) $criteria->add(OrderVersionTableMap::DELIVERY_MODULE_ID, $this->delivery_module_id); + if ($this->isColumnModified(OrderVersionTableMap::STATUS_ID)) $criteria->add(OrderVersionTableMap::STATUS_ID, $this->status_id); + if ($this->isColumnModified(OrderVersionTableMap::LANG_ID)) $criteria->add(OrderVersionTableMap::LANG_ID, $this->lang_id); + if ($this->isColumnModified(OrderVersionTableMap::CREATED_AT)) $criteria->add(OrderVersionTableMap::CREATED_AT, $this->created_at); + if ($this->isColumnModified(OrderVersionTableMap::UPDATED_AT)) $criteria->add(OrderVersionTableMap::UPDATED_AT, $this->updated_at); + if ($this->isColumnModified(OrderVersionTableMap::VERSION)) $criteria->add(OrderVersionTableMap::VERSION, $this->version); + if ($this->isColumnModified(OrderVersionTableMap::VERSION_CREATED_AT)) $criteria->add(OrderVersionTableMap::VERSION_CREATED_AT, $this->version_created_at); + if ($this->isColumnModified(OrderVersionTableMap::VERSION_CREATED_BY)) $criteria->add(OrderVersionTableMap::VERSION_CREATED_BY, $this->version_created_by); + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = new Criteria(OrderVersionTableMap::DATABASE_NAME); + $criteria->add(OrderVersionTableMap::ID, $this->id); + $criteria->add(OrderVersionTableMap::VERSION, $this->version); + + return $criteria; + } + + /** + * Returns the composite primary key for this object. + * The array elements will be in same order as specified in XML. + * @return array + */ + public function getPrimaryKey() + { + $pks = array(); + $pks[0] = $this->getId(); + $pks[1] = $this->getVersion(); + + return $pks; + } + + /** + * Set the [composite] primary key. + * + * @param array $keys The elements of the composite key (order must match the order in XML file). + * @return void + */ + public function setPrimaryKey($keys) + { + $this->setId($keys[0]); + $this->setVersion($keys[1]); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + + return (null === $this->getId()) && (null === $this->getVersion()); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Thelia\Model\OrderVersion (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setId($this->getId()); + $copyObj->setRef($this->getRef()); + $copyObj->setCustomerId($this->getCustomerId()); + $copyObj->setInvoiceOrderAddressId($this->getInvoiceOrderAddressId()); + $copyObj->setDeliveryOrderAddressId($this->getDeliveryOrderAddressId()); + $copyObj->setInvoiceDate($this->getInvoiceDate()); + $copyObj->setCurrencyId($this->getCurrencyId()); + $copyObj->setCurrencyRate($this->getCurrencyRate()); + $copyObj->setTransactionRef($this->getTransactionRef()); + $copyObj->setDeliveryRef($this->getDeliveryRef()); + $copyObj->setInvoiceRef($this->getInvoiceRef()); + $copyObj->setDiscount($this->getDiscount()); + $copyObj->setPostage($this->getPostage()); + $copyObj->setPaymentModuleId($this->getPaymentModuleId()); + $copyObj->setDeliveryModuleId($this->getDeliveryModuleId()); + $copyObj->setStatusId($this->getStatusId()); + $copyObj->setLangId($this->getLangId()); + $copyObj->setCreatedAt($this->getCreatedAt()); + $copyObj->setUpdatedAt($this->getUpdatedAt()); + $copyObj->setVersion($this->getVersion()); + $copyObj->setVersionCreatedAt($this->getVersionCreatedAt()); + $copyObj->setVersionCreatedBy($this->getVersionCreatedBy()); + if ($makeNew) { + $copyObj->setNew(true); + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Thelia\Model\OrderVersion Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + /** + * Declares an association between this object and a ChildOrder object. + * + * @param ChildOrder $v + * @return \Thelia\Model\OrderVersion The current object (for fluent API support) + * @throws PropelException + */ + public function setOrder(ChildOrder $v = null) + { + if ($v === null) { + $this->setId(NULL); + } else { + $this->setId($v->getId()); + } + + $this->aOrder = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildOrder object, it will not be re-added. + if ($v !== null) { + $v->addOrderVersion($this); + } + + + return $this; + } + + + /** + * Get the associated ChildOrder object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildOrder The associated ChildOrder object. + * @throws PropelException + */ + public function getOrder(ConnectionInterface $con = null) + { + if ($this->aOrder === null && ($this->id !== null)) { + $this->aOrder = ChildOrderQuery::create()->findPk($this->id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aOrder->addOrderVersions($this); + */ + } + + return $this->aOrder; + } + + /** + * Clears the current object and sets all attributes to their default values + */ + public function clear() + { + $this->id = null; + $this->ref = null; + $this->customer_id = null; + $this->invoice_order_address_id = null; + $this->delivery_order_address_id = null; + $this->invoice_date = null; + $this->currency_id = null; + $this->currency_rate = null; + $this->transaction_ref = null; + $this->delivery_ref = null; + $this->invoice_ref = null; + $this->discount = null; + $this->postage = null; + $this->payment_module_id = null; + $this->delivery_module_id = null; + $this->status_id = null; + $this->lang_id = null; + $this->created_at = null; + $this->updated_at = null; + $this->version = null; + $this->version_created_at = null; + $this->version_created_by = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->applyDefaultValues(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references to other model objects or collections of model objects. + * + * This method is a user-space workaround for PHP's inability to garbage collect + * objects with circular references (even in PHP 5.3). This is currently necessary + * when using Propel in certain daemon or large-volume/high-memory operations. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + } // if ($deep) + + $this->aOrder = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(OrderVersionTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/core/lib/Thelia/Model/Base/OrderVersionQuery.php b/core/lib/Thelia/Model/Base/OrderVersionQuery.php new file mode 100644 index 000000000..5d4dd6211 --- /dev/null +++ b/core/lib/Thelia/Model/Base/OrderVersionQuery.php @@ -0,0 +1,1335 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(array(12, 34), $con); + * + * + * @param array[$id, $version] $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildOrderVersion|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, $con = null) + { + if ($key === null) { + return null; + } + if ((null !== ($obj = OrderVersionTableMap::getInstanceFromPool(serialize(array((string) $key[0], (string) $key[1]))))) && !$this->formatter) { + // the object is already in the instance pool + return $obj; + } + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(OrderVersionTableMap::DATABASE_NAME); + } + $this->basePreSelect($con); + if ($this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins) { + return $this->findPkComplex($key, $con); + } else { + return $this->findPkSimple($key, $con); + } + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildOrderVersion A model object, or null if the key is not found + */ + protected function findPkSimple($key, $con) + { + $sql = 'SELECT `ID`, `REF`, `CUSTOMER_ID`, `INVOICE_ORDER_ADDRESS_ID`, `DELIVERY_ORDER_ADDRESS_ID`, `INVOICE_DATE`, `CURRENCY_ID`, `CURRENCY_RATE`, `TRANSACTION_REF`, `DELIVERY_REF`, `INVOICE_REF`, `DISCOUNT`, `POSTAGE`, `PAYMENT_MODULE_ID`, `DELIVERY_MODULE_ID`, `STATUS_ID`, `LANG_ID`, `CREATED_AT`, `UPDATED_AT`, `VERSION`, `VERSION_CREATED_AT`, `VERSION_CREATED_BY` FROM `order_version` WHERE `ID` = :p0 AND `VERSION` = :p1'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key[0], PDO::PARAM_INT); + $stmt->bindValue(':p1', $key[1], PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + $obj = new ChildOrderVersion(); + $obj->hydrate($row); + OrderVersionTableMap::addInstanceToPool($obj, serialize(array((string) $key[0], (string) $key[1]))); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildOrderVersion|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(array(12, 56), array(832, 123), array(123, 456)), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + $this->addUsingAlias(OrderVersionTableMap::ID, $key[0], Criteria::EQUAL); + $this->addUsingAlias(OrderVersionTableMap::VERSION, $key[1], Criteria::EQUAL); + + return $this; + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + if (empty($keys)) { + return $this->add(null, '1<>1', Criteria::CUSTOM); + } + foreach ($keys as $key) { + $cton0 = $this->getNewCriterion(OrderVersionTableMap::ID, $key[0], Criteria::EQUAL); + $cton1 = $this->getNewCriterion(OrderVersionTableMap::VERSION, $key[1], Criteria::EQUAL); + $cton0->addAnd($cton1); + $this->addOr($cton0); + } + + return $this; + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @see filterByOrder() + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(OrderVersionTableMap::ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(OrderVersionTableMap::ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::ID, $id, $comparison); + } + + /** + * Filter the query on the ref column + * + * Example usage: + * + * $query->filterByRef('fooValue'); // WHERE ref = 'fooValue' + * $query->filterByRef('%fooValue%'); // WHERE ref LIKE '%fooValue%' + * + * + * @param string $ref The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByRef($ref = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($ref)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $ref)) { + $ref = str_replace('*', '%', $ref); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::REF, $ref, $comparison); + } + + /** + * Filter the query on the customer_id column + * + * Example usage: + * + * $query->filterByCustomerId(1234); // WHERE customer_id = 1234 + * $query->filterByCustomerId(array(12, 34)); // WHERE customer_id IN (12, 34) + * $query->filterByCustomerId(array('min' => 12)); // WHERE customer_id > 12 + * + * + * @param mixed $customerId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByCustomerId($customerId = null, $comparison = null) + { + if (is_array($customerId)) { + $useMinMax = false; + if (isset($customerId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::CUSTOMER_ID, $customerId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($customerId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::CUSTOMER_ID, $customerId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::CUSTOMER_ID, $customerId, $comparison); + } + + /** + * Filter the query on the invoice_order_address_id column + * + * Example usage: + * + * $query->filterByInvoiceOrderAddressId(1234); // WHERE invoice_order_address_id = 1234 + * $query->filterByInvoiceOrderAddressId(array(12, 34)); // WHERE invoice_order_address_id IN (12, 34) + * $query->filterByInvoiceOrderAddressId(array('min' => 12)); // WHERE invoice_order_address_id > 12 + * + * + * @param mixed $invoiceOrderAddressId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByInvoiceOrderAddressId($invoiceOrderAddressId = null, $comparison = null) + { + if (is_array($invoiceOrderAddressId)) { + $useMinMax = false; + if (isset($invoiceOrderAddressId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID, $invoiceOrderAddressId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($invoiceOrderAddressId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID, $invoiceOrderAddressId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID, $invoiceOrderAddressId, $comparison); + } + + /** + * Filter the query on the delivery_order_address_id column + * + * Example usage: + * + * $query->filterByDeliveryOrderAddressId(1234); // WHERE delivery_order_address_id = 1234 + * $query->filterByDeliveryOrderAddressId(array(12, 34)); // WHERE delivery_order_address_id IN (12, 34) + * $query->filterByDeliveryOrderAddressId(array('min' => 12)); // WHERE delivery_order_address_id > 12 + * + * + * @param mixed $deliveryOrderAddressId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByDeliveryOrderAddressId($deliveryOrderAddressId = null, $comparison = null) + { + if (is_array($deliveryOrderAddressId)) { + $useMinMax = false; + if (isset($deliveryOrderAddressId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID, $deliveryOrderAddressId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($deliveryOrderAddressId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID, $deliveryOrderAddressId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID, $deliveryOrderAddressId, $comparison); + } + + /** + * Filter the query on the invoice_date column + * + * Example usage: + * + * $query->filterByInvoiceDate('2011-03-14'); // WHERE invoice_date = '2011-03-14' + * $query->filterByInvoiceDate('now'); // WHERE invoice_date = '2011-03-14' + * $query->filterByInvoiceDate(array('max' => 'yesterday')); // WHERE invoice_date > '2011-03-13' + * + * + * @param mixed $invoiceDate The value to use as filter. + * Values can be integers (unix timestamps), DateTime objects, or strings. + * Empty strings are treated as NULL. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByInvoiceDate($invoiceDate = null, $comparison = null) + { + if (is_array($invoiceDate)) { + $useMinMax = false; + if (isset($invoiceDate['min'])) { + $this->addUsingAlias(OrderVersionTableMap::INVOICE_DATE, $invoiceDate['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($invoiceDate['max'])) { + $this->addUsingAlias(OrderVersionTableMap::INVOICE_DATE, $invoiceDate['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::INVOICE_DATE, $invoiceDate, $comparison); + } + + /** + * Filter the query on the currency_id column + * + * Example usage: + * + * $query->filterByCurrencyId(1234); // WHERE currency_id = 1234 + * $query->filterByCurrencyId(array(12, 34)); // WHERE currency_id IN (12, 34) + * $query->filterByCurrencyId(array('min' => 12)); // WHERE currency_id > 12 + * + * + * @param mixed $currencyId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByCurrencyId($currencyId = null, $comparison = null) + { + if (is_array($currencyId)) { + $useMinMax = false; + if (isset($currencyId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::CURRENCY_ID, $currencyId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($currencyId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::CURRENCY_ID, $currencyId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::CURRENCY_ID, $currencyId, $comparison); + } + + /** + * Filter the query on the currency_rate column + * + * Example usage: + * + * $query->filterByCurrencyRate(1234); // WHERE currency_rate = 1234 + * $query->filterByCurrencyRate(array(12, 34)); // WHERE currency_rate IN (12, 34) + * $query->filterByCurrencyRate(array('min' => 12)); // WHERE currency_rate > 12 + * + * + * @param mixed $currencyRate The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByCurrencyRate($currencyRate = null, $comparison = null) + { + if (is_array($currencyRate)) { + $useMinMax = false; + if (isset($currencyRate['min'])) { + $this->addUsingAlias(OrderVersionTableMap::CURRENCY_RATE, $currencyRate['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($currencyRate['max'])) { + $this->addUsingAlias(OrderVersionTableMap::CURRENCY_RATE, $currencyRate['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::CURRENCY_RATE, $currencyRate, $comparison); + } + + /** + * Filter the query on the transaction_ref column + * + * Example usage: + * + * $query->filterByTransactionRef('fooValue'); // WHERE transaction_ref = 'fooValue' + * $query->filterByTransactionRef('%fooValue%'); // WHERE transaction_ref LIKE '%fooValue%' + * + * + * @param string $transactionRef The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByTransactionRef($transactionRef = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($transactionRef)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $transactionRef)) { + $transactionRef = str_replace('*', '%', $transactionRef); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::TRANSACTION_REF, $transactionRef, $comparison); + } + + /** + * Filter the query on the delivery_ref column + * + * Example usage: + * + * $query->filterByDeliveryRef('fooValue'); // WHERE delivery_ref = 'fooValue' + * $query->filterByDeliveryRef('%fooValue%'); // WHERE delivery_ref LIKE '%fooValue%' + * + * + * @param string $deliveryRef The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByDeliveryRef($deliveryRef = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($deliveryRef)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $deliveryRef)) { + $deliveryRef = str_replace('*', '%', $deliveryRef); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::DELIVERY_REF, $deliveryRef, $comparison); + } + + /** + * Filter the query on the invoice_ref column + * + * Example usage: + * + * $query->filterByInvoiceRef('fooValue'); // WHERE invoice_ref = 'fooValue' + * $query->filterByInvoiceRef('%fooValue%'); // WHERE invoice_ref LIKE '%fooValue%' + * + * + * @param string $invoiceRef The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByInvoiceRef($invoiceRef = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($invoiceRef)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $invoiceRef)) { + $invoiceRef = str_replace('*', '%', $invoiceRef); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::INVOICE_REF, $invoiceRef, $comparison); + } + + /** + * Filter the query on the discount column + * + * Example usage: + * + * $query->filterByDiscount(1234); // WHERE discount = 1234 + * $query->filterByDiscount(array(12, 34)); // WHERE discount IN (12, 34) + * $query->filterByDiscount(array('min' => 12)); // WHERE discount > 12 + * + * + * @param mixed $discount The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByDiscount($discount = null, $comparison = null) + { + if (is_array($discount)) { + $useMinMax = false; + if (isset($discount['min'])) { + $this->addUsingAlias(OrderVersionTableMap::DISCOUNT, $discount['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($discount['max'])) { + $this->addUsingAlias(OrderVersionTableMap::DISCOUNT, $discount['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::DISCOUNT, $discount, $comparison); + } + + /** + * Filter the query on the postage column + * + * Example usage: + * + * $query->filterByPostage(1234); // WHERE postage = 1234 + * $query->filterByPostage(array(12, 34)); // WHERE postage IN (12, 34) + * $query->filterByPostage(array('min' => 12)); // WHERE postage > 12 + * + * + * @param mixed $postage The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByPostage($postage = null, $comparison = null) + { + if (is_array($postage)) { + $useMinMax = false; + if (isset($postage['min'])) { + $this->addUsingAlias(OrderVersionTableMap::POSTAGE, $postage['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($postage['max'])) { + $this->addUsingAlias(OrderVersionTableMap::POSTAGE, $postage['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::POSTAGE, $postage, $comparison); + } + + /** + * Filter the query on the payment_module_id column + * + * Example usage: + * + * $query->filterByPaymentModuleId(1234); // WHERE payment_module_id = 1234 + * $query->filterByPaymentModuleId(array(12, 34)); // WHERE payment_module_id IN (12, 34) + * $query->filterByPaymentModuleId(array('min' => 12)); // WHERE payment_module_id > 12 + * + * + * @param mixed $paymentModuleId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByPaymentModuleId($paymentModuleId = null, $comparison = null) + { + if (is_array($paymentModuleId)) { + $useMinMax = false; + if (isset($paymentModuleId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::PAYMENT_MODULE_ID, $paymentModuleId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($paymentModuleId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::PAYMENT_MODULE_ID, $paymentModuleId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::PAYMENT_MODULE_ID, $paymentModuleId, $comparison); + } + + /** + * Filter the query on the delivery_module_id column + * + * Example usage: + * + * $query->filterByDeliveryModuleId(1234); // WHERE delivery_module_id = 1234 + * $query->filterByDeliveryModuleId(array(12, 34)); // WHERE delivery_module_id IN (12, 34) + * $query->filterByDeliveryModuleId(array('min' => 12)); // WHERE delivery_module_id > 12 + * + * + * @param mixed $deliveryModuleId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByDeliveryModuleId($deliveryModuleId = null, $comparison = null) + { + if (is_array($deliveryModuleId)) { + $useMinMax = false; + if (isset($deliveryModuleId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::DELIVERY_MODULE_ID, $deliveryModuleId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($deliveryModuleId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::DELIVERY_MODULE_ID, $deliveryModuleId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::DELIVERY_MODULE_ID, $deliveryModuleId, $comparison); + } + + /** + * Filter the query on the status_id column + * + * Example usage: + * + * $query->filterByStatusId(1234); // WHERE status_id = 1234 + * $query->filterByStatusId(array(12, 34)); // WHERE status_id IN (12, 34) + * $query->filterByStatusId(array('min' => 12)); // WHERE status_id > 12 + * + * + * @param mixed $statusId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByStatusId($statusId = null, $comparison = null) + { + if (is_array($statusId)) { + $useMinMax = false; + if (isset($statusId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::STATUS_ID, $statusId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($statusId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::STATUS_ID, $statusId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::STATUS_ID, $statusId, $comparison); + } + + /** + * Filter the query on the lang_id column + * + * Example usage: + * + * $query->filterByLangId(1234); // WHERE lang_id = 1234 + * $query->filterByLangId(array(12, 34)); // WHERE lang_id IN (12, 34) + * $query->filterByLangId(array('min' => 12)); // WHERE lang_id > 12 + * + * + * @param mixed $langId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByLangId($langId = null, $comparison = null) + { + if (is_array($langId)) { + $useMinMax = false; + if (isset($langId['min'])) { + $this->addUsingAlias(OrderVersionTableMap::LANG_ID, $langId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($langId['max'])) { + $this->addUsingAlias(OrderVersionTableMap::LANG_ID, $langId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::LANG_ID, $langId, $comparison); + } + + /** + * Filter the query on the created_at column + * + * Example usage: + * + * $query->filterByCreatedAt('2011-03-14'); // WHERE created_at = '2011-03-14' + * $query->filterByCreatedAt('now'); // WHERE created_at = '2011-03-14' + * $query->filterByCreatedAt(array('max' => 'yesterday')); // WHERE created_at > '2011-03-13' + * + * + * @param mixed $createdAt The value to use as filter. + * Values can be integers (unix timestamps), DateTime objects, or strings. + * Empty strings are treated as NULL. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByCreatedAt($createdAt = null, $comparison = null) + { + if (is_array($createdAt)) { + $useMinMax = false; + if (isset($createdAt['min'])) { + $this->addUsingAlias(OrderVersionTableMap::CREATED_AT, $createdAt['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($createdAt['max'])) { + $this->addUsingAlias(OrderVersionTableMap::CREATED_AT, $createdAt['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::CREATED_AT, $createdAt, $comparison); + } + + /** + * Filter the query on the updated_at column + * + * Example usage: + * + * $query->filterByUpdatedAt('2011-03-14'); // WHERE updated_at = '2011-03-14' + * $query->filterByUpdatedAt('now'); // WHERE updated_at = '2011-03-14' + * $query->filterByUpdatedAt(array('max' => 'yesterday')); // WHERE updated_at > '2011-03-13' + * + * + * @param mixed $updatedAt The value to use as filter. + * Values can be integers (unix timestamps), DateTime objects, or strings. + * Empty strings are treated as NULL. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByUpdatedAt($updatedAt = null, $comparison = null) + { + if (is_array($updatedAt)) { + $useMinMax = false; + if (isset($updatedAt['min'])) { + $this->addUsingAlias(OrderVersionTableMap::UPDATED_AT, $updatedAt['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($updatedAt['max'])) { + $this->addUsingAlias(OrderVersionTableMap::UPDATED_AT, $updatedAt['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::UPDATED_AT, $updatedAt, $comparison); + } + + /** + * Filter the query on the version column + * + * Example usage: + * + * $query->filterByVersion(1234); // WHERE version = 1234 + * $query->filterByVersion(array(12, 34)); // WHERE version IN (12, 34) + * $query->filterByVersion(array('min' => 12)); // WHERE version > 12 + * + * + * @param mixed $version The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByVersion($version = null, $comparison = null) + { + if (is_array($version)) { + $useMinMax = false; + if (isset($version['min'])) { + $this->addUsingAlias(OrderVersionTableMap::VERSION, $version['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($version['max'])) { + $this->addUsingAlias(OrderVersionTableMap::VERSION, $version['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::VERSION, $version, $comparison); + } + + /** + * Filter the query on the version_created_at column + * + * Example usage: + * + * $query->filterByVersionCreatedAt('2011-03-14'); // WHERE version_created_at = '2011-03-14' + * $query->filterByVersionCreatedAt('now'); // WHERE version_created_at = '2011-03-14' + * $query->filterByVersionCreatedAt(array('max' => 'yesterday')); // WHERE version_created_at > '2011-03-13' + * + * + * @param mixed $versionCreatedAt The value to use as filter. + * Values can be integers (unix timestamps), DateTime objects, or strings. + * Empty strings are treated as NULL. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByVersionCreatedAt($versionCreatedAt = null, $comparison = null) + { + if (is_array($versionCreatedAt)) { + $useMinMax = false; + if (isset($versionCreatedAt['min'])) { + $this->addUsingAlias(OrderVersionTableMap::VERSION_CREATED_AT, $versionCreatedAt['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($versionCreatedAt['max'])) { + $this->addUsingAlias(OrderVersionTableMap::VERSION_CREATED_AT, $versionCreatedAt['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::VERSION_CREATED_AT, $versionCreatedAt, $comparison); + } + + /** + * Filter the query on the version_created_by column + * + * Example usage: + * + * $query->filterByVersionCreatedBy('fooValue'); // WHERE version_created_by = 'fooValue' + * $query->filterByVersionCreatedBy('%fooValue%'); // WHERE version_created_by LIKE '%fooValue%' + * + * + * @param string $versionCreatedBy The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByVersionCreatedBy($versionCreatedBy = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($versionCreatedBy)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $versionCreatedBy)) { + $versionCreatedBy = str_replace('*', '%', $versionCreatedBy); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(OrderVersionTableMap::VERSION_CREATED_BY, $versionCreatedBy, $comparison); + } + + /** + * Filter the query by a related \Thelia\Model\Order object + * + * @param \Thelia\Model\Order|ObjectCollection $order The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function filterByOrder($order, $comparison = null) + { + if ($order instanceof \Thelia\Model\Order) { + return $this + ->addUsingAlias(OrderVersionTableMap::ID, $order->getId(), $comparison); + } elseif ($order instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(OrderVersionTableMap::ID, $order->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByOrder() only accepts arguments of type \Thelia\Model\Order or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Order relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function joinOrder($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Order'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Order'); + } + + return $this; + } + + /** + * Use the Order relation Order object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \Thelia\Model\OrderQuery A secondary query class using the current class as primary query + */ + public function useOrderQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinOrder($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Order', '\Thelia\Model\OrderQuery'); + } + + /** + * Exclude object from result + * + * @param ChildOrderVersion $orderVersion Object to remove from the list of results + * + * @return ChildOrderVersionQuery The current query, for fluid interface + */ + public function prune($orderVersion = null) + { + if ($orderVersion) { + $this->addCond('pruneCond0', $this->getAliasedColName(OrderVersionTableMap::ID), $orderVersion->getId(), Criteria::NOT_EQUAL); + $this->addCond('pruneCond1', $this->getAliasedColName(OrderVersionTableMap::VERSION), $orderVersion->getVersion(), Criteria::NOT_EQUAL); + $this->combine(array('pruneCond0', 'pruneCond1'), Criteria::LOGICAL_OR); + } + + return $this; + } + + /** + * Deletes all rows from the order_version table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + $affectedRows = 0; // initialize var to track total num of affected rows + try { + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + $con->beginTransaction(); + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + OrderVersionTableMap::clearInstancePool(); + OrderVersionTableMap::clearRelatedInstancePool(); + + $con->commit(); + } catch (PropelException $e) { + $con->rollBack(); + throw $e; + } + + return $affectedRows; + } + + /** + * Performs a DELETE on the database, given a ChildOrderVersion or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or ChildOrderVersion object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(OrderVersionTableMap::DATABASE_NAME); + + $affectedRows = 0; // initialize var to track total num of affected rows + + try { + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + $con->beginTransaction(); + + + OrderVersionTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + OrderVersionTableMap::clearRelatedInstancePool(); + $con->commit(); + + return $affectedRows; + } catch (PropelException $e) { + $con->rollBack(); + throw $e; + } + } + +} // OrderVersionQuery diff --git a/core/lib/Thelia/Model/Breadcrumb/BreadcrumbInterface.php b/core/lib/Thelia/Model/Breadcrumb/BreadcrumbInterface.php new file mode 100644 index 000000000..dcb928c78 --- /dev/null +++ b/core/lib/Thelia/Model/Breadcrumb/BreadcrumbInterface.php @@ -0,0 +1,28 @@ +generate('admin.catalog', [], Router::ABSOLUTE_URL); + $breadcrumb = [ + $translator->trans('Home', [], 'bo.default') => $router->generate('admin.home.view', [], Router::ABSOLUTE_URL), + $translator->trans('Catalog', [], 'bo.default') => $catalogUrl, + ]; + + $categoryPath = new CategoryPath($container); + $categoryPath->initializeArgs([ + 'category' => $categoryId, + 'visible' => '*' + ]); + + $results = $categoryPath->buildArray(); + + foreach ($results as $result) { + $breadcrumb[$result['TITLE']] = sprintf("%s?category_id=%d",$catalogUrl, $result['ID']); + } + + $locale = $result['LOCALE']; + + return $breadcrumb; + } + + public function getProductBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + $product = $this->getProduct(); + $locale = null; + + $breadcrumb = $this->getBaseBreadcrumb($router, $container, $product->getDefaultCategoryId(), $locale); + + $product->setLocale($locale); + + $breadcrumb[$product->getTitle()] = sprintf("%s?product_id=%d¤t_tab=%s", + $router->generate('admin.products.update', [], Router::ABSOLUTE_URL), + $product->getId(), + $tab + ); + + return $breadcrumb; + } + + public function getCategoryBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + $locale = null; + $category = $this->getCategory(); + $breadcrumb = $this->getBaseBreadcrumb($router, $container, $this->getParentId(), $locale); + + $category->setLocale($locale); + + $breadcrumb[$category->getTitle()] = sprintf("%s?category_id=%d¤t_tab=%s", + $router->generate('admin.categories.update',[], Router::ABSOLUTE_URL), + $category->getId(), + $tab + ); + + return $breadcrumb; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Breadcrumb/FolderBreadcrumbTrait.php b/core/lib/Thelia/Model/Breadcrumb/FolderBreadcrumbTrait.php new file mode 100644 index 000000000..3711002c3 --- /dev/null +++ b/core/lib/Thelia/Model/Breadcrumb/FolderBreadcrumbTrait.php @@ -0,0 +1,85 @@ +generate('admin.catalog', [], Router::ABSOLUTE_URL); + $breadcrumb = [ + $translator->trans('Home', [], 'bo.default') => $router->generate('admin.home.view', [], Router::ABSOLUTE_URL), + $translator->trans('Folder', [], 'bo.default') => $catalogUrl, + ]; + + $folderPath = new FolderPath($container); + $folderPath->initializeArgs([ + 'folder' => $folderId, + 'visible' => '*' + ]); + + $results = $folderPath->buildArray(); + + foreach ($results as $result) { + $breadcrumb[$result['TITLE']] = sprintf("%s?folder_id=%d", + $router->generate('admin.folders.default',[], Router::ABSOLUTE_URL), + $result['ID'] + ); + } + + $locale = $result['LOCALE']; + + return $breadcrumb; + } + + public function getFolderBreadcrumb($router, $container, $tab) + { + $locale = null; + $folder = $this->getFolder(); + $breadcrumb = $this->getBaseBreadcrumb($router, $container, $this->getParentId(), $locale); + + $folder->setLocale($locale); + + $breadcrumb[$folder->getTitle()] = sprintf("%s?current_tab=%s", + $router->generate('admin.folders.update',['folder_id' => $folder->getId()], Router::ABSOLUTE_URL), + $tab + ); + + return $breadcrumb; + } + + public function getContentBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + $content = $this->getContent(); + $locale = null; + + $breadcrumb = $this->getBaseBreadcrumb($router, $container, $content->getDefaultFolderId(), $locale); + + $content->setLocale($locale); + + $breadcrumb[$content->getTitle()] = sprintf("%s?current_tab=%s", + $router->generate('admin.content.update', ['content_id' => $content->getId()], Router::ABSOLUTE_URL), + $tab + ); + + return $breadcrumb; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Cart.php b/core/lib/Thelia/Model/Cart.php index aab17db46..b789374a8 100644 --- a/core/lib/Thelia/Model/Cart.php +++ b/core/lib/Thelia/Model/Cart.php @@ -44,7 +44,6 @@ class Cart extends BaseCart } $cart->save(); - $currentDateTime = new \DateTime(); foreach ($cartItems as $cartItem) { $product = $cartItem->getProduct(); diff --git a/core/lib/Thelia/Model/CartItem.php b/core/lib/Thelia/Model/CartItem.php index 7818f63d2..50f47c718 100644 --- a/core/lib/Thelia/Model/CartItem.php +++ b/core/lib/Thelia/Model/CartItem.php @@ -89,6 +89,23 @@ class CartItem extends BaseCartItem return $this->getPromo() == 1 ? $this->getPromoPrice() : $this->getPrice(); } + public function getProduct(ConnectionInterface $con = null, $locale = null) + { + $product = parent::getProduct($con); + + $translation = $product->getTranslation($locale); + + if ($translation->isNew()) { + if (ConfigQuery::getDefaultLangWhenNoTranslationAvailable()) { + $locale = Lang::getDefaultLanguage()->getLocale(); + } + } + + $product->setLocale($locale); + + return $product; + } + public function getRealTaxedPrice(Country $country) { return $this->getPromo() == 1 ? $this->getTaxedPromoPrice($country) : $this->getTaxedPrice($country); diff --git a/core/lib/Thelia/Model/CategoryDocument.php b/core/lib/Thelia/Model/CategoryDocument.php index a8cb463b7..4b20d8a59 100644 --- a/core/lib/Thelia/Model/CategoryDocument.php +++ b/core/lib/Thelia/Model/CategoryDocument.php @@ -2,13 +2,20 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\CategoryDocument as BaseCategoryDocument; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\CatalogBreadcrumbTrait; +use Thelia\Model\Tools\PositionManagementTrait; +use Thelia\Model\Tools\ModelEventDispatcherTrait; -class CategoryDocument extends BaseCategoryDocument +class CategoryDocument extends BaseCategoryDocument implements BreadcrumbInterface { - use \Thelia\Model\Tools\ModelEventDispatcherTrait; - use \Thelia\Model\Tools\PositionManagementTrait; + use ModelEventDispatcherTrait; + use PositionManagementTrait; + use CatalogBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +69,15 @@ class CategoryDocument extends BaseCategoryDocument return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getCategoryBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/CategoryImage.php b/core/lib/Thelia/Model/CategoryImage.php index f21a6d37c..5c277eba6 100644 --- a/core/lib/Thelia/Model/CategoryImage.php +++ b/core/lib/Thelia/Model/CategoryImage.php @@ -2,13 +2,20 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\CategoryImage as BaseCategoryImage; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\CatalogBreadcrumbTrait; +use Thelia\Model\Tools\ModelEventDispatcherTrait; +use Thelia\Model\Tools\PositionManagementTrait; -class CategoryImage extends BaseCategoryImage +class CategoryImage extends BaseCategoryImage implements BreadcrumbInterface { - use \Thelia\Model\Tools\ModelEventDispatcherTrait; - use \Thelia\Model\Tools\PositionManagementTrait; + use ModelEventDispatcherTrait; + use PositionManagementTrait; + use CatalogBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +69,15 @@ class CategoryImage extends BaseCategoryImage return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getCategoryBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/ConfigQuery.php b/core/lib/Thelia/Model/ConfigQuery.php index 31c56e229..9a688b80b 100644 --- a/core/lib/Thelia/Model/ConfigQuery.php +++ b/core/lib/Thelia/Model/ConfigQuery.php @@ -73,6 +73,11 @@ class ConfigQuery extends BaseConfigQuery return true; } + public static function getConfiguredShopUrl() + { + return ConfigQuery::read("url_site", ''); + } + public static function getDefaultLangWhenNoTranslationAvailable() { return ConfigQuery::read("default_lang_without_translation", 1); diff --git a/core/lib/Thelia/Model/ContentDocument.php b/core/lib/Thelia/Model/ContentDocument.php index 0ffa355d7..bd3e16ec9 100644 --- a/core/lib/Thelia/Model/ContentDocument.php +++ b/core/lib/Thelia/Model/ContentDocument.php @@ -2,13 +2,18 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\ContentDocument as BaseContentDocument; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\FolderBreadcrumbTrait; -class ContentDocument extends BaseContentDocument +class ContentDocument extends BaseContentDocument implements BreadcrumbInterface { use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\PositionManagementTrait; + use FolderBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +67,15 @@ class ContentDocument extends BaseContentDocument return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getContentBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/ContentImage.php b/core/lib/Thelia/Model/ContentImage.php index d8b919647..98fe5a669 100644 --- a/core/lib/Thelia/Model/ContentImage.php +++ b/core/lib/Thelia/Model/ContentImage.php @@ -2,13 +2,18 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\ContentImage as BaseContentImage; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\FolderBreadcrumbTrait; -class ContentImage extends BaseContentImage +class ContentImage extends BaseContentImage implements BreadcrumbInterface { use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\PositionManagementTrait; + use FolderBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +67,15 @@ class ContentImage extends BaseContentImage return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getContentBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index 45f701876..c8b15d43d 100644 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -41,6 +41,9 @@ use Thelia\Model\Tools\ModelEventDispatcherTrait; class Coupon extends BaseCoupon { + // Define the value of an unlimited coupon usage. + const UNLIMITED_COUPON_USE = -1; + use ModelEventDispatcherTrait; /** @@ -184,7 +187,8 @@ class Coupon extends BaseCoupon */ public function getAmount() { - $amount = $this->getEffects()['amount']; + // Amount is now optional + $amount = isset($this->getEffects()['amount']) ? $this->getEffects()['amount'] : 0; return floatval($amount); } @@ -199,10 +203,6 @@ class Coupon extends BaseCoupon { $effects = $this->unserializeEffects($this->getSerializedEffects()); - if (null === $effects['amount']) { - throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect coming from database'); - } - return $effects; } @@ -210,18 +210,12 @@ class Coupon extends BaseCoupon * Get the Coupon effects * * @param array $effects Effect ready to be serialized - * Needs at least the key 'amount' - * with the amount removed from the cart * * @throws Exception\InvalidArgumentException * @return $this */ public function setEffects(array $effects) { - if (null === $effects['amount']) { - throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect ready to be serialized array'); - } - $this->setSerializedEffects($this->serializeEffects($effects)); return $this; @@ -274,6 +268,10 @@ class Coupon extends BaseCoupon return CouponModuleQuery::create()->filterByCouponId($this->getId())->find(); } + public function isUsageUnlimited() + { + return $this->getMaxUsage() == self::UNLIMITED_COUPON_USE; + } /** * Get coupon usage left, either overall, or per customer. * diff --git a/core/lib/Thelia/Model/FolderDocument.php b/core/lib/Thelia/Model/FolderDocument.php index 3fce9450f..9e38d37fc 100644 --- a/core/lib/Thelia/Model/FolderDocument.php +++ b/core/lib/Thelia/Model/FolderDocument.php @@ -2,13 +2,18 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\FolderDocument as BaseFolderDocument; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\FolderBreadcrumbTrait; -class FolderDocument extends BaseFolderDocument +class FolderDocument extends BaseFolderDocument implements BreadcrumbInterface { use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\PositionManagementTrait; + use FolderBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +67,9 @@ class FolderDocument extends BaseFolderDocument return true; } + + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getFolderBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/FolderImage.php b/core/lib/Thelia/Model/FolderImage.php index 8c66e98d2..dfc630190 100644 --- a/core/lib/Thelia/Model/FolderImage.php +++ b/core/lib/Thelia/Model/FolderImage.php @@ -2,13 +2,18 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\FolderImage as BaseFolderImage; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\FolderBreadcrumbTrait; -class FolderImage extends BaseFolderImage +class FolderImage extends BaseFolderImage implements BreadcrumbInterface { use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\PositionManagementTrait; + use FolderBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +67,15 @@ class FolderImage extends BaseFolderImage return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getFolderBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/Lang.php b/core/lib/Thelia/Model/Lang.php index a0baa80c2..546eb7b20 100644 --- a/core/lib/Thelia/Model/Lang.php +++ b/core/lib/Thelia/Model/Lang.php @@ -17,6 +17,9 @@ use Thelia\Model\Map\LangTableMap; class Lang extends BaseLang { use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + protected static $defaultLanguage; + /** * Return the default language object, using a local variable to cache it. * @@ -24,10 +27,13 @@ class Lang extends BaseLang */ public static function getDefaultLanguage() { - $default_lang = LangQuery::create()->findOneByByDefault(1); + if (null === self::$defaultLanguage) { + self::$defaultLanguage = LangQuery::create()->findOneByByDefault(1); - if ($default_lang == null) throw new \RuntimeException("No default language is defined. Please define one."); - return $default_lang; + if (self::$defaultLanguage == null) throw new \RuntimeException("No default language is defined. Please define one."); + } + + return self::$defaultLanguage; } public function toggleDefault() diff --git a/core/lib/Thelia/Model/Map/OrderTableMap.php b/core/lib/Thelia/Model/Map/OrderTableMap.php index 2246af89c..a7324e414 100644 --- a/core/lib/Thelia/Model/Map/OrderTableMap.php +++ b/core/lib/Thelia/Model/Map/OrderTableMap.php @@ -58,7 +58,7 @@ class OrderTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 19; + const NUM_COLUMNS = 22; /** * The number of lazy-loaded columns @@ -68,7 +68,7 @@ class OrderTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 19; + const NUM_HYDRATE_COLUMNS = 22; /** * the column name for the ID field @@ -165,6 +165,21 @@ class OrderTableMap extends TableMap */ const UPDATED_AT = 'order.UPDATED_AT'; + /** + * the column name for the VERSION field + */ + const VERSION = 'order.VERSION'; + + /** + * the column name for the VERSION_CREATED_AT field + */ + const VERSION_CREATED_AT = 'order.VERSION_CREATED_AT'; + + /** + * the column name for the VERSION_CREATED_BY field + */ + const VERSION_CREATED_BY = 'order.VERSION_CREATED_BY'; + /** * The default string format for model objects of the related table */ @@ -177,12 +192,12 @@ class OrderTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'Ref', 'CustomerId', 'InvoiceOrderAddressId', 'DeliveryOrderAddressId', 'InvoiceDate', 'CurrencyId', 'CurrencyRate', 'TransactionRef', 'DeliveryRef', 'InvoiceRef', 'Discount', 'Postage', 'PaymentModuleId', 'DeliveryModuleId', 'StatusId', 'LangId', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'ref', 'customerId', 'invoiceOrderAddressId', 'deliveryOrderAddressId', 'invoiceDate', 'currencyId', 'currencyRate', 'transactionRef', 'deliveryRef', 'invoiceRef', 'discount', 'postage', 'paymentModuleId', 'deliveryModuleId', 'statusId', 'langId', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(OrderTableMap::ID, OrderTableMap::REF, OrderTableMap::CUSTOMER_ID, OrderTableMap::INVOICE_ORDER_ADDRESS_ID, OrderTableMap::DELIVERY_ORDER_ADDRESS_ID, OrderTableMap::INVOICE_DATE, OrderTableMap::CURRENCY_ID, OrderTableMap::CURRENCY_RATE, OrderTableMap::TRANSACTION_REF, OrderTableMap::DELIVERY_REF, OrderTableMap::INVOICE_REF, OrderTableMap::DISCOUNT, OrderTableMap::POSTAGE, OrderTableMap::PAYMENT_MODULE_ID, OrderTableMap::DELIVERY_MODULE_ID, OrderTableMap::STATUS_ID, OrderTableMap::LANG_ID, OrderTableMap::CREATED_AT, OrderTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'REF', 'CUSTOMER_ID', 'INVOICE_ORDER_ADDRESS_ID', 'DELIVERY_ORDER_ADDRESS_ID', 'INVOICE_DATE', 'CURRENCY_ID', 'CURRENCY_RATE', 'TRANSACTION_REF', 'DELIVERY_REF', 'INVOICE_REF', 'DISCOUNT', 'POSTAGE', 'PAYMENT_MODULE_ID', 'DELIVERY_MODULE_ID', 'STATUS_ID', 'LANG_ID', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'ref', 'customer_id', 'invoice_order_address_id', 'delivery_order_address_id', 'invoice_date', 'currency_id', 'currency_rate', 'transaction_ref', 'delivery_ref', 'invoice_ref', 'discount', 'postage', 'payment_module_id', 'delivery_module_id', 'status_id', 'lang_id', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, ) + self::TYPE_PHPNAME => array('Id', 'Ref', 'CustomerId', 'InvoiceOrderAddressId', 'DeliveryOrderAddressId', 'InvoiceDate', 'CurrencyId', 'CurrencyRate', 'TransactionRef', 'DeliveryRef', 'InvoiceRef', 'Discount', 'Postage', 'PaymentModuleId', 'DeliveryModuleId', 'StatusId', 'LangId', 'CreatedAt', 'UpdatedAt', 'Version', 'VersionCreatedAt', 'VersionCreatedBy', ), + self::TYPE_STUDLYPHPNAME => array('id', 'ref', 'customerId', 'invoiceOrderAddressId', 'deliveryOrderAddressId', 'invoiceDate', 'currencyId', 'currencyRate', 'transactionRef', 'deliveryRef', 'invoiceRef', 'discount', 'postage', 'paymentModuleId', 'deliveryModuleId', 'statusId', 'langId', 'createdAt', 'updatedAt', 'version', 'versionCreatedAt', 'versionCreatedBy', ), + self::TYPE_COLNAME => array(OrderTableMap::ID, OrderTableMap::REF, OrderTableMap::CUSTOMER_ID, OrderTableMap::INVOICE_ORDER_ADDRESS_ID, OrderTableMap::DELIVERY_ORDER_ADDRESS_ID, OrderTableMap::INVOICE_DATE, OrderTableMap::CURRENCY_ID, OrderTableMap::CURRENCY_RATE, OrderTableMap::TRANSACTION_REF, OrderTableMap::DELIVERY_REF, OrderTableMap::INVOICE_REF, OrderTableMap::DISCOUNT, OrderTableMap::POSTAGE, OrderTableMap::PAYMENT_MODULE_ID, OrderTableMap::DELIVERY_MODULE_ID, OrderTableMap::STATUS_ID, OrderTableMap::LANG_ID, OrderTableMap::CREATED_AT, OrderTableMap::UPDATED_AT, OrderTableMap::VERSION, OrderTableMap::VERSION_CREATED_AT, OrderTableMap::VERSION_CREATED_BY, ), + self::TYPE_RAW_COLNAME => array('ID', 'REF', 'CUSTOMER_ID', 'INVOICE_ORDER_ADDRESS_ID', 'DELIVERY_ORDER_ADDRESS_ID', 'INVOICE_DATE', 'CURRENCY_ID', 'CURRENCY_RATE', 'TRANSACTION_REF', 'DELIVERY_REF', 'INVOICE_REF', 'DISCOUNT', 'POSTAGE', 'PAYMENT_MODULE_ID', 'DELIVERY_MODULE_ID', 'STATUS_ID', 'LANG_ID', 'CREATED_AT', 'UPDATED_AT', 'VERSION', 'VERSION_CREATED_AT', 'VERSION_CREATED_BY', ), + self::TYPE_FIELDNAME => array('id', 'ref', 'customer_id', 'invoice_order_address_id', 'delivery_order_address_id', 'invoice_date', 'currency_id', 'currency_rate', 'transaction_ref', 'delivery_ref', 'invoice_ref', 'discount', 'postage', 'payment_module_id', 'delivery_module_id', 'status_id', 'lang_id', 'created_at', 'updated_at', 'version', 'version_created_at', 'version_created_by', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ) ); /** @@ -192,12 +207,12 @@ class OrderTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'Ref' => 1, 'CustomerId' => 2, 'InvoiceOrderAddressId' => 3, 'DeliveryOrderAddressId' => 4, 'InvoiceDate' => 5, 'CurrencyId' => 6, 'CurrencyRate' => 7, 'TransactionRef' => 8, 'DeliveryRef' => 9, 'InvoiceRef' => 10, 'Discount' => 11, 'Postage' => 12, 'PaymentModuleId' => 13, 'DeliveryModuleId' => 14, 'StatusId' => 15, 'LangId' => 16, 'CreatedAt' => 17, 'UpdatedAt' => 18, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'ref' => 1, 'customerId' => 2, 'invoiceOrderAddressId' => 3, 'deliveryOrderAddressId' => 4, 'invoiceDate' => 5, 'currencyId' => 6, 'currencyRate' => 7, 'transactionRef' => 8, 'deliveryRef' => 9, 'invoiceRef' => 10, 'discount' => 11, 'postage' => 12, 'paymentModuleId' => 13, 'deliveryModuleId' => 14, 'statusId' => 15, 'langId' => 16, 'createdAt' => 17, 'updatedAt' => 18, ), - self::TYPE_COLNAME => array(OrderTableMap::ID => 0, OrderTableMap::REF => 1, OrderTableMap::CUSTOMER_ID => 2, OrderTableMap::INVOICE_ORDER_ADDRESS_ID => 3, OrderTableMap::DELIVERY_ORDER_ADDRESS_ID => 4, OrderTableMap::INVOICE_DATE => 5, OrderTableMap::CURRENCY_ID => 6, OrderTableMap::CURRENCY_RATE => 7, OrderTableMap::TRANSACTION_REF => 8, OrderTableMap::DELIVERY_REF => 9, OrderTableMap::INVOICE_REF => 10, OrderTableMap::DISCOUNT => 11, OrderTableMap::POSTAGE => 12, OrderTableMap::PAYMENT_MODULE_ID => 13, OrderTableMap::DELIVERY_MODULE_ID => 14, OrderTableMap::STATUS_ID => 15, OrderTableMap::LANG_ID => 16, OrderTableMap::CREATED_AT => 17, OrderTableMap::UPDATED_AT => 18, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'REF' => 1, 'CUSTOMER_ID' => 2, 'INVOICE_ORDER_ADDRESS_ID' => 3, 'DELIVERY_ORDER_ADDRESS_ID' => 4, 'INVOICE_DATE' => 5, 'CURRENCY_ID' => 6, 'CURRENCY_RATE' => 7, 'TRANSACTION_REF' => 8, 'DELIVERY_REF' => 9, 'INVOICE_REF' => 10, 'DISCOUNT' => 11, 'POSTAGE' => 12, 'PAYMENT_MODULE_ID' => 13, 'DELIVERY_MODULE_ID' => 14, 'STATUS_ID' => 15, 'LANG_ID' => 16, 'CREATED_AT' => 17, 'UPDATED_AT' => 18, ), - self::TYPE_FIELDNAME => array('id' => 0, 'ref' => 1, 'customer_id' => 2, 'invoice_order_address_id' => 3, 'delivery_order_address_id' => 4, 'invoice_date' => 5, 'currency_id' => 6, 'currency_rate' => 7, 'transaction_ref' => 8, 'delivery_ref' => 9, 'invoice_ref' => 10, 'discount' => 11, 'postage' => 12, 'payment_module_id' => 13, 'delivery_module_id' => 14, 'status_id' => 15, 'lang_id' => 16, 'created_at' => 17, 'updated_at' => 18, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, ) + self::TYPE_PHPNAME => array('Id' => 0, 'Ref' => 1, 'CustomerId' => 2, 'InvoiceOrderAddressId' => 3, 'DeliveryOrderAddressId' => 4, 'InvoiceDate' => 5, 'CurrencyId' => 6, 'CurrencyRate' => 7, 'TransactionRef' => 8, 'DeliveryRef' => 9, 'InvoiceRef' => 10, 'Discount' => 11, 'Postage' => 12, 'PaymentModuleId' => 13, 'DeliveryModuleId' => 14, 'StatusId' => 15, 'LangId' => 16, 'CreatedAt' => 17, 'UpdatedAt' => 18, 'Version' => 19, 'VersionCreatedAt' => 20, 'VersionCreatedBy' => 21, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'ref' => 1, 'customerId' => 2, 'invoiceOrderAddressId' => 3, 'deliveryOrderAddressId' => 4, 'invoiceDate' => 5, 'currencyId' => 6, 'currencyRate' => 7, 'transactionRef' => 8, 'deliveryRef' => 9, 'invoiceRef' => 10, 'discount' => 11, 'postage' => 12, 'paymentModuleId' => 13, 'deliveryModuleId' => 14, 'statusId' => 15, 'langId' => 16, 'createdAt' => 17, 'updatedAt' => 18, 'version' => 19, 'versionCreatedAt' => 20, 'versionCreatedBy' => 21, ), + self::TYPE_COLNAME => array(OrderTableMap::ID => 0, OrderTableMap::REF => 1, OrderTableMap::CUSTOMER_ID => 2, OrderTableMap::INVOICE_ORDER_ADDRESS_ID => 3, OrderTableMap::DELIVERY_ORDER_ADDRESS_ID => 4, OrderTableMap::INVOICE_DATE => 5, OrderTableMap::CURRENCY_ID => 6, OrderTableMap::CURRENCY_RATE => 7, OrderTableMap::TRANSACTION_REF => 8, OrderTableMap::DELIVERY_REF => 9, OrderTableMap::INVOICE_REF => 10, OrderTableMap::DISCOUNT => 11, OrderTableMap::POSTAGE => 12, OrderTableMap::PAYMENT_MODULE_ID => 13, OrderTableMap::DELIVERY_MODULE_ID => 14, OrderTableMap::STATUS_ID => 15, OrderTableMap::LANG_ID => 16, OrderTableMap::CREATED_AT => 17, OrderTableMap::UPDATED_AT => 18, OrderTableMap::VERSION => 19, OrderTableMap::VERSION_CREATED_AT => 20, OrderTableMap::VERSION_CREATED_BY => 21, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'REF' => 1, 'CUSTOMER_ID' => 2, 'INVOICE_ORDER_ADDRESS_ID' => 3, 'DELIVERY_ORDER_ADDRESS_ID' => 4, 'INVOICE_DATE' => 5, 'CURRENCY_ID' => 6, 'CURRENCY_RATE' => 7, 'TRANSACTION_REF' => 8, 'DELIVERY_REF' => 9, 'INVOICE_REF' => 10, 'DISCOUNT' => 11, 'POSTAGE' => 12, 'PAYMENT_MODULE_ID' => 13, 'DELIVERY_MODULE_ID' => 14, 'STATUS_ID' => 15, 'LANG_ID' => 16, 'CREATED_AT' => 17, 'UPDATED_AT' => 18, 'VERSION' => 19, 'VERSION_CREATED_AT' => 20, 'VERSION_CREATED_BY' => 21, ), + self::TYPE_FIELDNAME => array('id' => 0, 'ref' => 1, 'customer_id' => 2, 'invoice_order_address_id' => 3, 'delivery_order_address_id' => 4, 'invoice_date' => 5, 'currency_id' => 6, 'currency_rate' => 7, 'transaction_ref' => 8, 'delivery_ref' => 9, 'invoice_ref' => 10, 'discount' => 11, 'postage' => 12, 'payment_module_id' => 13, 'delivery_module_id' => 14, 'status_id' => 15, 'lang_id' => 16, 'created_at' => 17, 'updated_at' => 18, 'version' => 19, 'version_created_at' => 20, 'version_created_by' => 21, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ) ); /** @@ -235,6 +250,9 @@ class OrderTableMap extends TableMap $this->addForeignKey('LANG_ID', 'LangId', 'INTEGER', 'lang', 'ID', true, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); + $this->addColumn('VERSION', 'Version', 'INTEGER', false, null, 0); + $this->addColumn('VERSION_CREATED_AT', 'VersionCreatedAt', 'TIMESTAMP', false, null, null); + $this->addColumn('VERSION_CREATED_BY', 'VersionCreatedBy', 'VARCHAR', false, 100, null); } // initialize() /** @@ -252,6 +270,7 @@ class OrderTableMap extends TableMap $this->addRelation('Lang', '\\Thelia\\Model\\Lang', RelationMap::MANY_TO_ONE, array('lang_id' => 'id', ), 'RESTRICT', 'RESTRICT'); $this->addRelation('OrderProduct', '\\Thelia\\Model\\OrderProduct', RelationMap::ONE_TO_MANY, array('id' => 'order_id', ), 'CASCADE', 'RESTRICT', 'OrderProducts'); $this->addRelation('OrderCoupon', '\\Thelia\\Model\\OrderCoupon', RelationMap::ONE_TO_MANY, array('id' => 'order_id', ), 'CASCADE', 'RESTRICT', 'OrderCoupons'); + $this->addRelation('OrderVersion', '\\Thelia\\Model\\OrderVersion', RelationMap::ONE_TO_MANY, array('id' => 'id', ), 'CASCADE', null, 'OrderVersions'); } // buildRelations() /** @@ -264,6 +283,7 @@ class OrderTableMap extends TableMap { return array( 'timestampable' => array('create_column' => 'created_at', 'update_column' => 'updated_at', ), + 'versionable' => array('version_column' => 'version', 'version_table' => '', 'log_created_at' => 'true', 'log_created_by' => 'true', 'log_comment' => 'false', 'version_created_at_column' => 'version_created_at', 'version_created_by_column' => 'version_created_by', 'version_comment_column' => 'version_comment', ), ); } // getBehaviors() /** @@ -275,6 +295,7 @@ class OrderTableMap extends TableMap // since one or more of them may be deleted by ON DELETE CASCADE/SETNULL rule. OrderProductTableMap::clearInstancePool(); OrderCouponTableMap::clearInstancePool(); + OrderVersionTableMap::clearInstancePool(); } /** @@ -434,6 +455,9 @@ class OrderTableMap extends TableMap $criteria->addSelectColumn(OrderTableMap::LANG_ID); $criteria->addSelectColumn(OrderTableMap::CREATED_AT); $criteria->addSelectColumn(OrderTableMap::UPDATED_AT); + $criteria->addSelectColumn(OrderTableMap::VERSION); + $criteria->addSelectColumn(OrderTableMap::VERSION_CREATED_AT); + $criteria->addSelectColumn(OrderTableMap::VERSION_CREATED_BY); } else { $criteria->addSelectColumn($alias . '.ID'); $criteria->addSelectColumn($alias . '.REF'); @@ -454,6 +478,9 @@ class OrderTableMap extends TableMap $criteria->addSelectColumn($alias . '.LANG_ID'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); + $criteria->addSelectColumn($alias . '.VERSION'); + $criteria->addSelectColumn($alias . '.VERSION_CREATED_AT'); + $criteria->addSelectColumn($alias . '.VERSION_CREATED_BY'); } } diff --git a/core/lib/Thelia/Model/Map/OrderVersionTableMap.php b/core/lib/Thelia/Model/Map/OrderVersionTableMap.php new file mode 100644 index 000000000..1c92b9ea1 --- /dev/null +++ b/core/lib/Thelia/Model/Map/OrderVersionTableMap.php @@ -0,0 +1,626 @@ + array('Id', 'Ref', 'CustomerId', 'InvoiceOrderAddressId', 'DeliveryOrderAddressId', 'InvoiceDate', 'CurrencyId', 'CurrencyRate', 'TransactionRef', 'DeliveryRef', 'InvoiceRef', 'Discount', 'Postage', 'PaymentModuleId', 'DeliveryModuleId', 'StatusId', 'LangId', 'CreatedAt', 'UpdatedAt', 'Version', 'VersionCreatedAt', 'VersionCreatedBy', ), + self::TYPE_STUDLYPHPNAME => array('id', 'ref', 'customerId', 'invoiceOrderAddressId', 'deliveryOrderAddressId', 'invoiceDate', 'currencyId', 'currencyRate', 'transactionRef', 'deliveryRef', 'invoiceRef', 'discount', 'postage', 'paymentModuleId', 'deliveryModuleId', 'statusId', 'langId', 'createdAt', 'updatedAt', 'version', 'versionCreatedAt', 'versionCreatedBy', ), + self::TYPE_COLNAME => array(OrderVersionTableMap::ID, OrderVersionTableMap::REF, OrderVersionTableMap::CUSTOMER_ID, OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID, OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID, OrderVersionTableMap::INVOICE_DATE, OrderVersionTableMap::CURRENCY_ID, OrderVersionTableMap::CURRENCY_RATE, OrderVersionTableMap::TRANSACTION_REF, OrderVersionTableMap::DELIVERY_REF, OrderVersionTableMap::INVOICE_REF, OrderVersionTableMap::DISCOUNT, OrderVersionTableMap::POSTAGE, OrderVersionTableMap::PAYMENT_MODULE_ID, OrderVersionTableMap::DELIVERY_MODULE_ID, OrderVersionTableMap::STATUS_ID, OrderVersionTableMap::LANG_ID, OrderVersionTableMap::CREATED_AT, OrderVersionTableMap::UPDATED_AT, OrderVersionTableMap::VERSION, OrderVersionTableMap::VERSION_CREATED_AT, OrderVersionTableMap::VERSION_CREATED_BY, ), + self::TYPE_RAW_COLNAME => array('ID', 'REF', 'CUSTOMER_ID', 'INVOICE_ORDER_ADDRESS_ID', 'DELIVERY_ORDER_ADDRESS_ID', 'INVOICE_DATE', 'CURRENCY_ID', 'CURRENCY_RATE', 'TRANSACTION_REF', 'DELIVERY_REF', 'INVOICE_REF', 'DISCOUNT', 'POSTAGE', 'PAYMENT_MODULE_ID', 'DELIVERY_MODULE_ID', 'STATUS_ID', 'LANG_ID', 'CREATED_AT', 'UPDATED_AT', 'VERSION', 'VERSION_CREATED_AT', 'VERSION_CREATED_BY', ), + self::TYPE_FIELDNAME => array('id', 'ref', 'customer_id', 'invoice_order_address_id', 'delivery_order_address_id', 'invoice_date', 'currency_id', 'currency_rate', 'transaction_ref', 'delivery_ref', 'invoice_ref', 'discount', 'postage', 'payment_module_id', 'delivery_module_id', 'status_id', 'lang_id', 'created_at', 'updated_at', 'version', 'version_created_at', 'version_created_by', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Ref' => 1, 'CustomerId' => 2, 'InvoiceOrderAddressId' => 3, 'DeliveryOrderAddressId' => 4, 'InvoiceDate' => 5, 'CurrencyId' => 6, 'CurrencyRate' => 7, 'TransactionRef' => 8, 'DeliveryRef' => 9, 'InvoiceRef' => 10, 'Discount' => 11, 'Postage' => 12, 'PaymentModuleId' => 13, 'DeliveryModuleId' => 14, 'StatusId' => 15, 'LangId' => 16, 'CreatedAt' => 17, 'UpdatedAt' => 18, 'Version' => 19, 'VersionCreatedAt' => 20, 'VersionCreatedBy' => 21, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'ref' => 1, 'customerId' => 2, 'invoiceOrderAddressId' => 3, 'deliveryOrderAddressId' => 4, 'invoiceDate' => 5, 'currencyId' => 6, 'currencyRate' => 7, 'transactionRef' => 8, 'deliveryRef' => 9, 'invoiceRef' => 10, 'discount' => 11, 'postage' => 12, 'paymentModuleId' => 13, 'deliveryModuleId' => 14, 'statusId' => 15, 'langId' => 16, 'createdAt' => 17, 'updatedAt' => 18, 'version' => 19, 'versionCreatedAt' => 20, 'versionCreatedBy' => 21, ), + self::TYPE_COLNAME => array(OrderVersionTableMap::ID => 0, OrderVersionTableMap::REF => 1, OrderVersionTableMap::CUSTOMER_ID => 2, OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID => 3, OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID => 4, OrderVersionTableMap::INVOICE_DATE => 5, OrderVersionTableMap::CURRENCY_ID => 6, OrderVersionTableMap::CURRENCY_RATE => 7, OrderVersionTableMap::TRANSACTION_REF => 8, OrderVersionTableMap::DELIVERY_REF => 9, OrderVersionTableMap::INVOICE_REF => 10, OrderVersionTableMap::DISCOUNT => 11, OrderVersionTableMap::POSTAGE => 12, OrderVersionTableMap::PAYMENT_MODULE_ID => 13, OrderVersionTableMap::DELIVERY_MODULE_ID => 14, OrderVersionTableMap::STATUS_ID => 15, OrderVersionTableMap::LANG_ID => 16, OrderVersionTableMap::CREATED_AT => 17, OrderVersionTableMap::UPDATED_AT => 18, OrderVersionTableMap::VERSION => 19, OrderVersionTableMap::VERSION_CREATED_AT => 20, OrderVersionTableMap::VERSION_CREATED_BY => 21, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'REF' => 1, 'CUSTOMER_ID' => 2, 'INVOICE_ORDER_ADDRESS_ID' => 3, 'DELIVERY_ORDER_ADDRESS_ID' => 4, 'INVOICE_DATE' => 5, 'CURRENCY_ID' => 6, 'CURRENCY_RATE' => 7, 'TRANSACTION_REF' => 8, 'DELIVERY_REF' => 9, 'INVOICE_REF' => 10, 'DISCOUNT' => 11, 'POSTAGE' => 12, 'PAYMENT_MODULE_ID' => 13, 'DELIVERY_MODULE_ID' => 14, 'STATUS_ID' => 15, 'LANG_ID' => 16, 'CREATED_AT' => 17, 'UPDATED_AT' => 18, 'VERSION' => 19, 'VERSION_CREATED_AT' => 20, 'VERSION_CREATED_BY' => 21, ), + self::TYPE_FIELDNAME => array('id' => 0, 'ref' => 1, 'customer_id' => 2, 'invoice_order_address_id' => 3, 'delivery_order_address_id' => 4, 'invoice_date' => 5, 'currency_id' => 6, 'currency_rate' => 7, 'transaction_ref' => 8, 'delivery_ref' => 9, 'invoice_ref' => 10, 'discount' => 11, 'postage' => 12, 'payment_module_id' => 13, 'delivery_module_id' => 14, 'status_id' => 15, 'lang_id' => 16, 'created_at' => 17, 'updated_at' => 18, 'version' => 19, 'version_created_at' => 20, 'version_created_by' => 21, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('order_version'); + $this->setPhpName('OrderVersion'); + $this->setClassName('\\Thelia\\Model\\OrderVersion'); + $this->setPackage('Thelia.Model'); + $this->setUseIdGenerator(false); + // columns + $this->addForeignPrimaryKey('ID', 'Id', 'INTEGER' , 'order', 'ID', true, null, null); + $this->addColumn('REF', 'Ref', 'VARCHAR', false, 45, null); + $this->addColumn('CUSTOMER_ID', 'CustomerId', 'INTEGER', true, null, null); + $this->addColumn('INVOICE_ORDER_ADDRESS_ID', 'InvoiceOrderAddressId', 'INTEGER', true, null, null); + $this->addColumn('DELIVERY_ORDER_ADDRESS_ID', 'DeliveryOrderAddressId', 'INTEGER', true, null, null); + $this->addColumn('INVOICE_DATE', 'InvoiceDate', 'DATE', false, null, null); + $this->addColumn('CURRENCY_ID', 'CurrencyId', 'INTEGER', true, null, null); + $this->addColumn('CURRENCY_RATE', 'CurrencyRate', 'FLOAT', true, null, null); + $this->addColumn('TRANSACTION_REF', 'TransactionRef', 'VARCHAR', false, 100, null); + $this->addColumn('DELIVERY_REF', 'DeliveryRef', 'VARCHAR', false, 100, null); + $this->addColumn('INVOICE_REF', 'InvoiceRef', 'VARCHAR', false, 100, null); + $this->addColumn('DISCOUNT', 'Discount', 'FLOAT', false, null, null); + $this->addColumn('POSTAGE', 'Postage', 'FLOAT', true, null, null); + $this->addColumn('PAYMENT_MODULE_ID', 'PaymentModuleId', 'INTEGER', true, null, null); + $this->addColumn('DELIVERY_MODULE_ID', 'DeliveryModuleId', 'INTEGER', true, null, null); + $this->addColumn('STATUS_ID', 'StatusId', 'INTEGER', true, null, null); + $this->addColumn('LANG_ID', 'LangId', 'INTEGER', true, null, null); + $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); + $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); + $this->addPrimaryKey('VERSION', 'Version', 'INTEGER', true, null, 0); + $this->addColumn('VERSION_CREATED_AT', 'VersionCreatedAt', 'TIMESTAMP', false, null, null); + $this->addColumn('VERSION_CREATED_BY', 'VersionCreatedBy', 'VARCHAR', false, 100, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('Order', '\\Thelia\\Model\\Order', RelationMap::MANY_TO_ONE, array('id' => 'id', ), 'CASCADE', null); + } // buildRelations() + + /** + * Adds an object to the instance pool. + * + * Propel keeps cached copies of objects in an instance pool when they are retrieved + * from the database. In some cases you may need to explicitly add objects + * to the cache in order to ensure that the same objects are always returned by find*() + * and findPk*() calls. + * + * @param \Thelia\Model\OrderVersion $obj A \Thelia\Model\OrderVersion object. + * @param string $key (optional) key to use for instance map (for performance boost if key was already calculated externally). + */ + public static function addInstanceToPool($obj, $key = null) + { + if (Propel::isInstancePoolingEnabled()) { + if (null === $key) { + $key = serialize(array((string) $obj->getId(), (string) $obj->getVersion())); + } // if key === null + self::$instances[$key] = $obj; + } + } + + /** + * Removes an object from the instance pool. + * + * Propel keeps cached copies of objects in an instance pool when they are retrieved + * from the database. In some cases -- especially when you override doDelete + * methods in your stub classes -- you may need to explicitly remove objects + * from the cache in order to prevent returning objects that no longer exist. + * + * @param mixed $value A \Thelia\Model\OrderVersion object or a primary key value. + */ + public static function removeInstanceFromPool($value) + { + if (Propel::isInstancePoolingEnabled() && null !== $value) { + if (is_object($value) && $value instanceof \Thelia\Model\OrderVersion) { + $key = serialize(array((string) $value->getId(), (string) $value->getVersion())); + + } elseif (is_array($value) && count($value) === 2) { + // assume we've been passed a primary key"; + $key = serialize(array((string) $value[0], (string) $value[1])); + } elseif ($value instanceof Criteria) { + self::$instances = []; + + return; + } else { + $e = new PropelException("Invalid value passed to removeInstanceFromPool(). Expected primary key or \Thelia\Model\OrderVersion object; got " . (is_object($value) ? get_class($value) . ' object.' : var_export($value, true))); + throw $e; + } + + unset(self::$instances[$key]); + } + } + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null && $row[TableMap::TYPE_NUM == $indexType ? 19 + $offset : static::translateFieldName('Version', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return serialize(array((string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], (string) $row[TableMap::TYPE_NUM == $indexType ? 19 + $offset : static::translateFieldName('Version', TableMap::TYPE_PHPNAME, $indexType)])); + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + + return $pks; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? OrderVersionTableMap::CLASS_DEFAULT : OrderVersionTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (OrderVersion object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = OrderVersionTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = OrderVersionTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + OrderVersionTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = OrderVersionTableMap::OM_CLASS; + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + OrderVersionTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = OrderVersionTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = OrderVersionTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + OrderVersionTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(OrderVersionTableMap::ID); + $criteria->addSelectColumn(OrderVersionTableMap::REF); + $criteria->addSelectColumn(OrderVersionTableMap::CUSTOMER_ID); + $criteria->addSelectColumn(OrderVersionTableMap::INVOICE_ORDER_ADDRESS_ID); + $criteria->addSelectColumn(OrderVersionTableMap::DELIVERY_ORDER_ADDRESS_ID); + $criteria->addSelectColumn(OrderVersionTableMap::INVOICE_DATE); + $criteria->addSelectColumn(OrderVersionTableMap::CURRENCY_ID); + $criteria->addSelectColumn(OrderVersionTableMap::CURRENCY_RATE); + $criteria->addSelectColumn(OrderVersionTableMap::TRANSACTION_REF); + $criteria->addSelectColumn(OrderVersionTableMap::DELIVERY_REF); + $criteria->addSelectColumn(OrderVersionTableMap::INVOICE_REF); + $criteria->addSelectColumn(OrderVersionTableMap::DISCOUNT); + $criteria->addSelectColumn(OrderVersionTableMap::POSTAGE); + $criteria->addSelectColumn(OrderVersionTableMap::PAYMENT_MODULE_ID); + $criteria->addSelectColumn(OrderVersionTableMap::DELIVERY_MODULE_ID); + $criteria->addSelectColumn(OrderVersionTableMap::STATUS_ID); + $criteria->addSelectColumn(OrderVersionTableMap::LANG_ID); + $criteria->addSelectColumn(OrderVersionTableMap::CREATED_AT); + $criteria->addSelectColumn(OrderVersionTableMap::UPDATED_AT); + $criteria->addSelectColumn(OrderVersionTableMap::VERSION); + $criteria->addSelectColumn(OrderVersionTableMap::VERSION_CREATED_AT); + $criteria->addSelectColumn(OrderVersionTableMap::VERSION_CREATED_BY); + } else { + $criteria->addSelectColumn($alias . '.ID'); + $criteria->addSelectColumn($alias . '.REF'); + $criteria->addSelectColumn($alias . '.CUSTOMER_ID'); + $criteria->addSelectColumn($alias . '.INVOICE_ORDER_ADDRESS_ID'); + $criteria->addSelectColumn($alias . '.DELIVERY_ORDER_ADDRESS_ID'); + $criteria->addSelectColumn($alias . '.INVOICE_DATE'); + $criteria->addSelectColumn($alias . '.CURRENCY_ID'); + $criteria->addSelectColumn($alias . '.CURRENCY_RATE'); + $criteria->addSelectColumn($alias . '.TRANSACTION_REF'); + $criteria->addSelectColumn($alias . '.DELIVERY_REF'); + $criteria->addSelectColumn($alias . '.INVOICE_REF'); + $criteria->addSelectColumn($alias . '.DISCOUNT'); + $criteria->addSelectColumn($alias . '.POSTAGE'); + $criteria->addSelectColumn($alias . '.PAYMENT_MODULE_ID'); + $criteria->addSelectColumn($alias . '.DELIVERY_MODULE_ID'); + $criteria->addSelectColumn($alias . '.STATUS_ID'); + $criteria->addSelectColumn($alias . '.LANG_ID'); + $criteria->addSelectColumn($alias . '.CREATED_AT'); + $criteria->addSelectColumn($alias . '.UPDATED_AT'); + $criteria->addSelectColumn($alias . '.VERSION'); + $criteria->addSelectColumn($alias . '.VERSION_CREATED_AT'); + $criteria->addSelectColumn($alias . '.VERSION_CREATED_BY'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(OrderVersionTableMap::DATABASE_NAME)->getTable(OrderVersionTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(OrderVersionTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(OrderVersionTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new OrderVersionTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a OrderVersion or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or OrderVersion object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Thelia\Model\OrderVersion) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(OrderVersionTableMap::DATABASE_NAME); + // primary key is composite; we therefore, expect + // the primary key passed to be an array of pkey values + if (count($values) == count($values, COUNT_RECURSIVE)) { + // array is not multi-dimensional + $values = array($values); + } + foreach ($values as $value) { + $criterion = $criteria->getNewCriterion(OrderVersionTableMap::ID, $value[0]); + $criterion->addAnd($criteria->getNewCriterion(OrderVersionTableMap::VERSION, $value[1])); + $criteria->addOr($criterion); + } + } + + $query = OrderVersionQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { OrderVersionTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { OrderVersionTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the order_version table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return OrderVersionQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a OrderVersion or Criteria object. + * + * @param mixed $criteria Criteria or OrderVersion object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(OrderVersionTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from OrderVersion object + } + + + // Set the correct dbName + $query = OrderVersionQuery::create()->mergeWith($criteria); + + try { + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + $con->beginTransaction(); + $pk = $query->doInsert($con); + $con->commit(); + } catch (PropelException $e) { + $con->rollBack(); + throw $e; + } + + return $pk; + } + +} // OrderVersionTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +OrderVersionTableMap::buildTableMap(); diff --git a/core/lib/Thelia/Model/Message.php b/core/lib/Thelia/Model/Message.php index b96887d07..3df786b0b 100644 --- a/core/lib/Thelia/Model/Message.php +++ b/core/lib/Thelia/Model/Message.php @@ -75,8 +75,6 @@ class Message extends BaseMessage { $body = false; - //$mail_template_path = TemplateHelper::getInstance()->getActiveMailTemplate()->getAbsolutePath() . DS; - // Try to get the body from template file, if a file is defined if (! empty($template)) { try { diff --git a/core/lib/Thelia/Model/ModuleQuery.php b/core/lib/Thelia/Model/ModuleQuery.php index c1f9394dd..fe08693af 100644 --- a/core/lib/Thelia/Model/ModuleQuery.php +++ b/core/lib/Thelia/Model/ModuleQuery.php @@ -3,6 +3,7 @@ namespace Thelia\Model; use Thelia\Model\Base\ModuleQuery as BaseModuleQuery; +use Thelia\Module\BaseModule; /** * Skeleton subclass for performing query and update operations on the 'module' table. @@ -24,7 +25,7 @@ class ModuleQuery extends BaseModuleQuery { if (null === self::$activated) { self::$activated = self::create() - ->filterByActivate(1) + ->filterByActivate(BaseModule::IS_ACTIVATED) ->orderByPosition() ->find(); } @@ -37,4 +38,17 @@ class ModuleQuery extends BaseModuleQuery self::$activated = null; } + /** + * @param int $moduleType the module type : classic, payment or delivery. Use BaseModule constant here. + * @param int $id the module id + * @return ModuleQuery + */ + public function filterActivatedByTypeAndId($moduleType, $id) + { + return $this + ->filterByType($moduleType) + ->filterByActivate(BaseModule::IS_ACTIVATED) + ->filterById($id); + } + } // ModuleQuery diff --git a/core/lib/Thelia/Model/Order.php b/core/lib/Thelia/Model/Order.php index 13311e51c..5cea21cc7 100644 --- a/core/lib/Thelia/Model/Order.php +++ b/core/lib/Thelia/Model/Order.php @@ -17,6 +17,8 @@ class Order extends BaseOrder protected $choosenDeliveryAddress = null; protected $choosenInvoiceAddress = null; + protected $disableVersioning = false; + /** * @param null $choosenDeliveryAddress */ @@ -27,6 +29,30 @@ class Order extends BaseOrder return $this; } + /** + * @param boolean $disableVersionning + */ + public function setDisableVersioning($disableVersioning) + { + $this->disableVersioning = (bool) $disableVersioning; + + return $this; + } + + public function isVersioningDisable() + { + return $this->disableVersioning; + } + + public function isVersioningNecessary($con = null) + { + if ($this->isVersioningDisable()) { + return false; + } else { + return parent::isVersioningNecessary($con); + } + } + /** * @return null */ @@ -69,6 +95,7 @@ class Order extends BaseOrder public function postInsert(ConnectionInterface $con = null) { $this->setRef($this->generateRef()) + ->setDisableVersioning(true) ->save($con); $this->dispatchEvent(TheliaEvents::ORDER_AFTER_CREATE, new OrderEvent($this)); } @@ -84,7 +111,7 @@ class Order extends BaseOrder public function generateRef() { - return sprintf('ORD%s', str_pad($this->getId(), 12, 0, STR_PAD_LEFT)); + return sprintf('ORD%s', str_pad($this->getId(), 12, 0, STR_PAD_LEFT)); } /** diff --git a/core/lib/Thelia/Model/OrderVersion.php b/core/lib/Thelia/Model/OrderVersion.php new file mode 100644 index 000000000..bda760833 --- /dev/null +++ b/core/lib/Thelia/Model/OrderVersion.php @@ -0,0 +1,10 @@ +filterByProductId($this->id)->filterByIsDefault(true)->find(); + return ProductSaleElementsQuery::create()->filterByProductId($this->id)->filterByIsDefault(true)->findOne(); } /** diff --git a/core/lib/Thelia/Model/ProductDocument.php b/core/lib/Thelia/Model/ProductDocument.php index 3e72a0d2b..cd00bdb1b 100644 --- a/core/lib/Thelia/Model/ProductDocument.php +++ b/core/lib/Thelia/Model/ProductDocument.php @@ -2,13 +2,20 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\ProductDocument as BaseProductDocument; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\CatalogBreadcrumbTrait; +use Thelia\Model\Tools\PositionManagementTrait; +use Thelia\Model\Tools\ModelEventDispatcherTrait; -class ProductDocument extends BaseProductDocument +class ProductDocument extends BaseProductDocument implements BreadcrumbInterface { - use \Thelia\Model\Tools\ModelEventDispatcherTrait; - use \Thelia\Model\Tools\PositionManagementTrait; + use ModelEventDispatcherTrait; + use PositionManagementTrait; + use CatalogBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -63,4 +70,14 @@ class ProductDocument extends BaseProductDocument return true; } + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getProductBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Model/ProductImage.php b/core/lib/Thelia/Model/ProductImage.php index 24cfee695..dba12e0e8 100644 --- a/core/lib/Thelia/Model/ProductImage.php +++ b/core/lib/Thelia/Model/ProductImage.php @@ -2,13 +2,20 @@ namespace Thelia\Model; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Routing\Router; use Thelia\Model\Base\ProductImage as BaseProductImage; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Breadcrumb\BreadcrumbInterface; +use Thelia\Model\Breadcrumb\CatalogBreadcrumbTrait; +use Thelia\Model\Tools\ModelEventDispatcherTrait; +use Thelia\Model\Tools\PositionManagementTrait; -class ProductImage extends BaseProductImage +class ProductImage extends BaseProductImage implements BreadcrumbInterface { - use \Thelia\Model\Tools\ModelEventDispatcherTrait; - use \Thelia\Model\Tools\PositionManagementTrait; + use ModelEventDispatcherTrait; + use PositionManagementTrait; + use CatalogBreadcrumbTrait; /** * Calculate next position relative to our parent @@ -62,4 +69,15 @@ class ProductImage extends BaseProductImage return true; } + + /** + * + * return the complete breadcrumb for a given resource. + * + * @return array + */ + public function getBreadcrumb(Router $router, ContainerInterface $container, $tab) + { + return $this->getProductBreadcrumb($router, $container, $tab); + } } diff --git a/core/lib/Thelia/Tests/Action/AddressTest.php b/core/lib/Thelia/Tests/Action/AddressTest.php index 91101544c..7677e66d8 100644 --- a/core/lib/Thelia/Tests/Action/AddressTest.php +++ b/core/lib/Thelia/Tests/Action/AddressTest.php @@ -12,8 +12,11 @@ namespace Thelia\Tests\Action; +use Propel\Runtime\Propel; use Thelia\Action\Address; use Thelia\Core\Event\Address\AddressCreateOrUpdateEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\AddressQuery; use Thelia\Model\CustomerQuery; /** @@ -121,4 +124,71 @@ class AddressTest extends \PHPUnit_Framework_TestCase } + /** + * Bug found in Thelia 2.0.2 + */ + public function testUpdateDefaultAddress() + { + /** + * Disable propel cache in order to get a new instance of the + * active record in $updatedAddress + */ + Propel::disableInstancePooling(); + + /** + * Get a customer and it's default address + */ + $customer = CustomerQuery::create()->findOne(); + $defaultAddress = $customer->getDefaultAddress(); + $addressId = $defaultAddress->getId(); + + /** + * Try to update the address, and set the isDefault argument, + * that should keep this address as the default one. + */ + $addressEvent = new AddressCreateOrUpdateEvent( + "", + 1, + "Thelia modif", + "Thelia modif", + "cour des étoiles", + "rue des miracles", + "", + "63000", + "clermont-ferrand", + 64, + "0102030405", + "", + "", + 1 + ); + + $addressEvent->setAddress($defaultAddress); + $addressEvent->setDispatcher( + $this->getMock("Symfony\Component\EventDispatcher\EventDispatcherInterface") + ); + + /** + * Do the update + */ + $actionAddress = new Address(); + $actionAddress->update($addressEvent); + + $updatedAddress = AddressQuery::create() + ->findPk($addressId); + + /** + * This address should still be the default address + */ + $this->assertEquals( + 1, + $updatedAddress->getIsDefault() + ); + + /** + * Renable it after + */ + Propel::enableInstancePooling(); + } + } diff --git a/core/lib/Thelia/Tests/Command/ModuleRefreshCommandTest.php b/core/lib/Thelia/Tests/Command/ModuleRefreshCommandTest.php new file mode 100644 index 000000000..15fd15a38 --- /dev/null +++ b/core/lib/Thelia/Tests/Command/ModuleRefreshCommandTest.php @@ -0,0 +1,105 @@ + + * + * Date: 2014-06-06 + * Time: 17:29 + */ +class ModuleRefreshCommandTest extends PHPUnit_Framework_TestCase +{ + /** + * Test ModuleRefreshCommand + */ + public function testModuleRefreshCommand() + { + $moduleManagement = new ModuleManagement; + $moduleManagement->updateModules(); + + $module = ModuleQuery::create()->filterByType(1)->orderByPosition(Criteria::DESC)->findOne(); + + if ($module !== null) { + $module->delete(); + + $application = new Application($this->getKernel()); + + $moduleRefresh = new ModuleRefreshCommand; + $moduleRefresh->setContainer($this->getContainer()); + + $application->add($moduleRefresh); + + $command = $application->find('module:refresh'); + $commandTester = new CommandTester($command); + $commandTester->execute([ + 'command' => $command->getName() + ]); + + $expected = $module; + $actual = ModuleQuery::create()->filterByType(1)->orderByPosition(Criteria::DESC)->findOne(); + + $this->assertEquals($expected->getCode(), $actual->getCode(), 'Last standard module code must be same after deleting this one and calling module:refresh'); + $this->assertEquals($expected->getType(), $actual->getType(), 'Last standard module type must be same after deleting this one and calling module:refresh'); + $this->assertEquals($expected->getFullNamespace(), $actual->getFullNamespace(), 'Last standard module namespace must be same after deleting this one and calling module:refresh'); + + // Restore activation status + $actual + ->setActivate($expected->getActivate()) + ->save(); + + } else { + $this->markTestIncomplete( + 'This test cannot be complete without at least one standard module.' + ); + } + } + + /** + * Get HttpKernel mock + * + * @return Kernel Not really a Kernel but the mocked one + */ + public function getKernel() + { + $kernel = $this->getMock('Symfony\\Component\\HttpKernel\\KernelInterface'); + + return $kernel; + } + + /** + * Get new ContainerBuilder + * + * @return ContainerBuilder + */ + public function getContainer() + { + $container = new ContainerBuilder; + + return $container; + } +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/CartContainsCategoriesTest.php b/core/lib/Thelia/Tests/Condition/Implementation/CartContainsCategoriesTest.php new file mode 100644 index 000000000..1a5259b5e --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/CartContainsCategoriesTest.php @@ -0,0 +1,365 @@ + + */ +class CartContainsCategoriesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $category1 = new Category(); + $category1->setId(10); + + $category2 = new Category(); + $category2->setId(20); + + $category3 = new Category(); + $category3->setId(30); + + $product1 = new Product(); + $product1->addCategory($category1)->addCategory($category2); + + $product2 = new Product(); + $product2->addCategory($category3); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub, $cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsCategories($stubFacade); + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array() + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsCategories($stubFacade); + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::IN + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array() + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsCategories($stubFacade); + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::IN + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array(10, 20) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsCategories($stubFacade); + + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::IN + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsCategories($stubFacade); + + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::IN + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsCategories($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsCategories($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\CartContainsCategories::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsCategories($stubFacade); + + $operators = array( + CartContainsCategories::CATEGORIES_LIST => Operators::IN + ); + $values = array( + CartContainsCategories::CATEGORIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + CartContainsCategories::CATEGORIES_LIST => array( + 'availableOperators' => array( + 'in' => 'Price', + 'out' => 'Price', + ), + 'value' => '', + 'selectedOperator' => 'in' + ) + ), + 'setOperators' => array( + 'categories' => 'in' + ), + 'setValues' => array( + 'categories' => array(50, 60) + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/CartContainsProductsTest.php b/core/lib/Thelia/Tests/Condition/Implementation/CartContainsProductsTest.php new file mode 100644 index 000000000..f24dea73a --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/CartContainsProductsTest.php @@ -0,0 +1,365 @@ + + */ +class CartContainsProductsTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $category1 = new Category(); + $category1->setId(10); + + $category2 = new Category(); + $category2->setId(20); + + $category3 = new Category(); + $category3->setId(30); + + $product1 = new Product(); + $product1->setId(10)->addCategory($category1)->addCategory($category2); + + $product2 = new Product(); + $product2->setId(20)->addCategory($category3); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub, $cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsProducts($stubFacade); + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array() + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsProducts($stubFacade); + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::IN + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array() + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsProducts($stubFacade); + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::IN + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array(10, 20) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsProducts($stubFacade); + + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::IN + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new CartContainsProducts($stubFacade); + + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::IN + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsProducts($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsProducts($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\CartContainsProducts::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new CartContainsProducts($stubFacade); + + $operators = array( + CartContainsProducts::PRODUCTS_LIST => Operators::IN + ); + $values = array( + CartContainsProducts::PRODUCTS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + CartContainsProducts::PRODUCTS_LIST => array( + 'availableOperators' => array( + 'in' => 'Price', + 'out' => 'Price', + ), + 'value' => '', + 'selectedOperator' => 'in' + ) + ), + 'setOperators' => array( + 'products' => 'in' + ), + 'setValues' => array( + 'products' => array(50, 60) + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/ForSomeCustomersTest.php b/core/lib/Thelia/Tests/Condition/Implementation/ForSomeCustomersTest.php new file mode 100644 index 000000000..018d7210d --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/ForSomeCustomersTest.php @@ -0,0 +1,304 @@ + + */ +class ForSomeCustomersTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $customer = new Customer(); + $customer->setId(10); + + $stubFacade->expects($this->any()) + ->method('getCustomer') + ->will($this->returnValue($customer)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new ForSomeCustomers($stubFacade); + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array() + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new ForSomeCustomers($stubFacade); + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::IN + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array() + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new ForSomeCustomers($stubFacade); + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::IN + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array(10, 20) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new ForSomeCustomers($stubFacade); + + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::IN + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new ForSomeCustomers($stubFacade); + + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::IN + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new ForSomeCustomers($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new ForSomeCustomers($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\ForSomeCustomers::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new ForSomeCustomers($stubFacade); + + $operators = array( + ForSomeCustomers::CUSTOMERS_LIST => Operators::IN + ); + $values = array( + ForSomeCustomers::CUSTOMERS_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + ForSomeCustomers::CUSTOMERS_LIST => array( + 'availableOperators' => array( + 'in' => 'Price', + 'out' => 'Price', + ), + 'value' => '', + 'selectedOperator' => 'in' + ) + ), + 'setOperators' => array( + 'customers' => 'in' + ), + 'setValues' => array( + 'customers' => array(50, 60) + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/MatchBillingCountriesTest.php b/core/lib/Thelia/Tests/Condition/Implementation/MatchBillingCountriesTest.php new file mode 100644 index 000000000..61ac53c2a --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/MatchBillingCountriesTest.php @@ -0,0 +1,312 @@ + + */ +class MatchBillingCountriesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $address = new Address(); + $address->setCountryId(10); + + $stubCustomer = $this->getMockBuilder('\Thelia\Model\Customer') + ->disableOriginalConstructor() + ->getMock(); + + $stubCustomer->expects($this->any()) + ->method('getDefaultAddress') + ->will($this->returnValue($address)); + + $stubFacade->expects($this->any()) + ->method('getCustomer') + ->will($this->returnValue($stubCustomer)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchBillingCountries($stubFacade); + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array() + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchBillingCountries($stubFacade); + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array() + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchBillingCountries($stubFacade); + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array(10, 20) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchBillingCountries($stubFacade); + + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchBillingCountries($stubFacade); + + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchBillingCountries($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchBillingCountries($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\MatchBillingCountries::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchBillingCountries($stubFacade); + + $operators = array( + MatchBillingCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchBillingCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + MatchBillingCountries::COUNTRIES_LIST => array( + 'availableOperators' => array( + 'in' => 'Price', + 'out' => 'Price', + ), + 'value' => '', + 'selectedOperator' => 'in' + ) + ), + 'setOperators' => array( + 'countries' => 'in' + ), + 'setValues' => array( + 'countries' => array(50, 60) + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/MatchDeliveryCountriesTest.php b/core/lib/Thelia/Tests/Condition/Implementation/MatchDeliveryCountriesTest.php new file mode 100644 index 000000000..623a1aeef --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/MatchDeliveryCountriesTest.php @@ -0,0 +1,304 @@ + + */ +class MatchDeliveryCountriesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $address = new Address(); + $address->setCountryId(10); + + $stubFacade->expects($this->any()) + ->method('getDeliveryAddress') + ->will($this->returnValue($address)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchDeliveryCountries($stubFacade); + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array() + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchDeliveryCountries($stubFacade); + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array() + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchDeliveryCountries($stubFacade); + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array(10, 20) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchDeliveryCountries($stubFacade); + + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new MatchDeliveryCountries($stubFacade); + + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchDeliveryCountries($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchDeliveryCountries($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\MatchDeliveryCountries::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new MatchDeliveryCountries($stubFacade); + + $operators = array( + MatchDeliveryCountries::COUNTRIES_LIST => Operators::IN + ); + $values = array( + MatchDeliveryCountries::COUNTRIES_LIST => array(50, 60) + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + MatchDeliveryCountries::COUNTRIES_LIST => array( + 'availableOperators' => array( + 'in' => 'Price', + 'out' => 'Price', + ), + 'value' => '', + 'selectedOperator' => 'in' + ) + ), + 'setOperators' => array( + 'countries' => 'in' + ), + 'setValues' => array( + 'countries' => array(50, 60) + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Condition/Implementation/MatchForEveryoneTest.php b/core/lib/Thelia/Tests/Condition/Implementation/MatchForEveryoneTest.php index ddf3d25ae..84b57afb1 100644 --- a/core/lib/Thelia/Tests/Condition/Implementation/MatchForEveryoneTest.php +++ b/core/lib/Thelia/Tests/Condition/Implementation/MatchForEveryoneTest.php @@ -13,7 +13,6 @@ namespace Thelia\Condition\Implementation; use Thelia\Condition\ConditionEvaluator; - use Thelia\Coupon\FacadeInterface; use Thelia\Model\Currency; diff --git a/core/lib/Thelia/Tests/Condition/Implementation/MatchForTotalAmountTest.php b/core/lib/Thelia/Tests/Condition/Implementation/MatchForTotalAmountTest.php index bffbda092..fa599a866 100644 --- a/core/lib/Thelia/Tests/Condition/Implementation/MatchForTotalAmountTest.php +++ b/core/lib/Thelia/Tests/Condition/Implementation/MatchForTotalAmountTest.php @@ -12,13 +12,12 @@ namespace Thelia\Tests\Condition\Implementation; +use Thelia\Condition\ConditionCollection; use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionFactory; use Thelia\Condition\Implementation\MatchForTotalAmount; use Thelia\Condition\Operators; -use Thelia\Condition\ConditionCollection; use Thelia\Coupon\FacadeInterface; - use Thelia\Model\Currency; use Thelia\Model\CurrencyQuery; diff --git a/core/lib/Thelia/Tests/Condition/Implementation/StartDateTest.php b/core/lib/Thelia/Tests/Condition/Implementation/StartDateTest.php new file mode 100644 index 000000000..6df0fddbb --- /dev/null +++ b/core/lib/Thelia/Tests/Condition/Implementation/StartDateTest.php @@ -0,0 +1,329 @@ + + */ +class StartDateTest extends \PHPUnit_Framework_TestCase +{ + + var $startDate; + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $this->startDate = time() - 2000; + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $address = new Address(); + $address->setCountryId(10); + + $stubFacade->expects($this->any()) + ->method('getDeliveryAddress') + ->will($this->returnValue($address)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $lang = new Lang(); + $lang->setDateFormat("d/m/Y"); + + $stubSession = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Session\Session') + ->disableOriginalConstructor() + ->getMock(); + + $stubSession->expects($this->any()) + ->method('getLang') + ->will($this->returnValue($lang)); + + $stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request') + ->disableOriginalConstructor() + ->getMock(); + + $stubRequest->expects($this->any()) + ->method('getSession') + ->will($this->returnValue($stubSession)); + + $stubFacade->expects($this->any()) + ->method('getRequest') + ->will($this->returnValue($stubRequest)); + + return $stubFacade; + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\StartDate::setValidators + * @expectedException \Thelia\Exception\InvalidConditionOperatorException + */ + public function testInValidBackOfficeInputOperator() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new StartDate($stubFacade); + + $operators = array( + StartDate::START_DATE => 'petite licorne' + ); + $values = array( + StartDate::START_DATE => $this->startDate + ); + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if validity test on BackOffice inputs are working + * + * @covers Thelia\Condition\Implementation\StartDate::setValidators + * @expectedException \Thelia\Exception\InvalidConditionValueException + */ + public function testInValidBackOfficeInputValue() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new StartDate($stubFacade); + $operators = array( + StartDate::START_DATE => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + StartDate::START_DATE => 'petit poney' + ); + + $condition1->setValidatorsFromForm($operators, $values); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\StartDate::isMatching + * + */ + public function testMatchingRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new StartDate($stubFacade); + $operators = array( + StartDate::START_DATE => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + StartDate::START_DATE => $this->startDate + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Condition\Implementation\StartDate::isMatching + * + */ + public function testNotMatching() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new StartDate($stubFacade); + + $operators = array( + StartDate::START_DATE => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + StartDate::START_DATE => time() + 2000 + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $isValid = $condition1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + /** @var FacadeInterface $stubFacade */ + $stubFacade = $this->generateFacadeStub(); + + $condition1 = new StartDate($stubFacade); + + $operators = array( + StartDate::START_DATE => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + StartDate::START_DATE => $this->startDate + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $serializableRule = $condition1->getSerializableCondition(); + + $expected = new SerializableCondition(); + $expected->conditionServiceId = $condition1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + /** + * Check getName i18n + * + * @covers Thelia\Condition\Implementation\StartDate::getName + * + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Number of articles in cart'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new StartDate($stubFacade); + + $actual = $condition1->getName(); + $expected = 'Number of articles in cart'; + $this->assertEquals($expected, $actual); + } + + /** + * Check tooltip i18n + * + * @covers Thelia\Condition\Implementation\StartDate::getToolTip + * + */ + public function testGetToolTip() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Sample coupon condition'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new StartDate($stubFacade); + + $actual = $condition1->getToolTip(); + $expected = 'Sample coupon condition'; + $this->assertEquals($expected, $actual); + } + + /** + * Check validator + * + * @covers Thelia\Condition\Implementation\StartDate::generateInputs + * + */ + public function testGetValidator() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Price'); + + /** @var FacadeInterface $stubFacade */ + $condition1 = new StartDate($stubFacade); + + $operators = array( + StartDate::START_DATE => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + StartDate::START_DATE => $this->startDate + ); + + $condition1->setValidatorsFromForm($operators, $values); + + $actual = $condition1->getValidators(); + + $validators = array( + 'inputs' => array( + StartDate::START_DATE => array( + 'availableOperators' => array( + '>=' => 'Price', + ), + 'value' => '', + 'selectedOperator' => '>=' + ) + ), + 'setOperators' => array( + 'start_date' => '>=' + ), + 'setValues' => array( + 'start_date' => $this->startDate + ) + ); + $expected = $validators; + + $this->assertEquals($expected, $actual); + + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Core/Template/Smarty/Plugins/FormatTest.php b/core/lib/Thelia/Tests/Core/Template/Smarty/Plugins/FormatTest.php index ad78dc670..b1643d7f9 100644 --- a/core/lib/Thelia/Tests/Core/Template/Smarty/Plugins/FormatTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Smarty/Plugins/FormatTest.php @@ -158,6 +158,23 @@ class FormatTest extends \PHPUnit_Framework_TestCase $this->assertEmpty($render); } + public function testFormatDateWithLocale() + { + $dateTime = new \DateTime(); + // 2014-06-17 + $dateTime->setTimestamp(1402987842); + + $formatClass = new Format($this->request); + + $render = $formatClass->formatDate(array( + 'date' => $dateTime, + 'locale' => ['fr_FR.UTF-8', 'fr_FR'], + 'format' => '%e %B %Y' + )); + + $this->assertEquals('17 juin 2014', $render); + } + /** * test formatNumber without mandatory parameters * diff --git a/core/lib/Thelia/Tests/Coupon/Type/FreeProductTest.php b/core/lib/Thelia/Tests/Coupon/Type/FreeProductTest.php new file mode 100644 index 000000000..72be02204 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/FreeProductTest.php @@ -0,0 +1,412 @@ + + */ +class FreeProductTest extends \PHPUnit_Framework_TestCase +{ + + /** @var Product $freeProduct */ + var $freeProduct; + var $originalPrice; + var $originalPromo; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $currency = CurrencyQuery::create()->filterByCode('EUR')->findOne(); + + // Find a product + $this->freeProduct = ProductQuery::create()->findOne(); + + $this->originalPrice = $this->freeProduct->getDefaultSaleElements()->getPricesByCurrency($currency)->getPrice(); + $this->originalPromo = $this->freeProduct->getDefaultSaleElements()->getPromo(); + + $this->freeProduct->getDefaultSaleElements()->setPromo(false)->save(); + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $stubDispatcher = $this->getMockBuilder('\Symfony\Component\EventDispatcher\EventDispatcher') + ->disableOriginalConstructor() + ->getMock(); + + $stubDispatcher->expects($this->any()) + ->method('dispatch') + ->will($this->returnCallback(function($dummy, $cartEvent) { + $ci = new CartItem(); + $ci->setId(3)->setPrice(123)->setPromo(0); + + $cartEvent->setCartItem($ci); + })); + + $stubFacade->expects($this->any()) + ->method('getDispatcher') + ->will($this->returnValue($stubDispatcher)); + + $stubSession = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Session\Session') + ->disableOriginalConstructor() + ->getMock(); + + $stubSession->expects($this->any()) + ->method('get') + ->will($this->onConsecutiveCalls(-1, 3)); + + $stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request') + ->disableOriginalConstructor() + ->getMock(); + + $stubRequest->expects($this->any()) + ->method('getSession') + ->will($this->returnValue($stubSession)); + + $stubFacade->expects($this->any()) + ->method('getRequest') + ->will($this->returnValue($stubRequest)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade, $count) { + + $product1 = new Product(); + $product1->setId(10); + + $product2 = new Product(); + $product2->setId(20); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(100)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(150)) + + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + if ($count == 1) + $ret = [$cartItem1Stub]; + else + $ret = [$cartItem1Stub, $cartItem2Stub]; + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue($ret)); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $product2 = new Product(); + $product2->setId(30); + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)) + ; + $cartItem2Stub->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(11000)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new FreeProduct($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20], 'offered_product_id' => $this->freeProduct->getId(), 'offered_category_id' => 1), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatchOne() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new FreeProduct($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20], 'offered_product_id' => $this->freeProduct->getId(), 'offered_category_id' => 1), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 1); + + $this->assertEquals(123.00, $coupon->exec()); + } + + public function testMatchSeveral() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new FreeProduct($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20], 'offered_product_id' => $this->freeProduct->getId(), 'offered_category_id' => 1), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 2); + + $this->assertEquals(123.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new FreeProduct($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20], 'offered_product_id' => $this->freeProduct->getId(), 'offered_category_id' => 1), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new FreeProduct($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new FreeProduct($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + $this->freeProduct->getDefaultSaleElements()->setPromo($this->originalPromo)->save(); + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnAttributeValuesTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnAttributeValuesTest.php new file mode 100644 index 000000000..67bd1ce60 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnAttributeValuesTest.php @@ -0,0 +1,398 @@ + + */ +class RemoveAmountOnAttributeValuesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade, $count) { + + $attrCombination1 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination1 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(10)) + ; + + $attrCombination2 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination2 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(20)) + ; + + $pse1 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock() + ; + $pse1 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1])) + ; + + $pse2 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock(); + ; + $pse2 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1, $attrCombination2])) + ; + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + if ($count == 1) + $ret = [$cartItem1Stub]; + else + $ret = [$cartItem1Stub, $cartItem2Stub]; + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue($ret)); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $attrCombination1 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination1 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(30)) + ; + + $pse1 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock() + ; + $pse1 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1])) + ; + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatchOne() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 1); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testMatchSeveral() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 2); + + $this->assertEquals(30.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnAttributeValues($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnCategoriesTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnCategoriesTest.php new file mode 100644 index 000000000..01be96bde --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnCategoriesTest.php @@ -0,0 +1,330 @@ + + */ +class RemoveAmountOnCategoriesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $category1 = new Category(); + $category1->setId(10); + + $category2 = new Category(); + $category2->setId(20); + + $category3 = new Category(); + $category3->setId(30); + + $product1 = new Product(); + $product1->addCategory($category1)->addCategory($category2); + + $product2 = new Product(); + $product2->addCategory($category3); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub, $cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $category3 = new Category(); + $category3->setId(30); + + $product2 = new Product(); + $product2->addCategory($category3); + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)); + + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + + $this->generateMatchingCart($stubFacade); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnCategories($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnCategories($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnProductsTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnProductsTest.php new file mode 100644 index 000000000..55e64f861 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveAmountOnProductsTest.php @@ -0,0 +1,343 @@ + + */ +class RemoveAmountOnProductsTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade, $count) { + + $product1 = new Product(); + $product1->setId(10); + + $product2 = new Product(); + $product2->setId(20); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + if ($count == 1) + $ret = [$cartItem1Stub]; + else + $ret = [$cartItem1Stub, $cartItem2Stub]; + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue($ret)); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $product2 = new Product(); + $product2->setId(30); + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)); + + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatchOne() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 1); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testMatchSeveral() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 2); + + $this->assertEquals(30.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemoveAmountOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('amount' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnProducts($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemoveAmountOnProducts($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnAttributeValuesTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnAttributeValuesTest.php new file mode 100644 index 000000000..eaa5e4de9 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnAttributeValuesTest.php @@ -0,0 +1,412 @@ + + */ +class RemovePercentageOnAttributeValuesTest extends \PHPUnit_Framework_TestCase +{ + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade, $count) { + + $attrCombination1 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination1 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(10)) + ; + + $attrCombination2 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination2 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(20)) + ; + + $pse1 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock() + ; + $pse1 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1])) + ; + + $pse2 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock(); + ; + $pse2 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1, $attrCombination2])) + ; + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(100)) + ; + + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(150)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + if ($count == 1) + $ret = [$cartItem1Stub]; + else + $ret = [$cartItem1Stub, $cartItem2Stub]; + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue($ret)); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $attrCombination1 = $this->getMockBuilder('\Thelia\Model\AttributeCombination') + ->disableOriginalConstructor() + ->getMock() + ; + + $attrCombination1 + ->expects($this->any()) + ->method('getAttributeAvId') + ->will($this->returnValue(30)) + ; + + $pse1 = $this->getMockBuilder('\Thelia\Model\ProductSaleElements') + ->disableOriginalConstructor() + ->getMock() + ; + $pse1 + ->expects($this->any()) + ->method('getAttributeCombinations') + ->will($this->returnValue([$attrCombination1])) + ; + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock() + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getProductSaleElements') + ->will($this->returnValue($pse1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(100)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatchOne() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 1); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testMatchSeveral() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 2); + + $this->assertEquals(40.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'attribute_avs' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnAttributeValues($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnCategoriesTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnCategoriesTest.php new file mode 100644 index 000000000..90b845531 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnCategoriesTest.php @@ -0,0 +1,346 @@ + + */ +class RemovePercentageOnCategoriesTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $category1 = new Category(); + $category1->setId(10); + + $category2 = new Category(); + $category2->setId(20); + + $category3 = new Category(); + $category3->setId(30); + + $product1 = new Product(); + $product1->addCategory($category1)->addCategory($category2); + + $product2 = new Product(); + $product2->addCategory($category3); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(100)) + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(200)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem1Stub, $cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $category3 = new Category(); + $category3->setId(30); + + $product2 = new Product(); + $product2->addCategory($category3); + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(200000)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnCategories($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10, 'categories' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + /** + * @covers Thelia\Coupon\Type\RemoveXAmount::getName + */ + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnCategories($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + /** + * @covers Thelia\Coupon\Type\RemoveXAmount::getToolTip + */ + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnCategories($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnProductsTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnProductsTest.php new file mode 100644 index 000000000..4c150b969 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemovePercentageOnProductsTest.php @@ -0,0 +1,360 @@ + + */ +class RemovePercentageOnProductsTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + } + + /** + * Generate adapter stub + * + * @param int $cartTotalPrice Cart total price + * @param string $checkoutCurrency Checkout currency + * @param string $i18nOutput Output from each translation + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function generateFacadeStub($cartTotalPrice = 400, $checkoutCurrency = 'EUR', $i18nOutput = '') + { + $stubFacade = $this->getMockBuilder('\Thelia\Coupon\BaseFacade') + ->disableOriginalConstructor() + ->getMock(); + + $currencies = CurrencyQuery::create(); + $currencies = $currencies->find(); + $stubFacade->expects($this->any()) + ->method('getAvailableCurrencies') + ->will($this->returnValue($currencies)); + + $stubFacade->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue($cartTotalPrice)); + + $stubFacade->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue($checkoutCurrency)); + + $stubFacade->expects($this->any()) + ->method('getConditionEvaluator') + ->will($this->returnValue(new ConditionEvaluator())); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + $stubTranslator->expects($this->any()) + ->method('trans') + ->will($this->returnValue($i18nOutput)); + + $stubFacade->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + return $stubFacade; + } + + public function generateMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade, $count) { + + $product1 = new Product(); + $product1->setId(10); + + $product2 = new Product(); + $product2->setId(20); + + $cartItem1Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem1Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product1)) + ; + + $cartItem1Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(1)) + ; + $cartItem1Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(100)) + + ; + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub + ->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)); + + $cartItem2Stub + ->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(150)) + + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + if ($count == 1) + $ret = [$cartItem1Stub]; + else + $ret = [$cartItem1Stub, $cartItem2Stub]; + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue($ret)); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function generateNoMatchingCart(\PHPUnit_Framework_MockObject_MockObject $stubFacade) { + + $product2 = new Product(); + $product2->setId(30); + + $cartItem2Stub = $this->getMockBuilder('\Thelia\Model\CartItem') + ->disableOriginalConstructor() + ->getMock(); + + $cartItem2Stub->expects($this->any()) + ->method('getProduct') + ->will($this->returnValue($product2)) + ; + $cartItem2Stub->expects($this->any()) + ->method('getQuantity') + ->will($this->returnValue(2)) + ; + $cartItem2Stub + ->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue(11000)) + ; + + $cartStub = $this->getMockBuilder('\Thelia\Model\Cart') + ->disableOriginalConstructor() + ->getMock(); + + $cartStub + ->expects($this->any()) + ->method('getCartItems') + ->will($this->returnValue([$cartItem2Stub])); + + $stubFacade->expects($this->any()) + ->method('getCart') + ->will($this->returnValue($cartStub)); + } + + public function testSet() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $condition1 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::SUPERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 40.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition1->setValidatorsFromForm($operators, $values); + + $condition2 = new MatchForTotalAmount($stubFacade); + $operators = array( + MatchForTotalAmount::CART_TOTAL => Operators::INFERIOR, + MatchForTotalAmount::CART_CURRENCY => Operators::EQUAL + ); + $values = array( + MatchForTotalAmount::CART_TOTAL => 400.00, + MatchForTotalAmount::CART_CURRENCY => 'EUR' + ); + $condition2->setValidatorsFromForm($operators, $values); + + $conditions = new ConditionCollection(); + $conditions[] = $condition1; + $conditions[] = $condition2; + $coupon->setConditions($conditions); + + $this->assertEquals('TEST', $coupon->getCode()); + $this->assertEquals('TEST Coupon', $coupon->getTitle()); + $this->assertEquals('This is a test coupon title', $coupon->getShortDescription()); + $this->assertEquals('This is a test coupon description', $coupon->getDescription()); + + $this->assertEquals(true, $coupon->isCumulative()); + $this->assertEquals(true, $coupon->isRemovingPostage()); + $this->assertEquals(true, $coupon->isAvailableOnSpecialOffers()); + $this->assertEquals(true, $coupon->isEnabled()); + + $this->assertEquals(254, $coupon->getMaxUsage()); + $this->assertEquals($date, $coupon->getExpirationDate()); + } + + public function testMatchOne() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 1); + + $this->assertEquals(10.00, $coupon->exec()); + } + + public function testMatchSeveral() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateMatchingCart($stubFacade, 2); + + $this->assertEquals(40.00, $coupon->exec()); + } + + public function testNoMatch() + { + $stubFacade = $this->generateFacadeStub(); + + $coupon = new RemovePercentageOnProducts($stubFacade); + + $date = new \DateTime(); + + $coupon->set( + $stubFacade, + 'TEST', 'TEST Coupon', 'This is a test coupon title', 'This is a test coupon description', + array('percentage' => 10.00, 'products' => [10, 20]), + true, true, true, true, + 254, + $date->setTimestamp(strtotime("today + 3 months")), + new ObjectCollection(), + new ObjectCollection(), + false + ); + + $this->generateNoMatchingCart($stubFacade); + + $this->assertEquals(0.00, $coupon->exec()); + } + + public function testGetName() + { + $stubFacade = $this->generateFacadeStub(399, 'EUR', 'Coupon test name'); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnProducts($stubFacade); + + $actual = $coupon->getName(); + $expected = 'Coupon test name'; + $this->assertEquals($expected, $actual); + } + + public function testGetToolTip() + { + $tooltip = 'Coupon test tooltip'; + $stubFacade = $this->generateFacadeStub(399, 'EUR', $tooltip); + + /** @var FacadeInterface $stubFacade */ + $coupon = new RemovePercentageOnProducts($stubFacade); + + $actual = $coupon->getToolTip(); + $expected = $tooltip; + $this->assertEquals($expected, $actual); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php index ed03a6fc3..730250967 100644 --- a/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php @@ -196,22 +196,6 @@ class RemoveXAmountTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $actual); } - /** - * @covers Thelia\Coupon\Type\RemoveXPercent::getToolTip - */ - public function testGetInputName() - { - $inputName = 'Amount removed from the cart'; - $stubFacade = $this->generateFacadeStub(399, 'EUR', $inputName); - - /** @var FacadeInterface $stubFacade */ - $coupon = new RemoveXAmount($stubFacade); - - $actual = $coupon->getInputName(); - $expected = $inputName; - $this->assertEquals($expected, $actual); - } - /** * Tears down the fixture, for example, closes a network connection. * This method is called after a test is executed. diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php index 2b36d27a2..5b58f59a7 100644 --- a/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php @@ -152,8 +152,6 @@ class RemoveXPercentTest extends \PHPUnit_Framework_TestCase $this->assertEquals(254, $coupon->getMaxUsage()); $this->assertEquals($date, $coupon->getExpirationDate()); - $this->assertEquals(array(RemoveXPercent::INPUT_PERCENTAGE_NAME), $coupon->getExtendedInputs()); - $this->assertEquals(40.00, $coupon->exec()); } @@ -188,22 +186,6 @@ class RemoveXPercentTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $actual); } - /** - * @covers Thelia\Coupon\Type\RemoveXPercent::getToolTip - */ - public function testGetInputName() - { - $inputName = 'Percentage removed from the cart'; - $stubFacade = $this->generateFacadeStub(399, 'EUR', $inputName); - - /** @var FacadeInterface $stubFacade */ - $coupon = new RemoveXPercent($stubFacade); - - $actual = $coupon->getInputName(); - $expected = $inputName; - $this->assertEquals($expected, $actual); - } - /** * Tears down the fixture, for example, closes a network connection. * This method is called after a test is executed. diff --git a/core/lib/Thelia/Tests/Tools/FileManagerTest.php b/core/lib/Thelia/Tests/Tools/FileManagerTest.php index 9fe76878b..8c9de5965 100644 --- a/core/lib/Thelia/Tests/Tools/FileManagerTest.php +++ b/core/lib/Thelia/Tests/Tools/FileManagerTest.php @@ -787,7 +787,7 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase ->getMock(); $stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile') - ->disableOriginalConstructor() + ->setConstructorArgs([__DIR__ . '/fixtures/test.xml', 'test.xml']) ->getMock(); $stubUploadedFile->expects($this->any()) ->method('getClientOriginalExtension') @@ -814,8 +814,9 @@ class FileManagerTest extends \PHPUnit_Framework_TestCase ->getMock(); $stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile') - ->disableOriginalConstructor() + ->setConstructorArgs([__DIR__ . '/fixtures/test.xml', 'test.xml']) ->getMock(); + $stubUploadedFile->expects($this->any()) ->method('getClientOriginalExtension') ->will($this->returnValue('')); diff --git a/local/modules/Tinymce/Resources/media/.gitkeep b/core/lib/Thelia/Tests/Tools/fixtures/test.xml old mode 100755 new mode 100644 similarity index 100% rename from local/modules/Tinymce/Resources/media/.gitkeep rename to core/lib/Thelia/Tests/Tools/fixtures/test.xml diff --git a/core/lib/Thelia/Tests/WebTestCase.php b/core/lib/Thelia/Tests/WebTestCase.php new file mode 100644 index 000000000..2976b6dfa --- /dev/null +++ b/core/lib/Thelia/Tests/WebTestCase.php @@ -0,0 +1,59 @@ + + */ +class WebTestCase extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Thelia\Core\Thelia + */ + protected static $kernel; + + /** + * @param array $options + * @param array $server + * @return \Symfony\Component\HttpKernel\Client + */ + protected static function createClient(array $options = [], array $server = []) + { + if (null !== static::$kernel) { + static::$kernel->shutdown(); + } + + static::$kernel = new Thelia('test', true); + static::$kernel->boot(); + + $client = static::$kernel->getContainer()->get('test.client'); + $client->setServerParameters($server); + + return $client; + } + + /** + * Shuts the kernel down if it was used in the test. + */ + protected function tearDown() + { + if (null !== static::$kernel) { + static::$kernel->shutdown(); + } + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tests/bootstrap.php b/core/lib/Thelia/Tests/bootstrap.php index 86f6d8355..c4733ca1d 100755 --- a/core/lib/Thelia/Tests/bootstrap.php +++ b/core/lib/Thelia/Tests/bootstrap.php @@ -5,6 +5,7 @@ * @file * Functions needed for Thelia bootstrap */ +ini_set('session.use_cookies', 0); $env = "test"; require_once __DIR__ . '/../../../bootstrap.php'; diff --git a/core/lib/Thelia/Tools/FileManager.php b/core/lib/Thelia/Tools/FileManager.php index 351283d8c..caf8fe61f 100644 --- a/core/lib/Thelia/Tools/FileManager.php +++ b/core/lib/Thelia/Tools/FileManager.php @@ -95,10 +95,11 @@ class FileManager if (!$model->save()) { throw new ImageException( sprintf( - '%s %s (%s) failed to be saved (image file)', + '%s %s (%s) with id %d failed to be saved (image file)', ucfirst($parentType), $model->getFile(), - $fileType + $fileType, + $parentId ) ); } diff --git a/local/config/schema.xml b/local/config/schema.xml index 24a80d46d..5f86bb9e8 100644 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -622,6 +622,10 @@ + + + + diff --git a/local/modules/Colissimo/Config/prices.json b/local/modules/Colissimo/Config/prices.json index 1b23c825c..f1e040600 100755 --- a/local/modules/Colissimo/Config/prices.json +++ b/local/modules/Colissimo/Config/prices.json @@ -1,17 +1,17 @@ {"1": { "_info": "area 1 : France", "slices": { - "0.25": "5.23", - "0.5": 5.8, - "0.75": 6.56, - "1": 7.13, - "2": 8.08, - "3": 9.22, - "5": 11.31, - "7": 13.4, - "10": 16.53, - "15": 19.14, - "30": 26.93 + "0.25": 5.23, + "0.5": 5.99, + "0.75": 6.75, + "1": 7.36, + "2": 8.36, + "3": 9.55, + "5": 11.73, + "7": 13.92, + "10": 17.15, + "15": 19.81, + "30": 27.79 } }, "2": { "_info": "area 2 : A Zone - Union Europ\u00e9enne et Suisse", @@ -34,87 +34,87 @@ }, "3": { "_info": "area 3 : B Zone - Pays de l\u2019Europe de l\u2019Est (hors Union Europ\u00e9enne), Norv\u00e8ge, Maghreb", "slices": { - "1": 18.81, - "2": 20.62, - "3": 24.94, - "4": 29.26, - "5": 33.58, - "6": 37.91, - "7": 42.23, - "8": 46.55, - "9": 50.87, - "10": 55.2, - "15": 65.08, - "20": 74.96 + "1": 19.38, + "2": 22.23, + "3": 26.46, + "4": 30.69, + "5": 34.96, + "6": 39.24, + "7": 43.51, + "8": 47.79, + "9": 52.06, + "10": 56.34, + "15": 66.79, + "20": 77.24 } }, "4": { "_info": "area 4 : C Zone - Pays d\u2019Afrique hors Maghreb, Canada, Etats-Unis, Proche et Moyen Orient", "slices": { - "1": 22.04, - "2": 29.55, - "3": 38.86, - "4": 48.17, - "5": 57.48, - "6": 66.79, - "7": 76.1, - "8": 85.41, - "9": 94.72, - "10": 104.03, - "15": 126.92, - "20": 149.82 + "1": 23.66, + "2": 31.26, + "3": 40.47, + "4": 49.69, + "5": 58.90, + "6": 68.12, + "7": 77.33, + "8": 86.55, + "9": 95.76, + "10": 104.98, + "15": 129.87, + "20": 154.76 } }, "5": { "_info": "area 5 : D Zone - Autres destinations", "slices": { - "1": 25.08, - "2": 37.72, - "3": 50.26, - "4": 62.8, - "5": 75.34, - "6": 87.88, - "7": 100.42, - "8": 112.96, - "9": 125.5, - "10": 138.04, - "15": 162.74, - "20": 187.44 + "1": 26.27, + "2": 38.81, + "3": 51.35, + "4": 63.89, + "5": 76.43, + "6": 88.97, + "7": 101.51, + "8": 114.05, + "9": 126.59, + "10": 139.13, + "15": 163.83, + "20": 188.53 } }, "6": { "_info": "area 6 : France OM1", "slices": { - "0.5": 8.27, - "1": 12.49, - "2": 17.05, - "3": 21.61, - "4": 26.17, - "5": 30.73, - "6": 35.29, - "7": 39.85, - "8": 44.41, - "9": 48.97, - "10": 53.53, - "15": 76.33, - "20": 99.13, - "25": 121.93, - "30": 144.73 + "0.5": 8.5, + "1": 12.87, + "2": 17.58, + "3": 22.28, + "4": 26.98, + "5": 31.68, + "6": 36.39, + "7": 41.09, + "8": 45.79, + "9": 50.49, + "10": 55.2, + "15": 78.95, + "20": 102.7, + "25": 126.45, + "30": 150.2 } }, "7": { "_info": "area 7 : France OM2", "slices": { - "0.5": 9.88, - "1": 14.92, - "2": 26.32, - "3": 37.72, - "4": 49.12, - "5": 60.52, - "6": 71.92, - "7": 83.32, - "8": 94.72, - "9": 106.12, - "10": 117.52, - "15": 174.52, - "20": 231.52, - "25": 288.52, - "30": 345.52 + "0.5": 10.17, + "1": 15.39, + "2": 27.12, + "3": 38.86, + "4": 50.59, + "5": 62.32, + "6": 74.05, + "7": 85.79, + "8": 97.52, + "9": 109.25, + "10": 120.98, + "15": 179.69, + "20": 238.4, + "25": 297.11, + "30": 355.82 } -}} \ No newline at end of file +}} diff --git a/local/modules/Colissimo/Listener/SendMail.php b/local/modules/Colissimo/Listener/SendMail.php index 58fb0d4c4..8464aca49 100755 --- a/local/modules/Colissimo/Listener/SendMail.php +++ b/local/modules/Colissimo/Listener/SendMail.php @@ -17,6 +17,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\Order\OrderEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Template\ParserInterface; +use Thelia\Log\Tlog; use Thelia\Mailer\MailerFactory; use Thelia\Model\ConfigQuery; use Thelia\Model\MessageQuery; @@ -47,7 +48,7 @@ class SendMail implements EventSubscriberInterface $order = $event->getOrder(); $colissimo = new Colissimo(); - if ($order->getStatusId() == OrderStatus::CODE_SENT && $order->getDeliveryModuleId() == $colissimo->getModuleModel()->getId()) { + if ($order->isSent() && $order->getDeliveryModuleId() == $colissimo->getModuleModel()->getId()) { $contact_email = ConfigQuery::read('store_email'); if ($contact_email) { @@ -83,6 +84,12 @@ class SendMail implements EventSubscriberInterface $message->buildMessage($this->parser, $instance); $this->mailer->send($instance); + + Tlog::getInstance()->debug("Colissimo shipping message sent to customer ".$customer->getEmail()); + } + else { + $customer = $order->getCustomer(); + Tlog::getInstance()->debug("Colissimo shipping message no contact email customer_id", $customer->getId()); } } } @@ -113,4 +120,4 @@ class SendMail implements EventSubscriberInterface TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128) ); } -} \ No newline at end of file +} diff --git a/local/modules/Front/Config/front.xml b/local/modules/Front/Config/front.xml index 0a987eaa2..c37b119ad 100644 --- a/local/modules/Front/Config/front.xml +++ b/local/modules/Front/Config/front.xml @@ -160,6 +160,11 @@ order-invoice + + Front\Controller\CouponController::clearAllCouponsAction + order-invoice + + Front\Controller\OrderController::pay diff --git a/local/modules/Front/Controller/ContactController.php b/local/modules/Front/Controller/ContactController.php index 2ff4452d7..0d49dcfce 100644 --- a/local/modules/Front/Controller/ContactController.php +++ b/local/modules/Front/Controller/ContactController.php @@ -46,7 +46,8 @@ class ContactController extends BaseFrontController $form = $this->validateForm($contactForm); $message = \Swift_Message::newInstance($form->get('subject')->getData()) - ->addFrom($form->get('email')->getData(), $form->get('name')->getData()) + ->addFrom(ConfigQuery::read("store_email"), $form->get('name')->getData()) + ->addReplyTo($form->get('email')->getData(), $form->get('name')->getData()) ->addTo(ConfigQuery::read('store_email'), ConfigQuery::read('store_name')) ->setBody($form->get('message')->getData()) ; diff --git a/local/modules/Front/Controller/CouponController.php b/local/modules/Front/Controller/CouponController.php index 98333dd0a..8bce7b206 100644 --- a/local/modules/Front/Controller/CouponController.php +++ b/local/modules/Front/Controller/CouponController.php @@ -40,9 +40,16 @@ use Thelia\Module\Exception\DeliveryException; */ class CouponController extends BaseFrontController { + /** + * Clear all coupons. + */ + public function clearAllCouponsAction() { + // Dispatch Event to the Action + $this->getDispatcher()->dispatch(TheliaEvents::COUPON_CLEAR_ALL); + } /** - * Test Coupon consuming + * Coupon consuming */ public function consumeAction() { diff --git a/local/modules/Tinymce/.gitignore b/local/modules/Tinymce/.gitignore deleted file mode 100644 index fc9e06409..000000000 --- a/local/modules/Tinymce/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Resources/* \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/category-edit-js.html b/local/modules/Tinymce/AdminIncludes/category-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/category-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/category-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/content-edit-js.html b/local/modules/Tinymce/AdminIncludes/content-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/content-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/content-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/coupon-create-js.html b/local/modules/Tinymce/AdminIncludes/coupon-create-js.html index 209efdd16..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/coupon-create-js.html +++ b/local/modules/Tinymce/AdminIncludes/coupon-create-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/coupon-update-js.html b/local/modules/Tinymce/AdminIncludes/coupon-update-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/coupon-update-js.html +++ b/local/modules/Tinymce/AdminIncludes/coupon-update-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/document-edit-js.html b/local/modules/Tinymce/AdminIncludes/document-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/document-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/document-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/folder-edit-js.html b/local/modules/Tinymce/AdminIncludes/folder-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/folder-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/folder-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/image-edit-js.html b/local/modules/Tinymce/AdminIncludes/image-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/image-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/image-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/AdminIncludes/product-edit-js.html b/local/modules/Tinymce/AdminIncludes/product-edit-js.html index a75604b18..8e2952d56 100644 --- a/local/modules/Tinymce/AdminIncludes/product-edit-js.html +++ b/local/modules/Tinymce/AdminIncludes/product-edit-js.html @@ -1 +1 @@ -{include file="include/tinymce_init.tpl"} \ No newline at end of file +{include file="includes/tinymce_init.tpl"} \ No newline at end of file diff --git a/local/modules/Tinymce/Config/config.xml b/local/modules/Tinymce/Config/config.xml index df0ef054b..b3ee6037b 100644 --- a/local/modules/Tinymce/Config/config.xml +++ b/local/modules/Tinymce/Config/config.xml @@ -4,33 +4,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd"> - - - - - - - - - - - - - - - - - - + + + + diff --git a/local/modules/Tinymce/Config/module.xml b/local/modules/Tinymce/Config/module.xml index c27913441..69c4f304c 100644 --- a/local/modules/Tinymce/Config/module.xml +++ b/local/modules/Tinymce/Config/module.xml @@ -7,12 +7,12 @@ Editeur visuel TinyMCE - 0.1 + 0.5 Manuel Raynaud manu@thelia.net classic 2.0.0 - alpha + beta diff --git a/local/modules/Tinymce/Config/schema.xml b/local/modules/Tinymce/Config/schema.xml deleted file mode 100644 index 1866f6300..000000000 --- a/local/modules/Tinymce/Config/schema.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/local/modules/Tinymce/I18n/backOffice/default/fr_FR.php b/local/modules/Tinymce/I18n/backOffice/default/fr_FR.php new file mode 100644 index 000000000..7a985ce9b --- /dev/null +++ b/local/modules/Tinymce/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,5 @@ + 'Explorateur de fichiers', +); diff --git a/local/modules/Tinymce/Listener/VerifyTinymceListener.php b/local/modules/Tinymce/Listener/VerifyTinymceListener.php deleted file mode 100644 index 2b8e5efce..000000000 --- a/local/modules/Tinymce/Listener/VerifyTinymceListener.php +++ /dev/null @@ -1,81 +0,0 @@ - - */ -class VerifyTinymceListener implements EventSubscriberInterface -{ - - public function verifyTinymce(Event $event) - { - $fs = new Filesystem(); - if (false === file_exists(THELIA_WEB_DIR . '/tinymce')) { - $fs->mirror(__DIR__ . DS .'..'. DS .'Resources'.DS.'js'.DS.'tinymce', THELIA_WEB_DIR . 'tinymce'); - } - - if (false === file_exists(THELIA_WEB_DIR . '/media')) { - $fs->symlink(__DIR__ . DS .'..'.DS.'Resources'.DS.'media', THELIA_WEB_DIR . 'media'); - } - } - - public function clearCache(CacheEvent $event) - { - if (true === file_exists(THELIA_WEB_DIR . '/tinymce')) { - $fs = new Filesystem(); - - $directory = new \DirectoryIterator(THELIA_WEB_DIR . '/tinymce'); - - $fs->remove($directory); - } - } - - /** - * Returns an array of event names this subscriber wants to listen to. - * - * The array keys are event names and the value can be: - * - * * The method name to call (priority defaults to 0) - * * An array composed of the method name to call and the priority - * * An array of arrays composed of the method names to call and respective - * priorities, or 0 if unset - * - * For instance: - * - * * array('eventName' => 'methodName') - * * array('eventName' => array('methodName', $priority)) - * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) - * - * @return array The event names to listen to - * - * @api - */ - public static function getSubscribedEvents() - { - return array( - TheliaEvents::BOOT => array('verifyTinymce', 128), - TheliaEvents::CACHE_CLEAR => array("clearCache", 0) - ); - } -} \ No newline at end of file diff --git a/local/modules/Tinymce/Resources/js/tinymce/filemanager/ajax_calls.php b/local/modules/Tinymce/Resources/js/tinymce/filemanager/ajax_calls.php new file mode 100644 index 000000000..6802ee276 --- /dev/null +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/ajax_calls.php @@ -0,0 +1,295 @@ +open($path) === TRUE) { + //make all the folders + for($i = 0; $i < $zip->numFiles; $i++) + { + $OnlyFileName = $zip->getNameIndex($i); + $FullFileName = $zip->statIndex($i); + if (substr($FullFileName['name'], -1, 1) =="/") + { + create_folder($base_folder.$FullFileName['name']); + } + } + //unzip into the folders + for($i = 0; $i < $zip->numFiles; $i++) + { + $OnlyFileName = $zip->getNameIndex($i); + $FullFileName = $zip->statIndex($i); + + if (!(substr($FullFileName['name'], -1, 1) =="/")) + { + $fileinfo = pathinfo($OnlyFileName); + if(in_array(strtolower($fileinfo['extension']),$ext)) + { + copy('zip://'. $path .'#'. $OnlyFileName , $base_folder.$FullFileName['name'] ); + } + } + } + $zip->close(); + } + else { + die(lang_Zip_No_Extract); + } + + break; + + case "gz": + $p = new PharData($path); + $p->decompress(); // creates files.tar + + break; + + case "tar": + // unarchive from the tar + $phar = new PharData($path); + $phar->decompressFiles(); + $files = array(); + check_files_extensions_on_phar( $phar, $files, '', $ext ); + $phar->extractTo( $current_path.fix_dirname( $_POST['path'] )."/", $files, TRUE ); + + break; + + default: + die(lang_Zip_Invalid); + } + break; + case 'media_preview': + $preview_file = $_GET["file"]; + $info = pathinfo($preview_file); + ?> + + + + + + + + + + \ No newline at end of file diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/config/.htaccess b/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess old mode 100755 new mode 100644 similarity index 100% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/config/.htaccess rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/config/config.php b/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php similarity index 55% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/config/config.php rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php index 9c2cd533b..02fb90f44 100644 --- a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/config/config.php +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php @@ -1,16 +1,16 @@ boot(); $httpKernel = $thelia->getContainer()->get('http_kernel'); @@ -18,64 +18,100 @@ $httpKernel = $thelia->getContainer()->get('http_kernel'); $httpKernel->getContainer()->enterScope('request'); $httpKernel->getContainer()->set('request', $request, 'request'); $httpKernel->initSession($request); + /** @var \Thelia\Core\Security\SecurityContext $securityContext */ $securityContext = $httpKernel->getContainer()->get('thelia.securityContext'); +// We just check the current user has the ADMIN role. $isGranted = $securityContext->isGranted( - array('ADMIN'), - array( - \Thelia\Core\Security\Resource\AdminResources::PRODUCT, - \Thelia\Core\Security\Resource\AdminResources::CATEGORY, - \Thelia\Core\Security\Resource\AdminResources::FOLDER, - \Thelia\Core\Security\Resource\AdminResources::CONTENT, - ), - array(), - array( - \Thelia\Core\Security\AccessManager::UPDATE, - \Thelia\Core\Security\AccessManager::CREATE, - ) + array('ADMIN'), array(), array(), array() ); if (false === $isGranted) { + echo "Sorry, it seems that you're not allowed to use this function. ADMIN role is required."; + exit; } - //------------------------------------------------------------------------------ -// DON'T COPY THIS VARIABLES IN FOLDERS config.php FILES +// DO NOT COPY THESE VARIABLES IN FOLDERS config.php FILES //------------------------------------------------------------------------------ //********************** //Path configuration //********************** -// In this configuration the folder tree is -// root -// |- source <- upload folder -// |- thumbs <- thumbnail folder [must have write permission (755)] -// |- filemanager -// |- js -// | |- tinymce -// | | |- plugins -// | | | |- responsivefilemanager -// | | | | |- plugin.min.js -$base_url=rtrim(\Thelia\Model\ConfigQuery::read('url_site'), '/'); // base url (only domain) of site (without final /). If you prefer relative urls leave empty -$upload_dir = '/media/'; // path from base_url to base of upload folder (with start and final /) -$current_path = '../../../media/'; // relative path from filemanager folder to upload folder (with final /) -//thumbs folder can't put inside upload folder -$thumbs_base_path = '../../../media/'; // relative path from filemanager folder to thumbs folder (with final /) +// In this configuration the media folder is located in the /web directory. -//------------------------------------------------------------------------------ -// YOU CAN COPY AND CHANGE THESE VARIABLES IN FOLDERS config.php FILES -//------------------------------------------------------------------------------ +// base url of site (without final /). if you prefer relative urls leave empty. +$base_url = rtrim(ConfigQuery::getConfiguredShopUrl(), '/'); -$MaxSizeUpload=100; //Mb +// Argh, url_site is not defined ?! +if (empty($base_url)) { + // A we did not used the router to access this dialog, we cannot use the URL class. Use the good old method. + $base_url = $request->getSchemeAndHttpHost() . preg_replace('!/tinymce/filemanager/dialog.php.*$!', '', $_SERVER['REQUEST_URI']); +} -$default_language="en_EN"; //default language file name +// path from base_url to base of upload folder (with start and final /) +$upload_dir = '/media/upload/'; -$show_folder_size=true; //Show or not show folder size in list view feature in filemanager (is possible, if there is a large folder, to greatly increase the calculations) -$show_sorting_bar=true; //Show or not show sorting feature in filemanager -$loading_bar=true; //Show or not show loading bar +// path to file manager folder to upload folder (with final /) +$current_path = THELIA_WEB_DIR . DS . 'media'. DS .'upload'. DS; + +// path to file manager folder to thumbs folder (with final /) +// WARNING: thumbs folder should not be inside the upload folder +$thumbs_base_path = THELIA_WEB_DIR . DS . 'media'. DS .'thumbs'. DS; + +// Set the language to the back-office current language, if it is available +$current_locale = $request->getSession()->getLang()->getLocale(); + +if (file_exists(__DIR__.DS.'..'.DS.'lang.'.DS.$current_locale.'.php')) { + $default_language = $current_locale; +} +else { + $default_language = 'en_EN'; +} + +// OPTIONAL SECURITY +// if set to true only those will access RF whose url contains the access key(akey) like: +// +// in tinymce a new parameter added: filemanager_access_key:"myPrivateKey" +// example tinymce config: +// tiny init ... +// +// external_filemanager_path:"../filemanager/", +// filemanager_title:"Filemanager" , +// filemanager_access_key:"myPrivateKey" , +// ... +define('USE_ACCESS_KEYS', FALSE); // TRUE or FALSE + +// add access keys eg: array('myPrivateKey', 'someoneElseKey'); +// keys should only containt (a-z A-Z 0-9 \ . _ -) characters +// if you are integrating lets say to a cms for admins, i recommend making keys randomized something like this: +// $username = 'Admin'; +// $salt = 'dsflFWR9u2xQa' (a hard coded string) +// $akey = md5($username.$salt); +// DO NOT use 'key' as access key! +// Keys are CASE SENSITIVE! +$access_keys = array('myPrivateKey','someoneElseKey'); + +//-------------------------------------------------------------------------------------------------------- +// YOU CAN COPY AND CHANGE THESE VARIABLES INTO FOLDERS config.php FILES TO CUSTOMIZE EACH FOLDER OPTIONS +//-------------------------------------------------------------------------------------------------------- + +$MaxSizeUpload = 100; //Mb + +// SERVER OVERRIDE +if ((int)(ini_get('post_max_size')) < $MaxSizeUpload){ + $MaxSizeUpload = (int)(ini_get('post_max_size')); +} + +// $default_language = "en_EN"; //default language file name +$icon_theme = "ico"; //ico or ico_dark you can cusatomize just putting a folder inside filemanager/img +$show_folder_size = TRUE; //Show or not show folder size in list view feature in filemanager (is possible, if there is a large folder, to greatly increase the calculations) +$show_sorting_bar = TRUE; //Show or not show sorting feature in filemanager +$loading_bar = TRUE; //Show or not show loading bar +$transliteration = FALSE; //active or deactive the transliteration (mean convert all strange characters in A..Za..z0..9 characters) //******************************************* //Images limit and resizing configuration @@ -84,16 +120,16 @@ $loading_bar=true; //Show or not show loading bar // set maximum pixel width and/or maximum pixel height for all images // If you set a maximum width or height, oversized images are converted to those limits. Images smaller than the limit(s) are unaffected // if you don't need a limit set both to 0 -$image_max_width=0; -$image_max_height=0; +$image_max_width = 0; +$image_max_height = 0; //Automatic resizing // -// If you set $image_resizing to true the script converts all uploaded images exactly to image_resizing_width x image_resizing_height dimension +// If you set $image_resizing to TRUE the script converts all uploaded images exactly to image_resizing_width x image_resizing_height dimension // If you set width or height to 0 the script automatically calculates the other dimension // Is possible that if you upload very big images the script not work to overcome this increase the php configuration of memory and time limit -$image_resizing=false; -$image_resizing_width=0; -$image_resizing_height=0; +$image_resizing = FALSE; +$image_resizing_width = 0; +$image_resizing_height = 0; //****************** // Default layout setting @@ -101,23 +137,35 @@ $image_resizing_height=0; // 0 => boxes // 1 => detailed list (1 column) // 2 => columns list (multiple columns depending on the width of the page) -// YOU CAN ALSO PASS THIS PARAMETERS USING SESSION VAR => $_SESSION["VIEW"]= +// YOU CAN ALSO PASS THIS PARAMETERS USING SESSION VAR => $_SESSION['RF']["VIEW"]= // //****************** -$default_view=0; +$default_view = 0; //set if the filename is truncated when overflow first row -$ellipsis_title_after_first_row=true; +$ellipsis_title_after_first_row = TRUE; //************************* //Permissions configuration //****************** -$delete_files=true; -$create_folders=true; -$delete_folders=true; -$upload_files=true; -$rename_files=true; -$rename_folders=true; +$delete_files = TRUE; +$create_folders = TRUE; +$delete_folders = TRUE; +$upload_files = TRUE; +$rename_files = TRUE; +$rename_folders = TRUE; +$duplicate_files = TRUE; +$copy_cut_files = TRUE; // for copy/cut files +$copy_cut_dirs = TRUE; // for copy/cut directories + + +// defines size limit for paste in MB / operation +// set 'FALSE' for no limit +$copy_cut_max_size = 100; +// defines file count limit for paste / operation +// set 'FALSE' for no limit +$copy_cut_max_count = 200; +//IF any of these limits reached, operation won't start and generate warning //********************** //Allowed extensions (lowercase insert) @@ -128,22 +176,22 @@ $ext_video = array('mov', 'mpeg', 'mp4', 'avi', 'mpg','wma',"flv","webm"); //Vid $ext_music = array('mp3', 'm4a', 'ac3', 'aiff', 'mid','ogg','wav'); //Audio $ext_misc = array('zip', 'rar','gz','tar','iso','dmg'); //Archives -$ext=array_merge($ext_img, $ext_file, $ext_misc, $ext_video,$ext_music); //allowed extensions - +$ext = array_merge($ext_img, $ext_file, $ext_misc, $ext_video,$ext_music); //allowed extensions /****************** * AVIARY config - *******************/ -$aviary_key="dvh8qudbp6yx2bnp"; -$aviary_secret="m6xaym5q42rpw433"; -$aviary_version=3; -$aviary_language='en'; +*******************/ +$aviary_active = FALSE; +$aviary_key = "dvh8qudbp6yx2bnp"; +$aviary_secret = "m6xaym5q42rpw433"; +$aviary_version = 3; +$aviary_language= 'en'; //The filter and sorter are managed through both javascript and php scripts because if you have a lot of //file in a folder the javascript script can't sort all or filter all, so the filemanager switch to php script. //The plugin automatic swich javascript to php when the current folder exceeds the below limit of files number -$file_number_limit_js=500; +$file_number_limit_js = 500; //********************** // Hidden files and folders @@ -154,10 +202,10 @@ $hidden_folders = array(); $hidden_files = array('config.php'); /******************* - * JAVA upload + * JAVA upload *******************/ -$java_upload=true; -$JAVAMaxSizeUpload=200; //Gb +$java_upload = TRUE; +$JAVAMaxSizeUpload = 200; //Gb //************************************ @@ -171,7 +219,7 @@ $JAVAMaxSizeUpload=200; //Gb // Remember than the image creation respect the folder hierarchy so if you are inside source/test/test1/ the new image will create at // path_from_filemanager/test/test1/ // PS if there isn't write permission in your destination folder you must set it -$fixed_image_creation = false; //activate or not the creation of one or more image resized with fixed path from filemanager folder +$fixed_image_creation = FALSE; //activate or not the creation of one or more image resized with fixed path from filemanager folder $fixed_path_from_filemanager = array('../test/','../test1/'); //fixed path of the image folder from the current position on upload folder $fixed_image_creation_name_to_prepend = array('','test_'); //name to prepend on filename $fixed_image_creation_to_append = array('_test',''); //name to appendon filename @@ -183,7 +231,7 @@ $fixed_image_creation_height = array(200,''); //height of image (you // With Responsive filemanager you can create automatically resized image inside the upload folder, also more than one at a time // just simply add a value in the array // The image creation path is always relative so if i'm inside source/test/test1 and I upload an image, the path start from here -$relative_image_creation = false; //activate or not the creation of one or more image resized with relative path from upload folder +$relative_image_creation = FALSE; //activate or not the creation of one or more image resized with relative path from upload folder $relative_path_from_current_pos = array('thumb/','thumb/'); //relative path of the image folder from the current position on upload folder $relative_image_creation_name_to_prepend= array('','test_'); //name to prepend on filename $relative_image_creation_name_to_append = array('_test',''); //name to append on filename diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap-lightbox.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-lightbox.min.css similarity index 100% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap-lightbox.min.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-lightbox.min.css diff --git a/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-modal.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-modal.min.css new file mode 100644 index 000000000..373c1b6ba --- /dev/null +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-modal.min.css @@ -0,0 +1,8 @@ +/*! + * Bootstrap Modal + * + * Copyright Jordan Schroter + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */.modal-open{overflow:hidden}.modal-open.page-overflow .page-container,.modal-open.page-overflow .page-container .navbar-fixed-top,.modal-open.page-overflow .page-container .navbar-fixed-bottom,.modal-open.page-overflow .modal-scrollable{overflow-y:scroll}@media (max-width:840px){.modal-open.page-overflow .page-container .navbar-fixed-top,.modal-open.page-overflow .page-container .navbar-fixed-bottom{overflow-y:visible}}.modal-scrollable{position:fixed;top:0;bottom:0;left:0;right:0;overflow:auto}.modal{outline:0;position:absolute;margin-top:0;top:50%;overflow:visible}.modal.fade{top:-100%;-webkit-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out}.modal.fade.in{top:50%}.modal-body{max-height:none;overflow:visible}.modal.modal-absolute{position:absolute;z-index:950}.modal .loading-mask{position:absolute;top:0;bottom:0;left:0;right:0;background:#fff;border-radius:6px}.modal-backdrop.modal-absolute{position:absolute;z-index:940}.modal-backdrop,.modal-backdrop.fade.in{opacity:.85;filter:alpha(opacity=85);background:#eee}.modal.container{width:940px;margin-left:-470px}.modal-overflow.modal{top:1%}.modal-overflow.modal.fade{top:-100%}.modal-overflow.modal.fade.in{top:1%}.modal-overflow .modal-body{overflow:auto;-webkit-overflow-scrolling:touch}@media (min-width:1200px){.modal.container{width:1170px;margin-left:-585px}}@media (max-width:840px){.modal,.modal.container,.modal.modal-overflow{top:1%;right:1%;left:1%;bottom:auto;width:auto!important;height:auto!important;margin:0!important;padding:0!important}.modal.fade.in,.modal.container.fade.in,.modal.modal-overflow.fade.in{top:1%;bottom:auto}.modal-body,.modal-overflow .modal-body{position:static;margin:0;height:auto!important;max-height:none!important;overflow:visible!important}.modal-footer,.modal-overflow .modal-footer{position:static}}.loading-spinner{position:absolute;top:50%;left:50%;margin:-12px 0 0 -12px}.animated{-webkit-animation-duration:1s;-moz-animation-duration:1s;-o-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;-o-animation-fill-mode:both;animation-fill-mode:both}@-webkit-keyframes shake{0%,100%{-webkit-transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px)}}@-moz-keyframes shake{0%,100%{-moz-transform:translateX(0)}10%,30%,50%,70%,90%{-moz-transform:translateX(-10px)}20%,40%,60%,80%{-moz-transform:translateX(10px)}}@-o-keyframes shake{0%,100%{-o-transform:translateX(0)}10%,30%,50%,70%,90%{-o-transform:translateX(-10px)}20%,40%,60%,80%{-o-transform:translateX(10px)}}@keyframes shake{0%,100%{transform:translateX(0)}10%,30%,50%,70%,90%{transform:translateX(-10px)}20%,40%,60%,80%{transform:translateX(10px)}}.shake{-webkit-animation-name:shake;-moz-animation-name:shake;-o-animation-name:shake;animation-name:shake} \ No newline at end of file diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap-responsive.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-responsive.min.css similarity index 100% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap-responsive.min.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap-responsive.min.css diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap.min.css similarity index 100% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/bootstrap.min.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/bootstrap.min.css diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/dropzone.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/dropzone.css similarity index 97% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/dropzone.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/dropzone.css index 569645a19..bb839c214 100644 --- a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/dropzone.css +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/dropzone.css @@ -169,7 +169,7 @@ -o-transition: opacity 0.3s ease-in-out; -ms-transition: opacity 0.3s ease-in-out; transition: opacity 0.3s ease-in-out; - background-image: url("../img/spritemap.png"); + /*background-image: url("../img/spritemap.png");*/ background-repeat: no-repeat; background-position: 0 0; position: absolute; @@ -182,7 +182,7 @@ } @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { .dropzone .dz-default.dz-message { - background-image: url("../img/spritemap@2x.png"); + /*background-image: url("../img/spritemap@2x.png");*/ -webkit-background-size: 428px 406px; -moz-background-size: 428px 406px; background-size: 428px 406px; @@ -251,7 +251,7 @@ -o-transition: opacity 0.4s ease-in-out; -ms-transition: opacity 0.4s ease-in-out; transition: opacity 0.4s ease-in-out; - background-image: url("../img/spritemap.png"); + /*background-image: url("../img/spritemap.png");*/ background-repeat: no-repeat; } @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { @@ -259,7 +259,7 @@ .dropzone-previews .dz-preview .dz-error-mark, .dropzone .dz-preview .dz-success-mark, .dropzone-previews .dz-preview .dz-success-mark { - background-image: url("../img/spritemap@2x.png"); + /*background-image: url("../img/spritemap@2x.png");*/ -webkit-background-size: 428px 406px; -moz-background-size: 428px 406px; background-size: 428px 406px; @@ -298,14 +298,14 @@ left: 0; width: 0%; height: 100%; - background-image: url("../img/spritemap.png"); + /*background-image: url("../img/spritemap.png");*/ background-repeat: repeat-x; background-position: 0px -400px; } @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { .dropzone .dz-preview .dz-progress .dz-upload, .dropzone-previews .dz-preview .dz-progress .dz-upload { - background-image: url("../img/spritemap@2x.png"); + /*background-image: url("../img/spritemap@2x.png");*/ -webkit-background-size: 428px 406px; -moz-background-size: 428px 406px; background-size: 428px 406px; diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/dropzone.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/dropzone.min.css similarity index 100% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/dropzone.min.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/dropzone.min.css diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/jquery.contextMenu.min.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/jquery.contextMenu.min.css similarity index 82% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/jquery.contextMenu.min.css rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/jquery.contextMenu.min.css index f7fb23a44..21d6805da 100644 --- a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/jquery.contextMenu.min.css +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/jquery.contextMenu.min.css @@ -1,5 +1,5 @@ -.context-menu-list{font-family:'Open Sans', sans-serif;width:200px;display:inline-block;position:absolute;list-style-type:none;border:1px solid #DDD;background:#fff;-webkit-box-shadow:0 2px 5px rgba(0,0,0,0.5);-moz-box-shadow:0 2px 5px rgba(0,0,0,0.5);-ms-box-shadow:0 2px 5px rgba(0,0,0,0.5);-o-box-shadow:0 2px 5px rgba(0,0,0,0.5);box-shadow:0 2px 5px rgba(0,0,0,0.5);font-size:12px;margin:0;padding:5px} -.context-menu-item{background-color:#fff;position:relative;border-bottom:1px solid #eee;height:auto;word-wrap:break-word;-webkit-user-select:none;-moz-user-select:0;-ms-user-select:none;user-select:none;padding:5px 5px 5px 30px} +.context-menu-list{font-family:'Open Sans', sans-serif;width:200px;display:inline-block;position:absolute;list-style-type:none;border:1px solid #DDD;background:#fff;font-size:12px;margin:0;padding:5px} +.context-menu-item{background-color:#fff;position:relative;height:auto;word-wrap:break-word;-webkit-user-select:none;-moz-user-select:0;-ms-user-select:none;user-select:none;padding:5px 5px 5px 30px} .context-menu-item:last-child{border:none} .context-menu-separator{padding-bottom:0;border-bottom:1px solid #DDD} .context-menu-item > label > input,.context-menu-item > label > textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text} @@ -10,7 +10,7 @@ .context-menu-item.icon{min-height:18px;vertical-align:middle;background-repeat:no-repeat;background-position:4px 5px;width:auto;display:list-item} .context-menu-item.icon-edit{background-image:url(../img/page_white_edit.png)} .context-menu-item.icon-cut{background-image:url(../img/cut.png)} -.context-menu-item.icon-copy{background-image:url(../img/page_white_copy.png)} +.context-menu-item.icon-copy{background-image:url(../img/copy.png)} .context-menu-item.icon-rename{background-image:url(../img/rename.png)} .context-menu-item.icon-preview{background-image:url(../img/preview.png)} .context-menu-item.icon-dimension{background-image:url(../img/dimension.png)} @@ -19,6 +19,7 @@ .context-menu-item.icon-size{background-image:url(../img/size.png)} .context-menu-item.icon-download{background-image:url(../img/download.png)} .context-menu-item.icon-paste{background-image:url(../img/page_white_paste.png)} +.context-menu-item.icon-clipboard-apply {background-image:url(../img/clipboard_apply.png)} .context-menu-item.icon-delete{background-image:url(../img/page_white_delete.png)} .context-menu-item.icon-add{background-image:url(../img/page_white_add.png)} .context-menu-item.icon-quit{background-image:url(../img/door.png)} @@ -26,6 +27,7 @@ .context-menu-item.icon-extract{background-image:url(../img/zip.png)} .context-menu-item.icon-url{background-image:url(../img/url.png)} .context-menu-item.icon-edit_img{background-image:url(../img/edit_img.png)} +.context-menu-item.icon-duplicate{background-image:url(../img/duplicate.png)} .context-menu-input > label > *{vertical-align:top} .context-menu-input > label > input[type=checkbox],.context-menu-input > label > input[type=radio]{margin-left:-17px} .context-menu-input > label > span{margin-left:5px} diff --git a/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css new file mode 100644 index 000000000..061ef75b4 --- /dev/null +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css @@ -0,0 +1 @@ +*,*:after,*:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body,html{font-family:'Open Sans',sans-serif;font-size:100%;padding:0;margin:0}body{padding-top:32px;font-weight:200;background:#ececec;overflow:-moz-scrollbars-vertical}#qLpercentage{font-family:'Open Sans',sans-serif;font-size:40px;line-height:40px;color:#bbb;font-weight:200;height:60px;-webkit-border-radius:10px;border-radius:10px;padding:10px;text-shadow:1px 1px 2px #fff;filter:dropshadow(color=#fff, offx=1, offy=1)}#qLbar{background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzdhN2E3YSIgc3RvcC1vcGFjaXR5PSIwLjQiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzdhN2E3YSIgc3RvcC1vcGFjaXR5PSIwLjQiLz4KICA8L2xpbmVhckdyYWRpZW50PgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZC11Y2dnLWdlbmVyYXRlZCkiIC8+Cjwvc3ZnPg==);background:-moz-linear-gradient(top, rgba(122,122,122,0.4) 0, rgba(122,122,122,0.4) 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(122,122,122,0.4)), color-stop(100%, rgba(122,122,122,0.4)));background:-webkit-linear-gradient(top, rgba(122,122,122,0.4) 0, rgba(122,122,122,0.4) 100%);background:-o-linear-gradient(top, rgba(122,122,122,0.4) 0, rgba(122,122,122,0.4) 100%);background:-ms-linear-gradient(top, rgba(122,122,122,0.4) 0, rgba(122,122,122,0.4) 100%);background:linear-gradient(to bottom, rgba(122,122,122,0.4) 0, rgba(122,122,122,0.4) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#667a7a7a', endColorstr='#667a7a7a', GradientType=0);z-index:200;margin:0;overflow:hidden}[class^="rficon-"],[class*=" rficon-"]{display:inline-block;width:16px;height:16px;margin-top:1px;*margin-right:.3em;line-height:16px;vertical-align:text-top;background-position:0 0;background-repeat:no-repeat}.rficon-clipboard-apply{background-image:url(../img/clipboard_apply.png)}.rficon-clipboard-clear{background-image:url(../img/clipboard_clear.png)}.btn{-webkit-border-radius:0;border-radius:0}.container-fluid{padding-right:0 !important;margin-top:10px !important}.img-precontainer{margin:auto;width:100%;text-align:center;background:#fff;border:none}.img-container{height:91px;width:122px;padding:0;border:none;overflow:hidden;display:table-cell;text-align:center;vertical-align:middle;margin:auto}ul.breadcrumb{margin-bottom:5px;-webkit-border-radius:0;border-radius:0;padding-bottom:4px;padding-top:6px;background:#f0f0f0;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);border-bottom:1px solid #bbb}ul.breadcrumb .pull-left i{margin-top:2px}.alert{padding:8px 35px 8px 14px;margin-bottom:2px;border:1px solid #aaa;color:#666;font-weight:200;font-size:13px;-webkit-border-radius:0;border-radius:0;background:#fff}.img-container *,.img-container-mini *{vertical-align:middle}#help{display:none}iframe{overflow:auto;-webkit-overflow-scrolling:touch}.upload-tabbable{margin-left:5px;margin-right:5px}.upload-tabbable .upload-help{font-size:11px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff;text-align:center}.upload-tabbable .nav{margin:0}.upload-tabbable .nav li a{font-size:13px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.upload-tabbable .tab-content{padding:5px;border-bottom:1px solid #ddd;border-left:1px solid #ddd;border-rigth:1px solid #ddd;background:#fff;margin-bottom:5px}input#filter-input{margin:0;width:84px;height:26px;vertical-align:bottom;margin-bottom:2px;-webkit-border-radius:0;border-radius:0;font-size:12px;font-weight:200;position:relative;left:1px}.qq-uploader .span9{margin-left:14px !important;width:690px !important}.space10{clear:both;height:10px}h4{font-size:12px;font-weight:200;margin:0;text-align:center;padding:0;margin-top:6px;line-height:18px}h3{font-size:14px;font-weight:200}.boxes{border:1px solid #ccc;word-wrap:break-word;background:#fff;-webkit-box-shadow:1px 1px 2px 0 rgba(0,0,0,0.2);box-shadow:1px 1px 2px 0 rgba(0,0,0,0.2);min-height:115px;text-align:center}.container-fluid{padding:0 10px !important}body .avpw .avpw_primary_button,body .avpw .avpw_primary_button:link,body .avpw .avpw_primary_button:visited,body .avpw .avpw_primary_button:active{background-color:#999;color:#fff;background-image:none;border:none}body .avpw .avpw_primary_button:hover{border:none;background-color:#666}.uploader{position:fixed;top:50px;left:14px;margin:auto;width:100%;z-index:9999;overflow:hidden;background:#eee;padding-top:20px;border:1px solid #ccc;display:none;-webkit-box-shadow:0 0 10px 0 rgba(1,1,1,0.5);box-shadow:0 0 10px 0 rgba(1,1,1,0.5)}.download-form{margin-bottom:25px}.grid li i{margin-left:2px;margin-right:2px;z-index:0}.box,.boxx{text-align:center;word-wrap:break-word;vertical-align:top;text-align:left;position:relative;border:none;box-shadow:none;z-index:100;padding:4px}.box .btn{width:100%;background:none;box-shadow:none;border:none;z-index:200}.navbar{margin-bottom:0;border-bottom:1px solid #bbb}.navbar .navbar-inner{border:none;min-height:35px;-webkit-border-radius:0;border-radius:0;padding-bottom:2px;margin:0;padding-right:8px;padding-left:8px}.navbar .navbar-inner .container-fluid{margin:0;margin-top:0 !important;padding:0}.navbar .navbar-inner .container-fluid .brand{display:none}.navbar .navbar-inner .container-fluid .filters span{margin-top:0;font-size:13px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}ul.sorting{position:absolute;left:-25px;top:20px;min-width:0;background:#eee}ul.sorting li a:hover{background:#aaa}.btn-group .dropdown-toggle.sorting-btn{background:none;border:none;box-shadow:none;position:relative;-webkit-box-shadow:none;top:-5px;font-size:13px}.btn-group .dropdown-toggle.sorting-btn:hover{background:none;border:none;box-shadow:none;-webkit-box-shadow:none}ul.sorting.dropdown-menu>li>a{font-size:12px;text-shadow:none}ul.sorting.dropdown-menu>li>a.ascending{background-image:url(../img/down.png);background-repeat:no-repeat;background-position:6px 8px}ul.sorting.dropdown-menu>li>a.descending{background-image:url(../img/up.png);background-repeat:no-repeat;background-position:6px 8px}.sorter-container{margin-top:5px;margin-bottom:0;-webkit-border-radius:0;border-radius:0;padding-bottom:4px;padding-top:6px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);background-color:#f5f5f5;position:relative;border-bottom:1px solid #bbb;height:24px}.sorter-container a.sorter{color:#000}.sorter-container a.ascending{padding-left:9px;background-image:url(../img/down.png);background-repeat:no-repeat;background-position:0 3px}.sorter-container a.descending{padding-left:9px;background-image:url(../img/up.png);background-repeat:no-repeat;background-position:0 4px}.sorter-container .img-dimension,.sorter-container .file-date,.sorter-container .file-size,.sorter-container .file-extension,.sorter-container .file-name,.sorter-container .file-operations{display:block;position:absolute;top:0;z-index:100;-webkit-box-shadow:none;box-shadow:none;text-align:left;font-size:13px;margin-top:1px;color:#999}.sorter-container .file-operations{width:110px;right:0}.sorter-container .img-dimension{width:65px;right:123px}.sorter-container .file-date{width:70px;right:188px}.sorter-container .file-size{width:55px;right:258px}.sorter-container .file-extension{width:40px;right:313px}.sorter-container .file-name{width:50px;left:52px}.img-dimension,.file-date,.file-size,.file-extension,.file-name,.file-operations{font-size:12px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff;display:none}.view-controller{text-align:left}.view-controller .btn-group>.btn:first-child,.view-controller .btn-group>.btn:last-child{-webkit-border-radius:0;border-radius:0}.navbar .filters .btn{margin-bottom:2px;padding-top:2px;padding-bottom:2px;padding-left:8px;padding-right:8px;margin-top:5px}.filters .types{text-align:right}@media (max-width:780px){#view2{display:none}}@media (max-width:839px){body{padding-top:0}.filters .types{text-align:left}.navbar .navbar-inner .container-fluid .brand{display:block}.navbar .navbar-inner{padding-bottom:4px}.filters div.span3.half,.filters div.half.span6{float:none;width:100%}.container-fluid{margin:0 !important;padding:0}#qLbar{height:50px !important}}@media (min-width:400px) and (max-width:839px){.filters .row-fluid .half{width:48.61878453038674%;*width:48.56559304102504%;float:left}}.tooltip.in{z-index:10000;opacity:1;filter:alpha(opacity=1);font-weight:bold}.tooltip{font-weight:bold;z-index:10000}.grid{padding:0 0;margin:0 auto;list-style:none;-webkit-overflow-scrolling:touch}.grid li{display:inline-block;width:124px;border:none;margin:4px;margin-bottom:8px;padding:0;vertical-align:top}.grid figure{margin:0;position:relative;display:block;width:122px;margin:auto}.grid figure:hover{background:#e0e0e0 !important}.list-view1.grid li{width:100%}.list-view1.grid li figure{width:100%}.grid figcaption{text-align:center;padding:2px;padding-top:8px;color:#fff;height:30px;width:122px;margin-left:0;margin-right:0;position:absolute;top:auto;bottom:0;-webkit-box-shadow:inset 0 0 8px 0 rgba(41,41,41,0.5);box-shadow:inset 0 0 8px 0 rgba(41,41,41,0.5)}.grid figcaption a{margin:0;padding:3px}.grid figcaption h3{margin:0;padding:0;color:#fff}.grid h4{text-align:center;color:#000;padding:0;margin-bottom:4px;margin-top:4px}.grid figure .box{box-sizing:content-box}.list-view0.grid figure .box,.list-view1.grid figure .box,.list-view2.grid figure .box{max-width:100%;display:block;position:relative;overflow:hidden;z-index:1}.list-view0.grid figure .box h4.ellipsis,.list-view1.grid figure .box h4.ellipsis,.list-view2.grid figure .box h4.ellipsis{height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-view0.grid figure .box h4,.list-view1.grid figure .box h4,.list-view2.grid figure .box h4{z-index:1}.list-view0.grid figure .box h4 a,.list-view1.grid figure .box h4 a,.list-view2.grid figure .box h4 a{z-index:1}.list-view0.grid .selected,.list-view1.grid .selected,.list-view2.grid .selected{-webkit-box-shadow:0 0 10px 5px rgba(0,0,0,0.25);box-shadow:0 0 10px 5px rgba(0,0,0,0.25)}.no-touch .list-view0 figure .box{z-index:1;-webkit-transition:-webkit-transform .3s;-moz-transition:-moz-transform .3s;transition:transform .3s}.ui-state-highlight{border:1px solid #f00}.no-touch .list-view0 figure:hover .box,.no-touch .list-view0 figure.cs-hover .box{-webkit-box-shadow:0 0 4px 0 rgba(1,1,1,0.5);box-shadow:0 0 4px 0 rgba(1,1,1,0.5);-webkit-transform:translateY(-26px);-moz-transform:translateY(-26px);-ms-transform:translateY(-26px);transform:translateY(-26px)}.list-view0 figure:hover .box.no-effect,.list-view0 figure.cs-hover .box.no-effect,.no-effect{-webkit-box-shadow:none;box-shadow:none;-webkit-transform:none;-moz-transform:none;-ms-transform:none;transform:none}.list-view0 .img-precontainer-mini{display:none;background:none}a,a:hover{color:#000;text-decoration:none}.back-directory .img-precontainer,.back-directory .img-precontainer-mini,.back-directory .box{background:none}form{margin:0;padding:0}.modal-body form,.modal-body input{margin:0}.modal-header h3{font-weight:300;font-size:20px}.list-view1.sorter-container{display:block}.list-view0.sorter-container,.list-view2.sorter-container{display:none}.list-view0.grid .img-precontainer .img-container img{max-width:122px !important;max-height:91px !important}.list-view0.grid .img-precontainer .img-container img.icon{width:122px;margin-top:0}.list-view0.grid .img-precontainer .filetype{position:absolute;top:0;width:120px;text-align:center;color:#fff;font-size:13px;line-height:22px}.list-view0.grid .cover{background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIwLjI1Ii8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMC4yNSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);background:-moz-linear-gradient(top, rgba(255,255,255,0.25) 0, rgba(255,255,255,0.25) 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(255,255,255,0.25)), color-stop(100%, rgba(255,255,255,0.25)));background:-webkit-linear-gradient(top, rgba(255,255,255,0.25) 0, rgba(255,255,255,0.25) 100%);background:-o-linear-gradient(top, rgba(255,255,255,0.25) 0, rgba(255,255,255,0.25) 100%);background:-ms-linear-gradient(top, rgba(255,255,255,0.25) 0, rgba(255,255,255,0.25) 100%);background:linear-gradient(to bottom, rgba(255,255,255,0.25) 0, rgba(255,255,255,0.25) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#40ffffff', endColorstr='#40ffffff', GradientType=0);width:122px;position:absolute;top:22px;right:0;height:69px}.list-view0.grid .box{background:#fff}.list-view0.grid .directory{background:#ddd}.list-view0.grid figure.back-directory .directory{background:#bbb}.list-view0.grid figcaption{background:#fff}.list-view1.grid li,.list-view2.grid li{margin:0}.list-view1.grid li.back figure.back-directory,.list-view2.grid li.back figure.back-directory{height:34px}.list-view1.grid li:nth-child(odd) figure,.list-view2.grid li:nth-child(odd) figure{background:#f9f9f9}.list-view1.grid li:nth-child(odd) figure.directory,.list-view2.grid li:nth-child(odd) figure.directory{background:#eaeaea}.list-view1.grid li figure,.list-view2.grid li figure{border-bottom:1px solid #ccc;background:#fff}.list-view1.grid li figure.back-directory,.list-view2.grid li figure.back-directory{background:#bbb}.list-view1.grid li figure.back-directory .box,.list-view2.grid li figure.back-directory .box{background:none}.list-view1.grid li figure.directory,.list-view2.grid li figure.directory{background:#efefef}.list-view1.grid li figure.directory box,.list-view2.grid li figure.directory box{padding:0;min-height:10px}.list-view1.grid li figure .box,.list-view2.grid li figure .box{margin-left:50px;-webkit-transition:none;-moz-transition:none;transition:none}.list-view1.grid li figure .box h4,.list-view2.grid li figure .box h4{padding-top:1px;font-size:13px;text-align:left}.list-view1.grid .img-precontainer-mini,.list-view2.grid .img-precontainer-mini{display:block;position:absolute;width:45px;height:34px;overflow:hidden;text-align:center}.list-view1.grid .img-precontainer-mini img,.list-view2.grid .img-precontainer-mini img{height:34px}.list-view1.grid .img-precontainer-mini .filetype,.list-view2.grid .img-precontainer-mini .filetype{position:absolute;top:5px;text-align:center;left:5px;padding:1px 2px;font-size:13px;line-height:22px;width:34px;height:24px;color:#fff;background:#333}.list-view1.grid .cover,.list-view2.grid .cover{display:none}.list-view1.grid .img-container-mini,.list-view2.grid .img-container-mini{width:45px;height:34px;border:none;overflow:hidden;display:table-cell;text-align:center;vertical-align:middle;margin:auto}.list-view1.grid .img-precontainer-mini.original-thumb,.list-view2.grid .img-precontainer-mini.original-thumb{padding:0}.list-view1.grid .img-precontainer-mini.original-thumb img,.list-view2.grid .img-precontainer-mini.original-thumb img{width:auto;margin:0;height:34px}.list-view1.grid .img-precontainer-mini.original-thumb img.original,.list-view2.grid .img-precontainer-mini.original-thumb img.original{width:auto;height:auto}.list-view1.grid .img-precontainer,.list-view2.grid .img-precontainer{display:none}.list-view1.grid figcaption,.list-view2.grid figcaption{background:none;width:120px;position:absolute;right:0;top:0;z-index:1;bottom:0;-webkit-box-shadow:none;box-shadow:none;text-align:right}.list-view1.grid .selected,.list-view2.grid .selected{-webkit-box-shadow:0 0 3px 2px rgba(0,0,0,0.2);box-shadow:0 0 3px 2px rgba(0,0,0,0.2)}.list-view1.grid .img-dimension,.list-view1.grid .file-date,.list-view1.grid .file-size,.list-view1.grid .file-extension{overflow:hidden;display:block;position:absolute;top:0;z-index:1;-webkit-box-shadow:none;box-shadow:none;text-align:left;margin-top:7px}.list-view1.grid .img-dimension{width:65px;right:120px}.list-view1.grid .file-date{width:70px;right:185px}.list-view1.grid .file-size{width:55px;right:255px}.list-view1.grid .file-extension{width:40px;right:310px}.list-view1.grid figure .box{padding-right:352px}.list-view2.grid figure .box{padding-right:115px}@media (max-width:610px){.list-view1.grid figure .box{padding-right:312px}.list-view1.grid figure .file-extension{display:none}.sorter-container .file-extension{display:none}}@media (max-width:565px){.list-view1.grid figure .box{padding-right:257px}.list-view1.grid figure .file-size{display:none}.sorter-container .file-size{display:none}}@media (max-width:495px){.list-view1.grid figure .box{padding-right:187px}.list-view1.grid figure .file-date{display:none}.sorter-container .file-date{display:none}}@media (max-width:430px){.list-view1.grid figure .box{padding-right:115px}.list-view1.grid figure .img-dimension{display:none}.sorter-container .img-dimension{display:none}.breadcrumb{margin-left:0;margin-right:0}}.list-view2.grid .img-precontainer-mini .filetype.pdf,.list-view1.grid .img-precontainer-mini .filetype.pdf{background:#cb0011}.list-view2.grid .img-precontainer-mini .filetype.css,.list-view1.grid .img-precontainer-mini .filetype.css{background:#d10698}.list-view2.grid .img-precontainer-mini .filetype.ai,.list-view1.grid .img-precontainer-mini .filetype.ai{background:#d6772f}.list-view2.grid .img-precontainer-mini .filetype.psd,.list-view1.grid .img-precontainer-mini .filetype.psd{background:#0960a4}.list-view2.grid .img-precontainer-mini .filetype.html,.list-view1.grid .img-precontainer-mini .filetype.html,.list-view2.grid .img-precontainer-mini .filetype.xhtml,.list-view1.grid .img-precontainer-mini .filetype.xhtml{background:#035bc4}.list-view2.grid .img-precontainer-mini .filetype.fla,.list-view1.grid .img-precontainer-mini .filetype.fla,.list-view2.grid .img-precontainer-mini .filetype.flv,.list-view1.grid .img-precontainer-mini .filetype.flv{background:#cf302e}.list-view2.grid .img-precontainer-mini .filetype.ppt,.list-view1.grid .img-precontainer-mini .filetype.ppt,.list-view2.grid .img-precontainer-mini .filetype.pptx,.list-view1.grid .img-precontainer-mini .filetype.pptx{background:#da5b00}.list-view2.grid .img-precontainer-mini .filetype.xls,.list-view1.grid .img-precontainer-mini .filetype.xls,.list-view2.grid .img-precontainer-mini .filetype.xlsx,.list-view1.grid .img-precontainer-mini .filetype.xlsx,.list-view2.grid .img-precontainer-mini .filetype.css,.list-view1.grid .img-precontainer-mini .filetype.css{background:#1a712c}.list-view2.grid .img-precontainer-mini .filetype.rts,.list-view1.grid .img-precontainer-mini .filetype.rts,.list-view2.grid .img-precontainer-mini .filetype.doc,.list-view1.grid .img-precontainer-mini .filetype.doc,.list-view2.grid .img-precontainer-mini .filetype.docx,.list-view1.grid .img-precontainer-mini .filetype.docx{background:#002093}.list-view2.grid .img-precontainer-mini .filetype.rar,.list-view1.grid .img-precontainer-mini .filetype.rar,.list-view2.grid .img-precontainer-mini .filetype.zip,.list-view1.grid .img-precontainer-mini .filetype.zip,.list-view2.grid .img-precontainer-mini .filetype.gzip,.list-view1.grid .img-precontainer-mini .filetype.gzip{background:#fe9221}.list-view2.grid .img-precontainer-mini .filetype.mp4,.list-view1.grid .img-precontainer-mini .filetype.mp4,.list-view2.grid .img-precontainer-mini .filetype.mpeg,.list-view1.grid .img-precontainer-mini .filetype.mpeg,.list-view2.grid .img-precontainer-mini .filetype.mov,.list-view1.grid .img-precontainer-mini .filetype.mov,.list-view2.grid .img-precontainer-mini .filetype.avi,.list-view1.grid .img-precontainer-mini .filetype.avi,.list-view2.grid .img-precontainer-mini .filetype.mpg,.list-view1.grid .img-precontainer-mini .filetype.mpg,.list-view2.grid .img-precontainer-mini .filetype.wma,.list-view1.grid .img-precontainer-mini .filetype.wma,.list-view2.grid .img-precontainer-mini .filetype.webm,.list-view1.grid .img-precontainer-mini .filetype.webm{background:#31231e}.list-view2.grid .img-precontainer-mini .filetype.mp3,.list-view1.grid .img-precontainer-mini .filetype.mp3,.list-view2.grid .img-precontainer-mini .filetype.m4a,.list-view1.grid .img-precontainer-mini .filetype.m4a,.list-view2.grid .img-precontainer-mini .filetype.ac3,.list-view1.grid .img-precontainer-mini .filetype.ac3,.list-view2.grid .img-precontainer-mini .filetype.aiff,.list-view1.grid .img-precontainer-mini .filetype.aiff,.list-view2.grid .img-precontainer-mini .filetype.mid,.list-view1.grid .img-precontainer-mini .filetype.mid,.list-view2.grid .img-precontainer-mini .filetype.ogg,.list-view1.grid .img-precontainer-mini .filetype.ogg,.list-view2.grid .img-precontainer-mini .filetype.wav,.list-view1.grid .img-precontainer-mini .filetype.wav{background:#9f008b}.list-view2.grid .img-precontainer-mini .filetype.odt,.list-view1.grid .img-precontainer-mini .filetype.odt,.list-view2.grid .img-precontainer-mini .filetype.ots,.list-view1.grid .img-precontainer-mini .filetype.ots,.list-view2.grid .img-precontainer-mini .filetype.ott,.list-view1.grid .img-precontainer-mini .filetype.ott,.list-view2.grid .img-precontainer-mini .filetype.odb,.list-view1.grid .img-precontainer-mini .filetype.odb,.list-view2.grid .img-precontainer-mini .filetype.odg,.list-view1.grid .img-precontainer-mini .filetype.odg,.list-view2.grid .img-precontainer-mini .filetype.otp,.list-view1.grid .img-precontainer-mini .filetype.otp,.list-view2.grid .img-precontainer-mini .filetype.otg,.list-view1.grid .img-precontainer-mini .filetype.otg,.list-view2.grid .img-precontainer-mini .filetype.odf,.list-view1.grid .img-precontainer-mini .filetype.odf,.list-view2.grid .img-precontainer-mini .filetype.ods,.list-view1.grid .img-precontainer-mini .filetype.ods,.list-view2.grid .img-precontainer-mini .filetype.odp,.list-view1.grid .img-precontainer-mini .filetype.odp{background:#367bbe}.list-view2.grid .img-precontainer-mini .filetype.jpg,.list-view1.grid .img-precontainer-mini .filetype.jpg,.list-view2.grid .img-precontainer-mini .filetype.jpeg,.list-view1.grid .img-precontainer-mini .filetype.jpeg,.list-view2.grid .img-precontainer-mini .filetype.png,.list-view1.grid .img-precontainer-mini .filetype.png,.list-view2.grid .img-precontainer-mini .filetype.bmp,.list-view1.grid .img-precontainer-mini .filetype.bmp,.list-view2.grid .img-precontainer-mini .filetype.gif,.list-view1.grid .img-precontainer-mini .filetype.gif,.list-view2.grid .img-precontainer-mini .filetype.tiff,.list-view1.grid .img-precontainer-mini .filetype.tiff,.list-view2.grid .img-precontainer-mini .filetype.svg,.list-view1.grid .img-precontainer-mini .filetype.svg{background:#cfa554}.list-view2.grid .img-precontainer-mini .filetype.txt,.list-view1.grid .img-precontainer-mini .filetype.txt,.list-view2.grid .img-precontainer-mini .filetype.sql,.list-view1.grid .img-precontainer-mini .filetype.sql,.list-view2.grid .img-precontainer-mini .filetype.xml,.list-view1.grid .img-precontainer-mini .filetype.xml,.list-view2.grid .img-precontainer-mini .filetype.log,.list-view1.grid .img-precontainer-mini .filetype.log,.list-view2.grid .img-precontainer-mini .filetype.iso,.list-view1.grid .img-precontainer-mini .filetype.iso,.list-view2.grid .img-precontainer-mini .filetype.dmg,.list-view1.grid .img-precontainer-mini .filetype.dmg{background:#cacaca}.list-view2.grid .img-precontainer-mini .filetype.ade,.list-view1.grid .img-precontainer-mini .filetype.ade,.list-view2.grid .img-precontainer-mini .filetype.adp,.list-view1.grid .img-precontainer-mini .filetype.adp,.list-view2.grid .img-precontainer-mini .filetype.mdb,.list-view1.grid .img-precontainer-mini .filetype.mdb,.list-view2.grid .img-precontainer-mini .filetype.accdb,.list-view1.grid .img-precontainer-mini .filetype.accdb{background:#b61c19} \ No newline at end of file diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/style.less b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.less similarity index 86% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/style.less rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.less index d75f4276d..74d25b12f 100644 --- a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/css/style.less +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.less @@ -5,7 +5,8 @@ body, html { body{ padding-top: 32px; font-weight:200; - background:#eeeeee; + background:#ececec; + overflow: -moz-scrollbars-vertical; } #qLpercentage{ @@ -33,10 +34,31 @@ body{ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#667a7a7a', endColorstr='#667a7a7a',GradientType=0 ); /* IE6-8 */ z-index:200; - margin-left: 10px; + margin:0px; overflow: hidden; } + +[class^="rficon-"],[class*=" rficon-"] { + display:inline-block; + width:16px; + height:16px; + margin-top:1px; + *margin-right:.3em; + line-height:16px; + vertical-align:text-top; + background-position: 0 0; + background-repeat:no-repeat +} + +.rficon-clipboard-apply { + background-image:url(../img/clipboard_apply.png); +} + +.rficon-clipboard-clear { + background-image:url(../img/clipboard_clear.png); +} + .btn{ -webkit-border-radius: 0px; border-radius: 0px; @@ -154,7 +176,7 @@ input#filter-input{ .qq-uploader .span9{margin-left:14px !important;width:690px !important;} .space10{ clear:both; height:10px; } -h4{ font-size:11px; font-weight:200; margin: 0px; text-align: center; padding: 0px; margin-top:6px; line-height: 18px; } +h4{ font-size:12px; font-weight:200; margin: 0px; text-align: center; padding: 0px; margin-top:6px; line-height: 18px; } h3{ font-size:14px; font-weight:200;} .boxes{ border:1px solid #CCCCCC; word-wrap: break-word; background:white; -webkit-box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.2);box-shadow: 1px 1px 2px 0px rgba(0, 0, 0, 0.2); min-height:115px; @@ -400,14 +422,20 @@ ul.sorting.dropdown-menu>li>a{ .navbar .navbar-inner{ padding-bottom: 4px; } + .filters{ + div.span3.half,div.half.span6{ + float:none; + width:100%; + + } + } .container-fluid{ margin:0px !important; padding: 0px; } #qLbar{ - position: absolute; - top:8px !important; + height:50px !important; } } @media(min-width:400px) and (max-width:839px){ @@ -437,9 +465,11 @@ ul.sorting.dropdown-menu>li>a{ .grid li { display: inline-block; - width: 126px; + width: 124px; + border:none; margin: 4px; - padding: 2px; + margin-bottom:8px; + padding: 0px; vertical-align: top; } @@ -465,26 +495,26 @@ ul.sorting.dropdown-menu>li>a{ padding-top: 8px; color: white; height: 30px; - width: 118px; - margin-left:2px; - margin-right: 2px; + width: 122px; + margin-left:0px; + margin-right: 0px; position: absolute; top: auto; bottom: 0; -webkit-box-shadow: inset 0px 0px 8px 0px rgba(41, 41, 41, 0.5); box-shadow: inset 0px 0px 8px 0px rgba(41, 41, 41, 0.5); + + a{ + margin: 0px; + padding: 3px; + } + h3 { + margin: 0; + padding: 0; + color: #fff; + } } - -.grid figcaption a{ - margin: 0px; - padding: 3px; -} - -.grid figcaption h3 { - margin: 0; - padding: 0; - color: #fff; -} + .grid h4{ text-align: center; @@ -528,8 +558,10 @@ ul.sorting.dropdown-menu>li>a{ } .selected{ - -webkit-box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.6); - box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.6); + -webkit-box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.25); + box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.25); + + //border: 1px solid #777777; } } @@ -539,7 +571,9 @@ ul.sorting.dropdown-menu>li>a{ -moz-transition: -moz-transform 0.3s; transition: transform 0.3s; } - +.ui-state-highlight{ + border:1px solid red; +} .no-touch .list-view0 figure:hover .box, .no-touch .list-view0 figure.cs-hover .box { @@ -564,6 +598,7 @@ ul.sorting.dropdown-menu>li>a{ .list-view0 .img-precontainer-mini{ display: none; + background: none; } a,a:hover{ color:black; @@ -601,49 +636,44 @@ form{ .list-view0.grid{ .img-precontainer{ .img-container{ + img{ - max-width:122px !important; max-height:91px !important; } img.icon{ width: 122px; - border:1px solid #cccccc; margin-top:0px; } } .filetype{ position:absolute; - top:1px; - right:1px; - padding:2px 3px; + top:0px; + width:120px; + text-align:center; color:white; - font-size: 16px; - line-height: 18px; - /* IE9 SVG, needs conditional override of 'filter' to 'none' */ -background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIwLjYiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIgc3RvcC1vcGFjaXR5PSIwLjYiLz4KICA8L2xpbmVhckdyYWRpZW50PgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZC11Y2dnLWdlbmVyYXRlZCkiIC8+Cjwvc3ZnPg==); -background: -moz-linear-gradient(top, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.6) 100%); /* FF3.6+ */ -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0.6)), color-stop(100%,rgba(0,0,0,0.6))); /* Chrome,Safari4+ */ -background: -webkit-linear-gradient(top, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%); /* Chrome10+,Safari5.1+ */ -background: -o-linear-gradient(top, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%); /* Opera 11.10+ */ -background: -ms-linear-gradient(top, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%); /* IE10+ */ -background: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%); /* W3C */ -filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', endColorstr='#99000000',GradientType=0 ); /* IE6-8 */ - border-bottom: 1px solid #111111; - border-left: 1px solid #111111; - -webkit-border-radius: 0px 0px 0px 6px; - border-radius: 0px 0px 0px 6px; + font-size: 13px; + line-height: 22px; + } } .cover{ - -webkit-box-shadow: inset 0px 0px 25px 0px rgba(0, 0, 0, 0.3); - - box-shadow: inset 0px 0px 25px 0px rgba(0, 0, 0, 0.3); +/* IE9 SVG, needs conditional override of 'filter' to 'none' */ +background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIwLjI1Ii8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiIHN0b3Atb3BhY2l0eT0iMC4yNSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +background: -moz-linear-gradient(top, rgba(255,255,255,0.25) 0%, rgba(255,255,255,0.25) 100%); /* FF3.6+ */ +background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.25)), color-stop(100%,rgba(255,255,255,0.25))); /* Chrome,Safari4+ */ +background: -webkit-linear-gradient(top, rgba(255,255,255,0.25) 0%,rgba(255,255,255,0.25) 100%); /* Chrome10+,Safari5.1+ */ +background: -o-linear-gradient(top, rgba(255,255,255,0.25) 0%,rgba(255,255,255,0.25) 100%); /* Opera 11.10+ */ +background: -ms-linear-gradient(top, rgba(255,255,255,0.25) 0%,rgba(255,255,255,0.25) 100%); /* IE10+ */ +background: linear-gradient(to bottom, rgba(255,255,255,0.25) 0%,rgba(255,255,255,0.25) 100%); /* W3C */ +filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#40ffffff', endColorstr='#40ffffff',GradientType=0 ); /* IE6-8 */ + + width: 122px; position:absolute; - top:0px; + top:22px; right:0px; - height: 91px; + height: 69px; } .box{ background: white; @@ -656,6 +686,10 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e background: #bbbbbb; } } + + figcaption{ + background:#ffffff; + } } .list-view1.grid , .list-view2.grid { @@ -667,8 +701,8 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e } } } - li:nth-child(odd) figure {background: #f6f6f6; } - li:nth-child(odd) figure.directory {background: #d2d2d2; } + li:nth-child(odd) figure {background: #f9f9f9; } + li:nth-child(odd) figure.directory {background: #eaeaea; } li figure{ border-bottom: 1px solid #cccccc; @@ -680,7 +714,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e } } &.directory{ - background: #dddddd; + background: #efefef; box{ padding: 0px; min-height: 10px; @@ -710,26 +744,20 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e } .filetype{ position:absolute; - top:0px; + top:5px; text-align: center; - left:0px; + left:5px; padding:1px 2px; - font-size: 14px; - line-height: 32px; - width:45px; - height: 34px; + font-size: 13px; + line-height: 22px; + width:34px; + height: 24px; color:white; - background: #333333; + background: #333333; } } .cover{ - position:absolute; - top:0; - left:0; - width: 45px; - height: 34px; - -webkit-box-shadow: inset 0px 0px 10px 0px rgba(0, 0, 0, 0.4); - box-shadow: inset 0px 0px 10px 0px rgba(0, 0, 0, 0.4); + display: none; } .img-container-mini{ width: 45px; @@ -762,6 +790,7 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e } figcaption{ + background:none; width: 120px; position: absolute; right: 0px; @@ -774,8 +803,8 @@ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#99000000', e } .selected{ - -webkit-box-shadow: 0px 0px 3px 2px rgba(0, 0, 0, 0.6); - box-shadow: 0px 0px 3px 2px rgba(0, 0, 0, 0.6); + -webkit-box-shadow: 0px 0px 3px 2px rgba(0, 0, 0, 0.2); + box-shadow: 0px 0px 3px 2px rgba(0, 0, 0, 0.2); } } diff --git a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/dialog.php b/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php similarity index 56% rename from local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/dialog.php rename to local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php index ff60db411..ad48ddf9e 100644 --- a/local/modules/Tinymce/Resources/js/tinymce/plugins/filemanager/dialog.php +++ b/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php @@ -1,8 +1,20 @@ console.log('The ".$lang." language file is not readable! Falling back...');"; + } } - +// add lang file to session for easy include +$_SESSION['RF']['language_file'] = $language_file; require_once $language_file; if(!isset($_GET['type'])) $_GET['type']=0; if(!isset($_GET['field_id'])) $_GET['field_id']=''; +$field_id=isset($_GET['field_id']) ? fix_get_params($_GET['field_id']) : ''; +$type_param=fix_get_params($_GET['type']); + $get_params = http_build_query(array( - 'type' => $_GET['type'], + 'type' => $type_param, 'lang' => $lang, 'popup' => $popup, - 'field_id' => isset($_GET['field_id']) ? $_GET['field_id'] : '', + 'field_id' => $field_id, + 'akey' => (isset($_GET['akey']) && $_GET['akey'] != '' ? $_GET['akey'] : 'key'), 'fldr' => '' )); ?> @@ -135,14 +158,53 @@ $get_params = http_build_query(array( + Responsive FileManager - - - - + + + + + console.log("Error: Spritemap not found!");'; + // exit(); + } + } + ?> + @@ -152,7 +214,7 @@ $get_params = http_build_query(array( height: 100%; } - + - + + + + + + + @@ -242,64 +319,77 @@ $get_params = http_build_query(array( + + - + " /> - + " /> - - + + + + + + + + + + + + + + + " /> - +
-
+
-
- -
- - -
- :
- - - - - - - - - -
- +
+ +
+ + +
+ :
+ + + + + + + + + + +
- -
-
-
- -
-
-
- + +
+
+
+
+ +
- +
@@ -308,15 +398,14 @@ $get_params = http_build_query(array( $class_ext = ''; $src = ''; - -$dir = opendir($current_path.$subfolder.$subdir); + if ($_GET['type']==1) $apply = 'apply_img'; elseif($_GET['type']==2) $apply = 'apply_link'; elseif($_GET['type']==0 && $_GET['field_id']=='') $apply = 'apply_none'; elseif($_GET['type']==3) $apply = 'apply_video'; else $apply = 'apply'; -$files = scandir($current_path.$subfolder.$subdir); +$files = scandir($current_path.$rfm_subfolder.$subdir); $n_files=count($files); //php sorting @@ -326,13 +415,13 @@ $prev_folder=array(); foreach($files as $k=>$file){ if($file==".") $current_folder=array('file'=>$file); elseif($file=="..") $prev_folder=array('file'=>$file); - elseif(is_dir($current_path.$subfolder.$subdir.$file)){ - $date=filemtime($current_path.$subfolder.$subdir. $file); - $size=foldersize($current_path.$subfolder.$subdir. $file); + elseif(is_dir($current_path.$rfm_subfolder.$subdir.$file)){ + $date=filemtime($current_path.$rfm_subfolder.$subdir. $file); + $size=foldersize($current_path.$rfm_subfolder.$subdir. $file); $file_ext=lang_Type_dir; $sorted[$k]=array('file'=>$file,'date'=>$date,'size'=>$size,'extension'=>$file_ext); }else{ - $file_path=$current_path.$subfolder.$subdir.$file; + $file_path=$current_path.$rfm_subfolder.$subdir.$file; $date=filemtime($file_path); $size=filesize($file_path); $file_ext = substr(strrchr($file,'.'),1); @@ -377,7 +466,7 @@ if($descending){ $files=array_merge(array($prev_folder),array($current_folder),$sorted); ?> - +
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x(" - +
{block name="contact-form"} {form name="thelia.front.contact"} @@ -89,3 +87,49 @@ {/block} + +{block name="javascript-initialization"} + + +{/block} diff --git a/templates/frontOffice/default/includes/mini-cart.html b/templates/frontOffice/default/includes/mini-cart.html index 1dad142c3..f785814e4 100644 --- a/templates/frontOffice/default/includes/mini-cart.html +++ b/templates/frontOffice/default/includes/mini-cart.html @@ -24,7 +24,7 @@

{$TITLE}

- {intl l="Remove"} + {intl l="Remove"} @@ -58,7 +58,7 @@ {/ifloop} {elseloop rel="cartloop"} - -{/elseloop} \ No newline at end of file +{/elseloop} diff --git a/templates/frontOffice/default/includes/single-product.html b/templates/frontOffice/default/includes/single-product.html index 4d8828741..f49e36e79 100644 --- a/templates/frontOffice/default/includes/single-product.html +++ b/templates/frontOffice/default/includes/single-product.html @@ -2,7 +2,7 @@ {assign var="hasSubmit" value = false} {assign var="productTitle" value="{$TITLE}"} {if not $product_id} - {assign var="$product_id" value=$ID} + {assign var="product_id" value=$ID} {/if}
@@ -17,7 +17,7 @@ {/loop} {/loop} -
{if $IS_PROMO == 1} @@ -32,7 +32,7 @@ {else} {assign "real_price" $TAXED_PRICE} {/if} - {$QUANTITY} X {$real_price} {currency attr="symbol"} + {$QUANTITY} X {$real_price} {currency attr="symbol"} {assign "total_price" $total_price + ($QUANTITY * $real_price)}