skip to Main Content

The issue is that we have lots of items that are very small 2-50g and a box + packaging weighs 100-200g

The package is often the heaviest part

If we set the item weight (in the product) as the actual weight of the item then when people order lots of things the box weight can make the total weight go over the chosen postage method.

If we ad the box weight to the item then it makes the cost of postage massively expensive and means people don’t make the purchase.

How can I set a box weight for each each package type.

is there an extension for this or is there a way to add some logic to add a tare weight for the box before Magento calculates the weight of a package.
It seems odd that this isn’t a feature of Magento as this seems like something everyone that sells items online would have to do.

I guess i would need some thing that checks order items weight

IF items total weight is less than 1KG THEN add (entered weight for small box)
IF items total weight is less the 2GK but Greater than 1KG then add (entered weight for Medium box)
IF items total is greater than 2KG then add (entered weight for Large Box)

expecting to be able to enter a packaging base weight for parcels

2

Answers


  1. This flow is set on Assumption that the Parcel weight and type information is for the admin And shipping charge is fixed.

    Step 1:- create etc/db_schema.xml

    <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
        <table name="sales_order" resource="default" engine="innodb" comment="sales_order">
            <column xsi:type="int" name="box_weight" default="0" comment="Box Weight" />
            <column xsi:type="varchar" name="box_type" nullable="false" length="255" comment="Box Type" />
        </table>
        <table name="sales_order_grid" resource="default" engine="innodb" comment="sales_order">
            <column xsi:type="int" name="box_weight" default="0" comment="Box Weight" />
            <column xsi:type="varchar" name="box_type" nullable="false" length="255" comment="Box Type" />
        </table>
    </schema>
    

    Step 2: Create Model/ResourceModel/Order/Grid/Collection.php file

    <?php
    
    namespace SunarcCustomModelResourceModelOrderGrid;
     
    use MagentoFrameworkDataCollectionDbFetchStrategyInterface as CoreFetchStrategy;
    use MagentoFrameworkDataCollectionEntityFactoryInterface as CoreEntityFactory;
    use MagentoFrameworkEventManagerInterface as CoreEventManager;
    use MagentoSalesModelResourceModelOrderGridCollection as CoreSalesGrid;
    use PsrLogLoggerInterface as Logger;
     
    
    class Collection extends CoreSalesGrid
    {
        /**
         * @param CoreEntityFactory $entityFactory
         * @param Logger            $logger       
         * @param CoreFetchStrategy $fetchStrategy
         * @param CoreEventManager  $eventManager 
         * @param string            $mainTable    
         * @param string            $resourceModel
         */
        public function __construct(
            CoreEntityFactory $entityFactory,
            Logger $logger,
            CoreFetchStrategy $fetchStrategy,
            CoreEventManager $eventManager,
            $mainTable = 'sales_order_grid',
            $resourceModel = MagentoSalesModelResourceModelOrder::class
        ) {
            parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel);
        }
     
        protected function _renderFiltersBefore()
        {
            $joinTable = $this->getTable('sales_order');
            $this->getSelect()->joinLeft(
                $joinTable,
                'main_table.entity_id = sales_order.entity_id',
                ['box_weight','box_type']
            );
            parent::_renderFiltersBefore();
        }
    }
    

    Step 3: Now, Create etc/di.xml file to add custom column data into order grid.

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <preference for="MagentoSalesControllerOrderHistory" type="SunarcCustomControllerOrderHistory" />
    
        <type name="MagentoFrameworkViewElementUiComponentDataProviderCollectionFactory">
            <arguments>
                <argument name="collections" xsi:type="array">
                    <item name="sales_order_grid_data_source" xsi:type="string">SunarcCustomModelResourceModelOrderGridCollection</item>
                </argument>
            </arguments>
        </type>
        <type name="SunarcCustomModelResourceModelOrderGridCollection">
            <arguments>
                <argument name="mainTable" xsi:type="string">sales_order_grid</argument>
                <argument name="resourceModel" xsi:type="string">MagentoSalesModelResourceModelOrder</argument>
            </arguments>
        </type>
    
    </config>
    

    Step 4 : create view/adminhtml/ui_component/sales_order_grid.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
        <columns name="sales_order_columns">
    
            <column name="box_weight">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="filter" xsi:type="string">text</item>
                        <item name="label" xsi:type="string" translate="true">Parcel Weight</item>
                    </item>
                </argument>
            </column>
    
            <column name="box_type">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="filter" xsi:type="string">text</item>
                        <item name="label" xsi:type="string" translate="true">Box Type</item>
                    </item>
                </argument>
            </column>
        </columns>
    </listing>
    

    Step 5:- Create etc/events.xml

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
        <event name="sales_order_save_before">
            <observer name="weight" instance="SunarcCustomObserverWeight" />
        </event>
    </config>
    

    step 6: Create Observer/Weight.php and write your custom logic

    <?php
    
    namespace SunarcCustomObserver;
    
    use MagentoFrameworkEventObserver;
    use MagentoFrameworkEventObserverInterface;
    use MagentoQuoteModelQuoteFactory;
    
    class Weight implements ObserverInterface
    {
    
        public function __construct(QuoteFactory $quoteFactory)
        {
            $this->quoteFactory = $quoteFactory;
        }
        /**
         * Below is the method that will fire whenever the event runs!
         *
         * @param Observer $observer
         */
        public function execute(Observer $observer)
        {
    
            //WRITE YOUR CUSTOM LOGIC HERE
            $order = $observer->getEvent()->getOrder();
    
            if ($order->getData('weight') == 1) {
                $order->setData('box_weight', 5); // Assumed wight of small parcel
                $order->setData('box_type', 'Small');
            } elseif ($order->getData('weight') > 1 && $order->getData('weight') <= 2) {
                $order->setData('box_weight', 7); // Assumed wight of Medium parcel
                $order->setData('box_type', 'Medium');
            } else {
                $order->setData('box_weight', 10);  // Assumed wight of Large parcel
                $order->setData('box_type', 'Large');
            }
        }
    }
    
    Login or Signup to reply.
  2. This is the CSV

    Step 1:- Create di.xml

    <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    
        <type name='MagentoOfflineShippingModelCarrierTablerate'>         
            <plugin name='tablerate_plugin' type='SunarcCustomPluginTableratePlugin' sortOrder='10' disabled='false'  />     
        </type>
    
    </config>
    

    Step 2:- Create a plugin to add your custom code

    <?php
    
    namespace SunarcCustomPlugin;
    
    use MagentoFrameworkExceptionLocalizedException;
    use MagentoQuoteModelQuoteAddressRateRequest;
    
    class TableratePlugin
    {
    
    
        /**
         * @var MagentoCatalogApiProductRepositoryInterface
         */
        private $productRepository;
    
        /**
         * @var MagentoQuoteModelQuoteAddressRateResultErrorFactory
         */
        private $rateErrorFactory;
    
        /**
         * @var string
         */
        protected $_code = 'tablerate';
        /**
         * @var string
         */
        protected $_defaultConditionName = 'package_weight';
    
        /**
         * @var MagentoShippingModelRateResultFactory
         */
        protected $_rateResultFactory;
    
        /**
         * @var MagentoQuoteModelQuoteAddressRateResultMethodFactory
         */
        protected $_resultMethodFactory;
    
        public function __construct(
            MagentoShippingModelRateResultFactory $rateResultFactory,
            MagentoQuoteModelQuoteAddressRateResultMethodFactory $resultMethodFactory,
            MagentoQuoteModelQuoteAddressRateResultErrorFactory $rateErrorFactory,
            MagentoCatalogApiProductRepositoryInterface $productRepository
        ) {
            $this->_rateResultFactory = $rateResultFactory;
            $this->_resultMethodFactory = $resultMethodFactory;
            $this->rateErrorFactory = $rateErrorFactory;
            $this->productRepository = $productRepository;
        }
        public function aroundCollectRates(
            MagentoOfflineShippingModelCarrierTablerate $subject,
            Closure $proceed,
            RateRequest $request
        ) {
    
            if (!$subject->getConfigFlag('active')) {
                return false;
            }
            // exclude Virtual products price from Package value if pre-configured
            if (!$subject->getConfigFlag('include_virtual_price') && $request->getAllItems()) {
                foreach ($request->getAllItems() as $item) {
                    if ($item->getParentItem()) {
                        continue;
                    }
                    if ($item->getHasChildren() && $item->isShipSeparately()) {
                        foreach ($item->getChildren() as $child) {
                            if ($child->getProduct()->isVirtual()) {
                                $request->setPackageValue($request->getPackageValue() - $child->getBaseRowTotal());
                            }
                        }
                    } elseif ($item->getProduct()->isVirtual()) {
                        $request->setPackageValue($request->getPackageValue() - $item->getBaseRowTotal());
                    }
                }
            }
    
            // Free shipping by qty
            $freeQty = 0;
            $freePackageValue = 0;
    
            if ($request->getAllItems()) {
                foreach ($request->getAllItems() as $item) {
                    if ($item->getProduct()->isVirtual() || $item->getParentItem()) {
                        continue;
                    }
    
                    if ($item->getHasChildren() && $item->isShipSeparately()) {
                        foreach ($item->getChildren() as $child) {
                            if ($child->getFreeShipping() && !$child->getProduct()->isVirtual()) {
                                $freeShipping = is_numeric($child->getFreeShipping()) ? $child->getFreeShipping() : 0;
                                $freeQty += $item->getQty() * ($child->getQty() - $freeShipping);
                            }
                        }
                    } elseif ($item->getFreeShipping() || $item->getAddress()->getFreeShipping()) {
                        $freeShipping = $item->getFreeShipping() ?
                            $item->getFreeShipping() : $item->getAddress()->getFreeShipping();
                        $freeShipping = is_numeric($freeShipping) ? $freeShipping : 0;
                        $freeQty += $item->getQty() - $freeShipping;
                        $freePackageValue += $item->getBaseRowTotal();
                    }
                }
                $oldValue = $request->getPackageValue();
                $request->setPackageValue($oldValue - $freePackageValue);
            }
    
            if (!$request->getConditionName()) {
                $conditionName = $subject->getConfigData('condition_name');
                $request->setConditionName($conditionName ? $conditionName : $this->_defaultConditionName);
            }
    
    
            // Package weight and qty free shipping
            $oldWeight = $request->getPackageWeight();
            $oldQty = $request->getPackageQty();
    
    
            // ADD YOUR CUSTOM CODE HERE //
    
            if ($request->getFreeMethodWeight() == 1) {
                $request->setPackageWeight(50);
            } elseif ($request->getFreeMethodWeight() > 1 && $request->getFreeMethodWeight() <= 2) {
                $request->setPackageWeight(40);
            } else {
                $request->setPackageWeight(40);
            }
    
            // $request->setPackageWeight($request->getFreeMethodWeight());
            $request->setPackageQty($oldQty - $freeQty);
    
            /** @var MagentoShippingModelRateResult $result */
            $result = $this->_rateResultFactory->create();
            $rate = $subject->getRate($request);
    
            $request->setPackageWeight($oldWeight);
            $request->setPackageQty($oldQty);
    
            if (!empty($rate) && $rate['price'] >= 0) {
                if ($request->getPackageQty() == $freeQty) {
                    $shippingPrice = 0;
                } else {
                    $shippingPrice = $subject->getFinalPriceWithHandlingFee($rate['price']);
                }
                $method = $this->createShippingMethod($shippingPrice, $rate['cost'], $subject, $request);
                $result->append($method);
            } elseif ($request->getPackageQty() == $freeQty) {
    
                /**
                 * Promotion rule was applied for the whole cart.
                 *  In this case all other shipping methods could be omitted
                 * Table rate shipping method with 0$ price must be shown if grand total is more than minimal value.
                 * Free package weight has been already taken into account.
                 */
                $request->setPackageValue($freePackageValue);
                $request->setPackageQty($freeQty);
                $rate = $subject->getRate($request);
                if (!empty($rate) && $rate['price'] >= 0) {
                    $method = $this->createShippingMethod(0, 0, $subject, $request);
                    $result->append($method);
                }
            } else {
                /** @var MagentoQuoteModelQuoteAddressRateResultError $error */
                $error = $this->rateErrorFactory->create(
                    [
                        'data' => [
                            'carrier' => $this->_code,
                            'carrier_title' => $subject->getConfigData('title'),
                            'error_message' => $subject->getConfigData('specificerrmsg'),
                        ],
                    ]
                );
                $result->append($error);
            }
            return $result;
        }
    
        /**
         * Get the method object based on the shipping price and cost
         *
         * @param float $shippingPrice
         * @param float $cost
         * @return MagentoQuoteModelQuoteAddressRateResultMethod
         */
        private function createShippingMethod($shippingPrice, $cost, $subject, $request)
        {
    
            /** @var  MagentoQuoteModelQuoteAddressRateResultMethod $method */
            $method = $this->_resultMethodFactory->create();
    
            $method->setCarrier('tablerate');
            $method->setCarrierTitle($subject->getConfigData('title'));
    
            $method->setMethod('bestway');
            $method->setMethodTitle($subject->getConfigData('name'));
    
            $method->setPrice($shippingPrice);
            $method->setCost($cost);
            return $method;
        }
    }
    

    You can calculate the weight according to your logic code and price will get updated accordingly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search