Added Attribute value related coupons

This commit is contained in:
Franck Allimant
2014-06-12 13:14:07 +02:00
parent 147d4a70f1
commit db29505fee
7 changed files with 507 additions and 0 deletions

View File

@@ -51,6 +51,24 @@
<tag name="thelia.coupon.addCoupon"/>
</service>
<service id="thelia.coupon.type.remove_percentage_on_products" class="Thelia\Coupon\Type\RemovePercentageOnProducts">
<argument type="service" id="thelia.facade" />
<tag name="thelia.coupon.addCoupon"/>
</service>
<service id="thelia.coupon.type.remove_amount_on_attribute_av" class="Thelia\Coupon\Type\RemoveAmountOnAttributeValues">
<argument type="service" id="thelia.facade" />
<tag name="thelia.coupon.addCoupon"/>
</service>
<service id="thelia.coupon.type.remove_percentage_on_attribute_av" class="Thelia\Coupon\Type\RemovePercentageOnAttributeValues">
<argument type="service" id="thelia.facade" />
<tag name="thelia.coupon.addCoupon"/>
</service>
<!-- Condition module -->

View File

@@ -0,0 +1,174 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Coupon\Type;
use Thelia\Core\Translation\Translator;
use Thelia\Coupon\FacadeInterface;
use Thelia\Model\AttributeCombination;
use Thelia\Model\CartItem;
/**
* The base class to process a discount related to Attribute values.
*
* @package Coupon
* @author Franck Allimant <franck@cqfdev.fr>
*/
abstract class AbstractRemoveOnAttributeValues extends CouponAbstract
{
const ATTRIBUTES_AV_LIST = 'attribute_avs';
const ATTRIBUTE = 'attribute_id';
public $attributeAvList = array();
public $attribute = 0;
/**
* Set the value of specific coupon fields.
* @param Array $effects the Coupon effects params
*/
protected abstract function setFieldsValue($effects);
/**
* Get the discount for a specific cart item.
*
* @param CartItem $cartItem the cart item
* @return float the discount value
*/
protected abstract function getCartItemDiscount($cartItem);
/**
* @inheritdoc
*/
public function set(
FacadeInterface $facade,
$code,
$title,
$shortDescription,
$description,
array $effects,
$isCumulative,
$isRemovingPostage,
$isAvailableOnSpecialOffers,
$isEnabled,
$maxUsage,
\DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules,
$perCustomerUsageCount
)
{
parent::set(
$facade, $code, $title, $shortDescription, $description, $effects,
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
$freeShippingForCountries,
$freeShippingForModules,
$perCustomerUsageCount
);
$this->attributeAvList = isset($effects[self::ATTRIBUTES_AV_LIST]) ? $effects[self::ATTRIBUTES_AV_LIST] : array();
if (! is_array($this->attributeAvList)) $this->attributeAvList = array($this->attributeAvList);
$this->attribute = isset($effects[self::ATTRIBUTE]) ? $effects[self::ATTRIBUTE] : 0;
$this->setFieldsValue($effects);
return $this;
}
/**
* @inheritdoc
*/
public function exec()
{
// This coupon subtracts the specified amount from the order total
// for each product which uses the selected attributes
$discount = 0;
$cartItems = $this->facade->getCart()->getCartItems();
/** @var CartItem $cartItem */
foreach ($cartItems as $cartItem) {
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
$productSaleElements = $cartItem->getProductSaleElements();
$combinations = $productSaleElements->getAttributeCombinations();
/** @var AttributeCombination $combination */
foreach ($combinations as $combination) {
$attrValue = $combination->getAttributeAvId();
if (in_array($attrValue, $this->attributeAvList)) {
$discount += $this->getCartItemDiscount($cartItem);
break;
}
}
}
}
return $discount;
}
/**
* @inheritdoc
*/
public function drawBaseBackOfficeInputs($templateName, $otherFields)
{
return $this->facade->getParser()->render($templateName, array_merge($otherFields, [
// The attributes list field
'attribute_field_name' => $this->makeCouponFieldName(self::ATTRIBUTE),
'attribute_value' => $this->attribute,
// The attributes list field
'attribute_av_field_name' => $this->makeCouponFieldName(self::ATTRIBUTES_AV_LIST),
'attribute_av_values' => $this->attributeAvList
]));
}
/**
* @inheritdoc
*/
protected function getBaseFieldList($otherFields)
{
return array_merge($otherFields, [self::ATTRIBUTE, self::ATTRIBUTES_AV_LIST]);
}
/**
* @inheritdoc
*/
protected function checkBaseCouponFieldValue($fieldName, $fieldValue)
{
if ($fieldName === self::ATTRIBUTE) {
if (empty($fieldValue)) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
'Please select an attribute'
)
);
}
} elseif ($fieldName === self::ATTRIBUTES_AV_LIST) {
if (empty($fieldValue)) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
'Please select at least one attribute value'
)
);
}
}
return $fieldValue;
}
}

View File

@@ -0,0 +1,108 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Coupon\Type;
use Thelia\Core\Translation\Translator;
/**
* Allow to remove an amount from the checkout total
*
* @package Coupon
* @author Franck Allimant <franck@cqfdev.fr>
*/
class RemoveAmountOnAttributeValues extends AbstractRemoveOnAttributeValues
{
/** @var string Service Id */
protected $serviceId = 'thelia.coupon.type.remove_amount_on_attribute_av';
/**
* @inheritdoc
*/
protected function setFieldsValue($effects) {
// Nothing to do, the amount is processed by CouponAbstract.
}
/**
* @inheritdoc
*/
public function getCartItemDiscount($cartItem) {
return $cartItem->getQuantity() * $this->amount;
}
/**
* @inheritdoc
*/
public function getName()
{
return $this->facade
->getTranslator()
->trans('Fixed amount discount for selected attribute values', array(), 'coupon');
}
/**
* @inheritdoc
*/
public function getToolTip()
{
$toolTip = $this->facade
->getTranslator()
->trans(
'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
array(),
'coupon'
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->drawBaseBackOfficeInputs('coupon/type-fragments/remove-amount-on-attributes.html', [
'amount_field_name' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
'amount_value' => $this->amount
]);
}
/**
* @inheritdoc
*/
protected function getFieldList()
{
return $this->getBaseFieldList([self::AMOUNT_FIELD_NAME]);
}
/**
* @inheritdoc
*/
protected function checkCouponFieldValue($fieldName, $fieldValue)
{
$this->checkBaseCouponFieldValue($fieldName, $fieldValue);
if ($fieldName === self::AMOUNT_FIELD_NAME) {
if (floatval($fieldValue) < 0) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
'Value %val for Discount Amount is invalid. Please enter a positive value.',
[ '%val' => $fieldValue]
)
);
}
}
return $fieldValue;
}
}

View File

@@ -0,0 +1,114 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Thelia\Coupon\Type;
use Thelia\Core\Translation\Translator;
/**
* Allow to remove an amount from the checkout total
*
* @package Coupon
* @author Franck Allimant <franck@cqfdev.fr>
*/
class RemovePercentageOnAttributeValues extends AbstractRemoveOnAttributeValues
{
const PERCENTAGE = 'percentage';
public $percentage = 0;
/** @var string Service Id */
protected $serviceId = 'thelia.coupon.type.remove_percentage_on_attribute_av';
/**
* @inheritdoc
*/
protected function setFieldsValue($effects) {
$this->percentage = $effects[self::PERCENTAGE];
}
/**
* @inheritdoc
*/
public function getCartItemDiscount($cartItem) {
return $cartItem->getQuantity() * $cartItem->getPrice() * $this->percentage;
}
/**
* @inheritdoc
*/
public function getName()
{
return $this->facade
->getTranslator()
->trans('Percentage discount for selected attribute values', array(), 'coupon');
}
/**
* @inheritdoc
*/
public function getToolTip()
{
$toolTip = $this->facade
->getTranslator()
->trans(
'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
array(),
'coupon'
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->drawBaseBackOfficeInputs('coupon/type-fragments/remove-percentage-on-attributes.html', [
'percentage_field_name' => $this->makeCouponFieldName(self::PERCENTAGE),
'percentage_value' => $this->percentage,
]);
}
/**
* @inheritdoc
*/
protected function getFieldList()
{
return $this->getBaseFieldList([self::PERCENTAGE]);
}
/**
* @inheritdoc
*/
protected function checkCouponFieldValue($fieldName, $fieldValue)
{
$this->checkBaseCouponFieldValue($fieldName, $fieldValue);
if ($fieldName === self::PERCENTAGE) {
$pcent = floatval($fieldValue);
if ($pcent <= 0 || $pcent > 100) {
throw new \InvalidArgumentException(
Translator::getInstance()->trans(
'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.',
[ '%val' => $fieldValue]
)
);
}
}
return $fieldValue;
}
}

View File

@@ -0,0 +1,63 @@
{block name="discount-field"}{/block}
<div class="form-group input-coupon-attribute-id">
<label for="coupon-category-id">{intl l="Select attribute :"} = {$attribute_value}</label>
<select required class="form-control" id="coupon-attribute-id" name="{$attribute_field_name}">
<option value="0">{intl l="Please select..."}</option>
{loop type="attribute" name="list-of-attributes" order="alpha" backend_context="1"}
<option value="{$ID}" {if $ID == $attribute_value}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
</div>
<div class="loading" id="input-coupon-attributeAvs-id-loading" style="display: none"></div>
<div class="form-group" id="input-coupon-attributeAvs-id" {if $attribute_value == 0}style="display: none"{/if}>
<label for="coupon-products-id">{intl l="Applies to attribute values :"}</label>
<select required multiple size="10" class="form-control" id="coupon-attributeAvs-id" name="{$attribute_av_field_name}[]">
{loop type="attribute_availability" attribute=$attribute_value name="list-of-attribute_avs" backend_context="1"}
<option value="{$ID}" {if in_array($ID, $attribute_av_values)}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
<span class="label-help-block">{intl l='Use Ctrl+click to select (or deselect) more that one attribute value'}</span>
</div>
<script>
function couponInputFormSetup() {
var $catSelect = $('#coupon-attribute-id');
$catSelect.change(function(ev) {
var $attribute_id = $(this).val();
$('#input-coupon-attributeAvs-id').hide();
$('#coupon-attributeAvs-id').html('');
if ($attribute_id != 0) {
$('#input-coupon-attributeAvs-id-loading').show();
$.ajax({
url: "{url path='/admin/coupon/type-fragments/ajax-attribute-avs-list'}",
type: 'POST',
data: {
attribute_id: $attribute_id
},
success: function(options) {
$('#coupon-attributeAvs-id').html(options);
$('#input-coupon-attributeAvs-id').show();
},
complete: function() {
$('#input-coupon-attributeAvs-id-loading').hide();
}
});
}
});
};
</script>

View File

@@ -0,0 +1,16 @@
{extends file="coupon/type-fragments/base-remove-on-attributes.html"}
{block name="discount-field"}
<div class="form-group input-coupon-amount">
<label for="coupon-amount" class="control-label">{intl l="Discount amount"}</label>
<div class="input-group">
<input id="coupon-amount" type="money" class="form-control" name="{$amount_field_name}" value="{$amount_value}" placeholder="14.50">
{loop type="currency" name="get-symbol" default_only="true"}
<div class="input-group-addon">{$SYMBOL}</div>
{/loop}
</div>
</div>
{/block}

View File

@@ -0,0 +1,14 @@
{extends file="coupon/type-fragments/base-remove-on-attributes.html"}
{block name="discount-field"}
<div class="form-group input-coupon-percentage">
<label for="coupon-percentage" class="control-label">{intl l="Discount percentage"}</label>
<div class="input-group">
<input id="coupon-percentage" type="number" class="form-control" name="{$percentage_field_name}" value="{$percentage_value}" placeholder="5">
<div class="input-group-addon">%</div>
</div>
</div>
{/block}