#StackBounty: #magento2 #admin #blocks Magento 2 : Counter Reset From Admin

Bounty: 50

I have simple code to run countdown, my phtml file
Counter.phtml


    require([
        'jquery',
        'circularCountDown',
        'domReady!'
    ], function($) {
        $('.timer').circularCountDown({

            size: 250,
            borderSize: 10,
            colorCircle: '#de7546',
            background: '#947769',
            fontFamily: 'sans-serif',
            fontColor: '#333333',
            fontSize: 20,
            delayToFadeIn: 0,
            delayToFadeOut: 0,
            reverseLoading: false,
            reverseRotation: false,
            duration: {
                hours: 5,
                minutes: 0,
                seconds: 0
            },
            beforeStart: function(){},
            end: function(){}
        });

    });

circular-countdown.js

define([
    'jquery'
], function($) {

    var defaultOptions = {
        size: 60,
        borderSize: 10,
        colorCircle: 'gray',
        background: 'white',
        fontFamily: 'sans-serif',
        fontColor: '#333333',
        fontSize: 16,
        delayToFadeIn: 0,
        delayToFadeOut: 0,
        reverseLoading: false,
        reverseRotation: false,
        duration: {
            hours: 0,
            minutes: 0,
            seconds: 10
        },
        beforeStart: function(){},
        end: function(){}
    };

    $.fn.circularCountDown = function (options) {
        new CircularCountDown(options, $(this));
    };

    function CircularCountDown(data, element) {
        this.element = element;
        this.data = jQuery.extend(true, defaultOptions, data);
        this.init();
    }

    CircularCountDown.prototype = {

        init: function () {
            this.formatData();
            this.draw();
            this.start();
        },
        start: function () {
            if (typeof this.data.beforeStart == "function") {
                this.data.beforeStart(this);
            }
            this.show();
            this.starDecrementTimeEvent();
            var time = this.getFormattedTimeByCircle();
            this.animate(time);
        },
        animate: function(time) {
            var that = this;

            if (!that.data.reverseLoading) {
                that.wrapperCircles.css(
                    'clip',
                    'rect(0px, ' + that.data.size + 'px, ' + that.data.size + 'px, ' + (that.data.size / 2) + 'px)'
                );
                that.rotate(that.circlelRight, 0, 180, time, function () {
                    that.wrapperCircles.css('clip', 'rect(auto, auto, auto, auto)');
                    that.rotate(that.circlelLeft, 180, 360, time);
                });
            } else {
                that.rotate(that.circlelRight, 180, 360, time, function() {
                    that.wrapperCircles.css(
                        'clip',
                        'rect(0px, ' + (that.data.size / 2) + 'px, ' + that.data.size + 'px, 0px)'
                    );
                    that.rotate(that.circlelLeft, 0, 180, time);
                    that.rotate(that.circlelRight, 0, 180, time);
                });
            }
        },
        formatData: function () {
            this.time =
                this.data.duration.seconds +
                (this.data.duration.minutes * 60) +
                (this.data.duration.hours * 3600)
            ;
            this.data.size = parseInt(this.data.size);
            this.data.borderSize = parseInt(this.data.borderSize);

            if (this.data.borderSize % 2 != 0) {
                this.data.borderSize++;
            }

            if (this.data.size % 2 != 0) {
                this.data.size++;
            }
        },
        draw: function () {
            this.hide();
            this.circlelLeft = this.drawCircle().addClass('coutndown-circle-left');
            this.circlelRight = this.drawCircle().addClass('coutndown-circle-right');
            this.wrapperCircles = $('<div>')
                .addClass('coutndown-wrapper')
                .css({
                    'width': this.data.size + 'px',
                    'height': this.data.size + 'px',
                    'position': 'absolute',
                })
                .append(this.circlelLeft)
                .append(this.circlelRight)
            ;
            this.wrapperTime = this.drawTime();
            this.element
                .css({
                    'position': 'relative',
                    'box-sizing': 'content-box'
                })
                .append(this.wrapperCircles)
                .append(this.wrapperTime)
            ;
            this.setTime(this.getStringTime(this.time));
        },
        drawCircle: function () {
            var size = this.data.size - (this.data.borderSize * 2);
            size += 'px';
            return $('<div>')
                .addClass('coutndown-circle')
                .css({
                    'width': size,
                    'height': size,
                    'border': this.data.borderSize + 'px solid ' + this.data.colorCircle,
                    '-moz-border-radius': this.data.size + 'px',
                    '-webkit-border-radius': this.data.size + 'px',
                    '-o-border-radius': this.data.size + 'px',
                    '-ms-border-radius': this.data.size + 'px',
                    'border-radius': this.data.size + 'px',
                    'box-sizing': 'content-box',
                    'background-color': this.data.background,
                    'position': 'absolute',
                    'clip': 'rect(0px, ' + (this.data.size / 2) + 'px, ' + this.data.size + 'px, 0px)'
                });
        },
        rotate: function (elem, startAngle, endAngle, duration, complete) {
            $({deg: startAngle}).animate({deg: endAngle}, {
                duration: duration,
                easing: 'linear',
                step: function (now) {
                    elem.css({
                        '-moz-transform': 'rotate(' + now + 'deg)',
                        '-webkit-transform': 'rotate(' + now + 'deg)',
                        '-o-transform': 'rotate(' + now + 'deg)',
                        '-ms-transform': 'rotate(' + now + 'deg)',
                        'transform': 'rotate(' + now + 'deg)'
                    });
                },
                complete: complete || $.noop
            });
        },
        hide: function () {
            this.element.fadeOut(this.data.delayToFadeOut);
            this.visible = false;
        },
        show: function () {
            this.element.fadeIn(this.data.delayToFadeIn);
            this.visible = true;
        },
        isVisible: function () {
            return this.visible;
        },
        getStringTime: function (time) {
            var duration = this.secondsToTime(time);

            if (duration.h > 0) {
                return this.addDigit(duration.h) + ':' + this.addDigit(duration.m) + ':' + this.addDigit(duration.s);
            }
            if (duration.m > 0) {
                return this.addDigit(duration.m) + ':' + this.addDigit(duration.s);
            }
            return this.addDigit(duration.s);
        },
        addDigit: function (number) {
            return ("0" + number).slice(-2);
        },
        secondsToTime: function (time) {
            var hours = Math.floor(time / (60 * 60));
            var divisor_for_minutes = time % (60 * 60);
            var minutes = Math.floor(divisor_for_minutes / 60);
            var divisor_for_seconds = divisor_for_minutes % 60;
            var seconds = Math.ceil(divisor_for_seconds);
            return {
                h: hours,
                m: minutes,
                s: seconds
            };
        },
        getFormattedTimeByCircle: function () {
            var time = this.time / 2 * 1000;

            if (time % 2 != 0) {
                time++;
            }
            return time;
        },
        starDecrementTimeEvent: function () {
            var that = this;
            this.decrementTimeEvent = setInterval(function () {
                that.time -= 1;
                that.setTime(that.getStringTime(that.time));
                if (that.time <= 0) {
                    that.time = 0;
                    that.stopDecrementTimeEvent();

                    if (typeof that.data.end == "function") {
                        that.data.end(that);
                    }
                }
            }, 1000);
        },
        stopDecrementTimeEvent: function () {
            clearInterval(this.decrementTimeEvent);
        },
        drawTime: function () {
            return $('<div>')
                .addClass('coutndown-wrapper-time')
                .css({
                    'position': 'absolute',
                    'height': this.data.size + 'px',
                    'width': this.data.size + 'px',
                    'line-height': this.data.size + 'px',
                    'text-align': 'center',
                    'font-size': this.data.fontSize + 'px',
                    'font-family': this.data.fontFamily,
                    'color': this.data.fontColor
                })
                ;
        },
        setTime: function (time) {
            this.wrapperTime.html(time);
        },
        destroy: function() {
            this.hide();
            this.element.html('').attr('style', null);
            this.circlelLeft = null;
            this.circlelRight = null;
            this.wrapperCircles = null;
            this.element = null;
            this.data = defaultOptions;
        }
    };
    return CircularCountDown;
});

I want add button in admin to reset this counter?
How can I do this?


Get this bounty!!!

#StackBounty: #magento2 #magento2.2 #mini-cart Custom "add to cart" button not updating minicart

Bounty: 50

I’ve added a custom “add to cart” button by overwriting the configurable.phtml file in my theme.

The button adds the product to the cart, however it doesn’t seem to show up in the minicart –

Minicart

Looking at the newtwork tab, it doesn’t seem to pick up any actual items –

Network tab

Whereas using the default template it passes stuff over in this –

enter image description here

Am I missing something in passing over this data?

I’m essentially changing the configurables from showing in a drop down menu, to having each simple product have an “add to basket” button on the page.

I’ve tried both adding to cart with AJAX and with refreshing the page, but neither seems to work. Once you go to the actual cart page, you can see what these items are – it’s just the minicart that isn’t displaying the items.

I’m also including the

 
        {
            "#product_addtocart_form": {
                "configurable": {
                    "spConfig": getJsonConfig() ?>,
                    "gallerySwitchStrategy": "getVar('gallery_switch_strategy',
            'Magento_ConfigurableProduct') ?: 'replace'; ?>"
                }
            }
        }
    

On the page, which has all the simple product details in JSON.

Here is a code excerpt of how i’m displaying / using the buy now button on my custom template –

<?php
        foreach ($_children as $child) :
            $productName = $child->getName();

            if ( strpos($productName, '-UK') !== false ) :
        ?>

        
getPrice(); echo $this->helper('MagentoFrameworkPricingHelperData')->currency($price,true,false); $productID = $child->getId(); ?>
getAttributeText('subscription_terms'); ?>
</div>
Buy Now getViewFileUrl('images/logos/logo_direct-debit.png'); ?>" />
getAddUrl($child);?>" method="post"> getBlockHtml("formkey");?>
  • MaestrogetViewFileUrl('images/logos/logo_maestro.png'); ?>" />
  • MastercardgetViewFileUrl('images/logos/logo_mastercard.png'); ?>" />
  • Verified by VisagetViewFileUrl('images/logos/logo_verified-by-visa.png'); ?>" />
  • PayPalgetViewFileUrl('images/logos/logo_paypal.png'); ?>" />
</div> <?php endif; endforeach; ?>

I’m doing a FOREACH on each simple assigned to the configurable, doing an IF to make sure the SKU is of a certain type and then outputting a Add to cart button for each one.

enter image description here

To get around another problem with the first item not actually going in the basket, I had to add an empty form –

  <form type="hidden" data-role="tocart-form" action=""  method="post"> <?php echo $block->getBlockHtml("formkey");?>
            <input type="hidden" name="product" value="">
            <input type="hidden" name="selected_configurable_option" value="">
        </form>

Could this be the cause of it?


Get this bounty!!!

#StackBounty: #magento2 #magento2.2 #controllers #redirect Automatic redirection Controller

Bounty: 50

I am creating a controller extending MagentoCustomerControllerAbstractAccount but it automatically get redirected to http://example.com/customer/account/login/ how can I stop that.
basically all the controller under Magento_customer/Controller/Account are extended by MagentoCustomerControllerAbstractAccount

but some are redirecting same as mine,like

Magento_customer/Controller/Account/index.php

while some are not redirected, like

Magento_customer/Controller/Account/create.php

Controller code

<?php
namespace VendorModuleControllerAccount;

class ControllerName extends MagentoCustomerControllerAbstractAccount
{
    public function execute()
    {
        echo "Test";
    }
}


Get this bounty!!!

#StackBounty: #magento2 #attributes #orders #search-criteria Magento 2 API: Filter orders by extension attribute

Bounty: 100

I have an extension with an attribute assigned to order items called warehouse.
I can see this attribute under the property “extension_attributes“.
I need to filter orders based on this attribute. I can’t find any documentation on how to do this.

Example API response snippet:

[items] => Array(
    [0] => Array(
        [extension_attributes] => Array(
            [warehouse] => MyWarehouse
        )
    )
)

The following filter generates an internal error:

searchCriteria[filter_groups][2][filters][0][field]=warehouse,searchCriteria[filter_groups][2][filters][0][value]=mywarehouse,searchCriteria[filter_groups][2][filters][0][condition_type]=eq

Any suggestions on how I can filter orders using the warehouse attribute via the API?

– Additional point on this question:

In this case, if we will follow Fooman blog.Then can we filter the collection by the extension* attribute?

  • Collection filter by this extension Attribute Should be run Fast?
  • If we use custom db table for save this extension attribute table then how can filter?
    Should magento frontend and backend also.
  • where in need do modification and which class need to add or any reference blog ?

Wait for good and describe/brief answer on this points?


Get this bounty!!!

#StackBounty: #magento2 Magento 2 send additional mail when creating invoice

Bounty: 50

This is a question about sending the shipment mail after a specific event.

When the shop admin go to “Sales” > “Orders” > “View” (on a pending order) and click “Invoice” there is a possibility to check “Create shipment”.

Then when the shop admin click “Invoice” shipment and invoice is completed at the same time.

My problem is that only the invoice email is send and not the shipment mail.

If I do both steps separately both mails are send.

My thinking is that I somehow could listen to the above “event” and trigger sending the shipment mail. Do you have any ideas how to achieve that?


Get this bounty!!!

#StackBounty: #magento2 #magento-2.1 #orders #edit-order Magento 2: How to edit existing Order without cancel?

Bounty: 50

I am trying to edit Order that includes the below possible cases:

  • Update Order Item Price
  • Increse Order Item Qty Or Cancel Order Item Qty
  • Add New Item into Order

For Adding new Item in Order, I am following the below Way:

$objectManager = MagentoFrameworkAppObjectManager::getInstance();
$order = $this->_orderFactory->load('3445');
$order = $objectManager->create('MagentoSalesModelOrder')->load($orderId);

$quote = $objectManager->create('MagentoQuoteModelQuote')->load($order->getQuoteId());

$productId = 4272;
$productQty = 2;

$product = $objectManager->create('MagentoCatalogModelProduct')->load($productId);

//Adding New Item into Quote
$objectManager->create('MagentoQuoteModelQuoteItem')
                ->setProduct($product)
                ->setQuote($quote)
                ->setQty($productQty)
                ->save();

//Quote Address Update
$shippingData = $order->getShippingAddress()->getData();
$quoteAddress = $quote->getShippingAddress();
$shippingData['address_id'] = $quoteAddress->getAddressId();
$quoteAddress->setData($shippingData);
$quoteAddress->save();

$billingData = $order->getBillingAddress()->getData();
$quoteAddress = $quote->getBillingAddress();
$billingData['address_id'] = $quoteAddress->getAddressId();
$quoteAddress->setData($billingData);
$quoteAddress->save();        

//Quote Collect Totals
$quote->getShippingAddress()
        ->setShippingMethod($order->getShippingMethod())
        ->setCollectShippingRates(true);
$quote->setTotalsCollectedFlag(false)->collectTotals();
$quote->save();

then I am planning to add this new Quote Item to convert into Order Item. But using the above code, All Quote Items are deleted and all grand total and subtotal in quote set to 0.

My question is: What is correct way to modify the existing Order ?

Like in sales_order_item table we have the field qty_canceled, Using the below code I can cancel the complete Item ordered qty. But when I am saving the order, Subtotal and Grand total all are set to 0.

$order = $this->_orderFactory->load('3432');
if ($order->canCancel()) {
    $orderItems = $order->getAllItems();        
    foreach ($orderItems as $item) {
        if($item['product_id']==3341) {    

            $item->setQtyCanceled($item['qty_ordered']);
            $item->save();  
        }
    }
    $order->save();
}


Get this bounty!!!

#StackBounty: #magento2 #configuration #store-view #system-config #store-id Get system config option inside source model of another opt…

Bounty: 150

In my custom module I have two custom option in the system configuration. Values of the second option depend on the value of the first option. My problem is that inside the source model of the second option I don’t know how to retrieve the value of the first option.

Options

Here’s how the options are defined:

View in Magento admin panel

appcodeCompanyImagesetcadminhtmlsystem.xml:

<field id="custom_folder" translate="label" sortOrder="10" type="text" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>Custom folder</label>
</field>
<field id="list_of_icons" translate="label" sortOrder="20" type="select" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>List of icons</label>
    <source_model>CompanyImagesModelSystemConfigSourceIconsCustom</source_model>
</field>

And here’s a short description of what these options actually do:

  • first option: custom_folder – folder path, user can define a path to custom folder which stores images (icons)

  • second option: list_of_icons – dropdown list of all icons inside the folder which is defined in the first option.

From this list the user can select an icon which will be displayed on the frontend. This dropdown list will be used in multiple places in the system configuration pages of my module (to add icons to multiple elements of the frontend) but it will always show the list of icons from the folder selected in the custom_folder option.

Source model

For the second option list_of_icons I’ve created a source model. It should list all icons which exist in the folder specified by user in the first option (custom_folder). Here’s the code of the source model:

appcodeCompanyImagesModelSystemConfigSourceIconsCustom.php:

<?php
namespace CompanyImagesModelSystemConfigSourceIcons;

class Custom
{
    /**
     * @var MagentoStoreModelStoreManagerInterface
     */
    protected $_storeManager;

    /**
     * @var MagentoFrameworkAppConfigScopeConfigInterface
     */
    protected $_scopeConfigInterface;

    public function __construct(
        MagentoStoreModelStoreManagerInterface $storeManager,
        MagentoFrameworkAppConfigScopeConfigInterface $configScopeConfigInterface

    ) {
        $this->_storeManager = $storeManager;
        $this->_scopeConfigInterface = $configScopeConfigInterface;
    }

    public function toOptionArray()
    {
        // Get current store view ID
        $storeId = $this->_storeManager->getStore()->getId();

        // Get value of the first option in the current store view
        $folderPath = $this->_scopeConfigInterface->getValue(
            'images/icons/custom_folder',
            'store',
            $storeId
        );

        $options = [];
        // Here we need to list all image files from the specified folder.
        // It's not relevant to my question, so this part of code can be omitted.
        // ...

        return $options;
    }
}

What I tried to do

So inside that source model in the toOptionArray() method I need to retrieve the value of the first option (the folder path). Of course I need the value from the current store view:

enter image description here

I tried to do it like this:

// Get current store view ID
$storeId = $this->_storeManager->getStore()->getId();

// Get value of the first option in the current store view
$folderPath = $this->_scopeConfigInterface->getValue(
    'images/icons/custom_folder',
    'store',
    $storeId
);

but this line:

$storeId = $this->_storeManager->getStore()->getId();

always returns the ID of the Default Config, instead of the current store view ID.

So my code always retrieves the value of the option from the Default Config, no matter in which store view I am at the moment on the system configuration page in admin panel.

I need the value from the current store view, because each store view can have different folder path configured by user, so in each store view the list of icons (presented in the second option) can be completely different.

The problem

So, to sum up, the problem is the following:

  • How to correctly retrieve the value of the first option when I’m inside the source model of the second option?

And this problem comes down to:

  • How I can get the ID of the current store view inside the code of the source model?

If I have the ID of the current store view I will be able to easily retrieve the value of the first option.


Get this bounty!!!

#StackBounty: #magento2 #product #cart Can't retrieve custom option from order items

Bounty: 50

I am writing an extension where I need to place an order with the items already in the user’s cart (added programmatically). I have been successful with this, however my orders lose custom options added via $_product->addCustomOption().

$addOptns['my_custom_option'] = 3;
foreach ($addOptns as $key => $value) {
    $_product->addCustomOption( $key, $value);
}
$params = array(
    'product' => 123, //product Id
    'qty'   => 100    //quantity of product
);
$this->_cart->addProduct(
    $_product,
    $params
);
$this->_cart->save();
$quote = $this->_cart->getQuote();

...[shipping and payment config]...

$order_id = $this->cartManagementInterface->placeOrder($quote->getId());

When I try to receive my_custom_option from the order that is placed, I get null.

var_dump($item->getCustomOptions()); // NULL

Any guess what is wrong with my approach?

Note: This is not a ‘custom option’ like those created in the admin UI nor do I expect it to be, I use these custom options for other customized processes and they are not directly user selectable.


Get this bounty!!!