diff --git a/app/code/Magento/Sales/Api/Data/CommentInterface.php b/app/code/Magento/Sales/Api/Data/CommentInterface.php
index d7021dc9f9546b76f427a282a38a31d64f033775..fcab786319340535c1c6309c884a678a91341d90 100644
--- a/app/code/Magento/Sales/Api/Data/CommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/CommentInterface.php
@@ -12,6 +12,16 @@ namespace Magento\Sales\Api\Data;
  */
 interface CommentInterface
 {
+    /*
+     * Is-visible-on-storefront flag.
+     */
+    const IS_VISIBLE_ON_FRONT = 'is_visible_on_front';
+
+    /*
+     * Comment.
+     */
+    const COMMENT = 'comment';
+
     /**
      * Gets the comment for the invoice.
      *
diff --git a/app/code/Magento/Sales/Api/Data/EntityInterface.php b/app/code/Magento/Sales/Api/Data/EntityInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..d09b25920f899aa652f87dad269047136892a061
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/EntityInterface.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Interface EntityInterface
+ * @api
+ */
+interface EntityInterface
+{
+    /*
+     * Entity ID.
+     */
+    const ENTITY_ID = 'entity_id';
+
+    /*
+     * Created-at timestamp.
+     */
+    const CREATED_AT = 'created_at';
+
+    /**
+     * Gets the created-at timestamp for the invoice.
+     *
+     * @return string|null Created-at timestamp.
+     */
+    public function getCreatedAt();
+
+    /**
+     * Sets the created-at timestamp for the invoice.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
+    /**
+     * Gets the ID for the invoice.
+     *
+     * @return int|null Invoice ID.
+     */
+    public function getEntityId();
+
+    /**
+     * Sets entity ID.
+     *
+     * @param int $entityId
+     * @return $this
+     */
+    public function setEntityId($entityId);
+}
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceCommentCreationInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceCommentCreationInterface.php
index 85c114da3821eb7cb0d98538c37513ddd10fed84..5e4d85e93cb98969580df87b71d7bcc9f6c916f6 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceCommentCreationInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceCommentCreationInterface.php
@@ -6,11 +6,29 @@
 
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Interface InvoiceCommentCreationInterface
  *
  * @api
  */
-interface InvoiceCommentCreationInterface extends \Magento\Sales\Api\Data\CommentInterface
+interface InvoiceCommentCreationInterface extends ExtensibleDataInterface, CommentInterface
 {
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface $extensionAttributes
+    );
 }
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
index 1447fab476ad9cad5a4f498450952324264b9eec..f661a1ab6a4ca1755f003304c9ff55ee287bba98 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Invoice comment interface.
  *
@@ -12,16 +14,11 @@ namespace Magento\Sales\Api\Data;
  * invoice history.
  * @api
  */
-interface InvoiceCommentInterface extends \Magento\Framework\Api\ExtensibleDataInterface,
-\Magento\Sales\Api\Data\InvoiceCommentCreationInterface
+interface InvoiceCommentInterface extends ExtensibleDataInterface, CommentInterface, EntityInterface
 {
     /**#@+
      * Constants for keys of data array. Identical to the name of the getter in snake case.
      */
-    /*
-     * Entity ID.
-     */
-    const ENTITY_ID = 'entity_id';
     /*
      * Parent ID.
      */
@@ -30,48 +27,6 @@ interface InvoiceCommentInterface extends \Magento\Framework\Api\ExtensibleDataI
      * Is-customer-notified flag.
      */
     const IS_CUSTOMER_NOTIFIED = 'is_customer_notified';
-    /*
-     * Is-visible-on-storefront flag.
-     */
-    const IS_VISIBLE_ON_FRONT = 'is_visible_on_front';
-    /*
-     * Comment.
-     */
-    const COMMENT = 'comment';
-    /*
-     * Created-at timestamp.
-     */
-    const CREATED_AT = 'created_at';
-
-    /**
-     * Gets the created-at timestamp for the invoice.
-     *
-     * @return string|null Created-at timestamp.
-     */
-    public function getCreatedAt();
-
-    /**
-     * Sets the created-at timestamp for the invoice.
-     *
-     * @param string $createdAt timestamp
-     * @return $this
-     */
-    public function setCreatedAt($createdAt);
-
-    /**
-     * Gets the ID for the invoice.
-     *
-     * @return int|null Invoice ID.
-     */
-    public function getEntityId();
-
-    /**
-     * Sets entity ID.
-     *
-     * @param int $entityId
-     * @return $this
-     */
-    public function setEntityId($entityId);
 
     /**
      * Gets the is-customer-notified flag value for the invoice.
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceItemCreationInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceItemCreationInterface.php
index 4b5c6fa2c6136f4d5896a418636d87632af5d603..2f2ddfbf758a0de4341b60b840263704bf6968ab 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceItemCreationInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceItemCreationInterface.php
@@ -6,6 +6,8 @@
 
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Input argument for invoice creation
  *
@@ -13,6 +15,22 @@ namespace Magento\Sales\Api\Data;
  *
  * @api
  */
-interface InvoiceItemCreationInterface extends LineItemInterface
+interface InvoiceItemCreationInterface extends LineItemInterface, ExtensibleDataInterface
 {
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface $extensionAttributes
+    );
 }
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceItemInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceItemInterface.php
index ecdcd07bc0ca5b90f4970dcffbfcbcdd3757774d..37a933f97a29ab26a192735e808c031ede534900 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceItemInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceItemInterface.php
@@ -5,14 +5,15 @@
  */
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Invoice item interface.
  *
  * An invoice is a record of the receipt of payment for an order. An invoice item is a purchased item in an invoice.
  * @api
  */
-interface InvoiceItemInterface extends \Magento\Sales\Api\Data\InvoiceItemCreationInterface,
-\Magento\Framework\Api\ExtensibleDataInterface
+interface InvoiceItemInterface extends ExtensibleDataInterface, LineItemInterface
 {
     /**#@+
      * Constants for keys of data array. Identical to the name of the getter in snake case.
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentCommentCreationInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentCommentCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..40beaa32d02f25c57af5fe93cbfd3e3f6d97e93f
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/ShipmentCommentCreationInterface.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+use Magento\Framework\Api\ExtensibleDataInterface;
+
+/**
+ * Interface ShipmentCommentCreationInterface
+ * @api
+ */
+interface ShipmentCommentCreationInterface extends ExtensibleDataInterface, CommentInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
index a67b0577a7761ee72bc1fad3c9fda679f31aa27e..0c00bf80d78f1d4f0311f7331a3639eec3e30bba 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Shipment comment interface.
  *
@@ -12,15 +14,11 @@ namespace Magento\Sales\Api\Data;
  * document lists the products and their quantities in the delivery package. A shipment document can contain comments.
  * @api
  */
-interface ShipmentCommentInterface extends \Magento\Framework\Api\ExtensibleDataInterface
+interface ShipmentCommentInterface extends ExtensibleDataInterface, CommentInterface, EntityInterface
 {
     /**#@+
      * Constants for keys of data array. Identical to the name of the getter in snake case.
      */
-    /*
-     * Entity ID.
-     */
-    const ENTITY_ID = 'entity_id';
     /*
      * Parent ID.
      */
@@ -29,55 +27,6 @@ interface ShipmentCommentInterface extends \Magento\Framework\Api\ExtensibleData
      * Is-customer-notified flag.
      */
     const IS_CUSTOMER_NOTIFIED = 'is_customer_notified';
-    /*
-     * Is-visible-on-storefront flag.
-     */
-    const IS_VISIBLE_ON_FRONT = 'is_visible_on_front';
-    /*
-     * Comment.
-     */
-    const COMMENT = 'comment';
-    /*
-     * Created-at timestamp.
-     */
-    const CREATED_AT = 'created_at';
-
-    /**
-     * Gets the comment for the shipment.
-     *
-     * @return string Comment.
-     */
-    public function getComment();
-
-    /**
-     * Gets the created-at timestamp for the shipment comment.
-     *
-     * @return string|null Created-at timestamp.
-     */
-    public function getCreatedAt();
-
-    /**
-     * Sets the created-at timestamp for the shipment comment.
-     *
-     * @param string $createdAt timestamp
-     * @return $this
-     */
-    public function setCreatedAt($createdAt);
-
-    /**
-     * Gets the ID for the shipment comment.
-     *
-     * @return int|null Shipment comment ID.
-     */
-    public function getEntityId();
-
-    /**
-     * Sets entity ID.
-     *
-     * @param int $entityId
-     * @return $this
-     */
-    public function setEntityId($entityId);
 
     /**
      * Gets the is-customer-notified flag value for the shipment comment.
@@ -86,13 +35,6 @@ interface ShipmentCommentInterface extends \Magento\Framework\Api\ExtensibleData
      */
     public function getIsCustomerNotified();
 
-    /**
-     * Gets the is-visible-on-storefront flag value for the shipment comment.
-     *
-     * @return int Is-visible-on-storefront flag value.
-     */
-    public function getIsVisibleOnFront();
-
     /**
      * Gets the parent ID for the shipment comment.
      *
@@ -116,22 +58,6 @@ interface ShipmentCommentInterface extends \Magento\Framework\Api\ExtensibleData
      */
     public function setIsCustomerNotified($isCustomerNotified);
 
-    /**
-     * Sets the is-visible-on-storefront flag value for the shipment comment.
-     *
-     * @param int $isVisibleOnFront
-     * @return $this
-     */
-    public function setIsVisibleOnFront($isVisibleOnFront);
-
-    /**
-     * Sets the comment for the shipment.
-     *
-     * @param string $comment
-     * @return $this
-     */
-    public function setComment($comment);
-
     /**
      * Retrieve existing extension attributes object or create a new one.
      *
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentCreationArgumentsInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentCreationArgumentsInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..f03d05be3c7426bf28d16a7976957b087c432b0d
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/ShipmentCreationArgumentsInterface.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Interface for creation arguments for Shipment.
+ *
+ * @api
+ */
+interface ShipmentCreationArgumentsInterface extends \Magento\Framework\Api\ExtensibleDataInterface
+{
+    /**
+     * Gets existing extension attributes.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentCreationArgumentsExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Sets extension attributes.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsExtensionInterface $extensionAttributes
+     *
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentItemCreationInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentItemCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..57c908fb88c5e9aa5e1dd7dbc6e8c39449d2217d
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/ShipmentItemCreationInterface.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Input argument for shipment item creation
+ *
+ * Interface ShipmentItemCreationInterface
+ *
+ * @api
+ */
+interface ShipmentItemCreationInterface extends LineItemInterface,
+\Magento\Framework\Api\ExtensibleDataInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentItemInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentItemInterface.php
index 03f8fba0b431cbb39be5642aede49993bb8d202c..6d891371d04a14be86c4740b70a4838ccbc5a8cb 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentItemInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentItemInterface.php
@@ -12,7 +12,8 @@ namespace Magento\Sales\Api\Data;
  * document lists the products and their quantities in the delivery package. A product is an item in a shipment.
  * @api
  */
-interface ShipmentItemInterface extends \Magento\Framework\Api\ExtensibleDataInterface
+interface ShipmentItemInterface extends \Magento\Sales\Api\Data\LineItemInterface,
+\Magento\Framework\Api\ExtensibleDataInterface
 {
     /**#@+
      * Constants for keys of data array. Identical to the name of the getter in snake case
@@ -102,13 +103,6 @@ interface ShipmentItemInterface extends \Magento\Framework\Api\ExtensibleDataInt
      */
     public function getName();
 
-    /**
-     * Gets the order item ID for the shipment item.
-     *
-     * @return int Order item ID.
-     */
-    public function getOrderItemId();
-
     /**
      * Gets the parent ID for the shipment item.
      *
@@ -130,13 +124,6 @@ interface ShipmentItemInterface extends \Magento\Framework\Api\ExtensibleDataInt
      */
     public function getProductId();
 
-    /**
-     * Gets the quantity for the shipment item.
-     *
-     * @return float Quantity.
-     */
-    public function getQty();
-
     /**
      * Gets the row total for the shipment item.
      *
@@ -190,14 +177,6 @@ interface ShipmentItemInterface extends \Magento\Framework\Api\ExtensibleDataInt
      */
     public function setWeight($weight);
 
-    /**
-     * Sets the quantity for the shipment item.
-     *
-     * @param float $qty
-     * @return $this
-     */
-    public function setQty($qty);
-
     /**
      * Sets the product ID for the shipment item.
      *
@@ -206,14 +185,6 @@ interface ShipmentItemInterface extends \Magento\Framework\Api\ExtensibleDataInt
      */
     public function setProductId($id);
 
-    /**
-     * Sets the order item ID for the shipment item.
-     *
-     * @param int $id
-     * @return $this
-     */
-    public function setOrderItemId($id);
-
     /**
      * Sets the additional data for the shipment item.
      *
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentPackageCreationInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentPackageCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c83c54b3019bec5dfe507c97fe82bab02dc8f96b
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/ShipmentPackageCreationInterface.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Shipment package interface.
+ *
+ * A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This
+ * document lists the products and their quantities in the delivery package.
+ * @api
+ */
+interface ShipmentPackageCreationInterface extends \Magento\Framework\Api\ExtensibleDataInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentPackageCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentPackageCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentPackageCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentTrackCreationInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentTrackCreationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a45242fcd1568275db8727b64e83a22fdbdd73f
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/ShipmentTrackCreationInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+use Magento\Framework\Api\ExtensibleDataInterface;
+
+/**
+ * Shipment Track Creation interface.
+ *
+ * @api
+ */
+interface ShipmentTrackCreationInterface extends TrackInterface, ExtensibleDataInterface
+{
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentTrackCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes();
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentTrackCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentTrackCreationExtensionInterface $extensionAttributes
+    );
+}
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
index f28a0b0e7a1970a05dfeef5739238966b1503182..beafa1370f107e1ba725568b893b4d390d9469b5 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Sales\Api\Data;
 
+use Magento\Framework\Api\ExtensibleDataInterface;
+
 /**
  * Shipment track interface.
  *
@@ -13,7 +15,7 @@ namespace Magento\Sales\Api\Data;
  * shipments.
  * @api
  */
-interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataInterface
+interface ShipmentTrackInterface extends TrackInterface, ExtensibleDataInterface
 {
     /**#@+
      * Constants for keys of data array. Identical to the name of the getter in snake case.
@@ -64,11 +66,19 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
     const UPDATED_AT = 'updated_at';
 
     /**
-     * Gets the carrier code for the shipment package.
+     * Sets the order_id for the shipment package.
      *
-     * @return string Carrier code.
+     * @param int $id
+     * @return $this
      */
-    public function getCarrierCode();
+    public function setOrderId($id);
+
+    /**
+     * Gets the order_id for the shipment package.
+     *
+     * @return int
+     */
+    public function getOrderId();
 
     /**
      * Gets the created-at timestamp for the shipment package.
@@ -85,13 +95,6 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
      */
     public function setCreatedAt($createdAt);
 
-    /**
-     * Gets the description for the shipment package.
-     *
-     * @return string Description.
-     */
-    public function getDescription();
-
     /**
      * Gets the ID for the shipment package.
      *
@@ -107,13 +110,6 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
      */
     public function setEntityId($entityId);
 
-    /**
-     * Gets the order_id for the shipment package.
-     *
-     * @return int
-     */
-    public function getOrderId();
-
     /**
      * Gets the parent ID for the shipment package.
      *
@@ -121,27 +117,6 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
      */
     public function getParentId();
 
-    /**
-     * Gets the quantity for the shipment package.
-     *
-     * @return float Quantity.
-     */
-    public function getQty();
-
-    /**
-     * Gets the title for the shipment package.
-     *
-     * @return string Title.
-     */
-    public function getTitle();
-
-    /**
-     * Gets the track number for the shipment package.
-     *
-     * @return string Track number.
-     */
-    public function getTrackNumber();
-
     /**
      * Gets the updated-at timestamp for the shipment package.
      *
@@ -149,13 +124,6 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
      */
     public function getUpdatedAt();
 
-    /**
-     * Gets the weight for the shipment package.
-     *
-     * @return float Weight.
-     */
-    public function getWeight();
-
     /**
      * Sets the updated-at timestamp for the shipment package.
      *
@@ -181,28 +149,26 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
     public function setWeight($weight);
 
     /**
-     * Sets the quantity for the shipment package.
+     * Gets the weight for the shipment package.
      *
-     * @param float $qty
-     * @return $this
+     * @return float Weight.
      */
-    public function setQty($qty);
+    public function getWeight();
 
     /**
-     * Sets the order_id for the shipment package.
+     * Sets the quantity for the shipment package.
      *
-     * @param int $id
+     * @param float $qty
      * @return $this
      */
-    public function setOrderId($id);
+    public function setQty($qty);
 
     /**
-     * Sets the track number for the shipment package.
+     * Gets the quantity for the shipment package.
      *
-     * @param string $trackNumber
-     * @return $this
+     * @return float Quantity.
      */
-    public function setTrackNumber($trackNumber);
+    public function getQty();
 
     /**
      * Sets the description for the shipment package.
@@ -213,20 +179,11 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
     public function setDescription($description);
 
     /**
-     * Sets the title for the shipment package.
-     *
-     * @param string $title
-     * @return $this
-     */
-    public function setTitle($title);
-
-    /**
-     * Sets the carrier code for the shipment package.
+     * Gets the description for the shipment package.
      *
-     * @param string $code
-     * @return $this
+     * @return string Description.
      */
-    public function setCarrierCode($code);
+    public function getDescription();
 
     /**
      * Retrieve existing extension attributes object or create a new one.
diff --git a/app/code/Magento/Sales/Api/Data/TrackInterface.php b/app/code/Magento/Sales/Api/Data/TrackInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..17c08ff9b983031efa1268fc0a4c0fc359f60bd5
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Data/TrackInterface.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Data;
+
+/**
+ * Shipment Track Creation interface.
+ *
+ * @api
+ */
+interface TrackInterface
+{
+    /**
+     * Sets the track number for the shipment package.
+     *
+     * @param string $trackNumber
+     * @return $this
+     */
+    public function setTrackNumber($trackNumber);
+
+    /**
+     * Gets the track number for the shipment package.
+     *
+     * @return string Track number.
+     */
+    public function getTrackNumber();
+
+    /**
+     * Sets the title for the shipment package.
+     *
+     * @param string $title
+     * @return $this
+     */
+    public function setTitle($title);
+
+    /**
+     * Gets the title for the shipment package.
+     *
+     * @return string Title.
+     */
+    public function getTitle();
+
+    /**
+     * Sets the carrier code for the shipment package.
+     *
+     * @param string $code
+     * @return $this
+     */
+    public function setCarrierCode($code);
+
+    /**
+     * Gets the carrier code for the shipment package.
+     *
+     * @return string Carrier code.
+     */
+    public function getCarrierCode();
+}
diff --git a/app/code/Magento/Sales/Api/Exception/CouldNotShipExceptionInterface.php b/app/code/Magento/Sales/Api/Exception/CouldNotShipExceptionInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b52e627791249eb6b347d495e32639e20536370e
--- /dev/null
+++ b/app/code/Magento/Sales/Api/Exception/CouldNotShipExceptionInterface.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api\Exception;
+
+/**
+ * @api
+ */
+interface CouldNotShipExceptionInterface
+{
+}
diff --git a/app/code/Magento/Sales/Api/OrderInvoiceInterface.php b/app/code/Magento/Sales/Api/InvoiceOrderInterface.php
similarity index 93%
rename from app/code/Magento/Sales/Api/OrderInvoiceInterface.php
rename to app/code/Magento/Sales/Api/InvoiceOrderInterface.php
index 80fa6159afc3e449115a6b373560628a5aa7157f..0f0ce4596991664671cc6ea4d1f231ad05066ed3 100644
--- a/app/code/Magento/Sales/Api/OrderInvoiceInterface.php
+++ b/app/code/Magento/Sales/Api/InvoiceOrderInterface.php
@@ -7,11 +7,11 @@
 namespace Magento\Sales\Api;
 
 /**
- * Class OrderInvoiceInterface
+ * Class InvoiceOrderInterface
  *
  * @api
  */
-interface OrderInvoiceInterface
+interface InvoiceOrderInterface
 {
     /**
      * @param int $orderId
diff --git a/app/code/Magento/Sales/Api/ShipOrderInterface.php b/app/code/Magento/Sales/Api/ShipOrderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..d28fedf4e507fc9c73f64ef60d42032e5d0c2114
--- /dev/null
+++ b/app/code/Magento/Sales/Api/ShipOrderInterface.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Api;
+
+/**
+ * Class ShipOrderInterface
+ *
+ * @api
+ */
+interface ShipOrderInterface
+{
+    /**
+     * Creates new Shipment for given Order.
+     *
+     * @param int $orderId
+     * @param \Magento\Sales\Api\Data\ShipmentItemCreationInterface[] $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\ShipmentTrackCreationInterface[] $tracks
+     * @param \Magento\Sales\Api\Data\ShipmentPackageCreationInterface[] $packages
+     * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments
+     * @return int Id of created Shipment.
+     */
+    public function execute(
+        $orderId,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        array $tracks = [],
+        array $packages = [],
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null
+    );
+}
diff --git a/app/code/Magento/Sales/Exception/CouldNotShipException.php b/app/code/Magento/Sales/Exception/CouldNotShipException.php
new file mode 100644
index 0000000000000000000000000000000000000000..4881bbd79a3a3eec84c74f66ffaf8a4c5553bd16
--- /dev/null
+++ b/app/code/Magento/Sales/Exception/CouldNotShipException.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Exception;
+
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Sales\Api\Exception\CouldNotShipExceptionInterface;
+
+/**
+ * Class CouldNotShipException
+ */
+class CouldNotShipException extends LocalizedException implements CouldNotShipExceptionInterface
+{
+}
diff --git a/app/code/Magento/Sales/Model/OrderInvoice.php b/app/code/Magento/Sales/Model/InvoiceOrder.php
similarity index 86%
rename from app/code/Magento/Sales/Model/OrderInvoice.php
rename to app/code/Magento/Sales/Model/InvoiceOrder.php
index b499b7028bce1336f29688b4ebb04aaa9db32048..e51b46082d943d8ff609bacb80fae19c861afba4 100644
--- a/app/code/Magento/Sales/Model/OrderInvoice.php
+++ b/app/code/Magento/Sales/Model/InvoiceOrder.php
@@ -9,22 +9,25 @@ namespace Magento\Sales\Model;
 use Magento\Framework\App\ResourceConnection;
 use Magento\Sales\Api\Data\InvoiceCommentCreationInterface;
 use Magento\Sales\Api\Data\InvoiceCreationArgumentsInterface;
-use Magento\Sales\Api\OrderInvoiceInterface;
+use Magento\Sales\Api\InvoiceOrderInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order\Config as OrderConfig;
+use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\Invoice\NotifierInterface;
 use Magento\Sales\Model\Order\InvoiceDocumentFactory;
+use Magento\Sales\Model\Order\InvoiceQuantityValidator;
 use Magento\Sales\Model\Order\InvoiceRepository;
-use Magento\Sales\Model\Order\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
+use Magento\Sales\Model\Order\Validation\CanInvoice;
 use Psr\Log\LoggerInterface;
 
 /**
- * Class InvoiceService
+ * Class InvoiceOrder
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class OrderInvoice implements OrderInvoiceInterface
+class InvoiceOrder implements InvoiceOrderInterface
 {
     /**
      * @var ResourceConnection
@@ -76,12 +79,18 @@ class OrderInvoice implements OrderInvoiceInterface
      */
     private $logger;
 
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
     /**
      * OrderInvoice constructor.
      * @param ResourceConnection $resourceConnection
      * @param OrderRepositoryInterface $orderRepository
      * @param InvoiceDocumentFactory $invoiceDocumentFactory
      * @param InvoiceValidatorInterface $invoiceValidator
+     * @param OrderValidatorInterface $orderValidator
      * @param PaymentAdapterInterface $paymentAdapter
      * @param OrderStateResolverInterface $orderStateResolver
      * @param OrderConfig $config
@@ -95,6 +104,7 @@ class OrderInvoice implements OrderInvoiceInterface
         OrderRepositoryInterface $orderRepository,
         InvoiceDocumentFactory $invoiceDocumentFactory,
         InvoiceValidatorInterface $invoiceValidator,
+        OrderValidatorInterface $orderValidator,
         PaymentAdapterInterface $paymentAdapter,
         OrderStateResolverInterface $orderStateResolver,
         OrderConfig $config,
@@ -106,6 +116,7 @@ class OrderInvoice implements OrderInvoiceInterface
         $this->orderRepository = $orderRepository;
         $this->invoiceDocumentFactory = $invoiceDocumentFactory;
         $this->invoiceValidator = $invoiceValidator;
+        $this->orderValidator = $orderValidator;
         $this->paymentAdapter = $paymentAdapter;
         $this->orderStateResolver = $orderStateResolver;
         $this->config = $config;
@@ -147,7 +158,16 @@ class OrderInvoice implements OrderInvoiceInterface
             ($appendComment && $notify),
             $arguments
         );
-        $errorMessages = $this->invoiceValidator->validate($invoice, $order);
+        $errorMessages = array_merge(
+            $this->invoiceValidator->validate(
+                $invoice,
+                [InvoiceQuantityValidator::class]
+            ),
+            $this->orderValidator->validate(
+                $order,
+                [CanInvoice::class]
+            )
+        );
         if (!empty($errorMessages)) {
             throw new \Magento\Sales\Exception\DocumentValidationException(
                 __("Invoice Document Validation Error(s):\n" . implode("\n", $errorMessages))
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/CommentCreation.php b/app/code/Magento/Sales/Model/Order/Invoice/CommentCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa53f72ebcafcccc24a5e0cbf35b9cf208ec49ad
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Invoice/CommentCreation.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Model\Order\Invoice;
+
+use Magento\Sales\Api\Data\InvoiceCommentCreationInterface;
+
+/**
+ * Class InvoiceCommentCreation
+ */
+class CommentCreation implements InvoiceCommentCreationInterface
+{
+
+    /**
+     * @var string
+     */
+    private $comment;
+
+    /**
+     * @var int
+     */
+    private $isVisibleOnFront;
+
+    /**
+     * @var \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * Gets the comment for the invoice.
+     *
+     * @return string Comment.
+     */
+    public function getComment()
+    {
+        return $this->comment;
+    }
+
+    /**
+     * Sets the comment for the invoice.
+     *
+     * @param string $comment
+     * @return $this
+     */
+    public function setComment($comment)
+    {
+        $this->comment = $comment;
+        return $this;
+    }
+
+    /**
+     * Gets the is-visible-on-storefront flag value for the invoice.
+     *
+     * @return int Is-visible-on-storefront flag value.
+     */
+    public function getIsVisibleOnFront()
+    {
+        return $this->isVisibleOnFront;
+    }
+
+    /**
+     * Sets the is-visible-on-storefront flag value for the invoice.
+     *
+     * @param int $isVisibleOnFront
+     * @return $this
+     */
+    public function setIsVisibleOnFront($isVisibleOnFront)
+    {
+        $this->isVisibleOnFront = $isVisibleOnFront;
+        return $this;
+    }
+
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\InvoiceCommentCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidator.php b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..cbb68edaa8a5508968ce4453973b5631a35768e5
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidator.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Invoice;
+
+use Magento\Sales\Api\Data\InvoiceInterface;
+
+/**
+ * Class InvoiceValidatorRunner
+ */
+class InvoiceValidator implements InvoiceValidatorInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Validator
+     */
+    private $validator;
+
+    /**
+     * InvoiceValidatorRunner constructor.
+     * @param \Magento\Sales\Model\Validator $validator
+     */
+    public function __construct(\Magento\Sales\Model\Validator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(InvoiceInterface $entity, array $validators)
+    {
+        return $this->validator->validate($entity, $validators);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..568019a40fce5bc69ccab49ca8b3f4fee048505e
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Invoice/InvoiceValidatorInterface.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Invoice;
+
+use Magento\Sales\Api\Data\InvoiceInterface;
+use Magento\Sales\Exception\DocumentValidationException;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Interface InvoiceValidatorInterface
+ */
+interface InvoiceValidatorInterface
+{
+    /**
+     * @param InvoiceInterface $entity
+     * @param ValidatorInterface[] $validators
+     * @return string[]
+     * @throws DocumentValidationException
+     */
+    public function validate(InvoiceInterface $entity, array $validators);
+}
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/ItemCreation.php b/app/code/Magento/Sales/Model/Order/Invoice/ItemCreation.php
index abc19c3aaa73d99550f9157634d315b1053baf1d..26d8d7ae6ca99fd7191fdfaae957d4a067cd1455 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/ItemCreation.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/ItemCreation.php
@@ -23,6 +23,11 @@ class ItemCreation implements InvoiceItemCreationInterface
      */
     private $qty;
 
+    /**
+     * @var \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
     /**
      * {@inheritdoc}
      */
@@ -54,4 +59,27 @@ class ItemCreation implements InvoiceItemCreationInterface
     {
         $this->qty = $qty;
     }
+
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\InvoiceItemCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Order/InvoiceValidator.php b/app/code/Magento/Sales/Model/Order/InvoiceQuantityValidator.php
similarity index 73%
rename from app/code/Magento/Sales/Model/Order/InvoiceValidator.php
rename to app/code/Magento/Sales/Model/Order/InvoiceQuantityValidator.php
index 35222599fc69ec67f636a6db69949d8d33006655..9ae81dacb0a17408337bec32961da40056ab4a8a 100644
--- a/app/code/Magento/Sales/Model/Order/InvoiceValidator.php
+++ b/app/code/Magento/Sales/Model/Order/InvoiceQuantityValidator.php
@@ -9,42 +9,38 @@ namespace Magento\Sales\Model\Order;
 use Magento\Sales\Api\Data\InvoiceInterface;
 use Magento\Sales\Api\Data\InvoiceItemInterface;
 use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\ValidatorInterface;
 
 /**
  * Interface InvoiceValidatorInterface
  */
-class InvoiceValidator implements InvoiceValidatorInterface
+class InvoiceQuantityValidator implements ValidatorInterface
 {
     /**
-     * @var OrderValidatorInterface
+     * @var OrderRepositoryInterface
      */
-    private $orderValidator;
+    private $orderRepository;
 
     /**
      * InvoiceValidator constructor.
-     * @param OrderValidatorInterface $orderValidator
+     * @param OrderRepositoryInterface $orderRepository
      */
-    public function __construct(OrderValidatorInterface $orderValidator)
+    public function __construct(OrderRepositoryInterface $orderRepository)
     {
-        $this->orderValidator = $orderValidator;
+        $this->orderRepository = $orderRepository;
     }
 
     /**
-     * @param InvoiceInterface $invoice
-     * @param OrderInterface $order
-     * @return array
+     * @inheritdoc
      */
-    public function validate(InvoiceInterface $invoice, OrderInterface $order)
+    public function validate($invoice)
     {
-        $messages = $this->checkQtyAvailability($invoice, $order);
-
-        if (!$this->orderValidator->canInvoice($order)) {
-            $messages[] = __(
-                'An invoice cannot be created when an order has a status of %1.',
-                $order->getStatus()
-            );
+        if ($invoice->getOrderId() === null) {
+            return [__('Order Id is required for invoice document')];
         }
-        return $messages;
+        $order = $this->orderRepository->get($invoice->getOrderId());
+        return $this->checkQtyAvailability($invoice, $order);
     }
 
     /**
diff --git a/app/code/Magento/Sales/Model/Order/InvoiceValidatorInterface.php b/app/code/Magento/Sales/Model/Order/InvoiceValidatorInterface.php
deleted file mode 100644
index 64b2f98dfe37eb15463d77509a14a9b5a579e043..0000000000000000000000000000000000000000
--- a/app/code/Magento/Sales/Model/Order/InvoiceValidatorInterface.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Sales\Model\Order;
-
-use Magento\Sales\Api\Data\InvoiceInterface;
-use Magento\Sales\Api\Data\OrderInterface;
-
-/**
- * Interface InvoiceValidatorInterface
- *
- * @api
- */
-interface InvoiceValidatorInterface
-{
-    /**
-     * @param InvoiceInterface $invoice
-     * @param OrderInterface $order
-     * @return array
-     */
-    public function validate(InvoiceInterface $invoice, OrderInterface $order);
-}
diff --git a/app/code/Magento/Sales/Model/Order/OrderValidator.php b/app/code/Magento/Sales/Model/Order/OrderValidator.php
index c476671136875658e16185770b223c538e0d4e2f..8208af96c93d34cbae918883047b116713faad98 100644
--- a/app/code/Magento/Sales/Model/Order/OrderValidator.php
+++ b/app/code/Magento/Sales/Model/Order/OrderValidator.php
@@ -3,40 +3,35 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Sales\Model\Order;
 
 use Magento\Sales\Api\Data\OrderInterface;
-use Magento\Sales\Model\Order;
+use Magento\Sales\Exception\DocumentValidationException;
 
 /**
- * Order Validator
- *
+ * Class OrderValidator
  */
 class OrderValidator implements OrderValidatorInterface
 {
     /**
-     * Retrieve order invoice availability
-     *
-     * @param OrderInterface $order
-     * @return bool
+     * @var \Magento\Sales\Model\Validator
+     */
+    private $validator;
+
+    /**
+     * OrderValidator constructor.
+     * @param \Magento\Sales\Model\Validator $validator
+     */
+    public function __construct(\Magento\Sales\Model\Validator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @inheritdoc
      */
-    public function canInvoice(OrderInterface $order)
+    public function validate(OrderInterface $entity, array $validators)
     {
-        if ($order->getState() === Order::STATE_PAYMENT_REVIEW ||
-            $order->getState() === Order::STATE_HOLDED ||
-            $order->getState() === Order::STATE_CANCELED ||
-            $order->getState() === Order::STATE_COMPLETE ||
-            $order->getState() === Order::STATE_CLOSED
-        ) {
-            return false;
-        };
-        /** @var \Magento\Sales\Model\Order\Item $item */
-        foreach ($order->getItems() as $item) {
-            if ($item->getQtyToInvoice() > 0 && !$item->getLockedDoInvoice()) {
-                return true;
-            }
-        }
-        return false;
+        return $this->validator->validate($entity, $validators);
     }
 }
diff --git a/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php b/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
index d0dcc38af642a7633af1b3ec4de124bc140c9497..c5a9a6c1d32963fcc223099efe1fcb81bb530464 100644
--- a/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
+++ b/app/code/Magento/Sales/Model/Order/OrderValidatorInterface.php
@@ -3,21 +3,22 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Sales\Model\Order;
 
 use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Exception\DocumentValidationException;
+use Magento\Sales\Model\ValidatorInterface;
 
 /**
  * Interface OrderValidatorInterface
- *
- * @api
  */
 interface OrderValidatorInterface
 {
     /**
-     * @param OrderInterface $order
-     * @return bool
+     * @param OrderInterface $entity
+     * @param ValidatorInterface[] $validators
+     * @return string[]
+     * @throws DocumentValidationException
      */
-    public function canInvoice(OrderInterface $order);
+    public function validate(OrderInterface $entity, array $validators);
 }
diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php
index 6647bae750fffebc8a28ca09102b596336badd7f..2277f92d6e0e8be638c919f02dfc13d1054fb819 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment.php
@@ -405,7 +405,7 @@ class Shipment extends AbstractModel implements EntityInterface, ShipmentInterfa
      * Adds comment to shipment with additional possibility to send it to customer via email
      * and show it in customer account
      *
-     * @param \Magento\Sales\Model\Order\Shipment\Comment $comment
+     * @param \Magento\Sales\Model\Order\Shipment\Comment|string $comment
      * @param bool $notify
      * @param bool $visibleOnFront
      * @return $this
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/CommentCreation.php b/app/code/Magento/Sales/Model/Order/Shipment/CommentCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..19d06fb0eff3275a41ccd2d0c9cc42e77c0436c7
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/CommentCreation.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\ShipmentCommentCreationInterface;
+
+/**
+ * Class CommentCreation
+ */
+class CommentCreation implements ShipmentCommentCreationInterface
+{
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * @var string
+     */
+    private $comment;
+
+    /**
+     * @var int
+     */
+    private $isVisibleOnFront;
+
+    /**
+     * Retrieve existing extension attributes object or create a new one.
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * Set an extension attributes object.
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentCommentCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+
+    /**
+     * Gets the comment for the invoice.
+     *
+     * @return string Comment.
+     */
+    public function getComment()
+    {
+        return $this->comment;
+    }
+
+    /**
+     * Sets the comment for the invoice.
+     *
+     * @param string $comment
+     * @return $this
+     */
+    public function setComment($comment)
+    {
+        $this->comment = $comment;
+        return $this;
+    }
+
+    /**
+     * Gets the is-visible-on-storefront flag value for the invoice.
+     *
+     * @return int Is-visible-on-storefront flag value.
+     */
+    public function getIsVisibleOnFront()
+    {
+        return $this->isVisibleOnFront;
+    }
+
+    /**
+     * Sets the is-visible-on-storefront flag value for the invoice.
+     *
+     * @param int $isVisibleOnFront
+     * @return $this
+     */
+    public function setIsVisibleOnFront($isVisibleOnFront)
+    {
+        $this->isVisibleOnFront = $isVisibleOnFront;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/CreationArguments.php b/app/code/Magento/Sales/Model/Order/Shipment/CreationArguments.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a43a73553e79ab7887995c3a691263ff86c7cd6
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/CreationArguments.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Creation arguments for Shipment.
+ *
+ * @api
+ */
+class CreationArguments implements \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface
+{
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentCreationArgumentsExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Item.php b/app/code/Magento/Sales/Model/Order/Shipment/Item.php
index c7fdca853b17e366e9a64201623b5f68697c8381..8627f76031b06657d2d727b5261a89cc261ea6e1 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/Item.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Item.php
@@ -151,22 +151,7 @@ class Item extends AbstractModel implements ShipmentItemInterface
      */
     public function setQty($qty)
     {
-        if ($this->getOrderItem()->getIsQtyDecimal()) {
-            $qty = (double)$qty;
-        } else {
-            $qty = (int)$qty;
-        }
-        $qty = $qty > 0 ? $qty : 0;
-        /**
-         * Check qty availability
-         */
-        if ($qty <= $this->getOrderItem()->getQtyToShip() || $this->getOrderItem()->isDummy(true)) {
-            $this->setData('qty', $qty);
-        } else {
-            throw new \Magento\Framework\Exception\LocalizedException(
-                __('We found an invalid quantity to ship for item "%1".', $this->getName())
-            );
-        }
+        $this->setData('qty', $qty);
         return $this;
     }
 
@@ -174,6 +159,7 @@ class Item extends AbstractModel implements ShipmentItemInterface
      * Applying qty to order item
      *
      * @return $this
+     * @throws \Magento\Framework\Exception\LocalizedException
      */
     public function register()
     {
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ItemCreation.php b/app/code/Magento/Sales/Model/Order/Shipment/ItemCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3cb2f23d7cf31e81a737fa06c64b89d1d11d796
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/ItemCreation.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\ShipmentItemCreationInterface;
+
+/**
+ * Class ItemCreation
+ */
+class ItemCreation implements ShipmentItemCreationInterface
+{
+    /**
+     * @var int
+     */
+    private $orderItemId;
+
+    /**
+     * @var float
+     */
+    private $qty;
+
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    //@codeCoverageIgnoreStart
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getOrderItemId()
+    {
+        return $this->orderItemId;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setOrderItemId($orderItemId)
+    {
+        $this->orderItemId = $orderItemId;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getQty()
+    {
+        return $this->qty;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setQty($qty)
+    {
+        $this->qty = $qty;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface|null
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface $extensionAttributes
+     * @return $this
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentItemCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+    //@codeCoverageIgnoreEnd
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Notifier.php b/app/code/Magento/Sales/Model/Order/Shipment/Notifier.php
new file mode 100644
index 0000000000000000000000000000000000000000..21dd5ad4a58f62ad2b77143e373f9e0f19c3bc66
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Notifier.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Shipment notifier.
+ *
+ * @api
+ */
+class Notifier implements \Magento\Sales\Model\Order\Shipment\NotifierInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Shipment\SenderInterface[]
+     */
+    private $senders;
+
+    /**
+     * @param \Magento\Sales\Model\Order\Shipment\SenderInterface[] $senders
+     */
+    public function __construct(array $senders = [])
+    {
+        $this->senders = $senders;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function notify(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\ShipmentInterface $shipment,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    ) {
+        foreach ($this->senders as $sender) {
+            $sender->send($order, $shipment, $comment, $forceSyncMode);
+        }
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/NotifierInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/NotifierInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..f34eb6178d09468de16f48fba3a717de3b22091a
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/NotifierInterface.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Interface for Shipment notifier.
+ *
+ * @api
+ */
+interface NotifierInterface
+{
+    /**
+     * Notifies customer.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\ShipmentInterface $shipment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return void
+     */
+    public function notify(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\ShipmentInterface $shipment,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php
new file mode 100644
index 0000000000000000000000000000000000000000..040ab12949be1748638cd7e83ff8c971b7e34161
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+
+class OrderRegistrar implements \Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface
+{
+    /**
+     * @param OrderInterface $order
+     * @param ShipmentInterface $shipment
+     * @return OrderInterface
+     */
+    public function register(OrderInterface $order, ShipmentInterface $shipment)
+    {
+        /** @var  \Magento\Sales\Api\Data\ShipmentItemInterface|\Magento\Sales\Model\Order\Shipment\Item $item */
+        foreach ($shipment->getItems() as $item) {
+            if ($item->getQty() > 0) {
+                $item->register();
+            }
+        }
+        return $order;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrarInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrarInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d54acece35997efcb2db7c62a9fb92c42cd4788
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrarInterface.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+
+/**
+ * Interface OrderRegistrarInterface
+ *
+ * Calculate order shipped data based on created shipment
+ *
+ * @api
+ */
+interface OrderRegistrarInterface
+{
+    /**
+     * @param OrderInterface $order
+     * @param ShipmentInterface $shipment
+     * @return OrderInterface
+     */
+    public function register(OrderInterface $order, ShipmentInterface $shipment);
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Package.php b/app/code/Magento/Sales/Model/Order/Shipment/Package.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f8f54336a2c5b989ef7728866d8b18039c492f4
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Package.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Class Package
+ * @api
+ */
+class Package implements \Magento\Sales\Api\Data\ShipmentPackageInterface
+{
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentPackageExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentPackageExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/PackageCreation.php b/app/code/Magento/Sales/Model/Order/Shipment/PackageCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..50ad944b8251c62a6df8af329839d58a49d8827d
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/PackageCreation.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Class PackageCreation
+ * @api
+ */
+class PackageCreation implements \Magento\Sales\Api\Data\ShipmentPackageCreationInterface
+{
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentPackageCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentPackageCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
new file mode 100644
index 0000000000000000000000000000000000000000..228a45ff16aaef74de124cbd24041d1e27227112
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment\Sender;
+
+use Magento\Sales\Model\Order\Email\Sender;
+use Magento\Sales\Model\Order\Shipment\SenderInterface;
+
+/**
+ * Email notification sender for Shipment.
+ */
+class EmailSender extends Sender implements SenderInterface
+{
+    /**
+     * @var \Magento\Payment\Helper\Data
+     */
+    private $paymentHelper;
+
+    /**
+     * @var \Magento\Sales\Model\ResourceModel\Order\Shipment
+     */
+    private $shipmentResource;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface
+     */
+    private $globalConfig;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface
+     */
+    private $eventManager;
+
+    /**
+     * @param \Magento\Sales\Model\Order\Email\Container\Template $templateContainer
+     * @param \Magento\Sales\Model\Order\Email\Container\ShipmentIdentity $identityContainer
+     * @param \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory
+     * @param \Psr\Log\LoggerInterface $logger
+     * @param \Magento\Sales\Model\Order\Address\Renderer $addressRenderer
+     * @param \Magento\Payment\Helper\Data $paymentHelper
+     * @param \Magento\Sales\Model\ResourceModel\Order\Shipment $shipmentResource
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig
+     * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     */
+    public function __construct(
+        \Magento\Sales\Model\Order\Email\Container\Template $templateContainer,
+        \Magento\Sales\Model\Order\Email\Container\ShipmentIdentity $identityContainer,
+        \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
+        \Psr\Log\LoggerInterface $logger,
+        \Magento\Sales\Model\Order\Address\Renderer $addressRenderer,
+        \Magento\Payment\Helper\Data $paymentHelper,
+        \Magento\Sales\Model\ResourceModel\Order\Shipment $shipmentResource,
+        \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
+        \Magento\Framework\Event\ManagerInterface $eventManager
+    ) {
+        parent::__construct(
+            $templateContainer,
+            $identityContainer,
+            $senderBuilderFactory,
+            $logger,
+            $addressRenderer
+        );
+
+        $this->paymentHelper = $paymentHelper;
+        $this->shipmentResource = $shipmentResource;
+        $this->globalConfig = $globalConfig;
+        $this->eventManager = $eventManager;
+    }
+
+    /**
+     * Sends order shipment email to the customer.
+     *
+     * Email will be sent immediately in two cases:
+     *
+     * - if asynchronous email sending is disabled in global settings
+     * - if $forceSyncMode parameter is set to TRUE
+     *
+     * Otherwise, email will be sent later during running of
+     * corresponding cron job.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\ShipmentInterface $shipment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return bool
+     */
+    public function send(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\ShipmentInterface $shipment,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    ) {
+        $shipment->setSendEmail(true);
+
+        if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
+            $transport = [
+                'order' => $order,
+                'shipment' => $shipment,
+                'comment' => $comment ? $comment->getComment() : '',
+                'billing' => $order->getBillingAddress(),
+                'payment_html' => $this->getPaymentHtml($order),
+                'store' => $order->getStore(),
+                'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+                'formattedBillingAddress' => $this->getFormattedBillingAddress($order)
+            ];
+
+            $this->eventManager->dispatch(
+                'email_shipment_set_template_vars_before',
+                ['sender' => $this, 'transport' => $transport]
+            );
+
+            $this->templateContainer->setTemplateVars($transport);
+
+            if ($this->checkAndSend($order)) {
+                $shipment->setEmailSent(true);
+
+                $this->shipmentResource->saveAttribute($shipment, ['send_email', 'email_sent']);
+
+                return true;
+            }
+        } else {
+            $shipment->setEmailSent(null);
+
+            $this->shipmentResource->saveAttribute($shipment, 'email_sent');
+        }
+
+        $this->shipmentResource->saveAttribute($shipment, 'send_email');
+
+        return false;
+    }
+
+    /**
+     * Returns payment info block as HTML.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     *
+     * @return string
+     */
+    private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order)
+    {
+        return $this->paymentHelper->getInfoBlockHtml(
+            $order->getPayment(),
+            $this->identityContainer->getStore()->getStoreId()
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/SenderInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/SenderInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..a030038b7b139a65ebc38fd5f9fb2c1a76f8a188
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/SenderInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+/**
+ * Interface for notification sender for Shipment.
+ */
+interface SenderInterface
+{
+    /**
+     * Sends notification to a customer.
+     *
+     * @param \Magento\Sales\Api\Data\OrderInterface $order
+     * @param \Magento\Sales\Api\Data\ShipmentInterface $shipment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param bool $forceSyncMode
+     *
+     * @return bool
+     */
+    public function send(
+        \Magento\Sales\Api\Data\OrderInterface $order,
+        \Magento\Sales\Api\Data\ShipmentInterface $shipment,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        $forceSyncMode = false
+    );
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidator.php b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..816551b8b322c126d82795349a4ba081598a955c
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidator.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\ShipmentInterface;
+
+/**
+ * Class ShipmentValidator
+ */
+class ShipmentValidator implements ShipmentValidatorInterface
+{
+    /**
+     * @var \Magento\Sales\Model\Validator
+     */
+    private $validator;
+
+    /**
+     * ShipmentValidator constructor.
+     * @param \Magento\Sales\Model\Validator $validator
+     */
+    public function __construct(\Magento\Sales\Model\Validator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function validate(ShipmentInterface $entity, array $validators)
+    {
+        return $this->validator->validate($entity, $validators);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..198a4019bf6b898e0c85fd2e2ff7c7ff77c2a9f6
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentValidatorInterface.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Exception\DocumentValidationException;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Interface ShipmentValidatorInterface
+ */
+interface ShipmentValidatorInterface
+{
+    /**
+     * @param ShipmentInterface $shipment
+     * @param ValidatorInterface[] $validators
+     * @return string[]
+     * @throws DocumentValidationException
+     */
+    public function validate(ShipmentInterface $shipment, array $validators);
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/TrackCreation.php b/app/code/Magento/Sales/Model/Order/Shipment/TrackCreation.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e8ce097f411d91794ea07ce904851bce725f169
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/TrackCreation.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment;
+
+use Magento\Sales\Api\Data\ShipmentTrackCreationInterface;
+
+/**
+ * Class TrackCreation
+ */
+class TrackCreation implements ShipmentTrackCreationInterface
+{
+    /**
+     * @var string
+     */
+    private $trackNumber;
+
+    /**
+     * @var string
+     */
+    private $title;
+
+    /**
+     * @var string
+     */
+    private $carrierCode;
+
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentTrackCreationExtensionInterface
+     */
+    private $extensionAttributes;
+
+    //@codeCoverageIgnoreStart
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTrackNumber()
+    {
+        return $this->trackNumber;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setTrackNumber($trackNumber)
+    {
+        $this->trackNumber = $trackNumber;
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setTitle($title)
+    {
+        $this->title = $title;
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCarrierCode()
+    {
+        return $this->carrierCode;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setCarrierCode($carrierCode)
+    {
+        $this->carrierCode = $carrierCode;
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getExtensionAttributes()
+    {
+        return $this->extensionAttributes;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setExtensionAttributes(
+        \Magento\Sales\Api\Data\ShipmentTrackCreationExtensionInterface $extensionAttributes
+    ) {
+        $this->extensionAttributes = $extensionAttributes;
+        return $this;
+    }
+
+    //@codeCoverageIgnoreEnd
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Validation/QuantityValidator.php b/app/code/Magento/Sales/Model/Order/Shipment/Validation/QuantityValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..20e3712d889ed249ebca9fbbab0945d37a8cb8cf
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Validation/QuantityValidator.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment\Validation;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Exception\DocumentValidationException;
+use Magento\Sales\Model\Order\Item;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class QuantityValidator
+ */
+class QuantityValidator implements ValidatorInterface
+{
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * InvoiceValidator constructor.
+     * @param OrderRepositoryInterface $orderRepository
+     */
+    public function __construct(
+        OrderRepositoryInterface $orderRepository
+    ) {
+        $this->orderRepository = $orderRepository;
+    }
+
+    /**
+     * @param ShipmentInterface $entity
+     * @return array
+     * @throws DocumentValidationException
+     * @throws NoSuchEntityException
+     */
+    public function validate($entity)
+    {
+        if ($entity->getOrderId() === null) {
+            return [__('Order Id is required for shipment document')];
+        }
+
+        if (empty($entity->getItems())) {
+            return [__('You can\'t create a shipment without products.')];
+        }
+        $messages = [];
+
+        $order = $this->orderRepository->get($entity->getOrderId());
+        $orderItemsById = $this->getOrderItems($order);
+
+        $totalQuantity = 0;
+        foreach ($entity->getItems() as $item) {
+            if (!isset($orderItemsById[$item->getOrderItemId()])) {
+                $messages[] = __(
+                    'The shipment contains product SKU "%1" that is not part of the original order.',
+                    $item->getSku()
+                );
+                continue;
+            }
+            $orderItem = $orderItemsById[$item->getOrderItemId()];
+
+            if (!$this->isQtyAvailable($orderItem, $item->getQty())) {
+                $messages[] =__(
+                    'The quantity to ship must not be greater than the unshipped quantity'
+                    . ' for product SKU "%1".',
+                    $orderItem->getSku()
+                );
+            } else {
+                $totalQuantity += $item->getQty();
+            }
+        }
+        if ($totalQuantity <= 0) {
+            $messages[] = __('You can\'t create a shipment without products.');
+        }
+
+        return $messages;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return OrderItemInterface[]
+     */
+    private function getOrderItems(OrderInterface $order)
+    {
+        $orderItemsById = [];
+        foreach ($order->getItems() as $item) {
+            $orderItemsById[$item->getItemId()] = $item;
+        }
+
+        return $orderItemsById;
+    }
+
+    /**
+     * @param Item $orderItem
+     * @param int $qty
+     * @return bool
+     */
+    private function isQtyAvailable(Item $orderItem, $qty)
+    {
+        return $qty <= $orderItem->getQtyToShip() || $orderItem->isDummy(true);
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Validation/TrackValidator.php b/app/code/Magento/Sales/Model/Order/Shipment/Validation/TrackValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..55970d37c597d7af6d0369e26b2085ab431108ed
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Validation/TrackValidator.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Shipment\Validation;
+
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class TrackRequiredField
+ */
+class TrackValidator implements ValidatorInterface
+{
+    /**
+     * @param object|ShipmentInterface $entity
+     * @return array
+     */
+    public function validate($entity)
+    {
+        $messages = [];
+        if (!$entity->getTracks()) {
+            return $messages;
+        }
+        foreach ($entity->getTracks() as $track) {
+            if (!$track->getTrackNumber()) {
+                $messages[] = __('Please enter a tracking number.');
+            }
+        }
+        return $messages;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..d10f84d8155432954ec95c75f9b49108767f2dd3
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order;
+
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Api\Data\ShipmentItemCreationInterface;
+use Magento\Sales\Api\Data\ShipmentPackageCreationInterface;
+use Magento\Sales\Api\Data\ShipmentTrackCreationInterface;
+use Magento\Framework\EntityManager\HydratorPool;
+use Magento\Sales\Model\Order\Shipment\TrackFactory;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentCommentCreationInterface;
+use Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface;
+
+/**
+ * Class ShipmentDocumentFactory
+ *
+ * @api
+ */
+class ShipmentDocumentFactory
+{
+    /**
+     * @var ShipmentFactory
+     */
+    private $shipmentFactory;
+
+    /**
+     * @var TrackFactory
+     */
+    private $trackFactory;
+
+    /**
+     * @var HydratorPool
+     */
+    private $hydratorPool;
+
+    /**
+     * ShipmentDocumentFactory constructor.
+     *
+     * @param ShipmentFactory $shipmentFactory
+     * @param HydratorPool $hydratorPool
+     * @param TrackFactory $trackFactory
+     */
+    public function __construct(
+        ShipmentFactory $shipmentFactory,
+        HydratorPool $hydratorPool,
+        TrackFactory $trackFactory
+    ) {
+        $this->shipmentFactory = $shipmentFactory;
+        $this->trackFactory = $trackFactory;
+        $this->hydratorPool = $hydratorPool;
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     *
+     * @param OrderInterface $order
+     * @param ShipmentItemCreationInterface[] $items
+     * @param ShipmentTrackCreationInterface[] $tracks
+     * @param ShipmentCommentCreationInterface|null $comment
+     * @param bool $appendComment
+     * @param ShipmentPackageCreationInterface[] $packages
+     * @param ShipmentCreationArgumentsInterface|null $arguments
+     * @return ShipmentInterface
+     */
+    public function create(
+        OrderInterface $order,
+        array $items = [],
+        array $tracks = [],
+        ShipmentCommentCreationInterface $comment = null,
+        $appendComment = false,
+        array $packages = [],
+        ShipmentCreationArgumentsInterface $arguments = null
+    ) {
+        $shipmentItems = $this->itemsToArray($items);
+        /** @var Shipment $shipment */
+        $shipment = $this->shipmentFactory->create(
+            $order,
+            $shipmentItems
+        );
+        $this->prepareTracks($shipment, $tracks);
+        if ($comment) {
+            $shipment->addComment(
+                $comment->getComment(),
+                $appendComment,
+                $comment->getIsVisibleOnFront()
+            );
+        }
+
+        return $shipment;
+    }
+
+    /**
+     * Adds tracks to the shipment.
+     *
+     * @param ShipmentInterface $shipment
+     * @param ShipmentTrackCreationInterface[] $tracks
+     * @return ShipmentInterface
+     */
+    private function prepareTracks(\Magento\Sales\Api\Data\ShipmentInterface $shipment, array $tracks)
+    {
+        foreach ($tracks as $track) {
+            $hydrator = $this->hydratorPool->getHydrator(
+                \Magento\Sales\Api\Data\ShipmentTrackCreationInterface::class
+            );
+            $shipment->addTrack($this->trackFactory->create(['data' => $hydrator->extract($track)]));
+        }
+        return $shipment;
+    }
+
+    /**
+     * Convert items to array
+     *
+     * @param ShipmentItemCreationInterface[] $items
+     * @return array
+     */
+    private function itemsToArray(array $items = [])
+    {
+        $shipmentItems = [];
+        foreach ($items as $item) {
+            $shipmentItems[$item->getOrderItemId()] = $item->getQty();
+        }
+        return $shipmentItems;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
index 2ac012760ee4704be9defe05cfe7c2d01529359e..a8839c75375870ce03294ca3d585635fdff84f14 100644
--- a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
+++ b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php
@@ -5,6 +5,10 @@
  */
 namespace Magento\Sales\Model\Order;
 
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+
 /**
  * Factory class for @see \Magento\Sales\Api\Data\ShipmentInterface
  */
@@ -72,6 +76,8 @@ class ShipmentFactory
      * @param \Magento\Sales\Model\Order $order
      * @param array $items
      * @return \Magento\Sales\Api\Data\ShipmentInterface
+     * @throws LocalizedException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     protected function prepareItems(
         \Magento\Sales\Api\Data\ShipmentInterface $shipment,
@@ -79,7 +85,6 @@ class ShipmentFactory
         array $items = []
     ) {
         $totalQty = 0;
-
         foreach ($order->getAllItems() as $orderItem) {
             if (!$this->canShipItem($orderItem, $items)) {
                 continue;
@@ -103,7 +108,7 @@ class ShipmentFactory
                             $qty = $bundleSelectionAttributes['qty'] * $items[$orderItem->getParentItemId()];
                             $qty = min($qty, $orderItem->getSimpleQtyToShip());
 
-                            $item->setQty($qty);
+                            $item->setQty($this->castQty($orderItem, $qty));
                             $shipment->addItem($item);
 
                             continue;
@@ -126,10 +131,9 @@ class ShipmentFactory
 
             $totalQty += $qty;
 
-            $item->setQty($qty);
+            $item->setQty($this->castQty($orderItem, $qty));
             $shipment->addItem($item);
         }
-
         return $shipment->setTotalQty($totalQty);
     }
 
@@ -211,4 +215,20 @@ class ShipmentFactory
             return $item->getQtyToShip() > 0;
         }
     }
+
+    /**
+     * @param Item $item
+     * @param string|int|float $qty
+     * @return float|int
+     */
+    private function castQty(\Magento\Sales\Model\Order\Item $item, $qty)
+    {
+        if ($item->getIsQtyDecimal()) {
+            $qty = (double)$qty;
+        } else {
+            $qty = (int)$qty;
+        }
+
+        return $qty > 0 ? $qty : 0;
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Order/Validation/CanInvoice.php b/app/code/Magento/Sales/Model/Order/Validation/CanInvoice.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb14dc1bb5180758825966d47d7f92bb06ddacda
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/CanInvoice.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class CanInvoice
+ */
+class CanInvoice implements ValidatorInterface
+{
+    /**
+     * @param OrderInterface $entity
+     * @return array
+     */
+    public function validate($entity)
+    {
+        $messages = [];
+
+        if (!$this->isStateReadyForInvoice($entity)) {
+            $messages[] = __('An invoice cannot be created when an order has a status of %1', $entity->getStatus());
+        } elseif (!$this->canInvoice($entity)) {
+            $messages[] = __('The order does not allow an invoice to be created.');
+        }
+
+        return $messages;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function isStateReadyForInvoice(OrderInterface $order)
+    {
+        if ($order->getState() === Order::STATE_PAYMENT_REVIEW ||
+            $order->getState() === Order::STATE_HOLDED ||
+            $order->getState() === Order::STATE_CANCELED ||
+            $order->getState() === Order::STATE_COMPLETE ||
+            $order->getState() === Order::STATE_CLOSED
+        ) {
+            return false;
+        };
+
+        return true;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function canInvoice(OrderInterface $order)
+    {
+        /** @var \Magento\Sales\Model\Order\Item $item */
+        foreach ($order->getItems() as $item) {
+            if ($item->getQtyToInvoice() > 0 && !$item->getLockedDoInvoice()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Order/Validation/CanShip.php b/app/code/Magento/Sales/Model/Order/Validation/CanShip.php
new file mode 100644
index 0000000000000000000000000000000000000000..46638a62483e6ce0f45a1c79d2774fe2c34d7970
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/Validation/CanShip.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model\Order\Validation;
+
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\ValidatorInterface;
+
+/**
+ * Class CanShip
+ */
+class CanShip implements ValidatorInterface
+{
+    /**
+     * @param OrderInterface $entity
+     * @return array
+     */
+    public function validate($entity)
+    {
+        $messages = [];
+        if (!$this->isStateReadyForShipment($entity)) {
+            $messages[] = __('A shipment cannot be created when an order has a status of %1', $entity->getStatus());
+        } elseif (!$this->canShip($entity)) {
+            $messages[] = __('The order does not allow a shipment to be created.');
+        }
+
+        return $messages;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function isStateReadyForShipment(OrderInterface $order)
+    {
+        if ($order->getState() === Order::STATE_PAYMENT_REVIEW ||
+            $order->getState() === Order::STATE_HOLDED ||
+            $order->getIsVirtual() ||
+            $order->getState() === Order::STATE_CANCELED
+        ) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param OrderInterface $order
+     * @return bool
+     */
+    private function canShip(OrderInterface $order)
+    {
+        /** @var \Magento\Sales\Model\Order\Item $item */
+        foreach ($order->getItems() as $item) {
+            if ($item->getQtyToShip() > 0 && !$item->getIsVirtual() && !$item->getLockedDoShip()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/ShipOrder.php b/app/code/Magento/Sales/Model/ShipOrder.php
new file mode 100644
index 0000000000000000000000000000000000000000..d051144cf73ca166c30ebd6eb9f626306b1720a6
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ShipOrder.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+use Magento\Framework\App\ResourceConnection;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Api\ShipmentRepositoryInterface;
+use Magento\Sales\Api\ShipOrderInterface;
+use Magento\Sales\Model\Order\Config as OrderConfig;
+use Magento\Sales\Model\Order\OrderStateResolverInterface;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\ShipmentDocumentFactory;
+use Magento\Sales\Model\Order\Shipment\NotifierInterface;
+use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
+use Magento\Sales\Model\Order\Shipment\Validation\TrackValidator;
+use Magento\Sales\Model\Order\Validation\CanShip;
+use Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class ShipOrder
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class ShipOrder implements ShipOrderInterface
+{
+    /**
+     * @var ResourceConnection
+     */
+    private $resourceConnection;
+
+    /**
+     * @var OrderRepositoryInterface
+     */
+    private $orderRepository;
+
+    /**
+     * @var ShipmentDocumentFactory
+     */
+    private $shipmentDocumentFactory;
+
+    /**
+     * @var ShipmentValidatorInterface
+     */
+    private $shipmentValidator;
+
+    /**
+     * @var OrderStateResolverInterface
+     */
+    private $orderStateResolver;
+
+    /**
+     * @var OrderConfig
+     */
+    private $config;
+
+    /**
+     * @var ShipmentRepositoryInterface
+     */
+    private $shipmentRepository;
+
+    /**
+     * @var NotifierInterface
+     */
+    private $notifierInterface;
+
+    /**
+     * @var LoggerInterface
+     */
+    private $logger;
+
+    /**
+     * @var OrderValidatorInterface
+     */
+    private $orderValidator;
+
+    /**
+     * @var OrderRegistrarInterface
+     */
+    private $orderRegistrar;
+
+    /**
+     * @param ResourceConnection $resourceConnection
+     * @param OrderRepositoryInterface $orderRepository
+     * @param ShipmentDocumentFactory $shipmentDocumentFactory
+     * @param ShipmentValidatorInterface $shipmentValidator
+     * @param OrderValidatorInterface $orderValidator
+     * @param OrderStateResolverInterface $orderStateResolver
+     * @param OrderConfig $config
+     * @param ShipmentRepositoryInterface $shipmentRepository
+     * @param NotifierInterface $notifierInterface
+     * @param OrderRegistrarInterface $orderRegistrar
+     * @param LoggerInterface $logger
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function __construct(
+        ResourceConnection $resourceConnection,
+        OrderRepositoryInterface $orderRepository,
+        ShipmentDocumentFactory $shipmentDocumentFactory,
+        ShipmentValidatorInterface $shipmentValidator,
+        OrderValidatorInterface $orderValidator,
+        OrderStateResolverInterface $orderStateResolver,
+        OrderConfig $config,
+        ShipmentRepositoryInterface $shipmentRepository,
+        NotifierInterface $notifierInterface,
+        OrderRegistrarInterface $orderRegistrar,
+        LoggerInterface $logger
+    ) {
+        $this->resourceConnection = $resourceConnection;
+        $this->orderRepository = $orderRepository;
+        $this->shipmentDocumentFactory = $shipmentDocumentFactory;
+        $this->shipmentValidator = $shipmentValidator;
+        $this->orderValidator = $orderValidator;
+        $this->orderStateResolver = $orderStateResolver;
+        $this->config = $config;
+        $this->shipmentRepository = $shipmentRepository;
+        $this->notifierInterface = $notifierInterface;
+        $this->logger = $logger;
+        $this->orderRegistrar = $orderRegistrar;
+    }
+
+    /**
+     * @param int $orderId
+     * @param \Magento\Sales\Api\Data\ShipmentItemCreationInterface[] $items
+     * @param bool $notify
+     * @param bool $appendComment
+     * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment
+     * @param \Magento\Sales\Api\Data\ShipmentTrackCreationInterface[] $tracks
+     * @param \Magento\Sales\Api\Data\ShipmentPackageCreationInterface[] $packages
+     * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments
+     * @return int
+     * @throws \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface
+     * @throws \Magento\Sales\Api\Exception\CouldNotShipExceptionInterface
+     * @throws \Magento\Framework\Exception\InputException
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \DomainException
+     */
+    public function execute(
+        $orderId,
+        array $items = [],
+        $notify = false,
+        $appendComment = false,
+        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
+        array $tracks = [],
+        array $packages = [],
+        \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null
+    ) {
+        $connection = $this->resourceConnection->getConnection('sales');
+        $order = $this->orderRepository->get($orderId);
+        $shipment = $this->shipmentDocumentFactory->create(
+            $order,
+            $items,
+            $tracks,
+            $comment,
+            ($appendComment && $notify),
+            $packages,
+            $arguments
+        );
+        $orderValidationResult = $this->orderValidator->validate(
+            $order,
+            [
+                CanShip::class
+            ]
+        );
+        $shipmentValidationResult = $this->shipmentValidator->validate(
+            $shipment,
+            [
+                QuantityValidator::class,
+                TrackValidator::class
+            ]
+        );
+        $validationMessages = array_merge($orderValidationResult, $shipmentValidationResult);
+        if (!empty($validationMessages)) {
+            throw new \Magento\Sales\Exception\DocumentValidationException(
+                __("Shipment Document Validation Error(s):\n" . implode("\n", $validationMessages))
+            );
+        }
+        $connection->beginTransaction();
+        try {
+            $this->orderRegistrar->register($order, $shipment);
+            $order->setState(
+                $this->orderStateResolver->getStateForOrder($order, [OrderStateResolverInterface::IN_PROGRESS])
+            );
+            $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
+            $this->shipmentRepository->save($shipment);
+            $this->orderRepository->save($order);
+            $connection->commit();
+        } catch (\Exception $e) {
+            $this->logger->critical($e);
+            $connection->rollBack();
+            throw new \Magento\Sales\Exception\CouldNotShipException(
+                __('Could not save a shipment, see error log for details')
+            );
+        }
+        if ($notify) {
+            if (!$appendComment) {
+                $comment = null;
+            }
+            $this->notifierInterface->notify($order, $shipment, $comment);
+        }
+        return $shipment->getEntityId();
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Validator.php b/app/code/Magento/Sales/Model/Validator.php
new file mode 100644
index 0000000000000000000000000000000000000000..b8d57ded2970209d5d2184945fbb22f13de47dbd
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Validator.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+use Magento\Framework\Exception\ConfigurationMismatchException;
+use Magento\Framework\ObjectManagerInterface;
+
+/**
+ * Class Validator
+ *
+ * @internal
+ */
+class Validator
+{
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * Validator constructor.
+     *
+     * @param ObjectManagerInterface $objectManager
+     */
+    public function __construct(ObjectManagerInterface $objectManager)
+    {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * @param object $entity
+     * @param ValidatorInterface[] $validators
+     * @return string[]
+     * @throws ConfigurationMismatchException
+     */
+    public function validate($entity, array $validators)
+    {
+        $messages = [];
+        foreach ($validators as $validatorName) {
+            $validator = $this->objectManager->get($validatorName);
+            if (!$validator instanceof ValidatorInterface) {
+                throw new ConfigurationMismatchException(
+                    __(
+                        sprintf('Validator %s is not instance of general validator interface', $validatorName)
+                    )
+                );
+            }
+            $messages = array_merge($messages, $validator->validate($entity));
+        }
+
+        return $messages;
+    }
+}
diff --git a/app/code/Magento/Sales/Model/ValidatorInterface.php b/app/code/Magento/Sales/Model/ValidatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1882782e314f7b47b507c042697f223eadbf36b7
--- /dev/null
+++ b/app/code/Magento/Sales/Model/ValidatorInterface.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Model;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Sales\Exception\DocumentValidationException;
+
+/**
+ * Interface ValidatorInterface
+ */
+interface ValidatorInterface
+{
+    /**
+     * @param object $entity
+     * @return array
+     * @throws DocumentValidationException
+     * @throws NoSuchEntityException
+     */
+    public function validate($entity);
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderInvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
similarity index 89%
rename from app/code/Magento/Sales/Test/Unit/Model/OrderInvoiceTest.php
rename to app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
index bc36da112aa291e82e5f06af887334095544f43f..6dfa929acb6290e0e95bf2011b76ec9811691ecc 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/OrderInvoiceTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/InvoiceOrderTest.php
@@ -14,21 +14,23 @@ use Magento\Sales\Api\Data\OrderInterface;
 use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Config as OrderConfig;
+use Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\Invoice\NotifierInterface;
 use Magento\Sales\Model\Order\InvoiceDocumentFactory;
 use Magento\Sales\Model\Order\InvoiceRepository;
-use Magento\Sales\Model\Order\InvoiceValidatorInterface;
 use Magento\Sales\Model\Order\OrderStateResolverInterface;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
 use Magento\Sales\Model\Order\PaymentAdapterInterface;
-use Magento\Sales\Model\OrderInvoice;
+use Magento\Sales\Model\InvoiceOrder;
 use Psr\Log\LoggerInterface;
 
 /**
- * Class OrderInvoiceTest
+ * Class InvoiceOrderTest
+ * 
  * @SuppressWarnings(PHPMD.TooManyFields)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
+class InvoiceOrderTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
@@ -50,6 +52,11 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
      */
     private $invoiceValidatorMock;
 
+    /**
+     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderValidatorMock;
+
     /**
      * @var PaymentAdapterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -76,9 +83,9 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
     private $notifierInterfaceMock;
 
     /**
-     * @var OrderInvoice|\PHPUnit_Framework_MockObject_MockObject
+     * @var InvoiceOrder|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $orderInvoice;
+    private $invoiceOrder;
 
     /**
      * @var InvoiceCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -128,6 +135,10 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class)
             ->disableOriginalConstructor()
             ->getMock();
@@ -172,11 +183,12 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $this->orderInvoice = new OrderInvoice(
+        $this->invoiceOrder = new InvoiceOrder(
             $this->resourceConnectionMock,
             $this->orderRepositoryMock,
             $this->invoiceDocumentFactoryMock,
             $this->invoiceValidatorMock,
+            $this->orderValidatorMock,
             $this->paymentAdapterMock,
             $this->orderStateResolverMock,
             $this->configMock,
@@ -212,7 +224,11 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
 
         $this->invoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->invoiceMock, $this->orderMock)
+            ->with($this->invoiceMock)
+            ->willReturn([]);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
             ->willReturn([]);
 
         $this->paymentAdapterMock->expects($this->once())
@@ -271,7 +287,7 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             2,
-            $this->orderInvoice->execute(
+            $this->invoiceOrder->execute(
                 $orderId,
                 $capture,
                 $items,
@@ -311,10 +327,14 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
 
         $this->invoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->invoiceMock, $this->orderMock)
+            ->with($this->invoiceMock)
             ->willReturn($errorMessages);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
+            ->willReturn([]);
 
-        $this->orderInvoice->execute(
+        $this->invoiceOrder->execute(
             $orderId,
             $capture,
             $items,
@@ -356,7 +376,11 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
 
         $this->invoiceValidatorMock->expects($this->once())
             ->method('validate')
-            ->with($this->invoiceMock, $this->orderMock)
+            ->with($this->invoiceMock)
+            ->willReturn([]);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
             ->willReturn([]);
         $e = new \Exception();
 
@@ -372,7 +396,7 @@ class OrderInvoiceTest extends \PHPUnit_Framework_TestCase
         $this->adapterInterface->expects($this->once())
             ->method('rollBack');
 
-        $this->orderInvoice->execute(
+        $this->invoiceOrder->execute(
             $orderId,
             $capture,
             $items,
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceQuantityValidatorTest.php
similarity index 66%
rename from app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceValidatorTest.php
rename to app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceQuantityValidatorTest.php
index 6fdfdb61b36359d367200e8506ef9484200c723e..8d800e12a6ff0a562330aee3ea09f25f44fae23d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceValidatorTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceQuantityValidatorTest.php
@@ -6,15 +6,16 @@
 
 namespace Magento\Sales\Test\Unit\Model\Order;
 
+use Magento\Sales\Api\OrderRepositoryInterface;
 use Magento\Sales\Model\Order;
 
 /**
  * Test for \Magento\Sales\Model\Order\InvoiceValidator class
  */
-class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
+class InvoiceQuantityValidatorTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Sales\Model\Order\InvoiceValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Sales\Model\Order\InvoiceQuantityValidator|\PHPUnit_Framework_MockObject_MockObject
      */
     private $model;
 
@@ -24,14 +25,14 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
     private $objectManager;
 
     /**
-     * @var \Magento\Sales\Model\Order\OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Sales\Api\Data\OrderInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $orderValidatorMock;
+    private $orderMock;
 
     /**
-     * @var \Magento\Sales\Api\Data\OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Sales\Api\OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    private $orderMock;
+    private $orderRepositoryMock;
 
     /**
      * @var \Magento\Sales\Api\Data\InvoiceInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -42,24 +43,21 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
-        $this->orderValidatorMock = $this->getMockBuilder(\Magento\Sales\Model\Order\OrderValidatorInterface::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['canInvoice'])
-            ->getMockForAbstractClass();
-
         $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getStatus'])
             ->getMockForAbstractClass();
 
         $this->invoiceMock = $this->getMockBuilder(\Magento\Sales\Api\Data\InvoiceInterface::class)
             ->disableOriginalConstructor()
             ->setMethods(['getTotalQty', 'getItems'])
             ->getMockForAbstractClass();
-
+        $this->orderRepositoryMock = $this->getMockBuilder(
+            OrderRepositoryInterface::class
+        )->disableOriginalConstructor()->getMockForAbstractClass();
+        $this->orderRepositoryMock->expects($this->any())->method('get')->willReturn($this->orderMock);
         $this->model = $this->objectManager->getObject(
-            \Magento\Sales\Model\Order\InvoiceValidator::class,
-            ['orderValidator' => $this->orderValidatorMock]
+            \Magento\Sales\Model\Order\InvoiceQuantityValidator::class,
+            ['orderRepository' => $this->orderRepositoryMock]
         );
     }
 
@@ -75,39 +73,12 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->once())
             ->method('getItems')
             ->willReturn([$orderItemMock]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('canInvoice')
-            ->with($this->orderMock)
-            ->willReturn(true);
-        $this->assertEquals(
-            $expectedResult,
-            $this->model->validate($this->invoiceMock, $this->orderMock)
-        );
-    }
-
-    public function testValidateCanNotInvoiceOrder()
-    {
-        $orderStatus = 'Test Status';
-        $expectedResult = [__('An invoice cannot be created when an order has a status of %1.', $orderStatus)];
-        $invoiceItemMock = $this->getInvoiceItemMock(1, 1);
-        $this->invoiceMock->expects($this->once())
-            ->method('getItems')
-            ->willReturn([$invoiceItemMock]);
-
-        $orderItemMock = $this->getOrderItemMock(1, 1, true);
-        $this->orderMock->expects($this->once())
-            ->method('getItems')
-            ->willReturn([$orderItemMock]);
-        $this->orderMock->expects($this->once())
-            ->method('getStatus')
-            ->willReturn($orderStatus);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('canInvoice')
-            ->with($this->orderMock)
-            ->willReturn(false);
+        $this->invoiceMock->expects($this->exactly(2))
+            ->method('getOrderId')
+            ->willReturn(1);
         $this->assertEquals(
             $expectedResult,
-            $this->model->validate($this->invoiceMock, $this->orderMock)
+            $this->model->validate($this->invoiceMock)
         );
     }
 
@@ -125,13 +96,12 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->once())
             ->method('getItems')
             ->willReturn([$orderItemMock]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('canInvoice')
-            ->with($this->orderMock)
-            ->willReturn(true);
+        $this->invoiceMock->expects($this->exactly(2))
+            ->method('getOrderId')
+            ->willReturn(1);
         $this->assertEquals(
             $expectedResult,
-            $this->model->validate($this->invoiceMock, $this->orderMock)
+            $this->model->validate($this->invoiceMock)
         );
     }
 
@@ -146,13 +116,21 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->once())
             ->method('getItems')
             ->willReturn([]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('canInvoice')
-            ->with($this->orderMock)
-            ->willReturn(true);
+        $this->invoiceMock->expects($this->exactly(2))
+            ->method('getOrderId')
+            ->willReturn(1);
+        $this->assertEquals(
+            $expectedResult,
+            $this->model->validate($this->invoiceMock)
+        );
+    }
+
+    public function testValidateNoOrder()
+    {
+        $expectedResult = [__('Order Id is required for invoice document')];
         $this->assertEquals(
             $expectedResult,
-            $this->model->validate($this->invoiceMock, $this->orderMock)
+            $this->model->validate($this->invoiceMock)
         );
     }
 
@@ -169,13 +147,12 @@ class InvoiceValidatorTest extends \PHPUnit_Framework_TestCase
         $this->orderMock->expects($this->once())
             ->method('getItems')
             ->willReturn([$orderItemMock]);
-        $this->orderValidatorMock->expects($this->once())
-            ->method('canInvoice')
-            ->with($this->orderMock)
-            ->willReturn(true);
+        $this->invoiceMock->expects($this->exactly(2))
+            ->method('getOrderId')
+            ->willReturn(1);
         $this->assertEquals(
             $expectedResult,
-            $this->model->validate($this->invoiceMock, $this->orderMock)
+            $this->model->validate($this->invoiceMock)
         );
     }
 
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5bff791edcca99d72918eaacb915a4257b60e37
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Shipment;
+
+class OrderRegistrarTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Shipment\OrderRegistrar
+     */
+    private $model;
+
+    /**
+     * @var \Magento\Sales\Api\Data\OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentMock;
+
+    protected function setUp()
+    {
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->shipmentMock = $this->getMockBuilder(\Magento\Sales\Api\Data\ShipmentInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->model = new \Magento\Sales\Model\Order\Shipment\OrderRegistrar();
+    }
+
+    public function testRegister()
+    {
+        $item1 = $this->getShipmentItemMock();
+        $item1->expects($this->once())
+            ->method('getQty')
+            ->willReturn(0);
+        $item1->expects($this->never())
+            ->method('register');
+
+        $item2 = $this->getShipmentItemMock();
+        $item2->expects($this->once())
+            ->method('getQty')
+            ->willReturn(0.5);
+        $item2->expects($this->once())
+            ->method('register');
+
+        $items = [$item1, $item2];
+        $this->shipmentMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn($items);
+        $this->assertEquals(
+            $this->orderMock,
+            $this->model->register($this->orderMock, $this->shipmentMock)
+        );
+    }
+
+    /**
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    private function getShipmentItemMock()
+    {
+        return $this->getMockBuilder(\Magento\Sales\Api\Data\ShipmentItemInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['register'])
+            ->getMockForAbstractClass();
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8373c7e57d0fe32a400a02f0f77362b9676bf3f6
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
@@ -0,0 +1,361 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Shipment\Sender;
+
+/**
+ * Unit test for email notification sender for Shipment.
+ *
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class EmailSenderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Shipment\Sender\EmailSender
+     */
+    private $subject;
+
+    /**
+     * @var \Magento\Sales\Model\Order|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Store\Model\Store|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Sender|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $senderMock;
+
+    /**
+     * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $commentMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Address|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressMock;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $globalConfigMock;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $eventManagerMock;
+
+    /**
+     * @var \Magento\Payment\Model\Info|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentInfoMock;
+
+    /**
+     * @var \Magento\Payment\Helper\Data|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $paymentHelperMock;
+
+    /**
+     * @var \Magento\Sales\Model\ResourceModel\Order\Shipment|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentResourceMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Address\Renderer|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $addressRendererMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Container\Template|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $templateContainerMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\Container\ShipmentIdentity|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $identityContainerMock;
+
+    /**
+     * @var \Magento\Sales\Model\Order\Email\SenderBuilderFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $senderBuilderFactoryMock;
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    protected function setUp()
+    {
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class)
+            ->setMethods(['getStoreId'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->storeMock->expects($this->any())
+            ->method('getStoreId')
+            ->willReturn(1);
+        $this->orderMock->expects($this->any())
+            ->method('getStore')
+            ->willReturn($this->storeMock);
+
+        $this->senderMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Sender::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['send', 'sendCopyTo'])
+            ->getMock();
+
+        $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['setSendEmail', 'setEmailSent'])
+            ->getMock();
+
+        $this->commentMock = $this->getMockBuilder(\Magento\Sales\Api\Data\ShipmentCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->commentMock->expects($this->any())
+            ->method('getComment')
+            ->willReturn('Comment text');
+
+        $this->addressMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock->expects($this->any())
+            ->method('getBillingAddress')
+            ->willReturn($this->addressMock);
+        $this->orderMock->expects($this->any())
+            ->method('getShippingAddress')
+            ->willReturn($this->addressMock);
+
+        $this->globalConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->paymentInfoMock = $this->getMockBuilder(\Magento\Payment\Model\Info::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock->expects($this->any())
+            ->method('getPayment')
+            ->willReturn($this->paymentInfoMock);
+
+        $this->paymentHelperMock = $this->getMockBuilder(\Magento\Payment\Helper\Data::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->paymentHelperMock->expects($this->any())
+            ->method('getInfoBlockHtml')
+            ->with($this->paymentInfoMock, 1)
+            ->willReturn('Payment Info Block');
+
+        $this->shipmentResourceMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->addressRendererMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address\Renderer::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->addressRendererMock->expects($this->any())
+            ->method('format')
+            ->with($this->addressMock, 'html')
+            ->willReturn('Formatted address');
+
+        $this->templateContainerMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Container\Template::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->identityContainerMock = $this->getMockBuilder(
+            \Magento\Sales\Model\Order\Email\Container\ShipmentIdentity::class
+        )
+        ->disableOriginalConstructor()
+        ->getMock();
+
+        $this->identityContainerMock->expects($this->any())
+            ->method('getStore')
+            ->willReturn($this->storeMock);
+
+        $this->senderBuilderFactoryMock = $this->getMockBuilder(
+            \Magento\Sales\Model\Order\Email\SenderBuilderFactory::class
+        )
+        ->disableOriginalConstructor()
+        ->setMethods(['create'])
+        ->getMock();
+
+        $this->subject = new \Magento\Sales\Model\Order\Shipment\Sender\EmailSender(
+            $this->templateContainerMock,
+            $this->identityContainerMock,
+            $this->senderBuilderFactoryMock,
+            $this->loggerMock,
+            $this->addressRendererMock,
+            $this->paymentHelperMock,
+            $this->shipmentResourceMock,
+            $this->globalConfigMock,
+            $this->eventManagerMock
+        );
+    }
+
+    /**
+     * @param int $configValue
+     * @param bool $forceSyncMode
+     * @param bool $isComment
+     * @param bool $emailSendingResult
+     *
+     * @dataProvider sendDataProvider
+     *
+     * @return void
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testSend($configValue, $forceSyncMode, $isComment, $emailSendingResult)
+    {
+        $this->globalConfigMock->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn($configValue);
+
+        if (!$isComment) {
+            $this->commentMock = null;
+        }
+
+        $this->shipmentMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        if (!$configValue || $forceSyncMode) {
+            $transport = [
+                'order' => $this->orderMock,
+                'shipment' => $this->shipmentMock,
+                'comment' => $isComment ? 'Comment text' : '',
+                'billing' => $this->addressMock,
+                'payment_html' => 'Payment Info Block',
+                'store' => $this->storeMock,
+                'formattedShippingAddress' => 'Formatted address',
+                'formattedBillingAddress' => 'Formatted address',
+            ];
+
+            $this->eventManagerMock->expects($this->once())
+                ->method('dispatch')
+                ->with(
+                    'email_shipment_set_template_vars_before',
+                    [
+                        'sender' => $this->subject,
+                        'transport' => $transport,
+                    ]
+                );
+
+            $this->templateContainerMock->expects($this->once())
+                ->method('setTemplateVars')
+                ->with($transport);
+
+            $this->identityContainerMock->expects($this->once())
+                ->method('isEnabled')
+                ->willReturn($emailSendingResult);
+
+            if ($emailSendingResult) {
+                $this->senderBuilderFactoryMock->expects($this->once())
+                    ->method('create')
+                    ->willReturn($this->senderMock);
+
+                $this->senderMock->expects($this->once())
+                    ->method('send');
+
+                $this->senderMock->expects($this->once())
+                    ->method('sendCopyTo');
+
+                $this->shipmentMock->expects($this->once())
+                    ->method('setEmailSent')
+                    ->with(true);
+
+                $this->shipmentResourceMock->expects($this->once())
+                    ->method('saveAttribute')
+                    ->with($this->shipmentMock, ['send_email', 'email_sent']);
+
+                $this->assertTrue(
+                    $this->subject->send(
+                        $this->orderMock,
+                        $this->shipmentMock,
+                        $this->commentMock,
+                        $forceSyncMode
+                    )
+                );
+            } else {
+                $this->shipmentResourceMock->expects($this->once())
+                    ->method('saveAttribute')
+                    ->with($this->shipmentMock, 'send_email');
+
+                $this->assertFalse(
+                    $this->subject->send(
+                        $this->orderMock,
+                        $this->shipmentMock,
+                        $this->commentMock,
+                        $forceSyncMode
+                    )
+                );
+            }
+        } else {
+            $this->shipmentMock->expects($this->once())
+                ->method('setEmailSent')
+                ->with(null);
+
+            $this->shipmentResourceMock->expects($this->at(0))
+                ->method('saveAttribute')
+                ->with($this->shipmentMock, 'email_sent');
+            $this->shipmentResourceMock->expects($this->at(1))
+                ->method('saveAttribute')
+                ->with($this->shipmentMock, 'send_email');
+
+            $this->assertFalse(
+                $this->subject->send(
+                    $this->orderMock,
+                    $this->shipmentMock,
+                    $this->commentMock,
+                    $forceSyncMode
+                )
+            );
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function sendDataProvider()
+    {
+        return [
+            'Successful sync sending with comment' => [0, false, true, true],
+            'Successful sync sending without comment' => [0, false, false, true],
+            'Failed sync sending with comment' => [0, false, true, false],
+            'Successful forced sync sending with comment' => [1, true, true, true],
+            'Async sending' => [1, false, false, false],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/QuantityValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/QuantityValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..01cccd2458695247f2c67f8e35fd40a71dc1b757
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/QuantityValidatorTest.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Shipment\Validation;
+
+use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Api\Data\ShipmentItemInterface;
+
+/**
+ * Class QuantityValidatorTest
+ */
+class QuantityValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var QuantityValidator
+     */
+    private $validator;
+
+    /**
+     * @var ShipmentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentMock;
+
+    /**
+     * @var ShipmentItemInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentItemMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManager($this);
+        $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class)
+            ->getMock();
+        $this->shipmentItemMock = $this->getMockBuilder(ShipmentItemInterface::class)
+            ->getMock();
+        $this->validator = $objectManagerHelper->getObject(QuantityValidator::class);
+    }
+
+    public function testValidateTrackWithoutOrderId()
+    {
+        $this->shipmentMock->expects($this->once())
+            ->method('getOrderId')
+            ->willReturn(null);
+        $this->assertEquals(
+            [__('Order Id is required for shipment document')],
+            $this->validator->validate($this->shipmentMock)
+        );
+    }
+
+    public function testValidateTrackWithoutItems()
+    {
+        $this->shipmentMock->expects($this->once())
+            ->method('getOrderId')
+            ->willReturn(1);
+        $this->shipmentMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn(null);
+        $this->assertEquals(
+            [__('You can\'t create a shipment without products.')],
+            $this->validator->validate($this->shipmentMock)
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/TrackValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/TrackValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d8d951ccf18acd29649b8de05a5c3f97ce5a8c1
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Validation/TrackValidatorTest.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order\Shipment\Validation;
+
+use Magento\Sales\Model\Order\Shipment\Validation\TrackValidator;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Api\Data\ShipmentTrackInterface;
+
+/**
+ * Class TrackValidatorTest
+ */
+class TrackValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var TrackValidator
+     */
+    private $validator;
+
+    /**
+     * @var ShipmentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentMock;
+
+    /**
+     * @var ShipmentTrackInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentTrackMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManager($this);
+        $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class)
+            ->getMockForAbstractClass();
+        $this->shipmentTrackMock = $this->getMockBuilder(ShipmentTrackInterface::class)
+            ->getMockForAbstractClass();
+        $this->validator = $objectManagerHelper->getObject(TrackValidator::class);
+    }
+
+    public function testValidateTrackWithNumber()
+    {
+        $this->shipmentTrackMock->expects($this->once())
+            ->method('getTrackNumber')
+            ->willReturn('12345');
+        $this->shipmentMock->expects($this->exactly(2))
+            ->method('getTracks')
+            ->willReturn([$this->shipmentTrackMock]);
+        $this->assertEquals([], $this->validator->validate($this->shipmentMock));
+    }
+
+    public function testValidateTrackWithoutNumber()
+    {
+        $this->shipmentTrackMock->expects($this->once())
+            ->method('getTrackNumber')
+            ->willReturn(null);
+        $this->shipmentMock->expects($this->exactly(2))
+            ->method('getTracks')
+            ->willReturn([$this->shipmentTrackMock]);
+        $this->assertEquals([__('Please enter a tracking number.')], $this->validator->validate($this->shipmentMock));
+    }
+
+    public function testValidateTrackWithEmptyTracks()
+    {
+        $this->shipmentTrackMock->expects($this->never())
+            ->method('getTrackNumber');
+        $this->shipmentMock->expects($this->once())
+            ->method('getTracks')
+            ->willReturn([]);
+        $this->assertEquals([], $this->validator->validate($this->shipmentMock));
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b0677b050f6fbe4f7b1894a34481a6aa59fcecd9
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model\Order;
+
+use Magento\Framework\EntityManager\HydratorPool;
+use Magento\Sales\Api\Data\ShipmentCommentCreationInterface;
+use Magento\Sales\Api\Data\ShipmentItemCreationInterface;
+use Magento\Sales\Api\Data\ShipmentTrackCreationInterface;
+use Magento\Sales\Model\Order\ShipmentFactory;
+use Magento\Sales\Model\Order\ShipmentDocumentFactory;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Model\Order\Shipment\TrackFactory;
+use Magento\Sales\Model\Order\Shipment\Track;
+use Magento\Framework\EntityManager\HydratorInterface;
+
+/**
+ * Class ShipmentDocumentFactoryTest
+ */
+class ShipmentDocumentFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ShipmentFactory
+     */
+    private $shipmentFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Order
+     */
+    private $orderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ShipmentItemCreationInterface
+     */
+    private $itemMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ShipmentCommentCreationInterface
+     */
+    private $commentMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ShipmentInterface
+     */
+    private $shipmentMock;
+
+    /**
+     * @var ShipmentDocumentFactory
+     */
+    private $shipmentDocumentFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|HydratorPool
+     */
+    private $hydratorPoolMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|TrackFactory
+     */
+    private $trackFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|HydratorInterface
+     */
+    private $hydratorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Track
+     */
+    private $trackMock;
+
+    protected function setUp()
+    {
+        $this->shipmentFactoryMock = $this->getMockBuilder(ShipmentFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderMock = $this->getMockBuilder(Order::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->itemMock = $this->getMockBuilder(ShipmentItemCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->commentMock = $this->getMockBuilder(ShipmentCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['addComment', 'addTrack'])
+            ->getMockForAbstractClass();
+
+        $this->hydratorPoolMock = $this->getMockBuilder(HydratorPool::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->trackFactoryMock = $this->getMockBuilder(TrackFactory::class)
+            ->setMethods(['create'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->trackMock = $this->getMockBuilder(Track::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->hydratorMock = $this->getMockBuilder(HydratorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentDocumentFactory = new ShipmentDocumentFactory(
+            $this->shipmentFactoryMock,
+            $this->hydratorPoolMock,
+            $this->trackFactoryMock
+        );
+    }
+
+    public function testCreate()
+    {
+        $trackNum = "123456789";
+        $trackData = [$trackNum];
+        $tracks = [$this->trackMock];
+        $appendComment = true;
+        $packages = [];
+        $items = [1 => 10];
+
+        $this->itemMock->expects($this->once())
+            ->method('getOrderItemId')
+            ->willReturn(1);
+
+        $this->itemMock->expects($this->once())
+            ->method('getQty')
+            ->willReturn(10);
+
+        $this->shipmentFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                $this->orderMock,
+                $items
+            )
+            ->willReturn($this->shipmentMock);
+
+        $this->shipmentMock->expects($this->once())
+            ->method('addTrack')
+            ->willReturnSelf();
+
+        $this->hydratorPoolMock->expects($this->once())
+            ->method('getHydrator')
+            ->with(ShipmentTrackCreationInterface::class)
+            ->willReturn($this->hydratorMock);
+
+        $this->hydratorMock->expects($this->once())
+            ->method('extract')
+            ->with($this->trackMock)
+            ->willReturn($trackData);
+
+        $this->trackFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(['data' => $trackData])
+            ->willReturn($this->trackMock);
+
+        if ($appendComment) {
+            $comment = "New comment!";
+            $visibleOnFront = true;
+            $this->commentMock->expects($this->once())
+                ->method('getComment')
+                ->willReturn($comment);
+
+            $this->commentMock->expects($this->once())
+                ->method('getIsVisibleOnFront')
+                ->willReturn($visibleOnFront);
+
+            $this->shipmentMock->expects($this->once())
+                ->method('addComment')
+                ->with($comment, $appendComment, $visibleOnFront)
+                ->willReturnSelf();
+        }
+
+        $this->assertEquals(
+            $this->shipmentDocumentFactory->create(
+                $this->orderMock,
+                [$this->itemMock],
+                $tracks,
+                $this->commentMock,
+                $appendComment,
+                $packages
+            ),
+            $this->shipmentMock
+        );
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
index 3760934457a85eae8f3e4f6f4b8070b1ef7d716a..46d6ac62fc256a45b76edb12c787f4627f8f0ed7 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php
@@ -5,10 +5,9 @@
  */
 namespace Magento\Sales\Test\Unit\Model\Order;
 
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-
 /**
  * Unit test for shipment factory class.
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class ShipmentFactoryTest extends \PHPUnit_Framework_TestCase
 {
@@ -39,7 +38,7 @@ class ShipmentFactoryTest extends \PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        $objectManager = new ObjectManager($this);
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $this->converter = $this->getMock(
             \Magento\Sales\Model\Convert\Order::class,
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/OrderValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php
similarity index 77%
rename from app/code/Magento/Sales/Test/Unit/Model/Order/OrderValidatorTest.php
rename to app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php
index 905d7c7a5b3f89951afcd261904a99df38f27ce5..dd76bc1e52586fe57a68d1e5c3278441a18eddd6 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/OrderValidatorTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php
@@ -4,17 +4,17 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Sales\Test\Unit\Model\Order;
+namespace Magento\Sales\Test\Unit\Model\Order\Validation;
 
 use Magento\Sales\Model\Order;
 
 /**
  * Test for \Magento\Sales\Model\Order\OrderValidator class
  */
-class OrderValidatorTest extends \PHPUnit_Framework_TestCase
+class CanInvoiceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Sales\Model\Order\OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Sales\Model\Order\Validation\CanInvoice|\PHPUnit_Framework_MockObject_MockObject
      */
     private $model;
 
@@ -47,7 +47,7 @@ class OrderValidatorTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['getQtyToInvoice', 'getLockedDoInvoice'])
             ->getMockForAbstractClass();
 
-        $this->model = new \Magento\Sales\Model\Order\OrderValidator();
+        $this->model = new \Magento\Sales\Model\Order\Validation\CanInvoice();
     }
 
     /**
@@ -62,9 +62,12 @@ class OrderValidatorTest extends \PHPUnit_Framework_TestCase
             ->willReturn($state);
         $this->orderMock->expects($this->never())
             ->method('getItems');
+        $this->orderMock->expects($this->once())
+            ->method('getStatus')
+            ->willReturn('status');
         $this->assertEquals(
-            false,
-            $this->model->canInvoice($this->orderMock)
+            [__('An invoice cannot be created when an order has a status of %1', 'status')],
+            $this->model->validate($this->orderMock)
         );
     }
 
@@ -93,9 +96,8 @@ class OrderValidatorTest extends \PHPUnit_Framework_TestCase
             ->method('getItems')
             ->willReturn([]);
 
-        $this->assertEquals(
-            false,
-            $this->model->canInvoice($this->orderMock)
+        $this->assertNotEmpty(
+            $this->model->validate($this->orderMock)
         );
     }
 
@@ -125,7 +127,7 @@ class OrderValidatorTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $expectedResult,
-            $this->model->canInvoice($this->orderMock)
+            $this->model->validate($this->orderMock)
         );
     }
 
@@ -137,10 +139,10 @@ class OrderValidatorTest extends \PHPUnit_Framework_TestCase
     public function canInvoiceDataProvider()
     {
         return [
-            [0, null, false],
-            [-1, null, false],
-            [1, true, false],
-            [0.5, false, true],
+            [0, null, [__('The order does not allow an invoice to be created.')]],
+            [-1, null, [__('The order does not allow an invoice to be created.')]],
+            [1, true, [__('The order does not allow an invoice to be created.')]],
+            [0.5, false, []],
         ];
     }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..11d99fbb9cced0e9a9d88de161898df42c5a71d7
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Sales\Test\Unit\Model\Order\Validation;
+
+use Magento\Sales\Model\Order;
+
+/**
+ * Test for \Magento\Sales\Model\Order\Validation\CanShip class
+ */
+class CanShipTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Sales\Model\Order\Validation\CanShip|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $model;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Sales\Api\Data\OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var \Magento\Sales\Api\Data\OrderItemInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderItemMock;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getStatus', 'getItems'])
+            ->getMockForAbstractClass();
+
+        $this->orderItemMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderItemInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getQtyToShip', 'getLockedDoShip'])
+            ->getMockForAbstractClass();
+
+        $this->model = new \Magento\Sales\Model\Order\Validation\CanShip();
+    }
+
+    /**
+     * @param string $state
+     *
+     * @dataProvider canShipWrongStateDataProvider
+     */
+    public function testCanShipWrongState($state)
+    {
+        $this->orderMock->expects($this->any())
+            ->method('getState')
+            ->willReturn($state);
+        $this->orderMock->expects($this->once())
+            ->method('getStatus')
+            ->willReturn('status');
+        $this->orderMock->expects($this->never())
+            ->method('getItems');
+        $this->assertEquals(
+            [__('A shipment cannot be created when an order has a status of %1', 'status')],
+            $this->model->validate($this->orderMock)
+        );
+    }
+
+    /**
+     * Data provider for testCanShipWrongState
+     * @return array
+     */
+    public function canShipWrongStateDataProvider()
+    {
+        return [
+            [Order::STATE_PAYMENT_REVIEW],
+            [Order::STATE_HOLDED],
+            [Order::STATE_CANCELED],
+        ];
+    }
+
+    public function testCanShipNoItems()
+    {
+        $this->orderMock->expects($this->any())
+            ->method('getState')
+            ->willReturn(Order::STATE_PROCESSING);
+
+        $this->orderMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn([]);
+
+        $this->assertNotEmpty(
+            $this->model->validate($this->orderMock)
+        );
+    }
+
+    /**
+     * @param float $qtyToShipment
+     * @param bool|null $itemLockedDoShipment
+     * @param bool $expectedResult
+     *
+     * @dataProvider canShipDataProvider
+     */
+    public function testCanShip($qtyToShipment, $itemLockedDoShipment, $expectedResult)
+    {
+        $this->orderMock->expects($this->any())
+            ->method('getState')
+            ->willReturn(Order::STATE_PROCESSING);
+
+        $items = [$this->orderItemMock];
+        $this->orderMock->expects($this->once())
+            ->method('getItems')
+            ->willReturn($items);
+        $this->orderItemMock->expects($this->any())
+            ->method('getQtyToShip')
+            ->willReturn($qtyToShipment);
+        $this->orderItemMock->expects($this->any())
+            ->method('getLockedDoShip')
+            ->willReturn($itemLockedDoShipment);
+
+        $this->assertEquals(
+            $expectedResult,
+            $this->model->validate($this->orderMock)
+        );
+    }
+
+    /**
+     * Data provider for testCanShip
+     *
+     * @return array
+     */
+    public function canShipDataProvider()
+    {
+        return [
+            [0, null, [__('The order does not allow a shipment to be created.')]],
+            [-1, null, [__('The order does not allow a shipment to be created.')]],
+            [1, true, [__('The order does not allow a shipment to be created.')]],
+            [0.5, false, []],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b719babf209f0ceb98c4d019f1e5929b23e7e11f
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
@@ -0,0 +1,430 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Test\Unit\Model;
+
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Api\Data\ShipmentCommentCreationInterface;
+use Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface;
+use Magento\Sales\Api\Data\ShipmentInterface;
+use Magento\Sales\Api\Data\ShipmentPackageInterface;
+use Magento\Sales\Api\Data\ShipmentTrackCreationInterface;
+use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Api\ShipmentRepositoryInterface;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\Order\Config as OrderConfig;
+use Magento\Sales\Model\Order\OrderStateResolverInterface;
+use Magento\Sales\Model\Order\OrderValidatorInterface;
+use Magento\Sales\Model\Order\ShipmentDocumentFactory;
+use Magento\Sales\Model\Order\Shipment\NotifierInterface;
+use Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface;
+use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Sales\Model\ShipOrder;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class ShipOrderTest
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ */
+class ShipOrderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceConnectionMock;
+
+    /**
+     * @var OrderRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRepositoryMock;
+
+    /**
+     * @var ShipmentDocumentFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentDocumentFactoryMock;
+
+    /**
+     * @var ShipmentValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentValidatorMock;
+
+    /**
+     * @var OrderValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderValidatorMock;
+
+    /**
+     * @var OrderRegistrarInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderRegistrarMock;
+
+    /**
+     * @var OrderStateResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderStateResolverMock;
+
+    /**
+     * @var OrderConfig|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configMock;
+
+    /**
+     * @var ShipmentRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentRepositoryMock;
+
+    /**
+     * @var NotifierInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $notifierInterfaceMock;
+
+    /**
+     * @var ShipOrder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $model;
+
+    /**
+     * @var ShipmentCreationArgumentsInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentCommentCreationMock;
+
+    /**
+     * @var ShipmentCommentCreationInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentCreationArgumentsMock;
+
+    /**
+     * @var OrderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $orderMock;
+
+    /**
+     * @var ShipmentInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentMock;
+
+    /**
+     * @var AdapterInterface
+     */
+    private $adapterMock;
+
+    /**
+     * @var ShipmentTrackCreationInterface
+     */
+    private $trackMock;
+
+    /**
+     * @var ShipmentPackageInterface
+     */
+    private $packageMock;
+
+    /**
+     * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $loggerMock;
+
+    protected function setUp()
+    {
+        $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentDocumentFactoryMock = $this->getMockBuilder(ShipmentDocumentFactory::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->shipmentValidatorMock = $this->getMockBuilder(ShipmentValidatorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->orderRegistrarMock = $this->getMockBuilder(OrderRegistrarInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->configMock = $this->getMockBuilder(OrderConfig::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->shipmentRepositoryMock = $this->getMockBuilder(ShipmentRepositoryInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->notifierInterfaceMock = $this->getMockBuilder(NotifierInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentCommentCreationMock = $this->getMockBuilder(ShipmentCommentCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentCreationArgumentsMock = $this->getMockBuilder(ShipmentCreationArgumentsInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->orderMock = $this->getMockBuilder(OrderInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->packageMock = $this->getMockBuilder(ShipmentPackageInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->trackMock = $this->getMockBuilder(ShipmentTrackCreationInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $this->adapterMock = $this->getMockBuilder(AdapterInterface::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->model = $helper->getObject(
+            ShipOrder::class,
+            [
+                'resourceConnection' => $this->resourceConnectionMock,
+                'orderRepository' => $this->orderRepositoryMock,
+                'shipmentRepository' => $this->shipmentRepositoryMock,
+                'shipmentDocumentFactory' => $this->shipmentDocumentFactoryMock,
+                'shipmentValidator' => $this->shipmentValidatorMock,
+                'orderValidator' => $this->orderValidatorMock,
+                'orderStateResolver' => $this->orderStateResolverMock,
+                'orderRegistrar' => $this->orderRegistrarMock,
+                'notifierInterface' => $this->notifierInterfaceMock,
+                'config' => $this->configMock,
+                'logger' => $this->loggerMock
+            ]
+        );
+    }
+
+    /**
+     * @dataProvider dataProvider
+     */
+    public function testExecute($orderId, $items, $notify, $appendComment)
+    {
+        $this->resourceConnectionMock->expects($this->once())
+            ->method('getConnection')
+            ->with('sales')
+            ->willReturn($this->adapterMock);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+
+        $this->shipmentDocumentFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                $this->orderMock,
+                $items,
+                [$this->trackMock],
+                $this->shipmentCommentCreationMock,
+                ($appendComment && $notify),
+                [$this->packageMock],
+                $this->shipmentCreationArgumentsMock
+            )->willReturn($this->shipmentMock);
+
+        $this->shipmentValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->shipmentMock)
+            ->willReturn([]);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
+            ->willReturn([]);
+
+        $this->orderRegistrarMock->expects($this->once())
+            ->method('register')
+            ->with($this->orderMock, $this->shipmentMock)
+            ->willReturn($this->orderMock);
+
+        $this->orderStateResolverMock->expects($this->once())
+            ->method('getStateForOrder')
+            ->with($this->orderMock, [OrderStateResolverInterface::IN_PROGRESS])
+            ->willReturn(Order::STATE_PROCESSING);
+
+        $this->orderMock->expects($this->once())
+            ->method('setState')
+            ->with(Order::STATE_PROCESSING)
+            ->willReturnSelf();
+
+        $this->orderMock->expects($this->once())
+            ->method('getState')
+            ->willReturn(Order::STATE_PROCESSING);
+
+        $this->configMock->expects($this->once())
+            ->method('getStateDefaultStatus')
+            ->with(Order::STATE_PROCESSING)
+            ->willReturn('Processing');
+
+        $this->orderMock->expects($this->once())
+            ->method('setStatus')
+            ->with('Processing')
+            ->willReturnSelf();
+
+        $this->shipmentRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->shipmentMock)
+            ->willReturn($this->shipmentMock);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($this->orderMock)
+            ->willReturn($this->orderMock);
+
+        if ($notify) {
+            $this->notifierInterfaceMock->expects($this->once())
+                ->method('notify')
+                ->with($this->orderMock, $this->shipmentMock, $this->shipmentCommentCreationMock);
+        }
+
+        $this->shipmentMock->expects($this->once())
+            ->method('getEntityId')
+            ->willReturn(2);
+
+        $this->assertEquals(
+            2,
+            $this->model->execute(
+                $orderId,
+                $items,
+                $notify,
+                $appendComment,
+                $this->shipmentCommentCreationMock,
+                [$this->trackMock],
+                [$this->packageMock],
+                $this->shipmentCreationArgumentsMock
+            )
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface
+     */
+    public function testDocumentValidationException()
+    {
+        $orderId = 1;
+        $items = [1 => 2];
+        $notify = true;
+        $appendComment = true;
+        $errorMessages = ['error1', 'error2'];
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+
+        $this->shipmentDocumentFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                $this->orderMock,
+                $items,
+                [$this->trackMock],
+                $this->shipmentCommentCreationMock,
+                ($appendComment && $notify),
+                [$this->packageMock],
+                $this->shipmentCreationArgumentsMock
+            )->willReturn($this->shipmentMock);
+
+        $this->shipmentValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->shipmentMock)
+            ->willReturn($errorMessages);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
+            ->willReturn([]);
+
+        $this->model->execute(
+            $orderId,
+            $items,
+            $notify,
+            $appendComment,
+            $this->shipmentCommentCreationMock,
+            [$this->trackMock],
+            [$this->packageMock],
+            $this->shipmentCreationArgumentsMock
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Sales\Api\Exception\CouldNotShipExceptionInterface
+     */
+    public function testCouldNotInvoiceException()
+    {
+        $orderId = 1;
+        $this->resourceConnectionMock->expects($this->once())
+            ->method('getConnection')
+            ->with('sales')
+            ->willReturn($this->adapterMock);
+
+        $this->orderRepositoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->orderMock);
+
+        $this->shipmentDocumentFactoryMock->expects($this->once())
+            ->method('create')
+            ->with(
+                $this->orderMock
+            )->willReturn($this->shipmentMock);
+
+        $this->shipmentValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->shipmentMock)
+            ->willReturn([]);
+        $this->orderValidatorMock->expects($this->once())
+            ->method('validate')
+            ->with($this->orderMock)
+            ->willReturn([]);
+        $e = new \Exception();
+
+        $this->orderRegistrarMock->expects($this->once())
+            ->method('register')
+            ->with($this->orderMock, $this->shipmentMock)
+            ->willThrowException($e);
+
+        $this->loggerMock->expects($this->once())
+            ->method('critical')
+            ->with($e);
+
+        $this->adapterMock->expects($this->once())
+            ->method('rollBack');
+
+        $this->model->execute(
+            $orderId
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProvider()
+    {
+        return [
+            'TestWithNotifyTrue' => [1, [1 => 2], true, true],
+            'TestWithNotifyFalse' => [1, [1 => 2], false, true],
+        ];
+    }
+}
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 383650c8688fc847ac030bc6c216293a925956bf..dfdb0f6a261c51490e99955bdd61fd1bae328e60 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -30,7 +30,9 @@
     <preference for="Magento\Sales\Api\Data\OrderStatusHistorySearchResultInterface" type="Magento\Sales\Model\ResourceModel\Order\Status\History\Collection"/>
     <preference for="Magento\Sales\Api\Data\ShipmentCommentInterface" type="Magento\Sales\Model\Order\Shipment\Comment"/>
     <preference for="Magento\Sales\Api\Data\ShipmentCommentSearchResultInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment\Comment\Collection"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface" type="Magento\Sales\Model\Order\Shipment\CreationArguments"/>
     <preference for="Magento\Sales\Api\Data\ShipmentInterface" type="Magento\Sales\Model\Order\Shipment"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentItemCreationInterface" type="Magento\Sales\Model\Order\Shipment\ItemCreation"/>
     <preference for="Magento\Sales\Api\Data\ShipmentItemInterface" type="Magento\Sales\Model\Order\Shipment\Item"/>
     <preference for="Magento\Sales\Api\Data\ShipmentItemSearchResultInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment\Item\Collection"/>
     <preference for="Magento\Sales\Api\Data\ShipmentSearchResultInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment\Collection"/>
@@ -49,7 +51,10 @@
     <preference for="Magento\Sales\Api\InvoiceItemRepositoryInterface" type="Magento\Sales\Api\Data\InvoiceItem\Repository"/>
     <preference for="Magento\Sales\Api\InvoiceRepositoryInterface" type="Magento\Sales\Model\Order\InvoiceRepository"/>
     <preference for="Magento\Sales\Api\InvoiceManagementInterface" type="Magento\Sales\Model\Service\InvoiceService"/>
-    <preference for="Magento\Sales\Api\InvoiceCreationArgumentsInterface" type="Magento\Sales\Model\Order\Invoice\CreationArguments"/>
+    <preference for="Magento\Sales\Api\Data\InvoiceCreationArgumentsInterface" type="Magento\Sales\Model\Order\Invoice\CreationArguments"/>
+    <preference for="Magento\Sales\Api\Data\InvoiceItemCreationInterface" type="Magento\Sales\Model\Order\Invoice\ItemCreation"/>
+    <preference for="Magento\Sales\Api\Data\InvoiceCommentCreationInterface" type="Magento\Sales\Model\Order\Invoice\CommentCreation"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentCommentCreationInterface" type="Magento\Sales\Model\Order\Shipment\CommentCreation"/>
     <preference for="Magento\Sales\Api\OrderAddressRepositoryInterface" type="Magento\Sales\Model\Order\AddressRepository"/>
     <preference for="Magento\Sales\Api\OrderCustomerManagementInterface" type="Magento\Sales\Model\Order\CustomerManagement"/>
     <preference for="Magento\Sales\Api\OrderItemRepositoryInterface" type="Magento\Sales\Model\Order\ItemRepository"/>
@@ -62,13 +67,14 @@
     <preference for="Magento\Sales\Api\ShipmentRepositoryInterface" type="Magento\Sales\Model\Order\ShipmentRepository"/>
     <preference for="Magento\Sales\Api\ShipmentManagementInterface" type="Magento\Sales\Model\Service\ShipmentService"/>
     <preference for="Magento\Sales\Api\ShipmentTrackRepositoryInterface" type="Magento\Sales\Api\Data\ShipmentTrack\Repository"/>
+    <preference for="Magento\Sales\Api\ShipOrderInterface" type="Magento\Sales\Model\ShipOrder"/>
     <preference for="Magento\Sales\Api\TransactionRepositoryInterface" type="Magento\Sales\Model\Order\Payment\Transaction\Repository"/>
     <preference for="Magento\Sales\Model\Order\Invoice\NotifierInterface" type="Magento\Sales\Model\Order\Invoice\Notifier"/>
-    <preference for="Magento\Sales\Model\Order\InvoiceValidatorInterface" type="Magento\Sales\Model\Order\InvoiceValidator"/>
+    <preference for="Magento\Sales\Model\Order\Shipment\NotifierInterface" type="Magento\Sales\Model\Order\Shipment\Notifier"/>
     <preference for="Magento\Sales\Model\Order\PaymentAdapterInterface" type="Magento\Sales\Model\Order\PaymentAdapter"/>
-    <preference for="Magento\Sales\Model\Order\OrderValidatorInterface" type="Magento\Sales\Model\Order\OrderValidator"/>
     <preference for="Magento\Sales\Model\Order\Payment\Transaction\ManagerInterface" type="Magento\Sales\Model\Order\Payment\Transaction\Manager"/>
     <preference for="Magento\Sales\Model\Order\Payment\Transaction\BuilderInterface" type="Magento\Sales\Model\Order\Payment\Transaction\Builder"/>
+    <preference for="Magento\Sales\Model\Order\Shipment\OrderRegistrarInterface" type="Magento\Sales\Model\Order\Shipment\OrderRegistrar"/>
     <preference for="Magento\Sales\Model\Spi\CreditmemoCommentResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Creditmemo\Comment"/>
     <preference for="Magento\Sales\Model\Spi\CreditmemoItemResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item"/>
     <preference for="Magento\Sales\Model\Spi\CreditmemoResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Creditmemo"/>
@@ -86,10 +92,14 @@
     <preference for="Magento\Sales\Model\Spi\ShipmentTrackResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Shipment\Track"/>
     <preference for="Magento\Sales\Model\Spi\TransactionResourceInterface" type="Magento\Sales\Model\ResourceModel\Order\Payment\Transaction"/>
     <preference for="Magento\Sales\Model\ResourceModel\Order\CollectionFactoryInterface" type="Magento\Sales\Model\ResourceModel\Order\CollectionFactory"/>
-    <preference for="Magento\Sales\Api\Data\InvoiceCommentCreationInterface" type="Magento\Sales\Model\Order\Invoice\Comment"/>
-    <preference for="Magento\Sales\Api\Data\InvoiceItemCreationInterface" type="Magento\Sales\Model\Order\Invoice\ItemCreation"/>
-    <preference for="Magento\Sales\Api\OrderInvoiceInterface" type="Magento\Sales\Model\OrderInvoice"/>
+    <preference for="Magento\Sales\Api\InvoiceOrderInterface" type="Magento\Sales\Model\InvoiceOrder"/>
     <preference for="Magento\Sales\Model\Order\OrderStateResolverInterface" type="Magento\Sales\Model\Order\StateResolver"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentTrackCreationInterface" type="Magento\Sales\Model\Order\Shipment\TrackCreation"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentPackageInterface" type="Magento\Sales\Model\Order\Shipment\Package"/>
+    <preference for="Magento\Sales\Api\Data\ShipmentPackageCreationInterface" type="Magento\Sales\Model\Order\Shipment\PackageCreation"/>
+    <preference for="Magento\Sales\Model\Order\OrderValidatorInterface" type="Magento\Sales\Model\Order\OrderValidator"/>
+    <preference for="Magento\Sales\Model\Order\Invoice\InvoiceValidatorInterface" type="Magento\Sales\Model\Order\Invoice\InvoiceValidator"/>
+    <preference for="Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface" type="Magento\Sales\Model\Order\Shipment\ShipmentValidator"/>
     <type name="Magento\Sales\Model\ResourceModel\Report" shared="false"/>
     <type name="Magento\Sales\Model\Order\Pdf\Config\Reader">
         <arguments>
@@ -909,4 +919,18 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Sales\Model\Order\Shipment\Notifier">
+        <arguments>
+            <argument name="senders" xsi:type="array">
+                <item name="email" xsi:type="object">Magento\Sales\Model\Order\Shipment\Sender\EmailSender</item>
+            </argument>
+        </arguments>
+    </type>
+    <type name="Magento\Framework\EntityManager\HydratorPool">
+        <arguments>
+            <argument name="hydrators" xsi:type="array">
+                <item name="Magento\Sales\Api\Data\ShipmentTrackCreationInterface" xsi:type="string">Magento\Framework\EntityManager\HydratorInterface</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Sales/etc/webapi.xml b/app/code/Magento/Sales/etc/webapi.xml
index 8d1b1fda5bc314fdbd3dec616f7af8d56f1d8191..4c7fe03a201f8b25c2af83219fd0576da4c2cd3e 100644
--- a/app/code/Magento/Sales/etc/webapi.xml
+++ b/app/code/Magento/Sales/etc/webapi.xml
@@ -235,6 +235,12 @@
             <resource ref="Magento_Sales::sales" />
         </resources>
     </route>
+    <route url="/V1/order/:orderId/ship" method="POST">
+        <service class="Magento\Sales\Api\ShipOrderInterface" method="execute"/>
+        <resources>
+            <resource ref="Magento_Sales::sales" />
+        </resources>
+    </route>
     <route url="/V1/orders/" method="POST">
         <service class="Magento\Sales\Api\OrderRepositoryInterface" method="save"/>
         <resources>
@@ -254,7 +260,7 @@
         </resources>
     </route>
     <route url="/V1/order/:orderId/invoice" method="POST">
-        <service class="Magento\Sales\Api\OrderInvoiceInterface" method="execute"/>
+        <service class="Magento\Sales\Api\InvoiceOrderInterface" method="execute"/>
         <resources>
             <resource ref="Magento_Sales::sales" />
         </resources>
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
index adbd96624649d5c7aff56a95156579ed16cc7f9d..d265159bc630be220bc4a7a64b706e36786510ef 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save.php
@@ -7,8 +7,12 @@
 namespace Magento\Shipping\Controller\Adminhtml\Order\Shipment;
 
 use Magento\Backend\App\Action;
-use Magento\Sales\Model\Order\Email\Sender\ShipmentSender;
+use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
 
+/**
+ * Class Save
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class Save extends \Magento\Backend\App\Action
 {
     /**
@@ -29,21 +33,26 @@ class Save extends \Magento\Backend\App\Action
     protected $labelGenerator;
 
     /**
-     * @var ShipmentSender
+     * @var \Magento\Sales\Model\Order\Email\Sender\ShipmentSender
      */
     protected $shipmentSender;
 
     /**
-     * @param Action\Context $context
+     * @var \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface
+     */
+    private $shipmentValidator;
+
+    /**
+     * @param \Magento\Backend\App\Action\Context $context
      * @param \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader
      * @param \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator
-     * @param ShipmentSender $shipmentSender
+     * @param \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender
      */
     public function __construct(
-        Action\Context $context,
+        \Magento\Backend\App\Action\Context $context,
         \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
         \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator,
-        ShipmentSender $shipmentSender
+        \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender
     ) {
         $this->shipmentLoader = $shipmentLoader;
         $this->labelGenerator = $labelGenerator;
@@ -119,7 +128,14 @@ class Save extends \Magento\Backend\App\Action
                 $shipment->setCustomerNote($data['comment_text']);
                 $shipment->setCustomerNoteNotify(isset($data['comment_customer_notify']));
             }
-
+            $errorMessages = $this->getShipmentValidator()->validate($shipment, [QuantityValidator::class]);
+            if (!empty($errorMessages)) {
+                $this->messageManager->addError(
+                    __("Shipment Document Validation Error(s):\n" . implode("\n", $errorMessages))
+                );
+                $this->_redirect('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
+                return;
+            }
             $shipment->register();
 
             $shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));
@@ -168,4 +184,19 @@ class Save extends \Magento\Backend\App\Action
             $this->_redirect('sales/order/view', ['order_id' => $shipment->getOrderId()]);
         }
     }
+
+    /**
+     * @return \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface
+     * @deprecated
+     */
+    private function getShipmentValidator()
+    {
+        if ($this->shipmentValidator === null) {
+            $this->shipmentValidator = $this->_objectManager->get(
+                \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface::class
+            );
+        }
+
+        return $this->shipmentValidator;
+    }
 }
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
index b452c88887c9e59bea3711578dff9e6db886ba84..c4efe6f6507d5641d7ef7d9ed378c73a6038c1de 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php
@@ -1,6 +1,5 @@
 <?php
 /**
- *
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
index af89f1a9146be07f49a31f7c5b0ad90c5d3c96b0..f8d9c06dc8ec05c07c699c4b22e7b830c796e4dc 100644
--- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
+++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/SaveTest.php
@@ -11,6 +11,9 @@ namespace Magento\Shipping\Test\Unit\Controller\Adminhtml\Order\Shipment;
 use Magento\Backend\App\Action;
 use Magento\Sales\Model\Order\Email\Sender\ShipmentSender;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface;
+use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;
+
 /**
  * Class SaveTest
  *
@@ -88,6 +91,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     protected $saveAction;
 
+    /**
+     * @var ShipmentValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $shipmentValidatorMock;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -210,6 +218,10 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->method('getFormKeyValidator')
             ->will($this->returnValue($this->formKeyValidator));
 
+        $this->shipmentValidatorMock = $this->getMockBuilder(ShipmentValidatorInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->saveAction = $objectManagerHelper->getObject(
             \Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save::class,
             [
@@ -218,7 +230,8 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 'context' => $this->context,
                 'shipmentLoader' => $this->shipmentLoader,
                 'request' => $this->request,
-                'response' => $this->response
+                'response' => $this->response,
+                'shipmentValidator' => $this->shipmentValidatorMock
             ]
         );
     }
@@ -346,6 +359,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
                 ->will($this->returnValue($orderId));
             $this->prepareRedirect($path, $arguments);
 
+            $this->shipmentValidatorMock->expects($this->once())
+                ->method('validate')
+                ->with($shipment, [QuantityValidator::class])
+                ->willReturn([]);
+
             $this->saveAction->execute();
             $this->assertEquals($this->response, $this->saveAction->getResponse());
         }
diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php
index cb384134a7c68c63955a0d97ab27aaa6c4f4f002..60c9f54ea132c5a0af3970ac58b87710b7b1688c 100644
--- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderInvoiceCreateTest.php
@@ -10,7 +10,7 @@ namespace Magento\Sales\Service\V1;
  */
 class OrderInvoiceCreateTest extends \Magento\TestFramework\TestCase\WebapiAbstract
 {
-    const SERVICE_READ_NAME = 'salesOrderInvoiceV1';
+    const SERVICE_READ_NAME = 'salesInvoiceOrderV1';
     const SERVICE_VERSION = 'V1';
 
     /**
diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8de7c4dc7f65b9318eca04c2656f22aa08cc447f
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Sales\Service\V1;
+
+/**
+ * API test for creation of Shipment for certain Order.
+ */
+class ShipOrderTest extends \Magento\TestFramework\TestCase\WebapiAbstract
+{
+    const SERVICE_READ_NAME = 'salesShipOrderV1';
+    const SERVICE_VERSION = 'V1';
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Sales\Api\ShipmentRepositoryInterface
+     */
+    private $shipmentRepository;
+
+    protected function setUp()
+    {
+        $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+        $this->shipmentRepository = $this->objectManager->get(
+            \Magento\Sales\Api\ShipmentRepositoryInterface::class
+        );
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/Sales/_files/order_new.php
+     */
+    public function testShipOrder()
+    {
+        /** @var \Magento\Sales\Model\Order $existingOrder */
+        $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId('100000001');
+
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/ship',
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_READ_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_READ_NAME . 'execute',
+            ],
+        ];
+
+        $requestData = [
+            'orderId' => $existingOrder->getId(),
+            'items' => [],
+            'comment' => [
+                'comment' => 'Test Comment',
+                'is_visible_on_front' => 1,
+            ],
+            'tracks' => [
+                [
+                    'track_number' => 'TEST_TRACK_0001',
+                    'title' => 'Simple shipment track',
+                    'carrier_code' => 'UPS'
+                ]
+            ]
+        ];
+
+        /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */
+        foreach ($existingOrder->getAllItems() as $item) {
+            $requestData['items'][] = [
+                'order_item_id' => $item->getItemId(),
+                'qty' => $item->getQtyOrdered(),
+            ];
+        }
+
+        $result = $this->_webApiCall($serviceInfo, $requestData);
+
+        $this->assertNotEmpty($result);
+
+        try {
+            $this->shipmentRepository->get($result);
+        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+            $this->fail('Failed asserting that Shipment was created');
+        }
+
+        /** @var \Magento\Sales\Model\Order $updatedOrder */
+        $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+            ->loadByIncrementId('100000001');
+
+        $this->assertNotEquals(
+            $existingOrder->getStatus(),
+            $updatedOrder->getStatus(),
+            'Failed asserting that Order status was changed'
+        );
+    }
+}
diff --git a/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php b/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php
index 9147d47f3d9dd8c21cec93ff47de2e065a13dd9d..fe3a199da86a32bdb866894b53831fe4c5e8a246 100644
--- a/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php
+++ b/lib/internal/Magento/Framework/EntityManager/CustomAttributesMapper.php
@@ -55,8 +55,9 @@ class CustomAttributesMapper implements MapperInterface
      */
     public function entityToDatabase($entityType, $data)
     {
-        $metadata = $this->metadataPool->getMetadata($entityType);
-        if (!$metadata->getEavEntityType()) {
+        if (!$this->metadataPool->hasConfiguration($entityType)
+            || !$this->metadataPool->getMetadata($entityType)->getEavEntityType()
+        ) {
             return $data;
         }
         if (isset($data[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES])) {
diff --git a/lib/internal/Magento/Framework/EntityManager/Test/Unit/CustomAttributesMapperTest.php b/lib/internal/Magento/Framework/EntityManager/Test/Unit/CustomAttributesMapperTest.php
index a39ad4afaa6eed43f552f14b5bdb85c16fa712dc..56977af1dd6eb5c62872572ec22f2024f7479223 100644
--- a/lib/internal/Magento/Framework/EntityManager/Test/Unit/CustomAttributesMapperTest.php
+++ b/lib/internal/Magento/Framework/EntityManager/Test/Unit/CustomAttributesMapperTest.php
@@ -48,12 +48,18 @@ class CustomAttributesMapperTest extends \PHPUnit_Framework_TestCase
 
         $metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class)
             ->disableOriginalConstructor()
-            ->setMethods(['getMetadata'])
+            ->setMethods(['getMetadata', 'hasConfiguration'])
             ->getMock();
+        $metadataPool->expects($this->any())
+            ->method('hasConfiguration')
+            ->willReturn(true);
         $metadataPool->expects($this->any())
             ->method('getMetadata')
             ->with($this->equalTo(\Magento\Customer\Api\Data\AddressInterface::class))
             ->will($this->returnValue($metadata));
+        $metadataPool->expects($this->once())
+            ->method('hasConfiguration')
+            ->willReturn(true);
 
         $searchCriteriaBuilder = $this->getMockBuilder(\Magento\Framework\Api\SearchCriteriaBuilder::class)
             ->disableOriginalConstructor()
@@ -76,6 +82,7 @@ class CustomAttributesMapperTest extends \PHPUnit_Framework_TestCase
                 'metadataPool' => $metadataPool,
                 'searchCriteriaBuilder' => $searchCriteriaBuilder
             ]);
+
         $actual = $customAttributesMapper->entityToDatabase(
             \Magento\Customer\Api\Data\AddressInterface::class,
             [
diff --git a/lib/internal/Magento/Framework/EntityManager/TypeResolver.php b/lib/internal/Magento/Framework/EntityManager/TypeResolver.php
index 28e2bdaa7094223d604cf174cd627982b6ecd0e9..2718162e80d669acfbc70eb78310b5911d7a668b 100644
--- a/lib/internal/Magento/Framework/EntityManager/TypeResolver.php
+++ b/lib/internal/Magento/Framework/EntityManager/TypeResolver.php
@@ -20,7 +20,8 @@ class TypeResolver
      */
     private $typeMapping = [
         \Magento\SalesRule\Model\Rule::class => \Magento\SalesRule\Api\Data\RuleInterface::class,
-        \Magento\SalesRule\Model\Rule\Interceptor::class => \Magento\SalesRule\Api\Data\RuleInterface::class
+        \Magento\SalesRule\Model\Rule\Interceptor::class => \Magento\SalesRule\Api\Data\RuleInterface::class,
+        \Magento\SalesRule\Model\Rule\Proxy::class => \Magento\SalesRule\Api\Data\RuleInterface::class
     ];
 
     /**
@@ -50,8 +51,7 @@ class TypeResolver
         $dataInterfaces = [];
         foreach ($interfaceNames as $interfaceName) {
             if (strpos($interfaceName, '\Api\Data\\')) {
-                $dataInterfaces[] = isset($this->config[$interfaceName])
-                    ? $this->config[$interfaceName] : $interfaceName;
+                $dataInterfaces[] = $interfaceName;
             }
         }
 
@@ -64,7 +64,9 @@ class TypeResolver
                 $this->typeMapping[$className] = $dataInterface;
             }
         }
-
+        if (empty($this->typeMapping[$className])) {
+            $this->typeMapping[$className] = reset($dataInterfaces);
+        }
         return $this->typeMapping[$className];
     }
 }