Мне любопытно, Джонатон, как ты это сделал, я не выбрал твой подход, мой немного сложнее.Мой действительно позволяет кому-то также разместить код купона в URL, и я установил cookie и все это для него.Я в основном настраиваю свою собственную форму в заголовке, которую пользователь может ввести в код купона, и он будет применяться, а также помещать купон в URL для кампаний по электронной почте.
Мне потребовалось бы некоторое время, чтобы подробно остановиться на нем, поэтому я опубликую некоторые фрагменты кода, которые, возможно, могут помочь вам начать работу, долгое время пытаясь понять, как говорит Джонатан.
Переопределите контроллер корзины и добавьте свое собственное действие.
public function couponExternalPostAction()
{
$quote = $this->_getQuote();
$couponCode = (string) $this->getRequest()->getParam('coupon_code');
$validateCoupon = Mage::getModel('package_module/coupon');
$json = $validateCoupon->addCouponCode($couponCode, $quote, $this->getRequest());
echo $json;
return;
}
Мне также пришлось переопределить couponPostAction (), чтобы все работало нормально, как обычно.
У меня есть addCouponметод в моей собственной модели
public function addCouponCode($code, $quote, $request){
$couponCode = (string) $code;
$removed = false;
if ($request->getParam('remove') == 1) {
$couponCode = '';
$removed = true;
}
$oldCouponCode = $quote->getCouponCode();
/* No point in applying the rule again if it is the same coupon code that is in the quote */
if ($couponCode === $oldCouponCode) {
$json = $this->_getResponseJson($removed, $couponCode, $quote, false, true);
return $json;
}
// Set the code get the rule base on validation even if it doesn't validate (false), which will also add it to the session, then get our response
$quote->setCouponCode(strlen($couponCode) ? $couponCode : '');
$rule = $this->_validateCoupon($quote,$couponCode);
// add coupon code to cookie, so we can delete from quote if the user closes their browser and comes back
if($rule && !$removed){
Mage::getModel('core/cookie')->set('coupon_code', $couponCode, 0, '/', null, null, null, false);
}else{
Mage::getModel('core/cookie')->delete('coupon_code');
}
$json = $this->_getResponseJson($removed, $couponCode, $quote, $rule);
//See if the quote id is set before saving
$quoteId = $quote->getQuoteId();
//Save the quote since everything has been set if not the data wont be set on page refresh
$quote->save();
//Set the quote id if it wasn't set before saving the quote. This makes sure we work off the same quote and a new one isn't created.
if(empty($quoteId)){
$this->_setQuoteId($quote);
}
return $json;
}
Проверка купона
protected function _validateCoupon($quote,$couponCode){
$store = Mage::app()->getStore($quote->getStoreId());
$validator = Mage::getModel('package_module/validator');
$validator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode());
return $validator->isValidExternalCode($couponCode, $quote->getShippingAddress(),false);
}
Я расширил Mage_SalesRule_Model_Validator
с помощью собственной функции проверки
public function isValidExternalCode($couponCode, $address, $setCoupon = true){
foreach ($this->_getRules() as $rule) {
if ($rule->getCode() && (in_array(strtolower($couponCode),explode(',',strtolower($rule->getCode()))))) {
if($setCoupon){
$address->setCouponCode($couponCode);
}
return $rule;
}
}
return false;
}
Здесь я генерирую jsonответ
rotected function _getResponseJson($removed, $couponCode, $quote, $rule = false, $isDup = false){
$json = '{"Response":{';
if($removed){
$json .= '"success":"Promotional code was cancelled successfully."';
Mage::getSingleton('checkout/session')->setData('coupon_rule',null);
}
if(!$removed && $isDup){
$json .= '"error":"' . $couponCode . ' is already applied"';
}else if(!$removed && $rule){
$json .= '"success":"Promotional code ' . $couponCode . ' has been applied",';
$json .= '"couponMessage":"<span>' . $rule->getName() . '</span>"';
Mage::getSingleton('checkout/session')->setData('coupon_rule','<span>' . $rule->getName() .'</span>');
}else if(!$removed){
$json .= '"error":"' . $couponCode . ' is not valid"';
$quote->setCouponCode('');
}
$json .= '}}';
return $json;
}
Мне также пришлось переопределить метод сбора в Mage_SalesRule_Model_Quote_Discount
public function collect(Mage_Sales_Model_Quote_Address $address)
{
Mage_Sales_Model_Quote_Address_Total_Abstract::collect($address);
$quote = $address->getQuote();
$store = Mage::app()->getStore($quote->getStoreId());
$eventArgs = array(
'website_id' => $store->getWebsiteId(),
'customer_group_id' => $quote->getCustomerGroupId(),
'coupon_code' => $quote->getCouponCode(),
);
$this->_calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode());
$items = $address->getAllItems();
/* EDITS
* Moved the if statement for no items in cart down past these previous methods and then if the address type is shipping and the coupon is set
* add the coupon code to the address to allow the validation to still pick up the coupon code
*/
if($quote->getCouponCode() && ($address->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_SHIPPING)){
$address->setCouponCode($quote->getCouponCode());
}
if (!count($items)) {
return $this;
}
$address->setDiscountDescription(array());
foreach ($items as $item) {
if ($item->getNoDiscount()) {
$item->setDiscountAmount(0);
$item->setBaseDiscountAmount(0);
}
else {
/**
* Child item discount we calculate for parent
*/
if ($item->getParentItemId()) {
continue;
}
$eventArgs['item'] = $item;
Mage::dispatchEvent('sales_quote_address_discount_item', $eventArgs);
if ($item->getHasChildren() && $item->isChildrenCalculated()) {
foreach ($item->getChildren() as $child) {
$this->_calculator->process($child);
$eventArgs['item'] = $child;
Mage::dispatchEvent('sales_quote_address_discount_item', $eventArgs);
$this->_aggregateItemDiscount($child);
}
} else {
$this->_calculator->process($item);
$this->_aggregateItemDiscount($item);
}
}
}
/**
* Process shipping amount discount
*/
$address->setShippingDiscountAmount(0);
$address->setBaseShippingDiscountAmount(0);
if ($address->getShippingAmount()) {
$this->_calculator->processShippingAmount($address);
$this->_addAmount(-$address->getShippingDiscountAmount());
$this->_addBaseAmount(-$address->getBaseShippingDiscountAmount());
}
$this->_calculator->prepareDescription($address);
return $this;
}