Splitting the order is not really necessary since the payment applies more to the invoice than the order itself. Check out this answer on Stackoverflow on how to make a partial invoice. If you have 2 payment methods that would result in 2 invoices.
From the checkout point of view it depends on what kind of payment method you're using. The real issue would come from 2 payment methods that are both handled by 3th parties thus needing a redirect. But if your 'special product' should be paid using a banktransfer for example create an extension that first makes an invoice out of that product adding bank transfer as payment method and then sending of the rest of the amount to pay to, for example, a Credit Card gateway
OK, your request is not difficult to implement, see my solution. It works only when you create shipment using Magento admin panel. I supposed that shipments are created manually.
1. Create local module (ex. ShipmentSplit) and rewrite Shipment controller, config.xml:
<?xml version="1.0"?>
<config>
<modules>
<Some_ShipmentSplit>
<version>0.1.0</version>
</Some_ShipmentSplit>
</modules>
<admin>
<routers>
<adminhtml>
<args>
<modules>
<Some_ShipmentSplit before="Mage_Adminhtml">Some_ShipmentSplit_Adminhtml</Some_ShipmentSplit>
</modules>
</args>
</adminhtml>
</routers>
</admin>
<global>
<helpers>
<some_shipmentsplit>
<class>Some_ShipmentSplit_Helper</class>
</some_shipmentsplit>
</helpers>
</global>
</config>
2. Create Configuration settings to enable/disable splitting functionality and store weight threshold parametr, system.xml.
<?xml version="1.0"?>
<config>
<sections>
<shipping>
<groups>
<splitting translate="label">
<label>Shipment Splitting</label>
<frontend_type>text</frontend_type>
<sort_order>10</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>0</show_in_website>
<show_in_store>0</show_in_store>
<fields>
<enable translate="label">
<label>Allow Shipping to Split</label>
<frontend_type>select</frontend_type>
<source_model>adminhtml/system_config_source_yesno</source_model>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
</enable>
<weight translate="label">
<label>Maximum Weight</label>
<frontend_type>text</frontend_type>
<validate>validate-number</validate>
<sort_order>2</sort_order>
<show_in_default>1</show_in_default>
<depends>
<enable>1</enable>
</depends>
</weight>
</fields>
</splitting>
</groups>
</shipping>
</sections>
</config>
3. Rewrite Shipment controller:
<?php
require_once 'Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php';
class Some_ShipmentSplit_Adminhtml_Sales_Order_ShipmentController extends Mage_Adminhtml_Sales_Order_ShipmentController
{
public function saveAction()
{
$enableSplitting = Mage::getStoreConfig('shipping/splitting/enable');
$isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
//if splitting not enabled use standard magento logic
if (!$enableSplitting || $isNeedCreateLabel) return parent::saveAction();
$data = $this->getRequest()->getPost('shipment');
if (!empty($data['comment_text'])) {
Mage::getSingleton('adminhtml/session')->setCommentText($data['comment_text']);
}
try {
$shipment = $this->_initShipment();
if (!$shipment) {
$this->_forward('noRoute');
return;
}
$comment = '';
if (!empty($data['comment_text'])) {
$shipment->addComment(
$data['comment_text'],
isset($data['comment_customer_notify']),
isset($data['is_visible_on_front'])
);
if (isset($data['comment_customer_notify'])) {
$comment = $data['comment_text'];
}
}
$shipmentCreatedMessage = $this->__('The shipment has been created.');
$labelCreatedMessage = $this->__('The shipping label has been created.');
//split to groups
$shipments = $this->_initShipmentGroups($shipment);
foreach ($shipments as $shipment) {
$shipment->register();
if (!empty($data['send_email'])) {
$shipment->setEmailSent(true);
}
$shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));
$this->_saveShipment($shipment);
$shipment->sendEmail(!empty($data['send_email']), $comment);
$this->_getSession()->addSuccess($isNeedCreateLabel ? $shipmentCreatedMessage . ' ' . $labelCreatedMessage
: $shipmentCreatedMessage);
Mage::getSingleton('adminhtml/session')->getCommentText(true);
}
} catch (Mage_Core_Exception $e) {
$this->_getSession()->addError($e->getMessage());
$this->_redirect('*/*/new', array('order_id' => $this->getRequest()->getParam('order_id')));
} catch (Exception $e) {
Mage::logException($e);
$this->_getSession()->addError($this->__('Cannot save shipment.'));
$this->_redirect('*/*/new', array('order_id' => $this->getRequest()->getParam('order_id')));
}
$this->_redirect('*/sales_order/view', array('order_id' => $shipment->getOrderId()));
}
/**
* this function splits shipment into groups
* @param Mage_Sales_Model_Order_Shipment $shipment
* @return array
*/
protected function _initShipmentGroups(Mage_Sales_Model_Order_Shipment $shipment)
{
/**
* @var $items Mage_Sales_Model_Resource_Order_Item_Collection
*/
if ($maxKg = (int)Mage::getStoreConfig('shipping/splitting/weight')) {
$qtys = $this->_getItemQtys();
$itemWeights = array();
$allItems = array();
$order = $shipment->getOrder();
$items = $shipment->getOrder()->getItemsCollection();
/**
* fetching items weight
*/
foreach ($qtys as $itemId => $qty) {
$itemWeights[$itemId] = $items->getItemById($itemId)->getWeight();
while ($qty--) $allItems[] = $itemId;
}
$groups = array();
$i = 0;
/**
* create item groups which every group weight up to $maxKg threshold
*/
while (count($allItems) > 0) {
$i++;
$groups[$i] = array(
'items' => array(),
'weight' => 0,
);
foreach ($allItems as $index => $itemId) {
$itemWeight = $itemWeights[$itemId];
if ($groups[$i]['weight'] + $itemWeight <= $maxKg) {
$groups[$i]['weight'] += $itemWeight;
$groups[$i]['items'][] = $itemId;
unset($allItems[$index]);
}
}
/**
* check if an item is added to the group,
* if not added, it means some product weight is over threshold
* you can throw within if or add this product to the group
* or you can remove this IF block
* if you are sure that all products have appropriate weight
*/
if (count($groups[$i]['items']) == 0) {
$itemWeight = $itemWeights[$itemId];
$groups[$i]['weight'] += $itemWeight;
$groups[$i]['items'][] = $itemId;
unset($allItems[$index]);
}
}
//print_r($groups);
$shipments = array();
if (count($groups) > 1) {
foreach ($groups as $data) {
$groupItems = array();
foreach ($data['items'] as $itemId) {
if (isset($groupItems[$itemId])) {
/**
* if same item then only increase quantity
*/
$groupItems[$itemId]++;
} else {
$groupItems[$itemId] = 1;
}
}
//create shipment for each group
$shipments[] = Mage::getModel('sales/service_order', $order)->prepareShipment($groupItems);
}
} else {
$shipments[] = $shipment;
}
return $shipments;
} else {
Mage::throwException('Shipment package weight not defined');
}
}
}
Enter to admin order management page, open order, click [ship] button, click [submit shipment] button (you can except some items giving 0 qty to ship) and our logic automatically create shipments based on weight threshold (minimum one shipment). See my results:
Best Answer
First, You should not use the ObjectManager
$product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
directly!Also, it seems you may be trying the same approach you would in Magento 1 style. Which can work, but with the code base a work in progress daily it's best to take the proper approach to ensure backwards and forward compatibility.
With that said, you probably will find your answer in the Type models
multishipping
https://github.com/magento/magento2/blob/2.1/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php#L705onepage
https://github.com/magento/magento2/blob/develop/app/code/Magento/Checkout/Model/Type/Onepage.php#L684-L755Hope this helps!