I'm running test orders on my almost ready Magento store but faced a very strange problem: I cannot save shipments in admin.
So there are some test orders I made myself as a guest and a signed-in customer. The payment process goes fine through. When I'm on the admin side I can invoice the orders normally, but when I select Ship > Submit Shipment I get this error "Cannot save shipment.".
However, if I scroll down to the orders provided in the Magento sample data, there are some orders that are in the state of Processing - when I follow the aforementioned procedure to ship those, the shippings are created normally and everything works fine.
Same problem occurs regardless of Payment Method or Shipping Method used. However, the sample data orders use Payment & Shipping Methods that are already disabled in the front-end, but that hasn't got any effect: the shipment creation succeeds for sample orders.
What on Earth causes this kind of behaviour? What can I do? Can there be something wrong with the products or Shipping Methods? Pls help me out.
Update 1:
I now edited the function canShip()
at app/code/core/Mage/Sales/Model/Order.php
public function canShip()
{
return true;/*FOR DEBUGGING PURPOSES*/
/*
if ($this->canUnhold() || $this->isPaymentReview()) {
return false;
}
if ($this->getIsVirtual() || $this->isCanceled()) {
return false;
}
if ($this->getActionFlag(self::ACTION_FLAG_SHIP) === false) {
return false;
}
foreach ($this->getAllItems() as $item) {
if ($item->getQtyToShip()>0 && !$item->getIsVirtual()
&& !$item->getLockedDoShip())
{
return true;
}
}
return false;
*/
}
But still I got the same results. I flushed Magento cache after making the changes. Then I also tried to set the function to return: false;
for every run but still I was able to ship the older orders (magento sample data's pending/processing orders).
Minor Update to above: So now it appears that canShip()
function returns true
because when I set it to return false;
for everything, the orders are just passed through to complete state without the need to Ship them in Admin. I didn't flush caches etc. properly enough yesterday.
UPDATE 2:
I managed to track down the problem a bit further:
On app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php
line 238 an Exception gets caught (catch (Exception $e)
), which results in the error msg "Cannot save shipment" on admin panel.
This is what the function tries to do:
public function 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;
}
$shipment->register();
$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'];
}
}
if (!empty($data['send_email'])) {
$shipment->setEmailSent(true);
}
$shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));
$responseAjax = new Varien_Object();
$isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
if ($isNeedCreateLabel && $this->_createShippingLabel($shipment)) {
$responseAjax->setOk(true);
}
$this->_saveShipment($shipment);
$shipment->sendEmail(!empty($data['send_email']), $comment);
$shipmentCreatedMessage = $this->__('The shipment has been created.');
$labelCreatedMessage = $this->__('The shipping label has been created.');
$this->_getSession()->addSuccess($isNeedCreateLabel ? $shipmentCreatedMessage . ' ' . $labelCreatedMessage
: $shipmentCreatedMessage);
Mage::getSingleton('adminhtml/session')->getCommentText(true);
} [...etc...]
Then comes the catch
part of the function.
Exception log:
exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '400000001' for key 'UNQ_SALES_FLAT_SHIPMENT_INCREMENT_ID'' in [my shop path]/lib/Zend/Db/Statement/Pdo.php:228
Next exception 'Zend_Db_Statement_Exception' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '400000001' for key 'UNQ_SALES_FLAT_SHIPMENT_INCREMENT_ID'' in [my shop path]/lib/Zend/Db/Statement/Pdo.php:234
(Note: "[my shop path]
" is added by me, it's not quoted from the exception message.)
UPDATE 4: FOUND THE SOLUTION
After googling the exception log messages and error codes, I found an issue on StackOverflow which was pretty similar. I write it down here since it's not 100 % the same in my case.
- Admin > Sales > Orders: Look up the highest order number (for each store view) and write it down. e.g.
100000054
, which means that there are 54 placed orders in the system. - Admin > System > Manage Stores: Hover your mouse over your Store View Names to see their ID:s. Write them down. e.g. ID for Store View
English
is usually1
. - Open your database in phpMyAdmin or your preferred db admin tool.
- Open the table
eav_entity_type
which tells you what is the id number for different entities. Now we are interested in rows withentity_type_code
isorder
andshipment
(and maybe alsoinvoice
andcreditmemo
, if your problem is related to those. My problem was about shipping). Write down theentity_type_id
values of those rows. In my case they were5
fororder
and8
forshipment
. - Open the table
eav_entity_store
. Look for rows that match theentity_type_id
s oforder
andshipment
AND also match your Store View ID:s. Now you can change the value ofincrement_last_id
to your last actual order number. Since my store isn't open yet, I played it safe and gave a value much bigger for bothorder
andshipment
related rows. e.g. if theincrement_last_id
s were100000053
for orders and100000040
for shipments, I gave them both the same new value100000100
to start over from a clean table. N.B. In my case there was no a row with my local store view and correct shipmententity_type_id
. So I copied the row of store view id1
, gave it new values (store id
->4
and alsoincrement_prefix
to matchstore_id
->4
, and of courseincrement_last_id
->400000100
) and saved it as a new row in the table.
And that's it. I've now placed a few test orders and everything seems to work. I was also able to ship some older test orders that were lagging behind in Processing
mode. That resulted in the fact that order ID:s and shipment ID:s aren't running side-by-side, but they wouldn't do that for long anyway so it's not a problem.
Reflecion:
If I understood this correctly, I think my problem was that for shipment
my increment_last_id
was too small and the system tried to create a new shipment with an ID that already existed in the database.
The reason why I was able to ship the magento sample data's orders was that they had been done in English Store View, which apparently wasn't corrupted. I'm not sure how my native Store View first ran into the problem – what made the increment_last_id
drop back. My guess is that since I'm running 4 different environments for testing Magento, there has happened something that I've different amounts of test purchases in different environments and there has occurred some kind of a version control issue. Dunno 'bout that.