From d16f3c28e5de2bf7254158dacd23271b3b9d7e50 Mon Sep 17 00:00:00 2001 From: gmorel Date: Wed, 11 Sep 2013 19:39:10 +0200 Subject: [PATCH 01/20] Working - CasperJS : coupon rule --- templates/admin/default/coupon/form.html | 16 +-- tests/functionnal/casperjs/exe/30_coupons.js | 102 ++++++++++++++++++- 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html index 5d30d201d..917a5ff19 100644 --- a/templates/admin/default/coupon/form.html +++ b/templates/admin/default/coupon/form.html @@ -122,17 +122,17 @@ {if $error}{$message}{/if} {/form_field} -
- + {*
*} + {**} {*form_field form=$form field='category'*} - + {**} {*if $error}{$message}{/if}*} {*/form_field*} -
+ {*
*} diff --git a/tests/functionnal/casperjs/exe/30_coupons.js b/tests/functionnal/casperjs/exe/30_coupons.js index 2ac04a759..4966e8ed2 100644 --- a/tests/functionnal/casperjs/exe/30_coupons.js +++ b/tests/functionnal/casperjs/exe/30_coupons.js @@ -12,7 +12,6 @@ casper.start(thelia2_login_coupon_update_url, function() { this.capture('tests/functionnal/casperjs/screenshot/coupons/init.png'); this.echo('\nCOUPON RULE - EDIT'); this.test.assertTitle('Update coupon - Thelia Back Office', 'Web page title OK'); -// this.test.assertSelectorHasText('#content-header > h1', 'Liste des pays', 'Web page main content OK'); this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); @@ -28,6 +27,7 @@ casper.wait(1000, function() { this.echo("\nWaiting...."); }); +// Test Rule updating casper.then(function(){ this.evaluate(function() { $('#quantity-operator').val('>=').change(); @@ -43,7 +43,107 @@ casper.wait(1000, function() { casper.then(function(){ this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added.png'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', ' If cart products quantity is superior or equals to 4','3rd rule found'); + + // Click on Edit button + this.click('tbody#constraint-list tr:nth-child(3) .constraint-update-btn'); +}); + +casper.wait(2000, function() { + this.echo("\nWaiting...."); +}); + +casper.then(function(){ + this.evaluate(function() { + $('#quantity-operator').val('==').change(); + return true; + }); + this.sendKeys('#quantity-value', '5'); + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-being-edited.png'); + this.click('#constraint-save-btn'); +}); + +casper.wait(2000, function() { + this.echo("\nWaiting...."); +}); +// Check if updated rule has been saved and list refreshed +casper.then(function(){ + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited.png'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equals to 5','3rd rule updated found'); +}); + +// Check if updated rule has been well saved +casper.start(thelia2_login_coupon_update_url, function() { + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited-refreshed.png'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equals to 5','3rd rule updated found'); + + // Click on Delete button + this.click('tbody#constraint-list tr:nth-child(2) .constraint-delete-btn'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equals to 5','3rd rule updated found'); +}); + +// Check if updated rule has been well saved +casper.start(thelia2_login_coupon_update_url, function() { + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-deleted-refreshed.png'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equals to 5','3rd rule updated found'); +}); + +// Test creating rule that won't be edited +casper.then(function(){ +// Create rule + this.evaluate(function() { + $('#category-rule').val('thelia.constraint.rule.available_for_total_amount').change(); + return true; + }); + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-selected2.png'); +}); + +casper.wait(1000, function() { + this.echo("\nWaiting...."); +}); + +// Test Rule creation +casper.then(function(){ + this.evaluate(function() { + $('#price-operator').val('<=').change(); + return true; + }); + this.sendKeys('input#price-value', '401'); + this.evaluate(function() { + $('#currency-value').val('GBP').change(); + return true; + }); + this.click('#constraint-save-btn'); +}); + +casper.wait(1000, function() { + this.echo("\nWaiting...."); +}); + +casper.then(function(){ + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equals to 5','3rd rule updated found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equals to 401 GBP','4rd rule created found'); +}); + +// Check if created rule has been well saved +casper.start(thelia2_login_coupon_update_url, function() { + this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added-refreshed.png'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equals to 5','3rd rule updated found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equals to 401 GBP','4rd rule created found'); }); ////EDIT CHECK From 936d0dbe37c0548aeb2ba8a2d770d74076f864fe Mon Sep 17 00:00:00 2001 From: gmorel Date: Thu, 12 Sep 2013 09:32:16 +0200 Subject: [PATCH 02/20] WIP - Coupon Add/Edit/Delete rule AJAX --- templates/admin/default/assets/js/coupon.js | 4 ++++ templates/admin/default/coupon-update.html | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/admin/default/assets/js/coupon.js b/templates/admin/default/assets/js/coupon.js index 5c52aa097..1ccd70861 100644 --- a/templates/admin/default/assets/js/coupon.js +++ b/templates/admin/default/assets/js/coupon.js @@ -67,6 +67,10 @@ $(function($){ var valueId = null; var idName = null; + if(id) { + couponManager.ruleToUpdate = couponManager.ruleToSave; + } + for (idName in couponManager.ruleToUpdate.operators) { // Setting idName operator select operatorId = idName + '-operator'; diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html index 16771539a..925296aae 100755 --- a/templates/admin/default/coupon-update.html +++ b/templates/admin/default/coupon-update.html @@ -19,7 +19,6 @@ {include file='coupon/form.html' formAction={url path={$formAction}} form=$form noRules=false} {/form} - {/block} From 8668bf93bd44abe1589695c1fe452bbb1e76cad4 Mon Sep 17 00:00:00 2001 From: gmorel Date: Thu, 12 Sep 2013 14:10:36 +0200 Subject: [PATCH 03/20] Working - Coupon Add/Edit/Delete rule AJAX --- core/lib/Thelia/Constraint/Rule/Operators.php | 6 +- templates/admin/default/assets/js/coupon.js | 67 ++++++----- templates/admin/default/coupon-update.html | 6 + .../admin/default/coupon/rule-input-ajax.html | 28 +++-- tests/functionnal/casperjs/exe/30_coupons.js | 113 +++++++++++++----- 5 files changed, 148 insertions(+), 72 deletions(-) diff --git a/core/lib/Thelia/Constraint/Rule/Operators.php b/core/lib/Thelia/Constraint/Rule/Operators.php index 41640810c..2ed5c2909 100644 --- a/core/lib/Thelia/Constraint/Rule/Operators.php +++ b/core/lib/Thelia/Constraint/Rule/Operators.php @@ -133,21 +133,21 @@ abstract class Operators break; case self::INFERIOR_OR_EQUAL: $ret = $translator->trans( - 'inferior or equals to', + 'inferior or equal to', array(), 'constraint' ); break; case self::EQUAL: $ret = $translator->trans( - 'equals to', + 'equal to', array(), 'constraint' ); break; case self::SUPERIOR_OR_EQUAL: $ret = $translator->trans( - 'superior or equals to', + 'superior or equal to', array(), 'constraint' ); diff --git a/templates/admin/default/assets/js/coupon.js b/templates/admin/default/assets/js/coupon.js index 1ccd70861..038c9114a 100644 --- a/templates/admin/default/assets/js/coupon.js +++ b/templates/admin/default/assets/js/coupon.js @@ -22,17 +22,20 @@ $(function($){ }; // Add 1 Rule / or update the temporary Rules array then Save Rules via AJAX - couponManager.addRuleAjax = function(id) { - console.log('addRuleAjax '+ id); + couponManager.createOrUpdateRuleAjax = function() { + var id = couponManager.ruleToUpdateId; + console.log('createOrUpdateRuleAjax '+ id); // If create if(!id) { console.log('pushing'); + console.log(couponManager.ruleToSave); couponManager.rulesToSave.push(couponManager.ruleToSave); } else { // else update console.log('editing ' + id); + console.log(couponManager.ruleToSave); couponManager.rulesToSave[id] = couponManager.ruleToSave; // reset edit mode to off - couponManager.ruleIdToUpdate = false; + couponManager.ruleToUpdateId = false; } // Save @@ -40,21 +43,21 @@ $(function($){ }; // Set rule inputs to allow editing - couponManager.updateRuleAjax = function(id) { - couponManager.ruleToUpdate = couponManager.rulesToSave[id]; + couponManager.updateRuleSelectAjax = function(id) { + couponManager.ruleToUpdateId = id; + couponManager.ruleToSave = couponManager.rulesToSave[id]; console.log('Set id to edit to ' + id); - couponManager.ruleIdToUpdate = id; - // Deleting this rule, we will reset it - delete couponManager.rulesToSave[id]; +// // Deleting this rule, we will reset it +// delete couponManager.rulesToSave[id]; // Set the rule selector $("#category-rule option").filter(function() { - return $(this).val() == couponManager.ruleToUpdate.serviceId; + return $(this).val() == couponManager.ruleToSave.serviceId; }).prop('selected', true); // Force rule input refresh - couponManager.loadRuleInputs(couponManager.ruleToUpdate.serviceId, function() { + couponManager.loadRuleInputs(couponManager.ruleToSave.serviceId, function() { couponManager.fillInRuleInputs(); }); }; @@ -62,39 +65,40 @@ $(function($){ // Fill in rule inputs couponManager.fillInRuleInputs = function() { console.log('fillInRuleInputs with'); - console.log(couponManager.ruleToUpdate); + console.log(couponManager.ruleToSave); var operatorId = null; var valueId = null; var idName = null; + var id = couponManager.ruleToUpdateId; if(id) { - couponManager.ruleToUpdate = couponManager.ruleToSave; + couponManager.ruleToSave = couponManager.rulesToSave[id]; } - for (idName in couponManager.ruleToUpdate.operators) { + for (idName in couponManager.ruleToSave.operators) { // Setting idName operator select operatorId = idName + '-operator'; - $('#' + operatorId).val(couponManager.ruleToUpdate.operators[idName]); + $('#' + operatorId).val(couponManager.ruleToSave.operators[idName]); - valueId = idName + '-value'; // Setting idName value input - $('#' + valueId).val(couponManager.ruleToUpdate.values[idName]); + valueId = idName + '-value'; + $('#' + valueId).val(couponManager.ruleToSave.values[idName]); } - couponManager.ruleToSave = couponManager.ruleToUpdate; +// couponManager.ruleToSave = couponManager.ruleToUpdate; - var id = couponManager.ruleIdToUpdate; - console.log('id to edit = ' + id); - if(id) { - console.log('setint rulesToSave[' + id + ']'); - console.log(couponManager.ruleToSave); - couponManager.rulesToSave[id] = couponManager.ruleToSave; - } +// var id = couponManager.ruleToUpdateId; +// console.log('id to edit = ' + id); +// if(id) { +// console.log('setint rulesToSave[' + id + ']'); +// console.log(couponManager.ruleToSave); +// couponManager.rulesToSave[id] = couponManager.ruleToSave; +// } }; // Save rules on click couponManager.onClickSaveRule = function() { $('#constraint-save-btn').on('click', function () { - couponManager.addRuleAjax(couponManager.ruleIdToUpdate); + couponManager.createOrUpdateRuleAjax(); }); }; couponManager.onClickSaveRule(); @@ -114,7 +118,7 @@ $(function($){ $('.constraint-update-btn').on('click', function (e) { e.preventDefault(); var $this = $(this); - couponManager.updateRuleAjax($this.attr('data-int')); + couponManager.updateRuleSelectAjax($this.attr('data-int')); // Hide row being updated $this.parent().parent().remove(); @@ -134,7 +138,7 @@ $(function($){ // Reload rule inputs when changing effect couponManager.onRuleChange = function() { $('#category-rule').on('change', function () { - couponManager.loadRuleInputs($(this).val(), function(ruleToSave) {}); + couponManager.loadRuleInputs($(this).val(), function() {}); }); }; couponManager.onRuleChange(); @@ -148,5 +152,12 @@ $(function($){ // Rule to save var couponManager = {}; +// Rule to be saved couponManager.ruleToSave = {}; -couponManager.ruleIdToUpdate = false; \ No newline at end of file +couponManager.ruleToSave.serviceId = false; +couponManager.ruleToSave.operators = {}; +couponManager.ruleToSave.values = {}; +// Rules payload to save +couponManager.rulesToSave = []; +// Rule being updated id +couponManager.ruleToUpdateId = false; \ No newline at end of file diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html index 925296aae..9d6e79c60 100755 --- a/templates/admin/default/coupon-update.html +++ b/templates/admin/default/coupon-update.html @@ -87,6 +87,11 @@ }).done(function(data) { $('#constraint-list').html(data); $('#constraint-add-operators-values').html(''); + // Set the rule selector + $("#category-rule option").filter(function() { + return $(this).val() == 'thelia.constraint.rule.available_for_everyone'; + }).prop('selected', true); + couponManager.onClickUpdateRule(); couponManager.onClickDeleteRule(); }); @@ -108,6 +113,7 @@ } }).done(function(data) { $('#constraint-add-operators-values').html(data); + couponManager.ruleToSave.serviceId = ruleId; return callBack(); }); diff --git a/templates/admin/default/coupon/rule-input-ajax.html b/templates/admin/default/coupon/rule-input-ajax.html index cdf683d21..76bb545f5 100644 --- a/templates/admin/default/coupon/rule-input-ajax.html +++ b/templates/admin/default/coupon/rule-input-ajax.html @@ -3,7 +3,7 @@
@@ -11,7 +11,7 @@
{if $input.type == 'select'} @@ -72,12 +72,20 @@ {/block} diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html index 917a5ff19..85b9438ef 100644 --- a/templates/admin/default/coupon/form.html +++ b/templates/admin/default/coupon/form.html @@ -202,6 +202,7 @@
+ {/form_field}
-
- - {form_field form=$form field='code'} + {form_field form=$form field='code'} +
+ {if $error}{$message}{/if} - {/form_field} -
+
+ {/form_field} -
- - {form_field form=$form field='title'} + {form_field form=$form field='title'} +
+ {if $error}{$message}{/if} - {/form_field} -
+
+ {/form_field} -
- +
+ {/form_field} -
- +
+ {/form_field} -
- +
+ {/form_field} -
-
-
- - {form_field form=$form field='effect'} + {form_field form=$form field='effect'} +
+ {if $error}{$message}{/if} - {/form_field} - {$availableCoupons.0.toolTip} -
+ {$availableCoupons.0.toolTip} +
+ {/form_field}
-
- - {form_field form=$form field='amount'} + {form_field form=$form field='amount'} +
+ {if $error}{$message}{/if} - {/form_field} -
- {*
*} +
+ {/form_field} + {*
*} {**} {*form_field form=$form field='category'*} {* + {form_field form=$form field='shortDescription'} +
+ + {if $error}{$message}{/if} - {/form_field} -
+
+ {/form_field}
-
- - {form_field form=$form field='description'} + {form_field form=$form field='description'} +
+ {if $error}{$message}{/if} - {/form_field} -
+
+ {/form_field} - +
@@ -186,16 +187,16 @@
- + {intl l='Save this rule'}
diff --git a/templates/admin/default/includes/coupon_breadcrumb.html b/templates/admin/default/includes/coupon_breadcrumb.html deleted file mode 100755 index 878d9605d..000000000 --- a/templates/admin/default/includes/coupon_breadcrumb.html +++ /dev/null @@ -1,5 +0,0 @@ -{* Breadcrumb for coupon browsing and editing *} - -
  • Home
  • -
  • Coupon
  • -
  • Browse
  • \ No newline at end of file From d829835d5182eb1314552aa254255edacfdc7a9b Mon Sep 17 00:00:00 2001 From: gmorel Date: Fri, 13 Sep 2013 15:36:15 +0200 Subject: [PATCH 15/20] Working : bootstrap datepicker commented out to keep style for jquery.datepicker (Mika) --- .../js/bootstrap-datepicker.js | 948 +++++++++--------- 1 file changed, 474 insertions(+), 474 deletions(-) diff --git a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js index bf3a56df0..97a3d67ed 100755 --- a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js +++ b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js @@ -1,474 +1,474 @@ -/* ========================================================= - * bootstrap-datepicker.js - * http://www.eyecon.ro/bootstrap-datepicker - * ========================================================= - * Copyright 2012 Stefan Petre - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -!function( $ ) { - - // Picker object - - var Datepicker = function(element, options){ - this.element = $(element); - this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); - this.picker = $(DPGlobal.template) - .appendTo('body') - .on({ - click: $.proxy(this.click, this)//, - //mousedown: $.proxy(this.mousedown, this) - }); - this.isInput = this.element.is('input'); - this.component = this.element.is('.date') ? this.element.find('.add-on') : false; - - if (this.isInput) { - this.element.on({ - focus: $.proxy(this.show, this), - //blur: $.proxy(this.hide, this), - keyup: $.proxy(this.update, this) - }); - } else { - if (this.component){ - this.component.on('click', $.proxy(this.show, this)); - } else { - this.element.on('click', $.proxy(this.show, this)); - } - } - - this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; - if (typeof this.minViewMode === 'string') { - switch (this.minViewMode) { - case 'months': - this.minViewMode = 1; - break; - case 'years': - this.minViewMode = 2; - break; - default: - this.minViewMode = 0; - break; - } - } - this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; - if (typeof this.viewMode === 'string') { - switch (this.viewMode) { - case 'months': - this.viewMode = 1; - break; - case 'years': - this.viewMode = 2; - break; - default: - this.viewMode = 0; - break; - } - } - this.startViewMode = this.viewMode; - this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; - this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; - this.onRender = options.onRender; - this.fillDow(); - this.fillMonths(); - this.update(); - this.showMode(); - }; - - Datepicker.prototype = { - constructor: Datepicker, - - show: function(e) { - this.picker.show(); - this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); - this.place(); - $(window).on('resize', $.proxy(this.place, this)); - if (e ) { - e.stopPropagation(); - e.preventDefault(); - } - if (!this.isInput) { - } - var that = this; - $(document).on('mousedown', function(ev){ - if ($(ev.target).closest('.datepicker').length == 0) { - that.hide(); - } - }); - this.element.trigger({ - type: 'show', - date: this.date - }); - }, - - hide: function(){ - this.picker.hide(); - $(window).off('resize', this.place); - this.viewMode = this.startViewMode; - this.showMode(); - if (!this.isInput) { - $(document).off('mousedown', this.hide); - } - //this.set(); - this.element.trigger({ - type: 'hide', - date: this.date - }); - }, - - set: function() { - var formated = DPGlobal.formatDate(this.date, this.format); - if (!this.isInput) { - if (this.component){ - this.element.find('input').prop('value', formated); - } - this.element.data('date', formated); - } else { - this.element.prop('value', formated); - } - }, - - setValue: function(newDate) { - if (typeof newDate === 'string') { - this.date = DPGlobal.parseDate(newDate, this.format); - } else { - this.date = new Date(newDate); - } - this.set(); - this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); - this.fill(); - }, - - place: function(){ - var offset = this.component ? this.component.offset() : this.element.offset(); - this.picker.css({ - top: offset.top + this.height, - left: offset.left - }); - }, - - update: function(newDate){ - this.date = DPGlobal.parseDate( - typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), - this.format - ); - this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); - this.fill(); - }, - - fillDow: function(){ - var dowCnt = this.weekStart; - var html = ''; - while (dowCnt < this.weekStart + 7) { - html += ''+DPGlobal.dates.daysMin[(dowCnt++)%7]+''; - } - html += ''; - this.picker.find('.datepicker-days thead').append(html); - }, - - fillMonths: function(){ - var html = ''; - var i = 0 - while (i < 12) { - html += ''+DPGlobal.dates.monthsShort[i++]+''; - } - this.picker.find('.datepicker-months td').append(html); - }, - - fill: function() { - var d = new Date(this.viewDate), - year = d.getFullYear(), - month = d.getMonth(), - currentDate = this.date.valueOf(); - this.picker.find('.datepicker-days th:eq(1)') - .text(DPGlobal.dates.months[month]+' '+year); - var prevMonth = new Date(year, month-1, 28,0,0,0,0), - day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); - prevMonth.setDate(day); - prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); - var nextMonth = new Date(prevMonth); - nextMonth.setDate(nextMonth.getDate() + 42); - nextMonth = nextMonth.valueOf(); - var html = []; - var clsName, - prevY, - prevM; - while(prevMonth.valueOf() < nextMonth) { - if (prevMonth.getDay() === this.weekStart) { - html.push(''); - } - clsName = this.onRender(prevMonth); - prevY = prevMonth.getFullYear(); - prevM = prevMonth.getMonth(); - if ((prevM < month && prevY === year) || prevY < year) { - clsName += ' old'; - } else if ((prevM > month && prevY === year) || prevY > year) { - clsName += ' new'; - } - if (prevMonth.valueOf() === currentDate) { - clsName += ' active'; - } - html.push(''+prevMonth.getDate() + ''); - if (prevMonth.getDay() === this.weekEnd) { - html.push(''); - } - prevMonth.setDate(prevMonth.getDate()+1); - } - this.picker.find('.datepicker-days tbody').empty().append(html.join('')); - var currentYear = this.date.getFullYear(); - - var months = this.picker.find('.datepicker-months') - .find('th:eq(1)') - .text(year) - .end() - .find('span').removeClass('active'); - if (currentYear === year) { - months.eq(this.date.getMonth()).addClass('active'); - } - - html = ''; - year = parseInt(year/10, 10) * 10; - var yearCont = this.picker.find('.datepicker-years') - .find('th:eq(1)') - .text(year + '-' + (year + 9)) - .end() - .find('td'); - year -= 1; - for (var i = -1; i < 11; i++) { - html += ''+year+''; - year += 1; - } - yearCont.html(html); - }, - - click: function(e) { - e.stopPropagation(); - e.preventDefault(); - var target = $(e.target).closest('span, td, th'); - if (target.length === 1) { - switch(target[0].nodeName.toLowerCase()) { - case 'th': - switch(target[0].className) { - case 'switch': - this.showMode(1); - break; - case 'prev': - case 'next': - this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( - this.viewDate, - this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + - DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) - ); - this.fill(); - this.set(); - break; - } - break; - case 'span': - if (target.is('.month')) { - var month = target.parent().find('span').index(target); - this.viewDate.setMonth(month); - } else { - var year = parseInt(target.text(), 10)||0; - this.viewDate.setFullYear(year); - } - if (this.viewMode !== 0) { - this.date = new Date(this.viewDate); - this.element.trigger({ - type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName - }); - } - this.showMode(-1); - this.fill(); - this.set(); - break; - case 'td': - if (target.is('.day') && !target.is('.disabled')){ - var day = parseInt(target.text(), 10)||1; - var month = this.viewDate.getMonth(); - if (target.is('.old')) { - month -= 1; - } else if (target.is('.new')) { - month += 1; - } - var year = this.viewDate.getFullYear(); - this.date = new Date(year, month, day,0,0,0,0); - this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); - this.fill(); - this.set(); - this.element.trigger({ - type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName - }); - } - break; - } - } - }, - - mousedown: function(e){ - e.stopPropagation(); - e.preventDefault(); - }, - - showMode: function(dir) { - if (dir) { - this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); - } - this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - } - }; - - $.fn.datepicker = function ( option, val ) { - return this.each(function () { - var $this = $(this), - data = $this.data('datepicker'), - options = typeof option === 'object' && option; - if (!data) { - $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); - } - if (typeof option === 'string') data[option](val); - }); - }; - - $.fn.datepicker.defaults = { - onRender: function(date) { - return ''; - } - }; - $.fn.datepicker.Constructor = Datepicker; - - var DPGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'Month', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'FullYear', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'FullYear', - navStep: 10 - }], - dates:{ - days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], - daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], - months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] - }, - isLeapYear: function (year) { - return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) - }, - getDaysInMonth: function (year, month) { - return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] - }, - parseFormat: function(format){ - var separator = format.match(/[.\/\-\s].*?/), - parts = format.split(/\W+/); - if (!separator || !parts || parts.length === 0){ - throw new Error("Invalid date format."); - } - return {separator: separator, parts: parts}; - }, - parseDate: function(date, format) { - var parts = date.split(format.separator), - date = new Date(), - val; - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - if (parts.length === format.parts.length) { - var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); - for (var i=0, cnt = format.parts.length; i < cnt; i++) { - val = parseInt(parts[i], 10)||1; - switch(format.parts[i]) { - case 'dd': - case 'd': - day = val; - date.setDate(val); - break; - case 'mm': - case 'm': - month = val - 1; - date.setMonth(val - 1); - break; - case 'yy': - year = 2000 + val; - date.setFullYear(2000 + val); - break; - case 'yyyy': - year = val; - date.setFullYear(val); - break; - } - } - date = new Date(year, month, day, 0 ,0 ,0); - } - return date; - }, - formatDate: function(date, format){ - var val = { - d: date.getDate(), - m: date.getMonth() + 1, - yy: date.getFullYear().toString().substring(2), - yyyy: date.getFullYear() - }; - val.dd = (val.d < 10 ? '0' : '') + val.d; - val.mm = (val.m < 10 ? '0' : '') + val.m; - var date = []; - for (var i=0, cnt = format.parts.length; i < cnt; i++) { - date.push(val[format.parts[i]]); - } - return date.join(format.separator); - }, - headTemplate: ''+ - ''+ - '‹'+ - ''+ - '›'+ - ''+ - '', - contTemplate: '' - }; - DPGlobal.template = ''; - -}( window.jQuery ); \ No newline at end of file +///* ========================================================= +// * bootstrap-datepicker.js +// * http://www.eyecon.ro/bootstrap-datepicker +// * ========================================================= +// * Copyright 2012 Stefan Petre +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// * ========================================================= */ +// +//!function( $ ) { +// +// // Picker object +// +// var Datepicker = function(element, options){ +// this.element = $(element); +// this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); +// this.picker = $(DPGlobal.template) +// .appendTo('body') +// .on({ +// click: $.proxy(this.click, this)//, +// //mousedown: $.proxy(this.mousedown, this) +// }); +// this.isInput = this.element.is('input'); +// this.component = this.element.is('.date') ? this.element.find('.add-on') : false; +// +// if (this.isInput) { +// this.element.on({ +// focus: $.proxy(this.show, this), +// //blur: $.proxy(this.hide, this), +// keyup: $.proxy(this.update, this) +// }); +// } else { +// if (this.component){ +// this.component.on('click', $.proxy(this.show, this)); +// } else { +// this.element.on('click', $.proxy(this.show, this)); +// } +// } +// +// this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; +// if (typeof this.minViewMode === 'string') { +// switch (this.minViewMode) { +// case 'months': +// this.minViewMode = 1; +// break; +// case 'years': +// this.minViewMode = 2; +// break; +// default: +// this.minViewMode = 0; +// break; +// } +// } +// this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; +// if (typeof this.viewMode === 'string') { +// switch (this.viewMode) { +// case 'months': +// this.viewMode = 1; +// break; +// case 'years': +// this.viewMode = 2; +// break; +// default: +// this.viewMode = 0; +// break; +// } +// } +// this.startViewMode = this.viewMode; +// this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; +// this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; +// this.onRender = options.onRender; +// this.fillDow(); +// this.fillMonths(); +// this.update(); +// this.showMode(); +// }; +// +// Datepicker.prototype = { +// constructor: Datepicker, +// +// show: function(e) { +// this.picker.show(); +// this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); +// this.place(); +// $(window).on('resize', $.proxy(this.place, this)); +// if (e ) { +// e.stopPropagation(); +// e.preventDefault(); +// } +// if (!this.isInput) { +// } +// var that = this; +// $(document).on('mousedown', function(ev){ +// if ($(ev.target).closest('.datepicker').length == 0) { +// that.hide(); +// } +// }); +// this.element.trigger({ +// type: 'show', +// date: this.date +// }); +// }, +// +// hide: function(){ +// this.picker.hide(); +// $(window).off('resize', this.place); +// this.viewMode = this.startViewMode; +// this.showMode(); +// if (!this.isInput) { +// $(document).off('mousedown', this.hide); +// } +// //this.set(); +// this.element.trigger({ +// type: 'hide', +// date: this.date +// }); +// }, +// +// set: function() { +// var formated = DPGlobal.formatDate(this.date, this.format); +// if (!this.isInput) { +// if (this.component){ +// this.element.find('input').prop('value', formated); +// } +// this.element.data('date', formated); +// } else { +// this.element.prop('value', formated); +// } +// }, +// +// setValue: function(newDate) { +// if (typeof newDate === 'string') { +// this.date = DPGlobal.parseDate(newDate, this.format); +// } else { +// this.date = new Date(newDate); +// } +// this.set(); +// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); +// this.fill(); +// }, +// +// place: function(){ +// var offset = this.component ? this.component.offset() : this.element.offset(); +// this.picker.css({ +// top: offset.top + this.height, +// left: offset.left +// }); +// }, +// +// update: function(newDate){ +// this.date = DPGlobal.parseDate( +// typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), +// this.format +// ); +// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); +// this.fill(); +// }, +// +// fillDow: function(){ +// var dowCnt = this.weekStart; +// var html = ''; +// while (dowCnt < this.weekStart + 7) { +// html += ''+DPGlobal.dates.daysMin[(dowCnt++)%7]+''; +// } +// html += ''; +// this.picker.find('.datepicker-days thead').append(html); +// }, +// +// fillMonths: function(){ +// var html = ''; +// var i = 0 +// while (i < 12) { +// html += ''+DPGlobal.dates.monthsShort[i++]+''; +// } +// this.picker.find('.datepicker-months td').append(html); +// }, +// +// fill: function() { +// var d = new Date(this.viewDate), +// year = d.getFullYear(), +// month = d.getMonth(), +// currentDate = this.date.valueOf(); +// this.picker.find('.datepicker-days th:eq(1)') +// .text(DPGlobal.dates.months[month]+' '+year); +// var prevMonth = new Date(year, month-1, 28,0,0,0,0), +// day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); +// prevMonth.setDate(day); +// prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); +// var nextMonth = new Date(prevMonth); +// nextMonth.setDate(nextMonth.getDate() + 42); +// nextMonth = nextMonth.valueOf(); +// var html = []; +// var clsName, +// prevY, +// prevM; +// while(prevMonth.valueOf() < nextMonth) { +// if (prevMonth.getDay() === this.weekStart) { +// html.push(''); +// } +// clsName = this.onRender(prevMonth); +// prevY = prevMonth.getFullYear(); +// prevM = prevMonth.getMonth(); +// if ((prevM < month && prevY === year) || prevY < year) { +// clsName += ' old'; +// } else if ((prevM > month && prevY === year) || prevY > year) { +// clsName += ' new'; +// } +// if (prevMonth.valueOf() === currentDate) { +// clsName += ' active'; +// } +// html.push(''+prevMonth.getDate() + ''); +// if (prevMonth.getDay() === this.weekEnd) { +// html.push(''); +// } +// prevMonth.setDate(prevMonth.getDate()+1); +// } +// this.picker.find('.datepicker-days tbody').empty().append(html.join('')); +// var currentYear = this.date.getFullYear(); +// +// var months = this.picker.find('.datepicker-months') +// .find('th:eq(1)') +// .text(year) +// .end() +// .find('span').removeClass('active'); +// if (currentYear === year) { +// months.eq(this.date.getMonth()).addClass('active'); +// } +// +// html = ''; +// year = parseInt(year/10, 10) * 10; +// var yearCont = this.picker.find('.datepicker-years') +// .find('th:eq(1)') +// .text(year + '-' + (year + 9)) +// .end() +// .find('td'); +// year -= 1; +// for (var i = -1; i < 11; i++) { +// html += ''+year+''; +// year += 1; +// } +// yearCont.html(html); +// }, +// +// click: function(e) { +// e.stopPropagation(); +// e.preventDefault(); +// var target = $(e.target).closest('span, td, th'); +// if (target.length === 1) { +// switch(target[0].nodeName.toLowerCase()) { +// case 'th': +// switch(target[0].className) { +// case 'switch': +// this.showMode(1); +// break; +// case 'prev': +// case 'next': +// this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( +// this.viewDate, +// this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + +// DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) +// ); +// this.fill(); +// this.set(); +// break; +// } +// break; +// case 'span': +// if (target.is('.month')) { +// var month = target.parent().find('span').index(target); +// this.viewDate.setMonth(month); +// } else { +// var year = parseInt(target.text(), 10)||0; +// this.viewDate.setFullYear(year); +// } +// if (this.viewMode !== 0) { +// this.date = new Date(this.viewDate); +// this.element.trigger({ +// type: 'changeDate', +// date: this.date, +// viewMode: DPGlobal.modes[this.viewMode].clsName +// }); +// } +// this.showMode(-1); +// this.fill(); +// this.set(); +// break; +// case 'td': +// if (target.is('.day') && !target.is('.disabled')){ +// var day = parseInt(target.text(), 10)||1; +// var month = this.viewDate.getMonth(); +// if (target.is('.old')) { +// month -= 1; +// } else if (target.is('.new')) { +// month += 1; +// } +// var year = this.viewDate.getFullYear(); +// this.date = new Date(year, month, day,0,0,0,0); +// this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); +// this.fill(); +// this.set(); +// this.element.trigger({ +// type: 'changeDate', +// date: this.date, +// viewMode: DPGlobal.modes[this.viewMode].clsName +// }); +// } +// break; +// } +// } +// }, +// +// mousedown: function(e){ +// e.stopPropagation(); +// e.preventDefault(); +// }, +// +// showMode: function(dir) { +// if (dir) { +// this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); +// } +// this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); +// } +// }; +// +// $.fn.datepicker = function ( option, val ) { +// return this.each(function () { +// var $this = $(this), +// data = $this.data('datepicker'), +// options = typeof option === 'object' && option; +// if (!data) { +// $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); +// } +// if (typeof option === 'string') data[option](val); +// }); +// }; +// +// $.fn.datepicker.defaults = { +// onRender: function(date) { +// return ''; +// } +// }; +// $.fn.datepicker.Constructor = Datepicker; +// +// var DPGlobal = { +// modes: [ +// { +// clsName: 'days', +// navFnc: 'Month', +// navStep: 1 +// }, +// { +// clsName: 'months', +// navFnc: 'FullYear', +// navStep: 1 +// }, +// { +// clsName: 'years', +// navFnc: 'FullYear', +// navStep: 10 +// }], +// dates:{ +// days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], +// daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], +// daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], +// months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], +// monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +// }, +// isLeapYear: function (year) { +// return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) +// }, +// getDaysInMonth: function (year, month) { +// return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] +// }, +// parseFormat: function(format){ +// var separator = format.match(/[.\/\-\s].*?/), +// parts = format.split(/\W+/); +// if (!separator || !parts || parts.length === 0){ +// throw new Error("Invalid date format."); +// } +// return {separator: separator, parts: parts}; +// }, +// parseDate: function(date, format) { +// var parts = date.split(format.separator), +// date = new Date(), +// val; +// date.setHours(0); +// date.setMinutes(0); +// date.setSeconds(0); +// date.setMilliseconds(0); +// if (parts.length === format.parts.length) { +// var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); +// for (var i=0, cnt = format.parts.length; i < cnt; i++) { +// val = parseInt(parts[i], 10)||1; +// switch(format.parts[i]) { +// case 'dd': +// case 'd': +// day = val; +// date.setDate(val); +// break; +// case 'mm': +// case 'm': +// month = val - 1; +// date.setMonth(val - 1); +// break; +// case 'yy': +// year = 2000 + val; +// date.setFullYear(2000 + val); +// break; +// case 'yyyy': +// year = val; +// date.setFullYear(val); +// break; +// } +// } +// date = new Date(year, month, day, 0 ,0 ,0); +// } +// return date; +// }, +// formatDate: function(date, format){ +// var val = { +// d: date.getDate(), +// m: date.getMonth() + 1, +// yy: date.getFullYear().toString().substring(2), +// yyyy: date.getFullYear() +// }; +// val.dd = (val.d < 10 ? '0' : '') + val.d; +// val.mm = (val.m < 10 ? '0' : '') + val.m; +// var date = []; +// for (var i=0, cnt = format.parts.length; i < cnt; i++) { +// date.push(val[format.parts[i]]); +// } +// return date.join(format.separator); +// }, +// headTemplate: ''+ +// ''+ +// '‹'+ +// ''+ +// '›'+ +// ''+ +// '', +// contTemplate: '' +// }; +// DPGlobal.template = ''; +// +//}( window.jQuery ); \ No newline at end of file From 6118a6837084af002f707c0c6a604bc2d74fbe81 Mon Sep 17 00:00:00 2001 From: gmorel Date: Fri, 13 Sep 2013 18:03:08 +0200 Subject: [PATCH 16/20] WIP : Coupon fix coupon creation issue --- .../Controller/Admin/CouponController.php | 108 +-------------- core/lib/Thelia/Form/CouponCreationForm.php | 1 + core/lib/Thelia/Model/Coupon.php | 1 - templates/admin/default/assets/js/coupon.js | 16 +-- templates/admin/default/coupon-create.html | 10 +- templates/admin/default/coupon/form.html | 36 ++--- .../functionnal/casperjs/exe/00_parameters.js | 2 +- tests/functionnal/casperjs/exe/30_coupons.js | 131 +++++++++++++++++- 8 files changed, 171 insertions(+), 134 deletions(-) diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php index 0b5b24daa..6803addfd 100755 --- a/core/lib/Thelia/Controller/Admin/CouponController.php +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -157,9 +157,10 @@ class CouponController extends BaseAdminController // If no input for expirationDate, now + 2 months $defaultDate = new \DateTime(); $args['defaultDate'] = $defaultDate->modify('+2 month') - ->format($lang->getDateFormat()); + ->format('Y-m-d'); } + $args['dateFormat'] = $this->getSession()->getLang()->getDateFormat(); $args['availableCoupons'] = $this->getAvailableCoupons(); $args['formAction'] = 'admin/coupon/create/'; @@ -224,7 +225,7 @@ class CouponController extends BaseAdminController 'shortDescription' => $coupon->getShortDescription(), 'description' => $coupon->getDescription(), 'isEnabled' => ($coupon->getIsEnabled() == 1), - 'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()), + 'expirationDate' => $coupon->getExpirationDate('Y-m-d'), 'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1), 'isCumulative' => ($coupon->getIsCumulative() == 1), 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), @@ -273,103 +274,6 @@ class CouponController extends BaseAdminController return $this->render('coupon-update', $args); } - -// /** -// * Manage Coupons Rule creation display -// * -// * @param int $couponId Coupon id -// * -// * @return \Symfony\Component\HttpFoundation\Response -// */ -// public function createRuleAction($couponId) -// { -// // Check current user authorization -// $response = $this->checkAuth('admin.coupon.update'); -// if ($response !== null) { -// return $response; -// } -// -// /** @var Coupon $coupon */ -// $coupon = CouponQuery::create()->findOneById($couponId); -// if (!$coupon) { -// $this->pageNotFound(); -// } -// -// // Parameters given to the template -// $args = array(); -// -// $i18n = new I18n(); -// /** @var Lang $lang */ -// $lang = $this->getSession()->get('lang'); -// $eventToDispatch = TheliaEvents::COUPON_RULE_CREATE; -// -// if ($this->getRequest()->isMethod('POST')) { -// $this->validateCreateOrUpdateForm( -// $i18n, -// $lang, -// $eventToDispatch, -// 'updated', -// 'update' -// ); -// } else { -// // Prepare the data that will hydrate the form -// -// /** @var ConstraintFactory $constraintFactory */ -// $constraintFactory = $this->container->get('thelia.constraint.factory'); -// -// $data = array( -// 'code' => $coupon->getCode(), -// 'title' => $coupon->getTitle(), -// 'amount' => $coupon->getAmount(), -// 'effect' => $coupon->getType(), -// 'shortDescription' => $coupon->getShortDescription(), -// 'description' => $coupon->getDescription(), -// 'isEnabled' => ($coupon->getIsEnabled() == 1), -// 'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()), -// 'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1), -// 'isCumulative' => ($coupon->getIsCumulative() == 1), -// 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), -// 'maxUsage' => $coupon->getMaxUsage(), -// 'rules' => $constraintFactory->unserializeCouponRuleCollection($coupon->getSerializedRules()), -// 'locale' => $coupon->getLocale(), -// ); -// -// /** @var CouponAdapterInterface $adapter */ -// $adapter = $this->container->get('thelia.adapter'); -// /** @var Translator $translator */ -// $translator = $this->container->get('thelia.translator'); -// -// $args['rulesObject'] = array(); -// /** @var CouponRuleInterface $rule */ -// foreach ($coupon->getRules()->getRules() as $rule) { -// $args['rulesObject'][] = array( -// 'name' => $rule->getName($translator), -// 'tooltip' => $rule->getToolTip($translator), -// 'validators' => $rule->getValidators() -// ); -// } -// -// $args['rules'] = $this->cleanRuleForTemplate($coupon->getRules()->getRules()); -// -// // Setup the object form -// $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); -// -// // Pass it to the parser -// $this->getParserContext()->addForm($changeForm); -// } -// -// $args['formAction'] = 'admin/coupon/update/' . $couponId; -// -// return $this->render( -// 'coupon-update', -// $args -// ); -// } - - - - - /** * Manage Coupons read display * @@ -569,7 +473,7 @@ class CouponController extends BaseAdminController /** * Validate the CreateOrUpdate form * - * @param string $i18n Local code (fr_FR) + * @param I18n $i18n Local code (fr_FR) * @param Lang $lang Local variables container * @param string $eventToDispatch Event which will activate actions * @param string $log created|edited @@ -577,7 +481,7 @@ class CouponController extends BaseAdminController * * @return $this */ - protected function validateCreateOrUpdateForm($i18n, $lang, $eventToDispatch, $log, $action) + protected function validateCreateOrUpdateForm(I18n $i18n, Lang $lang, $eventToDispatch, $log, $action) { // Create the form from the request $creationForm = new CouponCreationForm($this->getRequest()); @@ -597,7 +501,7 @@ class CouponController extends BaseAdminController $data['shortDescription'], $data['description'], $data['isEnabled'], - $i18n->getDateTimeFromForm($lang, $data['expirationDate']), + \DateTime::createFromFormat('Y-m-d', $data['expirationDate']), $data['isAvailableOnSpecialOffers'], $data['isCumulative'], $data['isRemovingPostage'], diff --git a/core/lib/Thelia/Form/CouponCreationForm.php b/core/lib/Thelia/Form/CouponCreationForm.php index 9e41bae4f..1625ab685 100755 --- a/core/lib/Thelia/Form/CouponCreationForm.php +++ b/core/lib/Thelia/Form/CouponCreationForm.php @@ -24,6 +24,7 @@ namespace Thelia\Form; use Symfony\Component\Validator\Constraints\Date; +use Symfony\Component\Validator\Constraints\DateTime; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotEqualTo; diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index 7a7ce1e4a..032de412a 100755 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -76,7 +76,6 @@ class Coupon extends BaseCoupon ->setType($effect) ->setAmount($amount) ->setIsRemovingPostage($isRemovingPostage) - ->setType($amount) ->setIsEnabled($isEnabled) ->setExpirationDate($expirationDate) ->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers) diff --git a/templates/admin/default/assets/js/coupon.js b/templates/admin/default/assets/js/coupon.js index 37f8de41f..41e0c1430 100644 --- a/templates/admin/default/assets/js/coupon.js +++ b/templates/admin/default/assets/js/coupon.js @@ -140,28 +140,21 @@ $(function($){ couponManager.onUsageUnlimitedChange = function() { if (!$('#max-usage').parent().hasClass('has-error')) { $('#max-usage').hide().attr('value', '-1'); + $('#max-usage-label').hide(); } $('#is-unlimited').change(function(){ var $this = $(this); if ($this.is(':checked')) { $('#max-usage').hide().attr('value', '-1'); + $('#max-usage-label').hide(); } else { $('#max-usage').show().val('').attr('value', ''); + $('#max-usage-label').show(); } }); }; couponManager.onUsageUnlimitedChange(); -// // -- Effect description -// if($('[name=effect]').length){ -// var $effectSelect = $('[name=effect]'), -// $helpBlock = $effectSelect.next('.help-block'); -// -// $effectSelect.change(function(){ -// var description = $(this).find(":selected").data('description'); -// $helpBlock.text(description); -// }); -// } }); // Rule to save @@ -175,4 +168,5 @@ couponManager.ruleToSave.values = {}; // Rules payload to save couponManager.rulesToSave = []; // Rule being updated id -couponManager.ruleToUpdateId = false; \ No newline at end of file +couponManager.ruleToUpdateId = false; + diff --git a/templates/admin/default/coupon-create.html b/templates/admin/default/coupon-create.html index b87b21195..f8a0411e1 100755 --- a/templates/admin/default/coupon-create.html +++ b/templates/admin/default/coupon-create.html @@ -20,7 +20,6 @@ {form name="thelia.admin.coupon.creation"} {include file='coupon/form.html' formAction={url path={$formAction}} noRules=true} {/form} -
    {include file='includes/confirmation-modal.html'} @@ -42,4 +41,13 @@ {javascripts file='assets/js/coupon.js'} {/javascripts} + + {**} + {**} + + {/block} diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html index 92b834fe7..a4ec8b14a 100644 --- a/templates/admin/default/coupon/form.html +++ b/templates/admin/default/coupon/form.html @@ -11,7 +11,7 @@ {/form_field} {form_field form=$form field='success_url'} - + {/form_field}
    @@ -35,40 +35,40 @@ {form_field form=$form field='isEnabled'}
    -
    {/form_field} {form_field form=$form field='isAvailableOnSpecialOffers'}
    -
    {/form_field} {form_field form=$form field='isCumulative'}
    -
    {/form_field} {form_field form=$form field='isRemovingPostage'}
    -
    {/form_field} @@ -77,7 +77,7 @@
    - + {if $error}{$message}{/if}
    @@ -86,11 +86,12 @@ {form_field form=$form field='maxUsage'}
    - + + {if $error}{$message}{/if}
    @@ -118,6 +119,7 @@
    {form_field form=$form field='amount'}
    + {$value} {if $error}{$message}{/if} @@ -157,7 +159,7 @@
    {/form_field} - +
    diff --git a/tests/functionnal/casperjs/exe/00_parameters.js b/tests/functionnal/casperjs/exe/00_parameters.js index a32ee89b5..df5470229 100644 --- a/tests/functionnal/casperjs/exe/00_parameters.js +++ b/tests/functionnal/casperjs/exe/00_parameters.js @@ -3,7 +3,7 @@ casper.test.comment('Please edit 00_parameters.js to add your configuration'); var thelia2_login_admin_url = thelia2_base_url + 'admin/login'; var thelia2_login_coupon_list_url = thelia2_base_url + 'admin/login'; -var thelia2_login_coupon_create_url = thelia2_base_url + 'admin/coupon/create'; +var thelia2_login_coupon_create_url = thelia2_base_url + 'admin/coupon/create/'; var thelia2_login_coupon_read_url = thelia2_base_url + 'admin/coupon/read/1'; var thelia2_login_coupon_update_url = thelia2_base_url + 'admin/coupon/update/1'; diff --git a/tests/functionnal/casperjs/exe/30_coupons.js b/tests/functionnal/casperjs/exe/30_coupons.js index 7cbd70578..2147c14cf 100644 --- a/tests/functionnal/casperjs/exe/30_coupons.js +++ b/tests/functionnal/casperjs/exe/30_coupons.js @@ -15,8 +15,137 @@ casper.test.comment('Testing coupons'); // @todo implement ////CREATE -// @todo implement +casper.start(thelia2_login_coupon_create_url, function() { + this.test.assertHttpStatus(200); + this.test.comment('Now on : ' + this.getCurrentUrl()); + this.capture('tests/functionnal/casperjs/screenshot/coupons/init.png'); + this.test.comment('COUPON - CREATE EMPTY'); + // Click on is unlimited button + this.click("form #is-unlimited"); + this.sendKeys('input#max-usage', '-2'); + + // cleaning expiration date default value + this.evaluate(function() { + $("#expiration-date").val('').change(); + return true; + }); + + this.capture('tests/functionnal/casperjs/screenshot/coupons/creating-new-coupon.png'); + this.click("form .control-group .btn.btn-default.btn-primary"); + +}); + +casper.wait(1000, function() { + this.echo("\nWaiting...."); +}); + +// Test Coupon creation if no input +casper.then(function(){ + this.test.assertHttpStatus(200); + this.capture('tests/functionnal/casperjs/screenshot/coupons/created-new-empty-coupon.png'); + this.test.assertExists('.has-error #code', 'Error on code input found'); + this.test.assertExists('.has-error #title', 'Error on title input found'); + + this.test.assertExists('.has-error #expiration-date', 'Error on expiration date input found'); + this.test.assertExists('.has-error #max-usage', 'Error on max usage input found'); + this.test.assertExists('.has-error #description', 'Error on description input found'); + this.test.assertExists('.has-error #effect', 'Error on effect input found'); + this.test.assertExists('.has-error #amount', 'Error on amount input found'); + this.test.assertExists('.has-error #short-description', 'Error on short-description input found'); +}); + +// Test Coupon creation if good input +casper.then(function(){ + + this.sendKeys('input#code', 'XMAS10'); + this.sendKeys('input#title', 'christmas'); + this.click("form #is-enabled"); + this.click("form #is-available-on-special-offers"); + this.click("form #is-cumulative"); + this.click("form #is-removing-postage"); + + this.evaluate(function() { + $("#expiration-date").val('2013-11-14').change(); + return true; + }); + + // Click on is unlimited button + this.click("form #is-unlimited"); + this.sendKeys('input#max-usage', '40'); + + this.evaluate(function() { + $('#effect').val('thelia.coupon.type.remove_x_amount').change(); + return true; + }); + + this.test.assertSelectorHasText( + '#effectToolTip', + this.evaluate(function () { + return $("#effect option[value^='thelia.coupon.type.remove_x_amount']").attr('data-description'); + }), + 'Tooltip found' + ); + this.sendKeys('input#amount', '42.12'); + this.sendKeys('#short-description', 'Mauris sed risus imperdiet, blandit arcu ac, tempus metus. Aliquam erat volutpat. Nullam dictum sed.'); + this.sendKeys('#description', 'Etiam sodales non nisi a condimentum. Morbi luctus mauris mattis sem ornare; ac blandit tortor porta! Sed vel viverra dolor. Nulla eget viverra eros. Donec rutrum felis ut quam blandit, eu massa nunc.'); + + this.capture('tests/functionnal/casperjs/screenshot/coupons/coupon-created-ready-to-be-saved.png'); + this.click("#save-coupon-btn"); +}); + +casper.wait(2000, function() { + this.echo("\nWaiting...."); +}); + +// Test Coupon creation if good input is well saved +casper.then(function(){ + this.test.assertHttpStatus(302); + this.test.comment('Now on : ' + this.getCurrentUrl()); + this.capture('tests/functionnal/casperjs/screenshot/coupons/created-new-coupon.png'); + this.test.assertField('thelia_coupon_creation[code]', 'XMAS10', 'Code found'); + this.test.assertField('thelia_coupon_creation[title]', 'christmas', 'Title found'); + + this.test.assert(this.evaluate(function () { + return document.getElementById('is-enabled').checked; + }), 'Checkbox is enabled checked'); + this.test.assert(this.evaluate(function () { + return document.getElementById('is-available-on-special-offers').checked; + }), 'Checkbox is available on special offers checked'); + this.test.assert(this.evaluate(function () { + return document.getElementById('is-cumulative').checked; + }), 'Checkbox is cumulative checked'); + this.test.assert(this.evaluate(function () { + return document.getElementById('is-removing-postage').checked; + }), 'Checkbox is cumulative checked'); + + this.test.assertField('thelia_coupon_creation[expirationDate]', '2013-11-14', 'Expiration date found'); + this.test.assertField('thelia_coupon_creation[maxUsage]', '40', 'Max usage found'); + this.test.assert(this.evaluate(function () { + return !document.getElementById('is-unlimited').checked; + }), 'Checkbox is unlimited not checked'); + + this.test.assert( + this.evaluate(function () { + return $("#effect").val(); + }), + 'thelia.coupon.type.remove_x_amount', + 'Effect found' + ); + this.test.assertSelectorHasText( + '#effectToolTip', + this.evaluate(function () { + return $("#effect option[value^='thelia.coupon.type.remove_x_amount']").attr('data-description'); + }), + 'Tooltip found' + ); + this.test.assertField('thelia_coupon_creation[amount]', '42.12', 'Amount found'); + + this.test.assertField('thelia_coupon_creation[shortDescription]', 'Mauris sed risus imperdiet, blandit arcu ac, tempus metus. Aliquam erat volutpat. Nullam dictum sed.', 'Short description found'); + this.test.assertField('thelia_coupon_creation[description]', 'Etiam sodales non nisi a condimentum. Morbi luctus mauris mattis sem ornare; ac blandit tortor porta! Sed vel viverra dolor. Nulla eget viverra eros. Donec rutrum felis ut quam blandit, eu massa nunc.', 'Description found'); + + +}); ////EDIT CHECK // @todo implement From 775fd09d7cc2660c2860b13b1355c139d879ef77 Mon Sep 17 00:00:00 2001 From: gmorel Date: Mon, 16 Sep 2013 10:01:02 +0200 Subject: [PATCH 17/20] WIP : Coupon fix coupon creation issue --- .../casperjs/exe/31_coupons_rule.js | 609 +++++++++--------- 1 file changed, 308 insertions(+), 301 deletions(-) diff --git a/tests/functionnal/casperjs/exe/31_coupons_rule.js b/tests/functionnal/casperjs/exe/31_coupons_rule.js index c96033d2d..66706aada 100644 --- a/tests/functionnal/casperjs/exe/31_coupons_rule.js +++ b/tests/functionnal/casperjs/exe/31_coupons_rule.js @@ -1,305 +1,312 @@ +//// +////var casper = require('casper').create({ +//// viewportSize:{ +//// width:1024, height:768 +//// }, +//// pageSettings:{ +//// userAgent:'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11' +//// }, +//// verbose:true +////}); // -//var casper = require('casper').create({ -// viewportSize:{ -// width:1024, height:768 -// }, -// pageSettings:{ -// userAgent:'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11' -// }, -// verbose:true +//casper.test.comment('Testing coupons rules'); +// +////UPDATE COUPON RULE +//casper.start(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/init.png'); +// this.test.comment('COUPON RULE - EDIT'); +// this.test.assertTitle('Update coupon - Thelia Back Office', 'Web page title OK'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1) 1st default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','1) 2nd default rule found'); +// +// // Create rule +// this.evaluate(function() { +// $('#category-rule').val('thelia.constraint.rule.available_for_x_articles').change(); +// return true; +// }); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-selected.png'); //}); - -casper.test.comment('Testing coupons rules'); - -//UPDATE COUPON RULE -casper.start(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/init.png'); - this.test.comment('COUPON RULE - EDIT'); - this.test.assertTitle('Update coupon - Thelia Back Office', 'Web page title OK'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1) 1st default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','1) 2nd default rule found'); - - // Create rule - this.evaluate(function() { - $('#category-rule').val('thelia.constraint.rule.available_for_x_articles').change(); - return true; - }); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-selected.png'); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); - -// Test Rule updating -casper.then(function(){ - this.evaluate(function() { - $('#quantity-operator').val('>=').change(); - return true; - }); - this.sendKeys('input#quantity-value', '4'); - this.click('#constraint-save-btn'); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); - -casper.then(function(){ - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','2) 1st default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', ' If cart products quantity is superior or equal to 4','2) 3rd rule found'); - - // Click on Edit button - this.click('tbody#constraint-list tr:nth-child(3) .constraint-update-btn'); -}); - -casper.wait(2000, function() { - this.echo("\nWaiting...."); -}); - -casper.then(function(){ - this.evaluate(function() { - $('#quantity-operator').val('==').change(); - return true; - }); - - // Removing old value -// casper.evaluate(function triggerKeyDownEvent() { -// var e = $.Event("keydown"); -// e.which = 8; -// e.keyCode = 8; -// $("#quantity-value").trigger(e); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +// +//// Test Rule updating +//casper.then(function(){ +// this.evaluate(function() { +// $('#quantity-operator').val('>=').change(); +// return true; // }); - this.evaluate(function() { - $("#quantity-value").val('').change(); - return true; - }); - - // Adding new value - this.sendKeys('#quantity-value', '5'); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-being-edited.png'); - this.click('#constraint-save-btn'); -}); - -casper.wait(2000, function() { - this.echo("\nWaiting...."); -}); -// Check if updated rule has been saved and list refreshed -casper.then(function(){ - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','3) 1st default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','3) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equal to 5','3) 3rd rule updated found'); -}); - -// Check if updated rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','4) 1st default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','4) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equal to 5','4) 3rd rule updated found'); - - // Click on Delete button - this.click('tbody#constraint-list tr:nth-child(2) .constraint-delete-btn'); -}); - -casper.wait(2000, function() { - this.echo("\nWaiting...."); -}); - -casper.then(function(){ - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','5) 1st default rule found'); - this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','5) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','5) 3rd rule updated found'); -}); - -// Check if updated rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-deleted-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','6) 1st default rule found'); - this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','6) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','6) 3rd rule updated found'); -}); - -// Test creating rule that won't be edited -casper.then(function(){ -// Create rule - this.evaluate(function() { - $('#category-rule').val('thelia.constraint.rule.available_for_total_amount').change(); - return true; - }); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-selected2.png'); -}); - -casper.wait(2000, function() { - this.echo("\nWaiting...."); -}); - -// Test Rule creation -casper.then(function(){ - this.evaluate(function() { - $('#price-operator').val('<=').change(); - return true; - }); - // Removing old value -// casper.evaluate(function triggerKeyDownEvent() { -// var e = $.Event("keydown"); -// e.which = 8; -// e.keyCode = 8; -// $("input#price-value").trigger(e); +// this.sendKeys('input#quantity-value', '4'); +// this.click('#constraint-save-btn'); +//}); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +// +//casper.then(function(){ +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','2) 1st default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', ' If cart products quantity is superior or equal to 4','2) 3rd rule found'); +// +// // Click on Edit button +// this.click('tbody#constraint-list tr:nth-child(3) .constraint-update-btn'); +//}); +// +//casper.wait(2000, function() { +// this.echo("\nWaiting...."); +//}); +// +//casper.then(function(){ +// this.evaluate(function() { +// $('#quantity-operator').val('==').change(); +// return true; // }); - this.evaluate(function() { - $("input#price-value").val('').change(); - return true; - }); - - // Changing 400 to 401 - this.sendKeys('input#price-value', '401'); - this.evaluate(function() { - $('#currency-value').val('GBP').change(); - return true; - }); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-saved-edited-before-click-save.png'); - this.click('#constraint-save-btn'); -}); - -casper.wait(2000, function() { - this.echo("\nWaiting...."); -}); - -casper.then(function(){ - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','7) 1st default rule found'); - this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','7) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','7) 3rd rule updated found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equal to 401 GBP','7) 4rd rule created found'); -}); - -// Check if created rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','8) 1st default rule found'); - this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','8) 2nd default rule found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','8) 3rd rule updated found'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equal to 401 GBP','8) 4rd rule created found'); -}); - -// Testing deleting all rules -casper.then(function(){ -// Click on Delete button - this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); -}); -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); -casper.then(function(){ -// Click on Delete button - this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); -}); -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); -casper.then(function(){ -// Click on Delete button - this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); -}); -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); -casper.then(function(){ - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','9) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - -// Check if created rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','10) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - - -// Test add no condition rule -casper.then(function(){ - this.evaluate(function() { - $('#category-rule').val('thelia.constraint.rule.available_for_x_articles').change(); - return true; - }); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); - -// Test Rule updating -casper.then(function(){ - this.evaluate(function() { - $('#quantity-operator').val('>').change(); - return true; - }); - this.sendKeys('input#quantity-value', '4'); - this.click('#constraint-save-btn'); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); - -casper.then(function(){ - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart products quantity is superior to 4', '11) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - -// Check if created rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart products quantity is superior to 4','12) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - -casper.then(function(){ - this.evaluate(function() { - $('#category-rule').val('thelia.constraint.rule.available_for_everyone').change(); - return true; - }); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); - -// Test Rule updating -casper.then(function(){ - this.click('#constraint-save-btn'); -}); - -casper.wait(1000, function() { - this.echo("\nWaiting...."); -}); -casper.then(function(){ - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','13) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - -// Check if created rule has been well saved -casper.thenOpen(thelia2_login_coupon_update_url, function() { - this.test.comment('Now on : ' + this.getCurrentUrl()); - this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); - this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','14) 1st default rule found'); - test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); -}); - -//RUN -casper.run(function() { - this.test.done(); -}); \ No newline at end of file +// +// // Removing old value +//// casper.evaluate(function triggerKeyDownEvent() { +//// var e = $.Event("keydown"); +//// e.which = 8; +//// e.keyCode = 8; +//// $("#quantity-value").trigger(e); +//// }); +// this.evaluate(function() { +// $("#quantity-value").val('').change(); +// return true; +// }); +// +// // Adding new value +// this.sendKeys('#quantity-value', '5'); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-being-edited.png'); +// this.click('#constraint-save-btn'); +//}); +// +//casper.wait(2000, function() { +// this.echo("\nWaiting...."); +//}); +//// Check if updated rule has been saved and list refreshed +//casper.then(function(){ +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','3) 1st default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','3) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equal to 5','3) 3rd rule updated found'); +//}); +// +//// Check if updated rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-edited-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','4) 1st default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','4) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart products quantity is equal to 5','4) 3rd rule updated found'); +// +// // Click on Delete button +// this.click('tbody#constraint-list tr:nth-child(2) .constraint-delete-btn'); +//}); +// +//casper.wait(2000, function() { +// this.echo("\nWaiting...."); +//}); +// +//casper.then(function(){ +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','5) 1st default rule found'); +// this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','5) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','5) 3rd rule updated found'); +//}); +// +//// Check if updated rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-deleted-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','6) 1st default rule found'); +// this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','6) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','6) 3rd rule updated found'); +//}); +// +//// Test creating rule that won't be edited +//casper.then(function(){ +//// Create rule +// this.evaluate(function() { +// $('#category-rule').val('thelia.constraint.rule.available_for_total_amount').change(); +// return true; +// }); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-selected2.png'); +//}); +// +//casper.wait(2000, function() { +// this.echo("\nWaiting...."); +//}); +// +//// Test Rule creation +//casper.then(function(){ +// this.evaluate(function() { +// $('#price-operator').val('<=').change(); +// return true; +// }); +// // Removing old value +//// casper.evaluate(function triggerKeyDownEvent() { +//// var e = $.Event("keydown"); +//// e.which = 8; +//// e.keyCode = 8; +//// $("input#price-value").trigger(e); +//// }); +// this.evaluate(function() { +// $("input#price-value").val('').change(); +// return true; +// }); +// +// // Changing 400 to 401 +// this.sendKeys('input#price-value', '401'); +// this.evaluate(function() { +// $('#currency-value').val('GBP').change(); +// return true; +// }); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-saved-edited-before-click-save.png'); +// this.click('#constraint-save-btn'); +//}); +// +//casper.wait(2000, function() { +// this.echo("\nWaiting...."); +//}); +// +//casper.then(function(){ +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','7) 1st default rule found'); +// this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','7) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','7) 3rd rule updated found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equal to 401 GBP','7) 4rd rule created found'); +//}); +// +//// Check if created rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-added-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','8) 1st default rule found'); +// this.test.assertSelectorDoesntHaveText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','8) 2nd default rule found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart products quantity is equal to 5','8) 3rd rule updated found'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(3)', 'If cart total amount is inferior or equal to 401 GBP','8) 4rd rule created found'); +//}); +// +//// Testing deleting all rules +//casper.then(function(){ +//// Click on Delete button +// this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); +//}); +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +//casper.then(function(){ +//// Click on Delete button +// this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); +//}); +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +//casper.then(function(){ +//// Click on Delete button +// this.click('tbody#constraint-list tr:nth-child(1) .constraint-delete-btn'); +//}); +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +//casper.then(function(){ +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','9) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +//// Check if created rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','10) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +// +//// Test add no condition rule +//casper.then(function(){ +// this.evaluate(function() { +// $('#category-rule').val('thelia.constraint.rule.available_for_x_articles').change(); +// return true; +// }); +//}); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +// +//// Test Rule updating +//casper.then(function(){ +// this.evaluate(function() { +// $('#quantity-operator').val('>').change(); +// return true; +// }); +// this.sendKeys('input#quantity-value', '4'); +// this.click('#constraint-save-btn'); +//}); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +// +//casper.then(function(){ +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart products quantity is superior to 4', '11) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +//// Check if created rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart products quantity is superior to 4','12) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +//casper.then(function(){ +// this.evaluate(function() { +// $('#category-rule').val('thelia.constraint.rule.available_for_everyone').change(); +// return true; +// }); +//}); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +// +//// Test Rule updating +//casper.then(function(){ +// this.click('#constraint-save-btn'); +//}); +// +//casper.wait(1000, function() { +// this.echo("\nWaiting...."); +//}); +//casper.then(function(){ +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','13) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +//// Check if created rule has been well saved +//casper.thenOpen(thelia2_login_coupon_update_url, function() { +// this.test.assertHttpStatus(200); +// this.test.comment('Now on : ' + this.getCurrentUrl()); +// this.capture('tests/functionnal/casperjs/screenshot/coupons/rule-all-deleted-refreshed.png'); +// this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'No conditions','14) 1st default rule found'); +// test.assertDoesntExist('tbody#constraint-list tr:nth-child(2)'); +//}); +// +////RUN +//casper.run(function() { +// this.test.done(); +//}); \ No newline at end of file From d4d876c78317892e510038792697e88bbba775b5 Mon Sep 17 00:00:00 2001 From: gmorel Date: Mon, 16 Sep 2013 10:09:34 +0200 Subject: [PATCH 18/20] Working : .gitignore phpmyadmin (vm) --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2af71adba..3063f9a02 100755 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ phpdoc*.log php-cs xhprof/ phpunit.phar -.DS_Store \ No newline at end of file +.DS_Store +phpmyadmin \ No newline at end of file From 5e3c10cd4fad7f7b8622c6d9f4e2b24331003f20 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Mon, 16 Sep 2013 10:16:54 +0200 Subject: [PATCH 19/20] add promo column in cart_item --- core/lib/Thelia/Model/Base/CartItem.php | 76 +- core/lib/Thelia/Model/Base/CartItemQuery.php | 47 +- .../lib/Thelia/Model/Map/CartItemTableMap.php | 36 +- install/thelia.sql | 3 +- local/config/schema.xml | 2325 +++++++++-------- 5 files changed, 1300 insertions(+), 1187 deletions(-) diff --git a/core/lib/Thelia/Model/Base/CartItem.php b/core/lib/Thelia/Model/Base/CartItem.php index 5dd573d39..e785ae0a5 100644 --- a/core/lib/Thelia/Model/Base/CartItem.php +++ b/core/lib/Thelia/Model/Base/CartItem.php @@ -116,6 +116,12 @@ abstract class CartItem implements ActiveRecordInterface */ protected $discount; + /** + * The value for the promo field. + * @var int + */ + protected $promo; + /** * The value for the created_at field. * @var string @@ -527,6 +533,17 @@ abstract class CartItem implements ActiveRecordInterface return $this->discount; } + /** + * Get the [promo] column value. + * + * @return int + */ + public function getPromo() + { + + return $this->promo; + } + /** * Get the [optionally formatted] temporal [created_at] column value. * @@ -768,6 +785,27 @@ abstract class CartItem implements ActiveRecordInterface return $this; } // setDiscount() + /** + * Set the value of [promo] column. + * + * @param int $v new value + * @return \Thelia\Model\CartItem The current object (for fluent API support) + */ + public function setPromo($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->promo !== $v) { + $this->promo = $v; + $this->modifiedColumns[] = CartItemTableMap::PROMO; + } + + + return $this; + } // setPromo() + /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. * @@ -885,13 +923,16 @@ abstract class CartItem implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : CartItemTableMap::translateFieldName('Discount', TableMap::TYPE_PHPNAME, $indexType)]; $this->discount = (null !== $col) ? (double) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : CartItemTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : CartItemTableMap::translateFieldName('Promo', TableMap::TYPE_PHPNAME, $indexType)]; + $this->promo = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 10 + $startcol : CartItemTableMap::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 ? 10 + $startcol : CartItemTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 11 + $startcol : CartItemTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -904,7 +945,7 @@ abstract class CartItem implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 11; // 11 = CartItemTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 12; // 12 = CartItemTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\CartItem object", 0, $e); @@ -1189,6 +1230,9 @@ abstract class CartItem implements ActiveRecordInterface if ($this->isColumnModified(CartItemTableMap::DISCOUNT)) { $modifiedColumns[':p' . $index++] = 'DISCOUNT'; } + if ($this->isColumnModified(CartItemTableMap::PROMO)) { + $modifiedColumns[':p' . $index++] = 'PROMO'; + } if ($this->isColumnModified(CartItemTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; } @@ -1233,6 +1277,9 @@ abstract class CartItem implements ActiveRecordInterface case 'DISCOUNT': $stmt->bindValue($identifier, $this->discount, PDO::PARAM_STR); break; + case 'PROMO': + $stmt->bindValue($identifier, $this->promo, 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; @@ -1329,9 +1376,12 @@ abstract class CartItem implements ActiveRecordInterface return $this->getDiscount(); break; case 9: - return $this->getCreatedAt(); + return $this->getPromo(); break; case 10: + return $this->getCreatedAt(); + break; + case 11: return $this->getUpdatedAt(); break; default: @@ -1372,8 +1422,9 @@ abstract class CartItem implements ActiveRecordInterface $keys[6] => $this->getPromoPrice(), $keys[7] => $this->getPriceEndOfLife(), $keys[8] => $this->getDiscount(), - $keys[9] => $this->getCreatedAt(), - $keys[10] => $this->getUpdatedAt(), + $keys[9] => $this->getPromo(), + $keys[10] => $this->getCreatedAt(), + $keys[11] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1453,9 +1504,12 @@ abstract class CartItem implements ActiveRecordInterface $this->setDiscount($value); break; case 9: - $this->setCreatedAt($value); + $this->setPromo($value); break; case 10: + $this->setCreatedAt($value); + break; + case 11: $this->setUpdatedAt($value); break; } // switch() @@ -1491,8 +1545,9 @@ abstract class CartItem implements ActiveRecordInterface if (array_key_exists($keys[6], $arr)) $this->setPromoPrice($arr[$keys[6]]); if (array_key_exists($keys[7], $arr)) $this->setPriceEndOfLife($arr[$keys[7]]); if (array_key_exists($keys[8], $arr)) $this->setDiscount($arr[$keys[8]]); - if (array_key_exists($keys[9], $arr)) $this->setCreatedAt($arr[$keys[9]]); - if (array_key_exists($keys[10], $arr)) $this->setUpdatedAt($arr[$keys[10]]); + if (array_key_exists($keys[9], $arr)) $this->setPromo($arr[$keys[9]]); + if (array_key_exists($keys[10], $arr)) $this->setCreatedAt($arr[$keys[10]]); + if (array_key_exists($keys[11], $arr)) $this->setUpdatedAt($arr[$keys[11]]); } /** @@ -1513,6 +1568,7 @@ abstract class CartItem implements ActiveRecordInterface if ($this->isColumnModified(CartItemTableMap::PROMO_PRICE)) $criteria->add(CartItemTableMap::PROMO_PRICE, $this->promo_price); if ($this->isColumnModified(CartItemTableMap::PRICE_END_OF_LIFE)) $criteria->add(CartItemTableMap::PRICE_END_OF_LIFE, $this->price_end_of_life); if ($this->isColumnModified(CartItemTableMap::DISCOUNT)) $criteria->add(CartItemTableMap::DISCOUNT, $this->discount); + if ($this->isColumnModified(CartItemTableMap::PROMO)) $criteria->add(CartItemTableMap::PROMO, $this->promo); if ($this->isColumnModified(CartItemTableMap::CREATED_AT)) $criteria->add(CartItemTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(CartItemTableMap::UPDATED_AT)) $criteria->add(CartItemTableMap::UPDATED_AT, $this->updated_at); @@ -1586,6 +1642,7 @@ abstract class CartItem implements ActiveRecordInterface $copyObj->setPromoPrice($this->getPromoPrice()); $copyObj->setPriceEndOfLife($this->getPriceEndOfLife()); $copyObj->setDiscount($this->getDiscount()); + $copyObj->setPromo($this->getPromo()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); if ($makeNew) { @@ -1783,6 +1840,7 @@ abstract class CartItem implements ActiveRecordInterface $this->promo_price = null; $this->price_end_of_life = null; $this->discount = null; + $this->promo = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; diff --git a/core/lib/Thelia/Model/Base/CartItemQuery.php b/core/lib/Thelia/Model/Base/CartItemQuery.php index 83705aeac..79d5d3cfe 100644 --- a/core/lib/Thelia/Model/Base/CartItemQuery.php +++ b/core/lib/Thelia/Model/Base/CartItemQuery.php @@ -30,6 +30,7 @@ use Thelia\Model\Map\CartItemTableMap; * @method ChildCartItemQuery orderByPromoPrice($order = Criteria::ASC) Order by the promo_price column * @method ChildCartItemQuery orderByPriceEndOfLife($order = Criteria::ASC) Order by the price_end_of_life column * @method ChildCartItemQuery orderByDiscount($order = Criteria::ASC) Order by the discount column + * @method ChildCartItemQuery orderByPromo($order = Criteria::ASC) Order by the promo column * @method ChildCartItemQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildCartItemQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * @@ -42,6 +43,7 @@ use Thelia\Model\Map\CartItemTableMap; * @method ChildCartItemQuery groupByPromoPrice() Group by the promo_price column * @method ChildCartItemQuery groupByPriceEndOfLife() Group by the price_end_of_life column * @method ChildCartItemQuery groupByDiscount() Group by the discount column + * @method ChildCartItemQuery groupByPromo() Group by the promo column * @method ChildCartItemQuery groupByCreatedAt() Group by the created_at column * @method ChildCartItemQuery groupByUpdatedAt() Group by the updated_at column * @@ -73,6 +75,7 @@ use Thelia\Model\Map\CartItemTableMap; * @method ChildCartItem findOneByPromoPrice(double $promo_price) Return the first ChildCartItem filtered by the promo_price column * @method ChildCartItem findOneByPriceEndOfLife(string $price_end_of_life) Return the first ChildCartItem filtered by the price_end_of_life column * @method ChildCartItem findOneByDiscount(double $discount) Return the first ChildCartItem filtered by the discount column + * @method ChildCartItem findOneByPromo(int $promo) Return the first ChildCartItem filtered by the promo column * @method ChildCartItem findOneByCreatedAt(string $created_at) Return the first ChildCartItem filtered by the created_at column * @method ChildCartItem findOneByUpdatedAt(string $updated_at) Return the first ChildCartItem filtered by the updated_at column * @@ -85,6 +88,7 @@ use Thelia\Model\Map\CartItemTableMap; * @method array findByPromoPrice(double $promo_price) Return ChildCartItem objects filtered by the promo_price column * @method array findByPriceEndOfLife(string $price_end_of_life) Return ChildCartItem objects filtered by the price_end_of_life column * @method array findByDiscount(double $discount) Return ChildCartItem objects filtered by the discount column + * @method array findByPromo(int $promo) Return ChildCartItem objects filtered by the promo column * @method array findByCreatedAt(string $created_at) Return ChildCartItem objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildCartItem objects filtered by the updated_at column * @@ -175,7 +179,7 @@ abstract class CartItemQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, CART_ID, PRODUCT_ID, QUANTITY, PRODUCT_SALE_ELEMENTS_ID, PRICE, PROMO_PRICE, PRICE_END_OF_LIFE, DISCOUNT, CREATED_AT, UPDATED_AT FROM cart_item WHERE ID = :p0'; + $sql = 'SELECT ID, CART_ID, PRODUCT_ID, QUANTITY, PRODUCT_SALE_ELEMENTS_ID, PRICE, PROMO_PRICE, PRICE_END_OF_LIFE, DISCOUNT, PROMO, CREATED_AT, UPDATED_AT FROM cart_item WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -641,6 +645,47 @@ abstract class CartItemQuery extends ModelCriteria return $this->addUsingAlias(CartItemTableMap::DISCOUNT, $discount, $comparison); } + /** + * Filter the query on the promo column + * + * Example usage: + * + * $query->filterByPromo(1234); // WHERE promo = 1234 + * $query->filterByPromo(array(12, 34)); // WHERE promo IN (12, 34) + * $query->filterByPromo(array('min' => 12)); // WHERE promo > 12 + * + * + * @param mixed $promo 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 ChildCartItemQuery The current query, for fluid interface + */ + public function filterByPromo($promo = null, $comparison = null) + { + if (is_array($promo)) { + $useMinMax = false; + if (isset($promo['min'])) { + $this->addUsingAlias(CartItemTableMap::PROMO, $promo['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($promo['max'])) { + $this->addUsingAlias(CartItemTableMap::PROMO, $promo['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CartItemTableMap::PROMO, $promo, $comparison); + } + /** * Filter the query on the created_at column * diff --git a/core/lib/Thelia/Model/Map/CartItemTableMap.php b/core/lib/Thelia/Model/Map/CartItemTableMap.php index 7520b39c9..c48d298e0 100644 --- a/core/lib/Thelia/Model/Map/CartItemTableMap.php +++ b/core/lib/Thelia/Model/Map/CartItemTableMap.php @@ -57,7 +57,7 @@ class CartItemTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 11; + const NUM_COLUMNS = 12; /** * The number of lazy-loaded columns @@ -67,7 +67,7 @@ class CartItemTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 11; + const NUM_HYDRATE_COLUMNS = 12; /** * the column name for the ID field @@ -114,6 +114,11 @@ class CartItemTableMap extends TableMap */ const DISCOUNT = 'cart_item.DISCOUNT'; + /** + * the column name for the PROMO field + */ + const PROMO = 'cart_item.PROMO'; + /** * the column name for the CREATED_AT field */ @@ -136,12 +141,12 @@ class CartItemTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'CartId', 'ProductId', 'Quantity', 'ProductSaleElementsId', 'Price', 'PromoPrice', 'PriceEndOfLife', 'Discount', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'cartId', 'productId', 'quantity', 'productSaleElementsId', 'price', 'promoPrice', 'priceEndOfLife', 'discount', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(CartItemTableMap::ID, CartItemTableMap::CART_ID, CartItemTableMap::PRODUCT_ID, CartItemTableMap::QUANTITY, CartItemTableMap::PRODUCT_SALE_ELEMENTS_ID, CartItemTableMap::PRICE, CartItemTableMap::PROMO_PRICE, CartItemTableMap::PRICE_END_OF_LIFE, CartItemTableMap::DISCOUNT, CartItemTableMap::CREATED_AT, CartItemTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'CART_ID', 'PRODUCT_ID', 'QUANTITY', 'PRODUCT_SALE_ELEMENTS_ID', 'PRICE', 'PROMO_PRICE', 'PRICE_END_OF_LIFE', 'DISCOUNT', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'cart_id', 'product_id', 'quantity', 'product_sale_elements_id', 'price', 'promo_price', 'price_end_of_life', 'discount', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ) + self::TYPE_PHPNAME => array('Id', 'CartId', 'ProductId', 'Quantity', 'ProductSaleElementsId', 'Price', 'PromoPrice', 'PriceEndOfLife', 'Discount', 'Promo', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'cartId', 'productId', 'quantity', 'productSaleElementsId', 'price', 'promoPrice', 'priceEndOfLife', 'discount', 'promo', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(CartItemTableMap::ID, CartItemTableMap::CART_ID, CartItemTableMap::PRODUCT_ID, CartItemTableMap::QUANTITY, CartItemTableMap::PRODUCT_SALE_ELEMENTS_ID, CartItemTableMap::PRICE, CartItemTableMap::PROMO_PRICE, CartItemTableMap::PRICE_END_OF_LIFE, CartItemTableMap::DISCOUNT, CartItemTableMap::PROMO, CartItemTableMap::CREATED_AT, CartItemTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'CART_ID', 'PRODUCT_ID', 'QUANTITY', 'PRODUCT_SALE_ELEMENTS_ID', 'PRICE', 'PROMO_PRICE', 'PRICE_END_OF_LIFE', 'DISCOUNT', 'PROMO', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'cart_id', 'product_id', 'quantity', 'product_sale_elements_id', 'price', 'promo_price', 'price_end_of_life', 'discount', 'promo', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ) ); /** @@ -151,12 +156,12 @@ class CartItemTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'CartId' => 1, 'ProductId' => 2, 'Quantity' => 3, 'ProductSaleElementsId' => 4, 'Price' => 5, 'PromoPrice' => 6, 'PriceEndOfLife' => 7, 'Discount' => 8, 'CreatedAt' => 9, 'UpdatedAt' => 10, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'cartId' => 1, 'productId' => 2, 'quantity' => 3, 'productSaleElementsId' => 4, 'price' => 5, 'promoPrice' => 6, 'priceEndOfLife' => 7, 'discount' => 8, 'createdAt' => 9, 'updatedAt' => 10, ), - self::TYPE_COLNAME => array(CartItemTableMap::ID => 0, CartItemTableMap::CART_ID => 1, CartItemTableMap::PRODUCT_ID => 2, CartItemTableMap::QUANTITY => 3, CartItemTableMap::PRODUCT_SALE_ELEMENTS_ID => 4, CartItemTableMap::PRICE => 5, CartItemTableMap::PROMO_PRICE => 6, CartItemTableMap::PRICE_END_OF_LIFE => 7, CartItemTableMap::DISCOUNT => 8, CartItemTableMap::CREATED_AT => 9, CartItemTableMap::UPDATED_AT => 10, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'CART_ID' => 1, 'PRODUCT_ID' => 2, 'QUANTITY' => 3, 'PRODUCT_SALE_ELEMENTS_ID' => 4, 'PRICE' => 5, 'PROMO_PRICE' => 6, 'PRICE_END_OF_LIFE' => 7, 'DISCOUNT' => 8, 'CREATED_AT' => 9, 'UPDATED_AT' => 10, ), - self::TYPE_FIELDNAME => array('id' => 0, 'cart_id' => 1, 'product_id' => 2, 'quantity' => 3, 'product_sale_elements_id' => 4, 'price' => 5, 'promo_price' => 6, 'price_end_of_life' => 7, 'discount' => 8, 'created_at' => 9, 'updated_at' => 10, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ) + self::TYPE_PHPNAME => array('Id' => 0, 'CartId' => 1, 'ProductId' => 2, 'Quantity' => 3, 'ProductSaleElementsId' => 4, 'Price' => 5, 'PromoPrice' => 6, 'PriceEndOfLife' => 7, 'Discount' => 8, 'Promo' => 9, 'CreatedAt' => 10, 'UpdatedAt' => 11, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'cartId' => 1, 'productId' => 2, 'quantity' => 3, 'productSaleElementsId' => 4, 'price' => 5, 'promoPrice' => 6, 'priceEndOfLife' => 7, 'discount' => 8, 'promo' => 9, 'createdAt' => 10, 'updatedAt' => 11, ), + self::TYPE_COLNAME => array(CartItemTableMap::ID => 0, CartItemTableMap::CART_ID => 1, CartItemTableMap::PRODUCT_ID => 2, CartItemTableMap::QUANTITY => 3, CartItemTableMap::PRODUCT_SALE_ELEMENTS_ID => 4, CartItemTableMap::PRICE => 5, CartItemTableMap::PROMO_PRICE => 6, CartItemTableMap::PRICE_END_OF_LIFE => 7, CartItemTableMap::DISCOUNT => 8, CartItemTableMap::PROMO => 9, CartItemTableMap::CREATED_AT => 10, CartItemTableMap::UPDATED_AT => 11, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'CART_ID' => 1, 'PRODUCT_ID' => 2, 'QUANTITY' => 3, 'PRODUCT_SALE_ELEMENTS_ID' => 4, 'PRICE' => 5, 'PROMO_PRICE' => 6, 'PRICE_END_OF_LIFE' => 7, 'DISCOUNT' => 8, 'PROMO' => 9, 'CREATED_AT' => 10, 'UPDATED_AT' => 11, ), + self::TYPE_FIELDNAME => array('id' => 0, 'cart_id' => 1, 'product_id' => 2, 'quantity' => 3, 'product_sale_elements_id' => 4, 'price' => 5, 'promo_price' => 6, 'price_end_of_life' => 7, 'discount' => 8, 'promo' => 9, 'created_at' => 10, 'updated_at' => 11, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ) ); /** @@ -184,6 +189,7 @@ class CartItemTableMap extends TableMap $this->addColumn('PROMO_PRICE', 'PromoPrice', 'FLOAT', false, null, null); $this->addColumn('PRICE_END_OF_LIFE', 'PriceEndOfLife', 'TIMESTAMP', false, null, null); $this->addColumn('DISCOUNT', 'Discount', 'FLOAT', false, null, 0); + $this->addColumn('PROMO', 'Promo', 'INTEGER', false, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -358,6 +364,7 @@ class CartItemTableMap extends TableMap $criteria->addSelectColumn(CartItemTableMap::PROMO_PRICE); $criteria->addSelectColumn(CartItemTableMap::PRICE_END_OF_LIFE); $criteria->addSelectColumn(CartItemTableMap::DISCOUNT); + $criteria->addSelectColumn(CartItemTableMap::PROMO); $criteria->addSelectColumn(CartItemTableMap::CREATED_AT); $criteria->addSelectColumn(CartItemTableMap::UPDATED_AT); } else { @@ -370,6 +377,7 @@ class CartItemTableMap extends TableMap $criteria->addSelectColumn($alias . '.PROMO_PRICE'); $criteria->addSelectColumn($alias . '.PRICE_END_OF_LIFE'); $criteria->addSelectColumn($alias . '.DISCOUNT'); + $criteria->addSelectColumn($alias . '.PROMO'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } diff --git a/install/thelia.sql b/install/thelia.sql index 5aa478da5..7e1818ef6 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -45,7 +45,7 @@ CREATE TABLE `product` PRIMARY KEY (`id`), UNIQUE INDEX `ref_UNIQUE` (`ref`), INDEX `idx_product_tax_rule_id` (`tax_rule_id`), - INDEX `fk_product_template1_idx` (`template_id`), + INDEX `fk_product_template_id` (`template_id`), CONSTRAINT `fk_product_tax_rule_id` FOREIGN KEY (`tax_rule_id`) REFERENCES `tax_rule` (`id`) @@ -1198,6 +1198,7 @@ CREATE TABLE `cart_item` `promo_price` FLOAT, `price_end_of_life` DATETIME, `discount` FLOAT DEFAULT 0, + `promo` INTEGER, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`), diff --git a/local/config/schema.xml b/local/config/schema.xml index 1ffeb028a..77dcf7c37 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -1,1162 +1,1163 @@ - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - -
    - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - -
    - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - -
    - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - -
    -
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + + +
    +
    From 2cf1c62b068634c1bab525ae261f56e5f8ef2593 Mon Sep 17 00:00:00 2001 From: franck Date: Mon, 16 Sep 2013 10:40:52 +0200 Subject: [PATCH 20/20] Finished Features management --- core/lib/Thelia/Action/Attribute.php | 25 +- core/lib/Thelia/Action/Feature.php | 186 ++++++++++ core/lib/Thelia/Action/FeatureAv.php | 143 ++++++++ core/lib/Thelia/Config/Resources/action.xml | 10 + core/lib/Thelia/Config/Resources/config.xml | 5 + .../Thelia/Config/Resources/routing/admin.xml | 57 +++ .../Controller/Admin/FeatureAvController.php | 196 +++++++++++ .../Controller/Admin/FeatureController.php | 289 ++++++++++++++++ .../Core/Event/FeatureAvCreateEvent.php | 68 ++++ .../Core/Event/FeatureAvDeleteEvent.php | 46 +++ core/lib/Thelia/Core/Event/FeatureAvEvent.php | 52 +++ .../Core/Event/FeatureAvUpdateEvent.php | 86 +++++ .../Thelia/Core/Event/FeatureCreateEvent.php | 68 ++++ .../Thelia/Core/Event/FeatureDeleteEvent.php | 46 +++ core/lib/Thelia/Core/Event/FeatureEvent.php | 52 +++ .../Thelia/Core/Event/FeatureUpdateEvent.php | 86 +++++ core/lib/Thelia/Core/Event/TheliaEvents.php | 37 ++ .../lib/Thelia/Form/FeatureAvCreationForm.php | 62 ++++ core/lib/Thelia/Form/FeatureCreationForm.php | 66 ++++ .../Thelia/Form/FeatureModificationForm.php | 62 ++++ core/lib/Thelia/Model/Feature.php | 63 ++++ core/lib/Thelia/Model/FeatureAv.php | 71 ++++ templates/admin/default/feature-edit.html | 316 +++++++++++++++++ templates/admin/default/features.html | 326 ++++++++++++++++++ 24 files changed, 2411 insertions(+), 7 deletions(-) create mode 100644 core/lib/Thelia/Action/Feature.php create mode 100644 core/lib/Thelia/Action/FeatureAv.php create mode 100644 core/lib/Thelia/Controller/Admin/FeatureAvController.php create mode 100644 core/lib/Thelia/Controller/Admin/FeatureController.php create mode 100644 core/lib/Thelia/Core/Event/FeatureAvCreateEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureAvDeleteEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureAvEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureAvUpdateEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureCreateEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureDeleteEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureEvent.php create mode 100644 core/lib/Thelia/Core/Event/FeatureUpdateEvent.php create mode 100644 core/lib/Thelia/Form/FeatureAvCreationForm.php create mode 100644 core/lib/Thelia/Form/FeatureCreationForm.php create mode 100644 core/lib/Thelia/Form/FeatureModificationForm.php create mode 100644 templates/admin/default/feature-edit.html create mode 100644 templates/admin/default/features.html diff --git a/core/lib/Thelia/Action/Attribute.php b/core/lib/Thelia/Action/Attribute.php index a2e956d8e..44c5968a4 100644 --- a/core/lib/Thelia/Action/Attribute.php +++ b/core/lib/Thelia/Action/Attribute.php @@ -41,6 +41,7 @@ use Thelia\Core\Event\CategoryEvent; use Thelia\Core\Event\AttributeEvent; use Thelia\Model\AttributeTemplate; use Thelia\Model\AttributeTemplateQuery; +use Thelia\Model\TemplateQuery; class Attribute extends BaseAction implements EventSubscriberInterface { @@ -137,23 +138,33 @@ class Attribute extends BaseAction implements EventSubscriberInterface } } - public function addToAllTemplates(AttributeEvent $event) + protected function doAddToAllTemplates(AttributeModel $attribute) { - $templates = AttributeTemplateQuery::create()->find(); + $templates = TemplateQuery::create()->find(); foreach($templates as $template) { - $pat = new AttributeTemplate(); - $pat->setTemplate($template->getId()) - ->setAttributeId($event->getAttribute()->getId()) - ->save(); + $attribute_template = new AttributeTemplate(); + + if (null === AttributeTemplateQuery::create()->filterByAttribute($attribute)->filterByTemplate($template)->findOne()) { + $attribute_template + ->setAttribute($attribute) + ->setTemplate($template) + ->save() + ; + } } } + public function addToAllTemplates(AttributeEvent $event) + { + $this->doAddToAllTemplates($event->getAttribute()); + } + public function removeFromAllTemplates(AttributeEvent $event) { // Delete this attribute from all product templates - AttributeTemplateQuery::create()->filterByAttributeId($event->getAttribute()->getId())->delete(); + AttributeTemplateQuery::create()->filterByAttribute($event->getAttribute())->delete(); } /** diff --git a/core/lib/Thelia/Action/Feature.php b/core/lib/Thelia/Action/Feature.php new file mode 100644 index 000000000..a746ce4e2 --- /dev/null +++ b/core/lib/Thelia/Action/Feature.php @@ -0,0 +1,186 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Action; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +use Thelia\Model\FeatureQuery; +use Thelia\Model\Feature as FeatureModel; + +use Thelia\Core\Event\TheliaEvents; + +use Thelia\Core\Event\FeatureUpdateEvent; +use Thelia\Core\Event\FeatureCreateEvent; +use Thelia\Core\Event\FeatureDeleteEvent; +use Thelia\Model\ConfigQuery; +use Thelia\Model\FeatureAv; +use Thelia\Model\FeatureAvQuery; +use Thelia\Core\Event\UpdatePositionEvent; +use Thelia\Core\Event\CategoryEvent; +use Thelia\Core\Event\FeatureEvent; +use Thelia\Model\FeatureTemplate; +use Thelia\Model\FeatureTemplateQuery; +use Thelia\Model\TemplateQuery; + +class Feature extends BaseAction implements EventSubscriberInterface +{ + /** + * Create a new feature entry + * + * @param FeatureCreateEvent $event + */ + public function create(FeatureCreateEvent $event) + { + $feature = new FeatureModel(); + + $feature + ->setDispatcher($this->getDispatcher()) + + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + + ->save() + ; + + $event->setFeature($feature); + + // Add atribute to all product templates if required + if ($event->getAddToAllTemplates() != 0) { + // TODO: add to all product template + } + } + + /** + * Change a product feature + * + * @param FeatureUpdateEvent $event + */ + public function update(FeatureUpdateEvent $event) + { + $search = FeatureQuery::create(); + + if (null !== $feature = FeatureQuery::create()->findPk($event->getFeatureId())) { + + $feature + ->setDispatcher($this->getDispatcher()) + + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + ->setDescription($event->getDescription()) + ->setChapo($event->getChapo()) + ->setPostscriptum($event->getPostscriptum()) + + ->save(); + + $event->setFeature($feature); + } + } + + /** + * Delete a product feature entry + * + * @param FeatureDeleteEvent $event + */ + public function delete(FeatureDeleteEvent $event) + { + + if (null !== ($feature = FeatureQuery::create()->findPk($event->getFeatureId()))) { + + $feature + ->setDispatcher($this->getDispatcher()) + ->delete() + ; + + $event->setFeature($feature); + } + } + + /** + * Changes position, selecting absolute ou relative change. + * + * @param CategoryChangePositionEvent $event + */ + public function updatePosition(UpdatePositionEvent $event) + { + if (null !== $feature = FeatureQuery::create()->findPk($event->getObjectId())) { + + $feature->setDispatcher($this->getDispatcher()); + + $mode = $event->getMode(); + + if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE) + return $feature->changeAbsolutePosition($event->getPosition()); + else if ($mode == UpdatePositionEvent::POSITION_UP) + return $feature->movePositionUp(); + else if ($mode == UpdatePositionEvent::POSITION_DOWN) + return $feature->movePositionDown(); + } + } + + protected function doAddToAllTemplates(FeatureModel $feature) + { + $templates = TemplateQuery::create()->find(); + + foreach($templates as $template) { + + $feature_template = new FeatureTemplate(); + + if (null === FeatureTemplateQuery::create()->filterByFeature($feature)->filterByTemplate($template)->findOne()) { + $feature_template + ->setFeature($feature) + ->setTemplate($template) + ->save() + ; + } + } + } + + public function addToAllTemplates(FeatureEvent $event) + { + $this->doAddToAllTemplates($event->getFeature()); + } + + public function removeFromAllTemplates(FeatureEvent $event) + { + // Delete this feature from all product templates + FeatureTemplateQuery::create()->filterByFeature($event->getFeature())->delete(); + } + + /** + * {@inheritDoc} + */ + public static function getSubscribedEvents() + { + return array( + TheliaEvents::FEATURE_CREATE => array("create", 128), + TheliaEvents::FEATURE_UPDATE => array("update", 128), + TheliaEvents::FEATURE_DELETE => array("delete", 128), + TheliaEvents::FEATURE_UPDATE_POSITION => array("updatePosition", 128), + + TheliaEvents::FEATURE_REMOVE_FROM_ALL_TEMPLATES => array("removeFromAllTemplates", 128), + TheliaEvents::FEATURE_ADD_TO_ALL_TEMPLATES => array("addToAllTemplates", 128), + + ); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Action/FeatureAv.php b/core/lib/Thelia/Action/FeatureAv.php new file mode 100644 index 000000000..2bd117b4b --- /dev/null +++ b/core/lib/Thelia/Action/FeatureAv.php @@ -0,0 +1,143 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Action; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +use Thelia\Model\FeatureAvQuery; +use Thelia\Model\FeatureAv as FeatureAvModel; + +use Thelia\Core\Event\TheliaEvents; + +use Thelia\Core\Event\FeatureAvUpdateEvent; +use Thelia\Core\Event\FeatureAvCreateEvent; +use Thelia\Core\Event\FeatureAvDeleteEvent; +use Thelia\Model\ConfigQuery; +use Thelia\Core\Event\UpdatePositionEvent; + +class FeatureAv extends BaseAction implements EventSubscriberInterface +{ + /** + * Create a new feature entry + * + * @param FeatureAvCreateEvent $event + */ + public function create(FeatureAvCreateEvent $event) + { + $feature = new FeatureAvModel(); + + $feature + ->setDispatcher($this->getDispatcher()) + + ->setFeatureId($event->getFeatureId()) + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + + ->save() + ; + + $event->setFeatureAv($feature); + } + + /** + * Change a product feature + * + * @param FeatureAvUpdateEvent $event + */ + public function update(FeatureAvUpdateEvent $event) + { + $search = FeatureAvQuery::create(); + + if (null !== $feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId())) { + + $feature + ->setDispatcher($this->getDispatcher()) + + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + ->setDescription($event->getDescription()) + ->setChapo($event->getChapo()) + ->setPostscriptum($event->getPostscriptum()) + + ->save(); + + $event->setFeatureAv($feature); + } + } + + /** + * Delete a product feature entry + * + * @param FeatureAvDeleteEvent $event + */ + public function delete(FeatureAvDeleteEvent $event) + { + + if (null !== ($feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId()))) { + + $feature + ->setDispatcher($this->getDispatcher()) + ->delete() + ; + + $event->setFeatureAv($feature); + } + } + + /** + * Changes position, selecting absolute ou relative change. + * + * @param CategoryChangePositionEvent $event + */ + public function updatePosition(UpdatePositionEvent $event) + { + if (null !== $feature = FeatureAvQuery::create()->findPk($event->getObjectId())) { + + $feature->setDispatcher($this->getDispatcher()); + + $mode = $event->getMode(); + + if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE) + return $feature->changeAbsolutePosition($event->getPosition()); + else if ($mode == UpdatePositionEvent::POSITION_UP) + return $feature->movePositionUp(); + else if ($mode == UpdatePositionEvent::POSITION_DOWN) + return $feature->movePositionDown(); + } + } + + + /** + * {@inheritDoc} + */ + public static function getSubscribedEvents() + { + return array( + TheliaEvents::FEATURE_AV_CREATE => array("create", 128), + TheliaEvents::FEATURE_AV_UPDATE => array("update", 128), + TheliaEvents::FEATURE_AV_DELETE => array("delete", 128), + TheliaEvents::FEATURE_AV_UPDATE_POSITION => array("updatePosition", 128), + ); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Config/Resources/action.xml b/core/lib/Thelia/Config/Resources/action.xml index f2fa776c3..a586667d1 100755 --- a/core/lib/Thelia/Config/Resources/action.xml +++ b/core/lib/Thelia/Config/Resources/action.xml @@ -67,11 +67,21 @@ + + + + + + + + + + diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 9735aca36..d8211c6cc 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -72,8 +72,13 @@
    + + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 8812d8ad4..14ab8d4de 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -292,6 +292,63 @@ + + + + Thelia\Controller\Admin\FeatureController::defaultAction + + + + Thelia\Controller\Admin\FeatureController::createAction + + + + Thelia\Controller\Admin\FeatureController::updateAction + + + + Thelia\Controller\Admin\FeatureController::processUpdateAction + + + + Thelia\Controller\Admin\FeatureController::deleteAction + + + + Thelia\Controller\Admin\FeatureController::updatePositionAction + + + + Thelia\Controller\Admin\FeatureController::removeFromAllTemplates + + + + Thelia\Controller\Admin\FeatureController::addToAllTemplates + + + + + Thelia\Controller\Admin\FeatureAvController::createAction + + + + Thelia\Controller\Admin\FeatureAvController::updateAction + + + + Thelia\Controller\Admin\FeatureAvController::processUpdateAction + + + + Thelia\Controller\Admin\FeatureAvController::deleteAction + + + + Thelia\Controller\Admin\FeatureAvController::updatePositionAction + + + + diff --git a/core/lib/Thelia/Controller/Admin/FeatureAvController.php b/core/lib/Thelia/Controller/Admin/FeatureAvController.php new file mode 100644 index 000000000..25c7a5495 --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/FeatureAvController.php @@ -0,0 +1,196 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +use Thelia\Core\Event\FeatureAvDeleteEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\FeatureAvUpdateEvent; +use Thelia\Core\Event\FeatureAvCreateEvent; +use Thelia\Model\FeatureAvQuery; +use Thelia\Form\FeatureAvModificationForm; +use Thelia\Form\FeatureAvCreationForm; +use Thelia\Core\Event\UpdatePositionEvent; + +/** + * Manages features-av sent by mail + * + * @author Franck Allimant + */ +class FeatureAvController extends AbstractCrudController +{ + public function __construct() + { + parent::__construct( + 'featureav', + 'manual', + 'order', + + 'admin.configuration.features-av.view', + 'admin.configuration.features-av.create', + 'admin.configuration.features-av.update', + 'admin.configuration.features-av.delete', + + TheliaEvents::FEATURE_AV_CREATE, + TheliaEvents::FEATURE_AV_UPDATE, + TheliaEvents::FEATURE_AV_DELETE, + null, // No visibility toggle + TheliaEvents::FEATURE_AV_UPDATE_POSITION + ); + } + + protected function getCreationForm() + { + return new FeatureAvCreationForm($this->getRequest()); + } + + protected function getUpdateForm() + { + return new FeatureAvModificationForm($this->getRequest()); + } + + protected function getCreationEvent($formData) + { + $createEvent = new FeatureAvCreateEvent(); + + $createEvent + ->setFeatureId($formData['feature_id']) + ->setTitle($formData['title']) + ->setLocale($formData["locale"]) + ; + + return $createEvent; + } + + protected function getUpdateEvent($formData) + { + $changeEvent = new FeatureAvUpdateEvent($formData['id']); + + // Create and dispatch the change event + $changeEvent + ->setLocale($formData["locale"]) + ->setTitle($formData['title']) + ->setChapo($formData['chapo']) + ->setDescription($formData['description']) + ->setPostscriptum($formData['postscriptum']) + ; + + return $changeEvent; + } + + protected function createUpdatePositionEvent($positionChangeMode, $positionValue) + { + return new UpdatePositionEvent( + $this->getRequest()->get('featureav_id', null), + $positionChangeMode, + $positionValue + ); + } + + protected function getDeleteEvent() + { + return new FeatureAvDeleteEvent($this->getRequest()->get('featureav_id')); + } + + protected function eventContainsObject($event) + { + return $event->hasFeatureAv(); + } + + protected function hydrateObjectForm($object) + { + $data = array( + 'id' => $object->getId(), + 'locale' => $object->getLocale(), + 'title' => $object->getTitle(), + 'chapo' => $object->getChapo(), + 'description' => $object->getDescription(), + 'postscriptum' => $object->getPostscriptum() + ); + + // Setup the object form + return new FeatureAvModificationForm($this->getRequest(), "form", $data); + } + + protected function getObjectFromEvent($event) + { + return $event->hasFeatureAv() ? $event->getFeatureAv() : null; + } + + protected function getExistingObject() + { + return FeatureAvQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->findOneById($this->getRequest()->get('featureav_id')); + } + + protected function getObjectLabel($object) + { + return $object->getTitle(); + } + + protected function getObjectId($object) + { + return $object->getId(); + } + + protected function getViewArguments() + { + return array( + 'feature_id' => $this->getRequest()->get('feature_id'), + 'order' => $this->getCurrentListOrder() + ); + } + + protected function renderListTemplate($currentOrder) + { + // We always return to the feature edition form + return $this->render( + 'feature-edit', + $this->getViewArguments() + ); + } + + protected function renderEditionTemplate() + { + // We always return to the feature edition form + return $this->render('feature-edit', $this->getViewArguments()); + } + + protected function redirectToEditionTemplate() + { + // We always return to the feature edition form + $this->redirectToRoute( + "admin.configuration.features.update", + $this->getViewArguments() + ); + } + + protected function redirectToListTemplate() + { + $this->redirectToRoute( + "admin.configuration.features.update", + $this->getViewArguments() + ); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/FeatureController.php b/core/lib/Thelia/Controller/Admin/FeatureController.php new file mode 100644 index 000000000..92cb89d33 --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/FeatureController.php @@ -0,0 +1,289 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +use Thelia\Core\Event\FeatureDeleteEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\FeatureUpdateEvent; +use Thelia\Core\Event\FeatureCreateEvent; +use Thelia\Model\FeatureQuery; +use Thelia\Form\FeatureModificationForm; +use Thelia\Form\FeatureCreationForm; +use Thelia\Core\Event\UpdatePositionEvent; +use Thelia\Model\FeatureAv; +use Thelia\Model\FeatureAvQuery; +use Thelia\Core\Event\FeatureAvUpdateEvent; +use Thelia\Core\Event\FeatureEvent; + +/** + * Manages features sent by mail + * + * @author Franck Allimant + */ +class FeatureController extends AbstractCrudController +{ + public function __construct() + { + parent::__construct( + 'feature', + 'manual', + 'order', + + 'admin.configuration.features.view', + 'admin.configuration.features.create', + 'admin.configuration.features.update', + 'admin.configuration.features.delete', + + TheliaEvents::FEATURE_CREATE, + TheliaEvents::FEATURE_UPDATE, + TheliaEvents::FEATURE_DELETE, + null, // No visibility toggle + TheliaEvents::FEATURE_UPDATE_POSITION + ); + } + + protected function getCreationForm() + { + return new FeatureCreationForm($this->getRequest()); + } + + protected function getUpdateForm() + { + return new FeatureModificationForm($this->getRequest()); + } + + protected function getCreationEvent($formData) + { + $createEvent = new FeatureCreateEvent(); + + $createEvent + ->setTitle($formData['title']) + ->setLocale($formData["locale"]) + ->setAddToAllTemplates($formData['add_to_all']) + ; + + return $createEvent; + } + + protected function getUpdateEvent($formData) + { + $changeEvent = new FeatureUpdateEvent($formData['id']); + + // Create and dispatch the change event + $changeEvent + ->setLocale($formData["locale"]) + ->setTitle($formData['title']) + ->setChapo($formData['chapo']) + ->setDescription($formData['description']) + ->setPostscriptum($formData['postscriptum']) + ; + + return $changeEvent; + } + + /** + * Process the features values (fix it in future version to integrate it in the feature form as a collection) + * + * @see \Thelia\Controller\Admin\AbstractCrudController::performAdditionalUpdateAction() + */ + protected function performAdditionalUpdateAction($updateEvent) + { + $attr_values = $this->getRequest()->get('feature_values', null); + + if ($attr_values !== null) { + + foreach($attr_values as $id => $value) { + + $event = new FeatureAvUpdateEvent($id); + + $event->setTitle($value); + $event->setLocale($this->getCurrentEditionLocale()); + + $this->dispatch(TheliaEvents::FEATURE_AV_UPDATE, $event); + } + } + + return null; + } + + protected function createUpdatePositionEvent($positionChangeMode, $positionValue) + { + return new UpdatePositionEvent( + $this->getRequest()->get('feature_id', null), + $positionChangeMode, + $positionValue + ); + } + + protected function getDeleteEvent() + { + return new FeatureDeleteEvent($this->getRequest()->get('feature_id')); + } + + protected function eventContainsObject($event) + { + return $event->hasFeature(); + } + + protected function hydrateObjectForm($object) + { + + $data = array( + 'id' => $object->getId(), + 'locale' => $object->getLocale(), + 'title' => $object->getTitle(), + 'chapo' => $object->getChapo(), + 'description' => $object->getDescription(), + 'postscriptum' => $object->getPostscriptum() + ); + + // Setup features values + /* + * FIXME : doesn't work. "We get a This form should not contain extra fields." error + $attr_av_list = FeatureAvQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->filterByFeatureId($object->getId()) + ->find(); + + $attr_array = array(); + + foreach($attr_av_list as $attr_av) { + $attr_array[$attr_av->getId()] = $attr_av->getTitle(); + } + + $data['feature_values'] = $attr_array; + */ + + // Setup the object form + return new FeatureModificationForm($this->getRequest(), "form", $data); + } + + protected function getObjectFromEvent($event) + { + return $event->hasFeature() ? $event->getFeature() : null; + } + + protected function getExistingObject() + { + return FeatureQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->findOneById($this->getRequest()->get('feature_id')); + } + + protected function getObjectLabel($object) + { + return $object->getTitle(); + } + + protected function getObjectId($object) + { + return $object->getId(); + } + + protected function renderListTemplate($currentOrder) + { + return $this->render('features', array('order' => $currentOrder)); + } + + protected function renderEditionTemplate() + { + return $this->render( + 'feature-edit', + array( + 'feature_id' => $this->getRequest()->get('feature_id'), + 'featureav_order' => $this->getFeatureAvListOrder() + ) + ); + } + + protected function redirectToEditionTemplate() + { + $this->redirectToRoute( + "admin.configuration.features.update", + array( + 'feature_id' => $this->getRequest()->get('feature_id'), + 'featureav_order' => $this->getFeatureAvListOrder() + ) + ); + } + + protected function redirectToListTemplate() + { + $this->redirectToRoute('admin.configuration.features.default'); + } + + /** + * Get the Feature value list order. + * + * @return string the current list order + */ + protected function getFeatureAvListOrder() + { + return $this->getListOrderFromSession( + 'featureav', + 'featureav_order', + 'manual' + ); + } + + /** + * Add or Remove from all product templates + */ + protected function addRemoveFromAllTemplates($eventType) + { + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.features.update")) return $response; + + try { + if (null !== $object = $this->getExistingObject()) { + + $event = new FeatureEvent($object); + + $this->dispatch($eventType, $event); + } + } + catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + + $this->redirectToListTemplate(); + } + + /** + * Remove from all product templates + */ + public function removeFromAllTemplates() + { + return $this->addRemoveFromAllTemplates(TheliaEvents::FEATURE_REMOVE_FROM_ALL_TEMPLATES); + } + + /** + * Add to all product templates + */ + public function addToAllTemplates() + { + return $this->addRemoveFromAllTemplates(TheliaEvents::FEATURE_ADD_TO_ALL_TEMPLATES); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/FeatureAvCreateEvent.php b/core/lib/Thelia/Core/Event/FeatureAvCreateEvent.php new file mode 100644 index 000000000..2c8fb228e --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureAvCreateEvent.php @@ -0,0 +1,68 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureAvCreateEvent extends FeatureAvEvent +{ + protected $title; + protected $locale; + protected $feature_id; + + public function getLocale() + { + return $this->locale; + } + + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + public function getTitle() + { + return $this->title; + } + + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + public function getFeatureId() + { + return $this->feature_id; + } + + public function setFeatureId($feature_id) + { + $this->feature_id = $feature_id; + + return $this; + } + +} diff --git a/core/lib/Thelia/Core/Event/FeatureAvDeleteEvent.php b/core/lib/Thelia/Core/Event/FeatureAvDeleteEvent.php new file mode 100644 index 000000000..aa0a3c729 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureAvDeleteEvent.php @@ -0,0 +1,46 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureAvDeleteEvent extends FeatureAvEvent +{ + protected $featureAv_id; + + public function __construct($featureAv_id) + { + $this->setFeatureAvId($featureAv_id); + } + + public function getFeatureAvId() + { + return $this->featureAv_id; + } + + public function setFeatureAvId($featureAv_id) + { + $this->featureAv_id = $featureAv_id; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/FeatureAvEvent.php b/core/lib/Thelia/Core/Event/FeatureAvEvent.php new file mode 100644 index 000000000..225acaf11 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureAvEvent.php @@ -0,0 +1,52 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; +use Thelia\Model\FeatureAv; + +class FeatureAvEvent extends ActionEvent +{ + protected $featureAv = null; + + public function __construct(FeatureAv $featureAv = null) + { + $this->featureAv = $featureAv; + } + + public function hasFeatureAv() + { + return ! is_null($this->featureAv); + } + + public function getFeatureAv() + { + return $this->featureAv; + } + + public function setFeatureAv($featureAv) + { + $this->featureAv = $featureAv; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/FeatureAvUpdateEvent.php b/core/lib/Thelia/Core/Event/FeatureAvUpdateEvent.php new file mode 100644 index 000000000..5db9604c2 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureAvUpdateEvent.php @@ -0,0 +1,86 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureAvUpdateEvent extends FeatureAvCreateEvent +{ + protected $featureAv_id; + + protected $description; + protected $chapo; + protected $postscriptum; + + public function __construct($featureAv_id) + { + $this->setFeatureAvId($featureAv_id); + } + + public function getFeatureAvId() + { + return $this->featureAv_id; + } + + public function setFeatureAvId($featureAv_id) + { + $this->featureAv_id = $featureAv_id; + + return $this; + } + + public function getDescription() + { + return $this->description; + } + + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + public function getChapo() + { + return $this->chapo; + } + + public function setChapo($chapo) + { + $this->chapo = $chapo; + + return $this; + } + + public function getPostscriptum() + { + return $this->postscriptum; + } + + public function setPostscriptum($postscriptum) + { + $this->postscriptum = $postscriptum; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/FeatureCreateEvent.php b/core/lib/Thelia/Core/Event/FeatureCreateEvent.php new file mode 100644 index 000000000..574433084 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureCreateEvent.php @@ -0,0 +1,68 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureCreateEvent extends FeatureEvent +{ + protected $title; + protected $locale; + protected $add_to_all_templates; + + public function getLocale() + { + return $this->locale; + } + + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + public function getTitle() + { + return $this->title; + } + + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + public function getAddToAllTemplates() + { + return $this->add_to_all_templates; + } + + public function setAddToAllTemplates($add_to_all_templates) + { + $this->add_to_all_templates = $add_to_all_templates; + + return $this; + } + +} diff --git a/core/lib/Thelia/Core/Event/FeatureDeleteEvent.php b/core/lib/Thelia/Core/Event/FeatureDeleteEvent.php new file mode 100644 index 000000000..1eca57982 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureDeleteEvent.php @@ -0,0 +1,46 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureDeleteEvent extends FeatureEvent +{ + protected $feature_id; + + public function __construct($feature_id) + { + $this->setFeatureId($feature_id); + } + + public function getFeatureId() + { + return $this->feature_id; + } + + public function setFeatureId($feature_id) + { + $this->feature_id = $feature_id; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/FeatureEvent.php b/core/lib/Thelia/Core/Event/FeatureEvent.php new file mode 100644 index 000000000..f1510ac63 --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureEvent.php @@ -0,0 +1,52 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; +use Thelia\Model\Feature; + +class FeatureEvent extends ActionEvent +{ + protected $feature = null; + + public function __construct(Feature $feature = null) + { + $this->feature = $feature; + } + + public function hasFeature() + { + return ! is_null($this->feature); + } + + public function getFeature() + { + return $this->feature; + } + + public function setFeature($feature) + { + $this->feature = $feature; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/FeatureUpdateEvent.php b/core/lib/Thelia/Core/Event/FeatureUpdateEvent.php new file mode 100644 index 000000000..6bee33ebb --- /dev/null +++ b/core/lib/Thelia/Core/Event/FeatureUpdateEvent.php @@ -0,0 +1,86 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class FeatureUpdateEvent extends FeatureCreateEvent +{ + protected $feature_id; + + protected $description; + protected $chapo; + protected $postscriptum; + + public function __construct($feature_id) + { + $this->setFeatureId($feature_id); + } + + public function getFeatureId() + { + return $this->feature_id; + } + + public function setFeatureId($feature_id) + { + $this->feature_id = $feature_id; + + return $this; + } + + public function getDescription() + { + return $this->description; + } + + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + public function getChapo() + { + return $this->chapo; + } + + public function setChapo($chapo) + { + $this->chapo = $chapo; + + return $this; + } + + public function getPostscriptum() + { + return $this->postscriptum; + } + + public function setPostscriptum($postscriptum) + { + $this->postscriptum = $postscriptum; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index d02c6d4d1..6708449b5 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -371,6 +371,25 @@ final class TheliaEvents const BEFORE_DELETEATTRIBUTE = "action.before_deleteAttribute"; const AFTER_DELETEATTRIBUTE = "action.after_deleteAttribute"; + // -- Features management --------------------------------------------- + + const FEATURE_CREATE = "action.createFeature"; + const FEATURE_UPDATE = "action.updateFeature"; + const FEATURE_DELETE = "action.deleteFeature"; + const FEATURE_UPDATE_POSITION = "action.updateFeaturePosition"; + + const FEATURE_REMOVE_FROM_ALL_TEMPLATES = "action.addFeatureToAllTemplate"; + const FEATURE_ADD_TO_ALL_TEMPLATES = "action.removeFeatureFromAllTemplate"; + + const BEFORE_CREATEFEATURE = "action.before_createFeature"; + const AFTER_CREATEFEATURE = "action.after_createFeature"; + + const BEFORE_UPDATEFEATURE = "action.before_updateFeature"; + const AFTER_UPDATEFEATURE = "action.after_updateFeature"; + + const BEFORE_DELETEFEATURE = "action.before_deleteFeature"; + const AFTER_DELETEFEATURE = "action.after_deleteFeature"; + // -- Attributes values management ---------------------------------------- const ATTRIBUTE_AV_CREATE = "action.createAttributeAv"; @@ -386,4 +405,22 @@ final class TheliaEvents const BEFORE_DELETEATTRIBUTE_AV = "action.before_deleteAttributeAv"; const AFTER_DELETEATTRIBUTE_AV = "action.after_deleteAttributeAv"; + + + // -- Features values management ---------------------------------------- + + const FEATURE_AV_CREATE = "action.createFeatureAv"; + const FEATURE_AV_UPDATE = "action.updateFeatureAv"; + const FEATURE_AV_DELETE = "action.deleteFeatureAv"; + const FEATURE_AV_UPDATE_POSITION = "action.updateFeatureAvPosition"; + + const BEFORE_CREATEFEATURE_AV = "action.before_createFeatureAv"; + const AFTER_CREATEFEATURE_AV = "action.after_createFeatureAv"; + + const BEFORE_UPDATEFEATURE_AV = "action.before_updateFeatureAv"; + const AFTER_UPDATEFEATURE_AV = "action.after_updateFeatureAv"; + + const BEFORE_DELETEFEATURE_AV = "action.before_deleteFeatureAv"; + const AFTER_DELETEFEATURE_AV = "action.after_deleteFeatureAv"; + } diff --git a/core/lib/Thelia/Form/FeatureAvCreationForm.php b/core/lib/Thelia/Form/FeatureAvCreationForm.php new file mode 100644 index 000000000..504cc9338 --- /dev/null +++ b/core/lib/Thelia/Form/FeatureAvCreationForm.php @@ -0,0 +1,62 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Thelia\Model\CurrencyQuery; +use Symfony\Component\Validator\ExecutionContextInterface; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class FeatureAvCreationForm extends BaseForm +{ + protected function buildForm() + { + $this->formBuilder + ->add("title" , "text" , array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Title *"), + "label_attr" => array( + "for" => "title" + )) + ) + ->add("locale" , "text" , array( + "constraints" => array( + new NotBlank() + )) + ) + ->add("feature_id", "hidden", array( + "constraints" => array( + new NotBlank() + )) + ) + ; + } + + public function getName() + { + return "thelia_featureav_creation"; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Form/FeatureCreationForm.php b/core/lib/Thelia/Form/FeatureCreationForm.php new file mode 100644 index 000000000..1977bd78b --- /dev/null +++ b/core/lib/Thelia/Form/FeatureCreationForm.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Thelia\Model\CurrencyQuery; +use Symfony\Component\Validator\ExecutionContextInterface; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class FeatureCreationForm extends BaseForm +{ + protected function buildForm() + { + $this->formBuilder + ->add("title" , "text" , array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Title *"), + "label_attr" => array( + "for" => "title" + )) + ) + ->add("locale" , "text" , array( + "constraints" => array( + new NotBlank() + )) + ) + ->add("add_to_all" , "checkbox" , array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Add to all product templates"), + "label_attr" => array( + "for" => "add_to_all" + )) + ) + ; + } + + public function getName() + { + return "thelia_feature_creation"; + } +} diff --git a/core/lib/Thelia/Form/FeatureModificationForm.php b/core/lib/Thelia/Form/FeatureModificationForm.php new file mode 100644 index 000000000..1702f299e --- /dev/null +++ b/core/lib/Thelia/Form/FeatureModificationForm.php @@ -0,0 +1,62 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Thelia\Model\CurrencyQuery; +use Symfony\Component\Validator\ExecutionContextInterface; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; +use Symfony\Component\Validator\Constraints\GreaterThan; + +class FeatureModificationForm extends FeatureCreationForm +{ + use StandardDescriptionFieldsTrait; + + protected function buildForm() + { + $this->formBuilder + ->add("id", "hidden", array( + "constraints" => array( + new GreaterThan( + array('value' => 0) + ) + ) + )) +/* FIXME: doesn't work + ->add('feature_values', 'collection', array( + 'type' => 'text', + 'options' => array('required' => false) + )) +*/ + ; + + // Add standard description fields + $this->addStandardDescFields(); + } + + public function getName() + { + return "thelia_feature_modification"; + } +} diff --git a/core/lib/Thelia/Model/Feature.php b/core/lib/Thelia/Model/Feature.php index ce7c57b1d..cf0284d2b 100755 --- a/core/lib/Thelia/Model/Feature.php +++ b/core/lib/Thelia/Model/Feature.php @@ -3,7 +3,70 @@ namespace Thelia\Model; use Thelia\Model\Base\Feature as BaseFeature; +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\FeatureEvent; class Feature extends BaseFeature { + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + use \Thelia\Model\Tools\PositionManagementTrait; + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_CREATEFEATURE, new FeatureEvent($this)); + + // Set the current position for the new object + $this->setPosition($this->getNextPosition()); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_CREATEFEATURE, new FeatureEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATEFEATURE, new FeatureEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_UPDATEFEATURE, new FeatureEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETEFEATURE, new FeatureEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_DELETEFEATURE, new FeatureEvent($this)); + } + } diff --git a/core/lib/Thelia/Model/FeatureAv.php b/core/lib/Thelia/Model/FeatureAv.php index 68b6fa92a..ae6e35087 100755 --- a/core/lib/Thelia/Model/FeatureAv.php +++ b/core/lib/Thelia/Model/FeatureAv.php @@ -3,7 +3,78 @@ namespace Thelia\Model; use Thelia\Model\Base\FeatureAv as BaseFeatureAv; +use Thelia\Core\Event\TheliaEvents; +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Core\Event\FeatureAvEvent; class FeatureAv extends BaseFeatureAv { + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + use \Thelia\Model\Tools\PositionManagementTrait; + + /** + * when dealing with position, be sure to work insite the current feature. + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByFeatureId($this->getFeatureId()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + // Set the current position for the new object + $this->setPosition($this->getNextPosition()); + + $this->dispatchEvent(TheliaEvents::BEFORE_CREATEFEATURE_AV, new FeatureAvEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_CREATEFEATURE_AV, new FeatureAvEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATEFEATURE_AV, new FeatureAvEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_UPDATEFEATURE_AV, new FeatureAvEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETEFEATURE_AV, new FeatureAvEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_DELETEFEATURE_AV, new FeatureAvEvent($this)); + } + } diff --git a/templates/admin/default/feature-edit.html b/templates/admin/default/feature-edit.html new file mode 100644 index 000000000..7bbed5965 --- /dev/null +++ b/templates/admin/default/feature-edit.html @@ -0,0 +1,316 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Edit an feature'}{/block} + +{block name="check-permissions"}admin.configuration.features.edit{/block} + +{block name="main-content"} +
    + +
    + + {loop name="feature_edit" type="feature" id=$feature_id backend_context="1" lang=$edit_language_id} + + + +
    +
    +
    + +
    + {intl l="Edit feature $TITLE"} +
    + +
    +
    + {form name="thelia.admin.feature.modification"} + + + {include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/configuration/features'}"} + +
    + +

    {intl l='Feature information'}

    + + {form_field form=$form field='id'} + + {/form_field} + + {* Be sure to get the feature ID, even if the form could not be validated *} + + + {form_hidden_fields form=$form} + + {form_field form=$form field='success_url'} + + {/form_field} + + {form_field form=$form field='locale'} + + {/form_field} + + {if $form_error}
    {$form_error_message}
    {/if} + + {include file="includes/standard-description-form-fields.html" form=$form} +
    + +
    + +

    + + {intl l='Feature values'} + + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.feature-av.create"} + + + + + + {/loop} +

    + +
    + {intl l="Enter here all possible feature values."} +
    + + + + + + + + + + + {module_include location='features_value_table_header'} + + + + + + + {loop name="list" type="feature_availability" feature=$feature_id backend_context="1" lang=$edit_language_id order=$featureav_order} + + + + + + + + {module_include location='features_value_table_row'} + + + + {/loop} + + {elseloop rel="list"} + + + + {/elseloop} + +
    + {admin_sortable_header + current_order=$featureav_order + order='id' + reverse_order='id_reverse' + request_parameter_name='featureav_order' + path={url path='/admin/configuration/features/update' feature_id=$feature_id} + label="{intl l='ID'}" + } + + {admin_sortable_header + current_order=$featureav_order + order='alpha' + reverse_order='alpha_reverse' + request_parameter_name='featureav_order' + path={url path='/admin/configuration/features/update' feature_id=$feature_id} + label="{intl l='Value'}" + } + + {admin_sortable_header + current_order=$featureav_order + order='manual' + reverse_order='manual_reverse' + request_parameter_name='featureav_order' + path={url path='/admin/configuration/features/update' feature_id=$feature_id} + label="{intl l="Position"}" + } + {intl l="Actions"}
    {$ID} + {* FIXME : integrate this in the encolsing form to provide standard form processing *} + + + {admin_position_block + permission="admin.features.edit" + path={url path='/admin/configuration/features-av/update-position' feature_id=$feature_id} + url_parameter="featureav_id" + in_place_edit_class="positionChange" + position="$POSITION" + id="$ID" + } + +
    + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.feature-av.delete"} + + + + {/loop} +
    +
    +
    + {intl l="No value has been created yet. Click the + button to create one."} +
    +
    +
    + + {/form} +
    +
    +
    +
    + +
    + + {/loop} + + {elseloop rel="feature_edit"} +
    +
    +
    + {intl l="Sorry, feature ID=$feature_id was not found."} +
    +
    +
    + {/elseloop} + +
    +
    + +{* Adding a new feature *} + +{form name="thelia.admin.featureav.creation"} + + {* Capture the dialog body, to pass it to the generic dialog *} + + {capture "creation_dialog"} + {form_hidden_fields form=$form} + + {* Be sure to get the feature ID, even if the form could not be validated *} + + + {form_field form=$form field='success_url'} + {* on success, redirect to this page *} + + {/form_field} + + {form_field form=$form field='feature_id'} + + {/form_field} + + {form_field form=$form field='title'} +
    + + + {loop type="lang" name="current-edit-lang" id="$edit_language_id"} +
    + + {intl l=$TITLE} +
    + +
    {intl l="Enter here the value in the current edit language ($TITLE)"}
    + + {form_field form=$form field='locale'} + + {/form_field} + {/loop} +
    + {/form_field} + + {module_include location='feature_value_create_form'} + + {/capture} + + {include + file = "includes/generic-create-dialog.html" + + dialog_id = "creation_dialog" + dialog_title = {intl l="Create a new feature value"} + dialog_body = {$smarty.capture.creation_dialog nofilter} + + dialog_ok_label = {intl l="Create this value"} + + form_action = {url path='/admin/configuration/features-av/create'} + form_enctype = {form_enctype form=$form} + form_error_message = $form_error_message + } +{/form} + +{* Delete value confirmation dialog *} + +{capture "delete_dialog"} + + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_dialog" + dialog_title = {intl l="Delete feature value"} + dialog_message = {intl l="Do you really want to delete this feature value ?"} + + form_action = {url path='/admin/configuration/features-av/delete'} + form_content = {$smarty.capture.delete_dialog nofilter} +} + +{/block} + +{block name="javascript-initialization"} + + {javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} + + {/javascripts} + + +{/block} \ No newline at end of file diff --git a/templates/admin/default/features.html b/templates/admin/default/features.html new file mode 100644 index 000000000..69ed1d5d4 --- /dev/null +++ b/templates/admin/default/features.html @@ -0,0 +1,326 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Thelia Product Features'}{/block} + +{block name="check-permissions"}admin.configuration.features.view{/block} + +{block name="main-content"} +
    + +
    + + + + {module_include location='features_top'} + +
    +
    +
    +
    + + + + + + + + + + + {module_include location='features_table_header'} + + + + + + + {loop name="list" type="feature" backend_context="1" lang=$lang_id order=$order} + + + + + + + + {module_include location='features_table_row'} + + + + {/loop} + + {elseloop rel="list"} + + + + {/elseloop} + +
    + {intl l='Thelia product features'} + + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.features.create"} + + + + {/loop} +
    + {admin_sortable_header + current_order=$order + order='id' + reverse_order='id_reverse' + path='/admin/configuration/features' + label="{intl l='ID'}" + } + + {admin_sortable_header + current_order=$order + order='alpha' + reverse_order='alpha_reverse' + path='/admin/configuration/features' + label="{intl l='Title'}" + } + + {admin_sortable_header + current_order=$order + order='manual' + reverse_order='manual_reverse' + path='/admin/configuration/features' + label="{intl l="Position"}" + } + {intl l="Actions"}
    {$ID} + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.features.change"} + {$TITLE} + {/loop} + {elseloop rel="can_change"} + {$TITLE} + {/elseloop} + + {admin_position_block + permission="admin.features.edit" + path="/admin/configuration/features/update-position" + url_parameter="feature_id" + in_place_edit_class="positionChange" + position="$POSITION" + id="$ID" + } + + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.features.change"} + + {/loop} + +
    + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.features.change"} + + {/loop} + + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.features.delete"} + + {/loop} +
    +
    +
    + {intl l="No product feature has been created yet. Click the + button to create one."} +
    +
    +
    +
    +
    +
    + + {module_include location='features_bottom'} + +
    +
    + +{* Adding a new feature *} + +{form name="thelia.admin.feature.creation"} + + {* Capture the dialog body, to pass it to the generic dialog *} + {capture "creation_dialog"} + {form_hidden_fields form=$form} + + {form_field form=$form field='success_url'} + {* on success, redirect to the edition page, _ID_ is replaced with the created feature ID, see controller *} + + {/form_field} + + {form_field form=$form field='title'} +
    + + + {loop type="lang" name="default-lang" default_only="1"} +
    + + {intl l=$TITLE} +
    + +
    {intl l="Enter here the feature name in the default language ($TITLE)"}
    + + {* Switch edition to the current locale *} + + + {form_field form=$form field='locale'} + + {/form_field} + {/loop} +
    + {/form_field} + + {form_field form=$form field='add_to_all'} +
    +
    + + {intl l='Check this box if you want to add this features to all product templates'} +
    +
    + {/form_field} + + {module_include location='feature_create_form'} + + {/capture} + + {include + file = "includes/generic-create-dialog.html" + + dialog_id = "creation_dialog" + dialog_title = {intl l="Create a new feature"} + dialog_body = {$smarty.capture.creation_dialog nofilter} + + dialog_ok_label = {intl l="Create this feature"} + + form_action = {url path='/admin/configuration/features/create'} + form_enctype = {form_enctype form=$form} + form_error_message = $form_error_message + } +{/form} + +{* Delete confirmation dialog *} + +{capture "delete_dialog"} + + + {module_include location='feature_delete_form'} + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_dialog" + dialog_title = {intl l="Delete feature"} + dialog_message = {intl l="Do you really want to delete this feature ? It will be removed from all product templates."} + + form_action = {url path='/admin/configuration/features/delete'} + form_content = {$smarty.capture.delete_dialog nofilter} +} + + +{* Add to all dialog *} + +{capture "add_to_all_dialog"} + + + {module_include location='feature_add_to_all_form'} + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "add_to_all_dialog" + dialog_title = {intl l="Add to all product templates"} + dialog_message = {intl l="Do you really want to add this feature to all product templates ?"} + + form_action = {url path='/admin/configuration/features/add-to-all-templates'} + form_content = {$smarty.capture.add_to_all_dialog nofilter} +} + +{* Remove from all dialog *} + +{capture "remove_from_all_dialog"} + + + {module_include location='feature_add_to_all_form'} + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "remove_from_all_dialog" + dialog_title = {intl l="Remove from all product templates"} + dialog_message = {intl l="Do you really want to remove this feature from all product templates ? You'll loose all product related data for this feature."} + + form_action = {url path='/admin/configuration/features/remove-from-all-templates'} + form_content = {$smarty.capture.remove_from_all_dialog nofilter} +} + +{/block} + +{block name="javascript-initialization"} + + {javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} + + {/javascripts} + + +{/block} \ No newline at end of file