Merge branch 'master' of https://github.com/thelia/thelia into coupon

* 'master' of https://github.com/thelia/thelia:
  theliatype in form : types now extends bastype which implement typeinterface basetype provides verifiyForm method wich can be call in Callback constraint
  restart thelia form type
  thelia type constraints
  tax management
  fix menu when child > 0
  taxes management
  tax rule edition
This commit is contained in:
gmorel
2013-10-17 01:38:35 +02:00
47 changed files with 1619 additions and 113 deletions

View File

@@ -0,0 +1,104 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Propel\Runtime\ActiveQuery\Criteria;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Tax\TaxEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Tax as TaxModel;
use Thelia\Model\TaxQuery;
class Tax extends BaseAction implements EventSubscriberInterface
{
/**
* @param TaxEvent $event
*/
public function create(TaxEvent $event)
{
$tax = new TaxModel();
$tax
->setDispatcher($this->getDispatcher())
->setType($event->getType())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
;
$tax->save();
$event->setTax($tax);
}
/**
* @param TaxEvent $event
*/
public function update(TaxEvent $event)
{
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
$tax
->setDispatcher($this->getDispatcher())
->setType($event->getType())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->save()
;
$event->setTax($tax);
}
}
/**
* @param TaxEvent $event
*/
public function delete(TaxEvent $event)
{
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
$tax
->delete()
;
$event->setTax($tax);
}
}
/**
* {@inheritDoc}
*/
public static function getSubscribedEvents()
{
return array(
TheliaEvents::TAX_CREATE => array("create", 128),
TheliaEvents::TAX_UPDATE => array("update", 128),
TheliaEvents::TAX_DELETE => array("delete", 128),
);
}
}

View File

@@ -111,6 +111,11 @@
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.tax" class="Thelia\Action\Tax">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.content" class="Thelia\Action\Content">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>

View File

@@ -120,6 +120,10 @@
<form name="thelia.admin.taxrule.taxlistupdate" class="Thelia\Form\TaxRuleTaxListUpdateForm"/>
<form name="thelia.admin.taxrule.add" class="Thelia\Form\TaxRuleCreationForm"/>
<form name="thelia.admin.tax.modification" class="Thelia\Form\TaxModificationForm"/>
<form name="thelia.admin.tax.taxlistupdate" class="Thelia\Form\TaxTaxListUpdateForm"/>
<form name="thelia.admin.tax.add" class="Thelia\Form\TaxCreationForm"/>
<form name="thelia.admin.template.creation" class="Thelia\Form\TemplateCreationForm"/>
<form name="thelia.admin.template.modification" class="Thelia\Form\TemplateModificationForm"/>

View File

@@ -822,7 +822,28 @@
<!-- end Modules rule management -->
<!-- taxe rules management -->
<!-- tax management -->
<route id="admin.configuration.taxes.update" path="/admin/configuration/taxes/update/{tax_id}">
<default key="_controller">Thelia\Controller\Admin\TaxController::updateAction</default>
<requirement key="tax_id">\d+</requirement>
</route>
<route id="admin.configuration.taxes.add" path="/admin/configuration/taxes/add">
<default key="_controller">Thelia\Controller\Admin\TaxController::createAction</default>
</route>
<route id="admin.configuration.taxes.save" path="/admin/configuration/taxes/save">
<default key="_controller">Thelia\Controller\Admin\TaxController::processUpdateAction</default>
</route>
<route id="admin.configuration.taxes.delete" path="/admin/configuration/taxes/delete">
<default key="_controller">Thelia\Controller\Admin\TaxController::deleteAction</default>
</route>
<!-- end tax management -->
<!-- tax rules management -->
<route id="admin.configuration.taxes-rules.list" path="/admin/configuration/taxes_rules">
<default key="_controller">Thelia\Controller\Admin\TaxRuleController::defaultAction</default>

View File

@@ -392,6 +392,8 @@ abstract class AbstractCrudController extends BaseAdminController
// Get the form field values
$data = $form->getData();
$dataType = $form->all();
$changeEvent = $this->getUpdateEvent($data);
$this->dispatch($this->updateEventIdentifier, $changeEvent);

View File

@@ -0,0 +1,210 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Admin;
use Thelia\Core\Event\Tax\TaxEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Form\TaxCreationForm;
use Thelia\Form\TaxModificationForm;
use Thelia\Form\TaxTaxListUpdateForm;
use Thelia\Model\TaxQuery;
class TaxController extends AbstractCrudController
{
public function __construct()
{
parent::__construct(
'tax',
'manual',
'order',
'admin.configuration.tax.view',
'admin.configuration.tax.create',
'admin.configuration.tax.update',
'admin.configuration.tax.delete',
TheliaEvents::TAX_CREATE,
TheliaEvents::TAX_UPDATE,
TheliaEvents::TAX_DELETE
);
}
protected function getCreationForm()
{
return new TaxCreationForm($this->getRequest());
}
protected function getUpdateForm()
{
return new TaxModificationForm($this->getRequest());
}
protected function getCreationEvent($formData)
{
$event = new TaxEvent();
$event->setLocale($formData['locale']);
$event->setTitle($formData['title']);
$event->setDescription($formData['description']);
$event->setType($formData['type']);
return $event;
}
protected function getUpdateEvent($formData)
{
$event = new TaxEvent();
/* check the requirements */
if(!$this->checkRequirements($formData)) {
}
$event->setLocale($formData['locale']);
$event->setId($formData['id']);
$event->setTitle($formData['title']);
$event->setDescription($formData['description']);
$event->setType($formData['type']);
return $event;
}
protected function getDeleteEvent()
{
$event = new TaxEvent();
$event->setId(
$this->getRequest()->get('tax_id', 0)
);
return $event;
}
protected function eventContainsObject($event)
{
return $event->hasTax();
}
protected function hydrateObjectForm($object)
{
$data = array(
'id' => $object->getId(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'description' => $object->getDescription(),
'type' => $object->getType(),
);
// Setup the object form
return new TaxModificationForm($this->getRequest(), "form", $data);
}
protected function getObjectFromEvent($event)
{
return $event->hasTax() ? $event->getTax() : null;
}
protected function getExistingObject()
{
return TaxQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->findOneById($this->getRequest()->get('tax_id'));
}
protected function getObjectLabel($object)
{
return $object->getTitle();
}
protected function getObjectId($object)
{
return $object->getId();
}
protected function getViewArguments()
{
return array();
}
protected function getRouteArguments($tax_id = null)
{
return array(
'tax_id' => $tax_id === null ? $this->getRequest()->get('tax_id') : $tax_id,
);
}
protected function renderListTemplate($currentOrder)
{
// We always return to the feature edition form
return $this->render(
'taxes-rules',
array()
);
}
protected function renderEditionTemplate()
{
// We always return to the feature edition form
return $this->render('tax-edit', array_merge($this->getViewArguments(), $this->getRouteArguments()));
}
protected function redirectToEditionTemplate($request = null, $country = null)
{
// We always return to the feature edition form
$this->redirectToRoute(
"admin.configuration.taxes.update",
$this->getViewArguments($country),
$this->getRouteArguments()
);
}
/**
* Put in this method post object creation processing if required.
*
* @param TaxEvent $createEvent the create event
* @return Response a response, or null to continue normal processing
*/
protected function performAdditionalCreateAction($createEvent)
{
$this->redirectToRoute(
"admin.configuration.taxes.update",
$this->getViewArguments(),
$this->getRouteArguments($createEvent->getTax()->getId())
);
}
protected function redirectToListTemplate()
{
$this->redirectToRoute(
"admin.configuration.taxes-rules.list"
);
}
protected function checkRequirements($formData)
{
$type = $formData['type'];
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Tax;
use Thelia\Core\Event\ActionEvent;
use Thelia\Model\Tax;
class TaxEvent extends ActionEvent
{
protected $tax = null;
protected $locale;
protected $id;
protected $title;
protected $description;
protected $type;
public function __construct(Tax $tax = null)
{
$this->tax = $tax;
}
public function hasTax()
{
return ! is_null($this->tax);
}
public function getTax()
{
return $this->tax;
}
public function setTax(Tax $tax)
{
$this->tax = $tax;
return $this;
}
public function setDescription($description)
{
$this->description = $description;
}
public function getDescription()
{
return $this->description;
}
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setLocale($locale)
{
$this->locale = $locale;
}
public function getLocale()
{
return $this->locale;
}
public function setType($type)
{
$this->type = $type;
}
public function getType()
{
return $this->type;
}
}

View File

@@ -543,6 +543,12 @@ final class TheliaEvents
const CHANGE_DEFAULT_CURRENCY = 'action.changeDefaultCurrency';
// -- Tax management ---------------------------------------------
const TAX_CREATE = "action.createTax";
const TAX_UPDATE = "action.updateTax";
const TAX_DELETE = "action.deleteTax";
// -- Tax Rules management ---------------------------------------------
const TAX_RULE_CREATE = "action.createTaxRule";

View File

@@ -0,0 +1,49 @@
<?php
namespace Thelia\Core\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TheliaType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'instance' => false,
'type' => false,
'options' => false,
));
$resolver->setAllowedTypes(array(
'instance' => array('Thelia\Type\TypeInterface'),
));
$resolver->setAllowedValues(array(
'type' => array('text', 'choice'),
));
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars = array_replace($view->vars, array(
'instance' => $options['instance'],
'type' => $options['type'],
'options' => $options['options'],
));
}
public function getParent()
{
return 'text';
}
public function getName()
{
return 'thelia_type';
}
}

View File

@@ -254,7 +254,7 @@ abstract class BaseLoop
*
* @param $pagination
*
* @return mixed
* @return LoopResult
*/
abstract public function exec(&$pagination);

View File

@@ -84,10 +84,14 @@ class CategoryTree extends BaseI18nLoop
$loopResultRow = new LoopResultRow();
$loopResultRow
->set("ID", $result->getId())->set("TITLE", $result->getVirtualColumn('i18n_TITLE'))
->set("PARENT", $result->getParent())->set("URL", $result->getUrl($locale))
->set("VISIBLE", $result->getVisible() ? "1" : "0")->set("LEVEL", $level)
->set('CHILD_COUNT', $result->countChild())->set('PREV_LEVEL', $previousLevel)
->set("ID", $result->getId())
->set("TITLE", $result->getVirtualColumn('i18n_TITLE'))
->set("PARENT", $result->getParent())
->set("URL", $result->getUrl($locale))
->set("VISIBLE", $result->getVisible() ? "1" : "0")
->set("LEVEL", $level)
->set('CHILD_COUNT', $result->countChild())
->set('PREV_LEVEL', $previousLevel)
;
$loopResult->addRow($loopResultRow);

View File

@@ -151,12 +151,16 @@ class Tax extends BaseI18nLoop
$loopResultRow = new LoopResultRow($loopResult, $tax, $this->versionable, $this->timestampable, $this->countable);
$requirements = json_decode( base64_decode( $tax->getSerializedRequirements() ), true );
$loopResultRow
->set("ID" , $tax->getId())
->set("IS_TRANSLATED" , $tax->getVirtualColumn('IS_TRANSLATED'))
->set("LOCALE" , $locale)
->set("TITLE" , $tax->getVirtualColumn('i18n_TITLE'))
->set("DESCRIPTION" , $tax->getVirtualColumn('i18n_DESCRIPTION'))
->set("ID" , $tax->getId())
->set("TYPE" , $tax->getType())
->set("REQUIREMENTS" , $requirements)
->set("IS_TRANSLATED" , $tax->getVirtualColumn('IS_TRANSLATED'))
->set("LOCALE" , $locale)
->set("TITLE" , $tax->getVirtualColumn('i18n_TITLE'))
->set("DESCRIPTION" , $tax->getVirtualColumn('i18n_DESCRIPTION'))
;
$loopResult->addRow($loopResultRow);

View File

@@ -32,6 +32,7 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\CountryQuery;
use Thelia\Model\Map\CountryTableMap;
use Thelia\Model\Map\TaxRuleCountryTableMap;
use Thelia\Model\Map\TaxTableMap;
@@ -58,8 +59,14 @@ class TaxRuleCountry extends BaseI18nLoop
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntTypeArgument('country'),
Argument::createIntListTypeArgument('taxes'),
Argument::createIntTypeArgument('country', null, true),
new Argument(
'ask',
new TypeCollection(
new Type\EnumType(array('taxes', 'countries'))
),
'taxes'
),
Argument::createIntTypeArgument('tax_rule', null, true)
);
}
@@ -73,40 +80,54 @@ class TaxRuleCountry extends BaseI18nLoop
{
$search = TaxRuleCountryQuery::create();
$ask = $this->getAsk();
$country = $this->getCountry();
$taxes = $this->getTaxes();
$taxRule = $this->getTax_rule();
if((null === $country && null === $taxes)) {
throw new \InvalidArgumentException('You must provide either `country` or `taxes` parameter in tax-rule-country loop');
}
if($ask === 'countries') {
$taxCountForOriginCountry = TaxRuleCountryQuery::create()->filterByCountryId($country)->count();
if((null === $country && null !== $taxes)) {
throw new \InvalidArgumentException('You must provide `country` parameter with `taxes` parameter in tax-rule-country loop');
}
if($taxCountForOriginCountry > 0) {
$search->groupByCountryId();
if(null !== $taxes) {
$search->groupByCountryId();
$originalCountryJoin = new Join();
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', null, TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', 'origin', Criteria::NOT_EQUAL);
$originalCountryJoin->setJoinType(Criteria::LEFT_JOIN);
$originalCountryJoin = new Join();
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', null, TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', 'origin');
$originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', 'origin', Criteria::NOT_EQUAL);
$originalCountryJoin->setJoinType(Criteria::LEFT_JOIN);
$search->addJoinObject($originalCountryJoin, 's_to_o');
$search->where('`origin`.`COUNTRY_ID`' . Criteria::EQUAL . '?', $country, \PDO::PARAM_INT);
$search->addJoinObject($originalCountryJoin, 's_to_o');
$search->where('`origin`.`COUNTRY_ID`' . Criteria::EQUAL . '?', $country, \PDO::PARAM_INT);
$search->having('COUNT(*)=?', $taxCountForOriginCountry, \PDO::PARAM_INT);
$search->having('COUNT(*)=?', count($taxes), \PDO::PARAM_INT);
$search->filterByTaxRuleId($taxRule);
/* manage tax translation */
$this->configureI18nProcessing(
$search,
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
CountryTableMap::TABLE_NAME,
'COUNTRY_ID'
);
} elseif(null !== $country) {
/* manage tax translation */
$this->configureI18nProcessing(
$search,
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
CountryTableMap::TABLE_NAME,
'COUNTRY_ID'
);
$search->addAscendingOrderByColumn('`' . CountryTableMap::TABLE_NAME . '_i18n_TITLE`');
} else {
$search = CountryQuery::create()
->joinTaxRuleCountry('trc', Criteria::LEFT_JOIN);
/* manage tax translation */
$this->configureI18nProcessing(
$search
);
$search->where('ISNULL(`trc`.`COUNTRY_ID`)');
$search->addAscendingOrderByColumn('i18n_TITLE');
}
} elseif($ask === 'taxes') {
$search->filterByCountryId($country);
/* manage tax translation */
@@ -116,13 +137,11 @@ class TaxRuleCountry extends BaseI18nLoop
TaxTableMap::TABLE_NAME,
'TAX_ID'
);
$search->filterByTaxRuleId($taxRule);
$search->orderByPosition(Criteria::ASC);
}
$taxRule = $this->getTax_rule();
$search->filterByTaxRuleId($taxRule);
$search->orderByPosition(Criteria::ASC);
/* perform search */
$taxRuleCountries = $this->search($search, $pagination);
@@ -132,16 +151,23 @@ class TaxRuleCountry extends BaseI18nLoop
$loopResultRow = new LoopResultRow($loopResult, $taxRuleCountry, $this->versionable, $this->timestampable, $this->countable);
if(null !== $taxes) {
$loopResultRow
->set("TAX_RULE" , $taxRuleCountry->getTaxRuleId())
->set("COUNTRY" , $taxRuleCountry->getCountryId())
->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_TITLE'))
->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_CHAPO'))
->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_DESCRIPTION'))
->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM'))
;
}elseif(null !== $country) {
if($ask === 'countries') {
if($taxCountForOriginCountry > 0) {
$loopResultRow
->set("COUNTRY" , $taxRuleCountry->getCountryId())
->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_TITLE'))
->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_CHAPO'))
->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_DESCRIPTION'))
->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM'));
} else {
$loopResultRow
->set("COUNTRY" , $taxRuleCountry->getId())
->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn('i18n_TITLE'))
->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn('i18n_CHAPO'))
->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn('i18n_DESCRIPTION'))
->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn('i18n_POSTSCRIPTUM'));
}
} elseif($ask === 'taxes') {
$loopResultRow
->set("TAX_RULE" , $taxRuleCountry->getTaxRuleId())
->set("COUNTRY" , $taxRuleCountry->getCountryId())

View File

@@ -22,7 +22,11 @@
/*************************************************************************************/
namespace Thelia\Core\Template\Smarty\Plugins;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Component\Form\FormView;
use Thelia\Core\Form\Type\TheliaType;
use Thelia\Form\BaseForm;
use Thelia\Core\Template\Element\Exception\ElementNotFoundException;
use Symfony\Component\HttpFoundation\Request;
@@ -56,6 +60,8 @@ use Thelia\Core\Template\ParserContext;
*/
class Form extends AbstractSmartyPlugin
{
static private $taggedFieldsStack = null;
static private $taggedFieldsStackPosition = null;
protected $request;
protected $parserContext;
@@ -118,11 +124,16 @@ class Form extends AbstractSmartyPlugin
$template->assign("value", $fieldValue);
$template->assign("options", $formFieldView->vars);
// If Checkbox input type
if ($fieldVars['checked'] !== null) {
$this->renderFormFieldCheckBox($template, $formFieldView['checked']);
}
//data
$template->assign("data", $fieldVars['data']);
$template->assign("label", $fieldVars["label"]);
$template->assign("label_attr", $fieldVars["label_attr"]);
@@ -141,20 +152,54 @@ class Form extends AbstractSmartyPlugin
}
$template->assign("attr", implode(" ", $attr));
$template->assign("attr_list", $fieldVars["attr"]);
}
protected function assignFormTypeValues($template, $formFieldConfig, $formFieldView)
{
$formFieldType = $formFieldConfig->getType()->getInnerType();
/* access to choices */
if($formFieldType instanceof ChoiceType) {
$template->assign("choices", $formFieldView->vars['choices']);
}
/* access to collections */
if($formFieldType instanceof CollectionType) {
if( true === $formFieldConfig->getOption('prototype') ) {
} else {
}
}
/* access to thelia type */
if($formFieldType instanceof TheliaType) {
$template->assign("formType", $formFieldView->vars['type']);
switch($formFieldView->vars['type']) {
case "choice":
if(!isset($formFieldView->vars['options']['choices']) || !is_array($formFieldView->vars['options']['choices'])) {
//throw new
}
$choices = array();
foreach($formFieldView->vars['options']['choices'] as $value => $choice) {
$choices[] = new ChoiceView($value, $value, $choice);
}
$template->assign("choices", $choices);
break;
}
}
}
public function renderFormField($params, $content, \Smarty_Internal_Template $template, &$repeat)
{
if ($repeat) {
if ($repeat) {
$formFieldView = $this->getFormFieldView($params);
$formFieldView = $this->getFormFieldView($params);
$formFieldConfig = $this->getFormFieldConfig($params);
$template->assign("options", $formFieldView->vars);
/* access to choices */
if(isset($formFieldView->vars['choices'])) {
$template->assign("choices", $formFieldView->vars['choices']);
}
$this->assignFormTypeValues($template, $formFieldConfig, $formFieldView);
$value = $formFieldView->vars["value"];
/* FIXME: doesnt work. We got "This form should not contain extra fields." error.
@@ -185,6 +230,38 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar
}
}
public function renderTaggedFormFields($params, $content, \Smarty_Internal_Template $template, &$repeat)
{
if(null === $content) {
self::$taggedFieldsStack = $this->getFormFieldsFromTag($params);
self::$taggedFieldsStackPosition = 0;
} else {
self::$taggedFieldsStackPosition++;
}
if(isset(self::$taggedFieldsStack[self::$taggedFieldsStackPosition])) {
$this->assignFieldValues(
$template,
self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars["full_name"],
self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars["value"],
self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars
);
$this->assignFormTypeValues($template, self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['config'], self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']);
self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->setRendered();
$repeat = true;
}
if (! $repeat) {
self::$taggedFieldsStack = null;
self::$taggedFieldsStackPosition = null;
}
return $content;
}
public function renderHiddenFormField($params, \Smarty_Internal_Template $template)
{
$attrFormat = '%s="%s"';
@@ -266,6 +343,48 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar
return $instance->getView()[$fieldName];
}
protected function getFormFieldsFromTag($params)
{
$instance = $this->getInstanceFromParams($params);
$tag = $this->getParam($params, 'tag');
if (null == $tag)
throw new \InvalidArgumentException("'tag' parameter is missing");
$viewList = array();
foreach($instance->getView() as $view) {
if(isset($view->vars['attr']['tag']) && $tag == $view->vars['attr']['tag']) {
$fieldData = $instance->getForm()->all()[$view->vars['name']];
$viewList[] = array(
'view' => $view,
'config' => $fieldData->getConfig(),
);
}
}
return $viewList;
}
protected function getFormFieldConfig($params)
{
$instance = $this->getInstanceFromParams($params);
$fieldName = $this->getParam($params, 'field');
if (null == $fieldName) {
throw new \InvalidArgumentException("'field' parameter is missing");
}
$fieldData = $instance->getForm()->all()[$fieldName];
if (empty( $fieldData )) {
throw new \InvalidArgumentException(sprintf("Field name '%s' not found in form %s children", $fieldName, $instance->getName()));
}
return $fieldData->getConfig();
}
protected function getInstanceFromParams($params)
{
$instance = $this->getParam($params, 'form');
@@ -304,6 +423,7 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar
return array(
new SmartyPluginDescriptor("block", "form", $this, "generateForm"),
new SmartyPluginDescriptor("block", "form_field", $this, "renderFormField"),
new SmartyPluginDescriptor("block", "form_tagged_fields", $this, "renderTaggedFormFields"),
new SmartyPluginDescriptor("function", "form_hidden_fields", $this, "renderHiddenFormField"),
new SmartyPluginDescriptor("function", "form_enctype", $this, "formEnctype"),
new SmartyPluginDescriptor("block", "form_error", $this, "formError")

View File

@@ -300,7 +300,7 @@ class TheliaLoop extends AbstractSmartyPlugin
/**
* @param $smartyParams
*
* @return object
* @return BaseLoop
* @throws \Thelia\Core\Template\Element\Exception\InvalidElementException
* @throws \Thelia\Core\Template\Element\Exception\ElementNotFoundException
*/

View File

@@ -0,0 +1,106 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\ExecutionContextInterface;
use Thelia\Core\Form\Type\TheliaType;
use Thelia\Core\Translation\Translator;
use Thelia\TaxEngine\TaxEngine;
use Thelia\TaxEngine\TaxType;
class TaxCreationForm extends BaseForm
{
use StandardDescriptionFieldsTrait;
protected function buildForm($change_mode = false)
{
$types = TaxEngine::getInstance()->getTaxTypeList();
$typeList = array();
$requirementList = array();
foreach($types as $type) {
$classPath = "\\Thelia\\TaxEngine\\TaxType\\$type";
$instance = new $classPath();
$typeList[$type] = $instance->getTitle();
$requirementList[$type] = $instance->getRequirementsList();
}
$this->formBuilder
->add("locale", "text", array(
"constraints" => array(new NotBlank())
))
->add("type", "choice", array(
"choices" => $typeList,
"required" => true,
"constraints" => array(
new Constraints\NotBlank(),
),
"label" => Translator::getInstance()->trans("Type"),
"label_attr" => array("for" => "type_field"),
))
;
foreach($requirementList as $type => $requirements) {
foreach($requirements as $name => $requirementType) {
$this->formBuilder
->add($type . '_' . $name, new TheliaType(), array(
"instance" => $requirementType,
"constraints" => array(
new Constraints\Callback(
array(
"methods" => array(
array($requirementType, "verifyForm"),
),
)
),
),
"attr" => array(
"tag" => "requirements",
),
"data" => array(
"tax_type" => $type,
),
"label" => Translator::getInstance()->trans($name),
"type" => $requirementType->getFormType(),
"options" => $requirementType->getFormOptions(),
))
;
}
}
$this->addStandardDescFields(array('postscriptum', 'chapo', 'locale'));
}
public function getName()
{
return "thelia_tax_creation";
}
public function verifyForm($value, ExecutionContextInterface $context)
{
$in = true;
//$this->getForm()->getChildren()
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\ExecutionContextInterface;
use Thelia\Model\TaxQuery;
class TaxModificationForm extends TaxCreationForm
{
protected function buildForm()
{
parent::buildForm(true);
$this->formBuilder
->add("id", "hidden", array(
"required" => true,
"constraints" => array(
new Constraints\NotBlank(),
new Constraints\Callback(
array(
"methods" => array(
array($this, "verifyTaxId"),
),
)
),
)
))
;
}
public function getName()
{
return "thelia_tax_modification";
}
public function verifyTaxId($value, ExecutionContextInterface $context)
{
$tax = TaxQuery::create()
->findPk($value);
if (null === $tax) {
$context->addViolation("Tax ID not found");
}
}
}

View File

@@ -4,10 +4,13 @@ namespace Thelia\Model;
use Thelia\Exception\TaxEngineException;
use Thelia\Model\Base\Tax as BaseTax;
use Thelia\Model\Tools\ModelEventDispatcherTrait;
use Thelia\TaxEngine\TaxType\BaseTaxType;
class Tax extends BaseTax
{
use ModelEventDispatcherTrait;
public function calculateTax($amount)
{
if(false === filter_var($amount, FILTER_VALIDATE_FLOAT)) {

View File

@@ -0,0 +1,71 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\TaxEngine;
/**
* Class TaxEngine
* @package Thelia\TaxEngine
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*/
class TaxEngine
{
static public function getInstance()
{
return new TaxEngine();
}
private function getTaxTypeDirectory()
{
return __DIR__ . "/TaxType";
}
public function getTaxTypeList()
{
$typeList = array();
try {
$directoryBrowser = new \DirectoryIterator($this->getTaxTypeDirectory($this->getTaxTypeDirectory()));
} catch (\UnexpectedValueException $e) {
return $typeList;
}
/* browse the directory */
foreach ($directoryBrowser as $directoryContent) {
/* is it a file ? */
if (!$directoryContent->isFile()) {
continue;
}
$fileName = $directoryContent->getFilename();
$className = substr($fileName, 0, (1+strlen($directoryContent->getExtension())) * -1);
if($className == "BaseTaxType") {
continue;
}
$typeList[] = $className;
}
return $typeList;
}
}

View File

@@ -41,6 +41,8 @@ abstract class BaseTaxType
public abstract function getRequirementsList();
public abstract function getTitle();
public function calculate(Product $product, $untaxedPrice)
{
return $untaxedPrice * $this->pricePercentRetriever() + $this->fixAmountRetriever($product);

View File

@@ -65,4 +65,9 @@ class FeatureFixAmountTaxType extends BaseTaxType
'feature' => new ModelValidIdType('Feature'),
);
}
public function getTitle()
{
return "Fix amount Tax depending on a feature";
}
}

View File

@@ -45,8 +45,13 @@ class featureSlicePercentTaxType extends BaseTaxType
public function getRequirementsList()
{
return array(
'featureId' => new ModelValidIdType('Currency'),
'featureId' => new ModelValidIdType('Feature'),
'slices' => new FloatToFloatArrayType(),
);
}
public function getTitle()
{
return "% slice Tax depending on a feature";
}
}

View File

@@ -47,4 +47,9 @@ class FixAmountTaxType extends BaseTaxType
'amount' => new FloatType(),
);
}
public function getTitle()
{
return "Fix amount Tax";
}
}

View File

@@ -47,6 +47,9 @@ class PricePercentTaxType extends BaseTaxType
'percent' => new FloatType(),
);
}
}
//600 / (1 + 0,10 + 0,10) =/= 600 / (1 + 0,10 ) + 600 / (1 + 0,10 )
public function getTitle()
{
return "Price % Tax";
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class AlphaNumStringListType implements TypeInterface
class AlphaNumStringListType extends BaseType
{
public function getType()
{
@@ -50,4 +50,14 @@ class AlphaNumStringListType implements TypeInterface
{
return $this->isValid($values) ? explode(',', $values) : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class AlphaNumStringType implements TypeInterface
class AlphaNumStringType extends BaseType
{
public function getType()
{
@@ -44,4 +44,14 @@ class AlphaNumStringType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class AnyType implements TypeInterface
class AnyType extends BaseType
{
public function getType()
{
@@ -44,4 +44,14 @@ class AnyType implements TypeInterface
{
return $value;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Type;
use Symfony\Component\Validator\ExecutionContextInterface;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
abstract class BaseType implements TypeInterface
{
abstract public function getType();
abstract public function isValid($value);
abstract public function getFormattedValue($value);
abstract public function getFormType();
abstract public function getFormOptions();
public function verifyForm($value, ExecutionContextInterface $context)
{
if( ! $this->isValid($value) ) {
$context->addViolation("Thelia Type not matched");
}
}
}

View File

@@ -29,7 +29,7 @@ namespace Thelia\Type;
*
*/
class BooleanOrBothType implements TypeInterface
class BooleanOrBothType extends BaseType
{
const ANY = '*';
@@ -49,4 +49,14 @@ class BooleanOrBothType implements TypeInterface
if ($value === self::ANY) return $value;
return $value === null ? null : filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class BooleanType implements TypeInterface
class BooleanType extends BaseType
{
public function getType()
{
@@ -44,4 +44,14 @@ class BooleanType implements TypeInterface
{
return $value === null ? null : filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class EnumListType implements TypeInterface
class EnumListType extends BaseType
{
protected $values = array();
@@ -69,4 +69,14 @@ class EnumListType implements TypeInterface
{
return in_array($value, $this->values);
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class EnumType implements TypeInterface
class EnumType extends BaseType
{
protected $values = array();
@@ -52,4 +52,14 @@ class EnumType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class FloatToFloatArrayType implements TypeInterface
class FloatToFloatArrayType extends BaseType
{
public function getType()
{
@@ -54,4 +54,14 @@ class FloatToFloatArrayType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class FloatType implements TypeInterface
class FloatType extends BaseType
{
public function getType()
{
@@ -44,4 +44,14 @@ class FloatType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class IntListType implements TypeInterface
class IntListType extends BaseType
{
public function getType()
{
@@ -50,4 +50,14 @@ class IntListType implements TypeInterface
{
return $this->isValid($values) ? explode(',', $values) : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class IntToCombinedIntsListType implements TypeInterface
class IntToCombinedIntsListType extends BaseType
{
public function getType()
{
@@ -124,4 +124,14 @@ class IntToCombinedIntsListType implements TypeInterface
return true;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class IntToCombinedStringsListType implements TypeInterface
class IntToCombinedStringsListType extends BaseType
{
public function getType()
{
@@ -124,4 +124,14 @@ class IntToCombinedStringsListType implements TypeInterface
return true;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class IntType implements TypeInterface
class IntType extends BaseType
{
public function getType()
{
@@ -44,4 +44,14 @@ class IntType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -28,7 +28,7 @@ namespace Thelia\Type;
*
*/
class JsonType implements TypeInterface
class JsonType extends BaseType
{
public function getType()
{
@@ -46,4 +46,14 @@ class JsonType implements TypeInterface
{
return $this->isValid($value) ? json_decode($value, true) : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -30,7 +30,7 @@ use Thelia\Exception\TypeException;
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
class ModelType implements TypeInterface
class ModelType extends BaseType
{
protected $expectedModelActiveRecord = null;
@@ -63,4 +63,14 @@ class ModelType implements TypeInterface
{
return $this->isValid($value) ? $value : null;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -30,7 +30,7 @@ use Thelia\Exception\TypeException;
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
class ModelValidIdType implements TypeInterface
class ModelValidIdType extends BaseType
{
protected $expectedModelActiveRecordQuery = null;
@@ -67,4 +67,23 @@ class ModelValidIdType implements TypeInterface
return $this->isValid($value) ? $queryClass::create()->findPk($value) : null;
}
public function getFormType()
{
return 'choice';
}
public function getFormOptions()
{
$queryClass = $this->expectedModelActiveRecordQuery;
$choices = array();
foreach($queryClass::create()->find() as $item) {
$choices[$item->getId()] = method_exists($item, "getTitle") ? $item->getTitle() : $item->getId();
}
return array(
"choices" => $choices,
);
}
}

View File

@@ -22,12 +22,13 @@
/*************************************************************************************/
namespace Thelia\Type;
use Symfony\Component\Validator\ExecutionContextInterface;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
interface TypeInterface
{
public function getType();
@@ -35,4 +36,8 @@ interface TypeInterface
public function isValid($value);
public function getFormattedValue($value);
public function getFormType();
public function getFormOptions();
public function verifyForm($value, ExecutionContextInterface $context);
}

View File

@@ -0,0 +1,152 @@
{extends file="admin-layout.tpl"}
{block name="page-title"}{intl l='Edit a tax'}{/block}
{block name="check-permissions"}admin.configuration.taxes.edit{/block}
{block name="main-content"}
<div class="taxes-rules edit-taxes-rules">
<div id="wrapper" class="container">
<ul class="breadcrumb">
<li><a href="{url path='/admin/home'}">{intl l="Home"}</a></li>
<li><a href="{url path='/admin/configuration'}">{intl l="Configuration"}</a></li>
<li><a href="{url path='/admin/configuration/taxes_rules'}">{intl l="Taxes"}</a></li>
<li>{intl l='Editing tax'}</li>
</ul>
{loop type="tax" name="tax" id=$tax_id backend_context="1" lang=$edit_language_id}
<div class="row">
<div class="col-md-12 general-block-decorator clearfix">
<div class="form-container">
{form name="thelia.admin.tax.modification"}
<form method="POST" action="{url path="/admin/configuration/taxes/save"}" {form_enctype form=$form} >
{include
file = "includes/inner-form-toolbar.html"
hide_submit_buttons = false
page_url = {url path="/admin/configuration/taxes/update/$tax_id"}
close_url = {url path="/admin/configuration/taxes_rules"}
}
{* Be sure to get the product ID, even if the form could not be validated *}
<input type="hidden" name="tax_id" value="{$ID}" />
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/admin/configuration/taxes_rules"}" />
{/form_field}
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l=$label} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{if $error}{$value}{else}{if $IS_TRANSLATED == 1}{$TITLE}{/if}{/if}">
</div>
{/form_field}
{form_field form=$form field='description'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l=$label} :
<span class="label-help-block">{intl l="The detailed description."}</span>
</label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control wysiwyg">{if $error}{$value}{else}{if $IS_TRANSLATED == 1}{$DESCRIPTION}{/if}{/if}</textarea>
</div>
{/form_field}
{form_field form=$form field='type'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l=$label} :
</label>
<div class="form-group">
<select name="{$name}" class="js-change-tax-type" data-toggle="selectpicker">
{foreach $choices as $choice}
<option value="{$choice->value}" {if $choice->value == $TYPE}selected="selected" {/if}>{$choice->label}</option>
{/foreach}
</select>
</div>
</div>
{/form_field}
{form_tagged_fields form=$form tag='requirements'}
<div class="form-group {if $error}has-error{/if} js-tax-requirements" data-tax-type="{$data.tax_type}" {if $data.tax_type != $TYPE}style="display: none"{/if}>
<label for="{$label_attr.for}" class="control-label">
{intl l=$label} : {$formType}
</label>
{if $formType == 'choice'}
<select name="{$name}">
{foreach $choices as $choice}
<option value="{$choice->value}" {if $REQUIREMENTS.$label == $choice->value}selected="selected" {/if}>{$choice->label}</option>
{/foreach}
</select>
{/if}
{if $formType == 'text'}
<input type="text" name="{$name}" value="{$REQUIREMENTS.$label}">
{/if}
</div>
{/form_tagged_fields}
<div class="row">
<div class="col-md-12">
<div class="control-group">
<label>&nbsp;</label>
<div class="controls">
<p>{intl l='Tax created on %date_create. Last modification: %date_change' date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE}}</p>
</div>
</div>
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
{/loop}
</div>
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-select/bootstrap-select.js'}
<script src='{$asset_url}'></script>
{/javascripts}
{javascripts file='assets/js/main.js'}
<script src='{$asset_url}'></script>
{/javascripts}
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
$('.js-change-tax-type').change(function(e){
$('.js-tax-requirements').hide();
$('.js-tax-requirements[data-tax-type="' + $(this).val() + '"]').show();
});
});
</script>
{/block}

View File

@@ -116,11 +116,11 @@
</div>
<p><strong>{intl l="Countries that have the same tax rule"} :<strong></p>
<p class="lead">
<p class="lead js-collapse" id="same_countries" data-collapse-height="86">
{$matchedCountries.first=$asked_country}
{loop type="tax-rule-country" name="same-country-list" tax_rule=$ID taxes="1,2,3" country=$asked_country}
{loop type="tax-rule-country" name="same-country-list" tax_rule=$ID ask="countries" country=$asked_country}
{$matchedCountries[]=$COUNTRY}
<span class="label label-info">{$COUNTRY_TITLE}</span>
{/loop}
@@ -129,6 +129,7 @@
<span class="label label-danger">{intl l="NONE"}</span>
{/elseloop}
</p>
<button data-collapse-block="same_countries" type="button" class="btn btn-info btn-sm btn-block js-collapse-btn" style="margin-bottom: 15px">See all countries</button>
<div class="row">
<div class="col-md-6">
@@ -234,11 +235,16 @@
<p>{intl l="Tax rule taxes will be update for the following countries :"}</p>
<div class="form-group">
<select name="{$name}" data-toggle="selectpicker" multiple>
{loop type="country" name="country-list"}
<option value='{$ID}' {if (!$value AND in_array($ID, $matchedCountries)) OR ($value AND in_array($ID, $value))}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
<div class="input-group">
<select id="countries-select" class="" name="{$name}" data-toggle="selectpicker" multiple>
{loop type="country" name="country-list"}
<option value='{$ID}' {if (!$value AND in_array($ID, $matchedCountries)) OR ($value AND in_array($ID, $value))}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
<span class="input-group-btn">
<button class="btn btn-primary js-uncheck-all" data-uncheck-select="countries-select">{intl l="uncheck all"}</button>
</span>
</div>
</div>
{/form_field}
@@ -283,6 +289,29 @@
$('#tax_list_update_dialog').modal();
{/if}
$('.js-collapse').each(function(k, v) {
var h = $(v).data('collapse-height');
if( $(v).height() > h ) {
$(v).css('overflow', 'hidden').css('height', h + 'px');
} else {
$('[data-collapse-block=' + $(v).attr('id') + ']').hide();
}
});
$('.js-collapse-btn').click(function(e) {
e.preventDefault();
var block = $(this).data('collapseBlock');
$('#' + block).css('overflow', 'initial').css('height', 'initial');
$(this).unbind().remove();
});
$('.js-uncheck-all').click(function(e) {
e.preventDefault();
var selectId = $(this).data('uncheckSelect');
$('#' + selectId).selectpicker('deselectAll');
});
{literal}
$('#country-selector').change(function(e) {
$('#country-selector-form').submit();
@@ -308,7 +337,6 @@
});
});
console.log(taxesRules);
$('#tax_list').val(JSON.stringify(taxesRules));
});

View File

@@ -21,6 +21,72 @@
<div class="row">
<div class="col-md-12">
<div class="alert alert-info">
<p>{intl l="In order to manges your shop taxes you can manage"} <strong>{intl l="taxes"}</strong> {intl l="and"} <strong>{intl l="tax rules"}</strong>.</p>
<p>{intl l="Taxes define the amount of money which is add to a bought product."}</p>
<p>
{intl l="Example :"}
<ul>
<li>{intl l="French 19.6% VAT is a tax which add a 19.6% tax to the product price."}</li>
<li>{intl l="Ecotax is a tax wich add a defined amount (throug a product feature) to the product price."}</li>
</ul>
</p>
<p>{intl l="Tax rules are combination of different taxes."}</p>
<p>
{intl l="Example :"}
<ul>
<li>{intl l="French 19.6% VAT with ecotax is the applicance of the ecotax (on the product price) then the applicance of the 19.6% tax (on the product price + the ecotax amount)."}</li>
</ul>
</p>
<p>{intl l="you can combine taxes in tax rules and chose if they are applied one after the other or at the same time : it allows to apply taxes on an already taxed price or not."}</p>
</div>
<div class="general-block-decorator">
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<caption class="clearfix">
{intl l="Taxes"}
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.taxes.create"}
<a class="btn btn-default btn-primary pull-right" title="{intl l='Create a new tax'}" href="#tax_create_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus"></span>
</a>
{/loop}
</caption>
<thead>
<tr>
<th>{intl l="Name"}</th>
<th>{intl l="Description"}</th>
<th>{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop type="tax" name="taxes" backend_context="1"}
<tr>
<td>{$TITLE}</td>
<td>{$DESCRIPTION}</td>
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.taxes.change"}
<a class="btn btn-default btn-xs" title="{intl l='Change this tax'}" href="{url path="/admin/configuration/taxes/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.taxes.change"}
<a class="btn btn-default btn-xs js-delete-tax" title="{intl l='Delete this tax'}" href="#tax_delete_dialog" data-id="{$ID}" data-toggle="modal"><span class="glyphicon glyphicon-trash"></span></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
</div>
<div class="general-block-decorator">
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
@@ -41,7 +107,7 @@
</thead>
<tbody>
{loop type="tax-rule" name="taxes-rules"}
{loop type="tax-rule" name="taxes-rules" backend_context="1"}
<tr>
<td>{$TITLE}</td>
@@ -61,10 +127,10 @@
{/loop}
</tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@@ -73,8 +139,8 @@
</div>
</div>
{* -- Add tax rule confirmation dialog ----------------------------------- *}
{form name="thelia.admin.taxrule.add"}
{* -- Add tax confirmation dialog ----------------------------------- *}
{form name="thelia.admin.tax.add"}
{if $form_error_message}
{$taxCreateError = true}
@@ -82,6 +148,99 @@
{$taxCreateError = false}
{/if}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "tax_create_dialog"}
{form_hidden_fields form=$form}
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l=$label} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{if $error}{$value}{else}{if $IS_TRANSLATED == 1}{$TITLE}{/if}{/if}">
</div>
{/form_field}
{form_field form=$form field='description'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l=$label} :
<span class="label-help-block">{intl l="The detailed description."}</span>
</label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control wysiwyg">{if $error}{$value}{else}{if $IS_TRANSLATED == 1}{$DESCRIPTION}{/if}{/if}</textarea>
</div>
{/form_field}
{form_field form=$form field='type'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l=$label} :
</label>
<div class="form-group">
<select name="{$name}" data-toggle="selectpicker">
{foreach $choices as $choice}
<option value="{$choice->value}" {if $choice->value == $TYPE}selected="selected" {/if}>{$choice->label}</option>
{/foreach}
</select>
</div>
</div>
{/form_field}
{/capture}
{include
file = "includes/generic-create-dialog.html"
dialog_id = "tax_create_dialog"
dialog_title = {intl l="Create a new tax"}
dialog_body = {$smarty.capture.tax_create_dialog nofilter}
dialog_ok_label = {intl l="Create"}
dialog_cancel_label = {intl l="Cancel"}
form_action = {url path="/admin/configuration/taxes/add"}
form_enctype = {form_enctype form=$form}
form_error_message = $form_error_message
}
{/form}
{* -- Delete tax confirmation dialog ----------------------------------- *}
{capture "tax_delete_dialog"}
<input type="hidden" name="tax_id" id="tax_delete_id" value="" />
{module_include location='tax_delete_form'}
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "tax_delete_dialog"
dialog_title = {intl l="Delete tax"}
dialog_message = {intl l="Do you really want to delete this tax ?"}
form_action = {url path='/admin/configuration/taxes/delete'}
form_content = {$smarty.capture.tax_delete_dialog nofilter}
}
{* -- Add tax rule confirmation dialog ----------------------------------- *}
{form name="thelia.admin.taxrule.add"}
{if $form_error_message}
{$taxRuleCreateError = true}
{else}
{$taxRuleCreateError = false}
{/if}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "tax_rule_create_dialog"}
@@ -154,15 +313,31 @@
{block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-select/bootstrap-select.js'}
<script src='{$asset_url}'></script>
{/javascripts}
{javascripts file='assets/js/main.js'}
<script src='{$asset_url}'></script>
{/javascripts}
<script type="text/javascript">
{if $taxCreateError == true}
{if $taxRuleCreateError == true}
$('#tax_rule_create_dialog').modal();
{/if}
{if $taxCreateError == true}
$('#tax_create_dialog').modal();
{/if}
$(".js-delete-tax-rule").click(function(e){
$('#tax_rule_delete_id').val($(this).data('id'))
});
$(".js-delete-tax").click(function(e){
$('#tax_delete_id').val($(this).data('id'))
});
</script>
{/block}

View File

@@ -46,6 +46,4 @@
</aside>
</div>
</div><!-- /.container -->
{/block}

View File

@@ -3,25 +3,28 @@
<div class="block-content">
<nav class="nav-categories">
<ul id="category" class="accordion">
{assign "previousLevel" 0}
{loop name="cat-parent" type="category-tree" category="0"}
{assign "previousLevel" 0}
{loop name="cat-parent" type="category-tree" category="0"}
{for $foo=1 to $previousLevel-$LEVEL}
</ul>
</li>
{for $foo=1 to $previousLevel-$LEVEL}
</ul>
</li>
{/for}
{if $CHILD_COUNT > 0 }
<li><a class="accordion-toggle" data-toggle="collapse" data-parent="#category" href="{$URL}#collapse{$ID}">{$TITLE} <span class="amount">({$CHILD_COUNT})</span></a>
<li>
<a class="accordion-toggle" data-toggle="collapse" data-parent="#category" href="{$URL}#collapse{$ID}">{$TITLE} <span class="amount">({$CHILD_COUNT})</span></a>
<ul id="collapse{$ID}" class="collapse">
{else}
<li><a href="{$URL}">{$TITLE} <span class="amount">(0)</span></a></li>
{/if}
{assign "previousLevel" $LEVEL}
{/loop}
{else}
<li><a href="{$URL}">{$TITLE} <span class="amount">(0)</span></a></li>
{/if}
{assign "previousLevel" $LEVEL}
{/loop}
{for $i=$previousLevel to 1 step -1}
</ul>
</li>
{/for}
</ul>
</nav>
</div>
</section>
</section>