Merge branch 'tax'

This commit is contained in:
Etienne Roudeix
2013-10-16 12:03:31 +02:00
42 changed files with 1496 additions and 76 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

@@ -118,6 +118,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

@@ -0,0 +1,198 @@
<?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();
$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"
);
}
}

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,45 @@
<?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'),
));
}
/**
* {@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 'form';
}
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

@@ -152,11 +152,13 @@ class Tax extends BaseI18nLoop
$loopResultRow = new LoopResultRow($loopResult, $tax, $this->versionable, $this->timestampable, $this->countable);
$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("SERIALIZED_REQUIREMENTS" , $tax->getSerializedRequirements())
->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"]);
@@ -143,18 +154,51 @@ class Form extends AbstractSmartyPlugin
$template->assign("attr", implode(" ", $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 +229,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 +342,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 +422,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,94 @@
<?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 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(
"methods" => array(
array($this, "verifyTaxId"),
),
),
"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";
}
}

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

@@ -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

@@ -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

@@ -44,4 +44,14 @@ class AnyType implements TypeInterface
{
return $value;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -124,4 +124,14 @@ class IntToCombinedIntsListType implements TypeInterface
return true;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -124,4 +124,14 @@ class IntToCombinedStringsListType implements TypeInterface
return true;
}
public function getFormType()
{
return 'text';
}
public function getFormOptions()
{
return array();
}
}

View File

@@ -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

@@ -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

@@ -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

@@ -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

@@ -35,4 +35,7 @@ interface TypeInterface
public function isValid($value);
public function getFormattedValue($value);
public function getFormType();
public function getFormOptions();
}

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} :
</label>
{if $formType == 'choice'}
<select name="{$name}">
{foreach $choices as $choice}
<option value="{$choice->value}">{$choice->label}</option>
{/foreach}
</select>
{/if}
{if $formType == 'text'}
<input type="text" name="{$name}" value="">
{/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}