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]; } }