【问题标题】:Is there a way to refresh Magento *Catalog* (not Shopping Cart) prices with a Coupon code?有没有办法使用优惠券代码刷新 Magento *Catalog*(不是购物车)价格?
【发布时间】:2011-01-31 23:06:00
【问题描述】:

在这里和谷歌中一直在搜索类似的问题,我很惊讶我找不到任何类似的东西。

我熟悉客户组和分层定价,但它不符合我的客户设定的目标。

我们想要的是让用户来到我们的 Magento 商店并以正常价格查看常规主页。此时,我们希望有一个突出的文本字段供用户添加优惠券代码,网站将刷新并显示新的折扣价格,其中常规价格被删除(或通过其他视觉方法“削减”。

客户组/分层定价不是解决方案,因为它们要求客户登录。未登录组也无济于事,因为所有用户都会看到折扣。

这也不能在购物车中发生,因为到那时已经太晚了,这需要在目录级别发生。

我们目前正在使用 OSCommerce 并很快过渡到 Magento。现在我们正在做的模拟这种行为是在我们的常规网站上的商店访问页面上有一个文本字段,用户可以在其中单击一个区域或输入优惠券代码。如果他们输入代码,他们将被重定向到具有特价的定制商店。

我知道通过创建商店视图然后使用相同的功能可以很容易地在 Magento 中重新创建我们当前的方法,但是当考虑迁移到功能强大得多的新平台时这样做似乎很可惜。

我还没有看到任何扩展程序可以做到这一点。有没有人知道这样的事情是否可以实现,如果可以,如何实现?

【问题讨论】:

    标签: magento catalog discounts


    【解决方案1】:

    我很好奇 Jonathon 你是怎么做到的,我没有采用你的方法,我的方法有点复杂。我的确实允许有人在 url 中发布优惠券代码,但我设置了一个 cookie 和所有这些。我基本上在标题中设置了我自己的表单,用户可以输入优惠券代码并应用它,并将优惠券放在电子邮件活动的 url 中。

    我需要一段时间才能详细回顾它,所以我将发布一些代码 sn-ps,也许可以帮助您继续前进,也可以尝试 Jonathan 所说的方式。

    覆盖购物车控制器并添加您自己的操作。

     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 中的 collect 方法

    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;
    }
    

    【讨论】:

    • 很适合发布所有代码@Dan。我会非常担心覆盖 Cart 控制器和 couponPostAction 方法。这意味着任何未来的 Magento 升级或补丁都可能由于您的自定义而破坏该站点。如果可以避免,我建议永远不要覆盖控制器(事件观察者更可取)。我将尝试在我的解决方案上发布更多信息,以演示如何避免覆盖关键控制器。
    • 我第一次进入 Magento 时就这样做了,所以我现在可能会做不同的事情。至于这种情况,它是针对特定客户的,据了解,如果我们要进行升级,则必须在发布前进行彻底的 QA 测试,但我想这是不言而喻的。
    • 一切都好,听起来你已经控制住了,我只是想为那些可能是 Magento 新手阅读解决方案的人指出这些问题 :)
    【解决方案2】:

    这绝对可以实现。它涉及编写一个自定义模块(启动herehere),其中的控制器接受您的优惠券字段的值,为该用户($session = Mage::getSingleton('checkout/session'))启动结帐会话并将优惠券代码存储在结帐会话中( $session-&gt;setData('coupon_code',$coupon)。

    然后您将扩展价格模型以在会话中检查优惠券代码。您可以使用&lt;rewrite&gt; 语法在您自己的模块中覆盖Mage_Catalog_Model_Product_Type_Price。检索优惠券代码 ($couponCode = Mage::getSingleton("checkout/session")-&gt;getData("coupon_code");)。请注意,对于 Bundle 和其他非简单产品类型,Price 对象是不同的。

    如果您需要更多信息,我可以发布代码示例。

    【讨论】:

    • 这样的事情有多复杂?我对 Magento 非常熟悉(40 小时),虽然我了解 MVC 范例,但(玩 CodeIgniter 的一天)我还处于初学者水平。作为程序员,呵呵。但是,无论成功还是失败,我都非常愿意学习并尽一切努力,但是鉴于我的“个人资料”,您认为我是否可以尝试咬掉它?我绝不是要求别人为我做这件事。如果我在此过程中得到一些指导,我只是想弄清楚我是否有合法的机会完成这项工作。代码示例会很棒!
    • 它比较复杂,但我建议如果您打算在中长期使用 Magento,这是一个很好的开始项目。它将使用您熟悉的概念向您介绍 Magento 的代码结构。 Magento 确实有一个学习曲线(很多人为此抱怨),但是一旦你熟悉了它,它的架构实际上是优雅且高度可重复的。
    • 我最近做了一个有不同需求的小项目,但我使用了类似的方法。为此,我肯定会遵循乔纳森的建议。我还要说,如果您需要进行一些自定义增强(例如这个),那么您与 Magento 的旅程将是一个漫长而动荡的旅程。 Magento 具有极大的可配置性,并且可以为“轻松”定制而扩展。唯一的问题是,其中一些简单的定制最终会让人头疼,而且需要很长时间。这就是为什么 Jonathan 说你真的需要长期致力于 Magento。
    猜你喜欢
    • 1970-01-01
    • 2013-07-16
    • 2017-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多