Skip to content

Commit

Permalink
Merge branch '5.3' into feature/5.3-teller
Browse files Browse the repository at this point in the history
  • Loading branch information
lukeholder authored Dec 11, 2024
2 parents e83628d + c8105c9 commit ca0f88b
Show file tree
Hide file tree
Showing 19 changed files with 473 additions and 190 deletions.
15 changes: 13 additions & 2 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@

### Store Management

- Added support for `to`, `bcc`, and `cc` email fields to support environment variables. ([#3738](https://github.com/craftcms/commerce/issues/3738))
- Added an `originalCart` value to the `commerce/update-cart` failed ajax response. ([#430](https://github.com/craftcms/commerce/issues/430))
- Order conditions can now have a “Payment Gateway” rule. ([#3722](https://github.com/craftcms/commerce/discussions/3722))
- Variant conditions can now have a “Product” rule.

### Administration

- Added support for `to`, `bcc`, and `cc` email fields to support environment variables. ([#3738](https://github.com/craftcms/commerce/issues/3738))

### Development

- Added an `originalCart` value to the `commerce/update-cart` failed ajax response. ([#430](https://github.com/craftcms/commerce/issues/430))

### Extensibility

- Added `craft\commerce\elements\Order::getTeller()`.
- Added `craft\commerce\elements\conditions\variants\ProductConditionRule`.
- Added `craft\commerce\base\InventoryItemTrait`.
- Added `craft\commerce\base\InventoryLocationTrait`.
- Added `craft\commerce\elements\conditions\variants\ProductConditionRule`.
- Added `craft\commerce\services\Inventory::updateInventoryLevel()`.
- Added `craft\commerce\services\Inventory::updatePurchasableInventoryLevel()`.
61 changes: 61 additions & 0 deletions src/base/InventoryItemTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\commerce\base;

use craft\commerce\models\InventoryItem;
use craft\commerce\Plugin;

/**
* Inventory Item Trait
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 5.3.0
*/
trait InventoryItemTrait
{
/**
* @var int|null The inventory item ID
*/
public ?int $inventoryItemId = null;

/**
* @var InventoryItem|null The inventory item
* @see getInventoryItem()
* @see setInventoryItem()
*/
private ?InventoryItem $_inventoryItem = null;

/**
* @param InventoryItem|null $inventoryItem
* @return void
*/
public function setInventoryItem(?InventoryItem $inventoryItem): void
{
$this->_inventoryItem = $inventoryItem;
$this->inventoryItemId = $inventoryItem?->id ?? null;
}

/**
* @return InventoryItem|null
* @throws \yii\base\InvalidConfigException
*/
public function getInventoryItem(): ?InventoryItem
{
if (isset($this->_inventoryItem)) {
return $this->_inventoryItem;
}

if ($this->inventoryItemId) {
$this->_inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($this->inventoryItemId);

return $this->_inventoryItem;
}

return null;
}
}
61 changes: 61 additions & 0 deletions src/base/InventoryLocationTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\commerce\base;

use craft\commerce\models\InventoryLocation;
use craft\commerce\Plugin;

/**
* Inventory Location Trait
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 5.3.0
*/
trait InventoryLocationTrait
{
/**
* @var int|null The inventory item ID
*/
public ?int $inventoryLocationId = null;

/**
* @var InventoryLocation|null The inventory item
* @see getInventoryLocation()
* @see setInventoryLocation()
*/
private ?InventoryLocation $_inventoryLocation = null;

/**
* @param InventoryLocation|null $inventoryLocation
* @return void
*/
public function setInventoryLocation(?InventoryLocation $inventoryLocation): void
{
$this->_inventoryLocation = $inventoryLocation;
$this->inventoryLocationId = $inventoryLocation?->id ?? null;
}

/**
* @return InventoryLocation|null
* @throws \yii\base\InvalidConfigException
*/
public function getInventoryLocation(): ?InventoryLocation
{
if (isset($this->_inventoryLocation)) {
return $this->_inventoryLocation;
}

if ($this->inventoryLocationId) {
$this->_inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($this->inventoryLocationId);

return $this->_inventoryLocation;
}

return null;
}
}
24 changes: 12 additions & 12 deletions src/base/InventoryMovement.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
namespace craft\commerce\base;

use craft\commerce\enums\InventoryTransactionType;
use craft\commerce\models\InventoryItem;
use craft\commerce\models\InventoryLocation;

/**
Expand All @@ -18,10 +17,7 @@
*/
abstract class InventoryMovement extends Model implements InventoryMovementInterface
{
/**
* @var InventoryItem The inventory item
*/
public InventoryItem $inventoryItem;
use InventoryItemTrait;

/**
* @var InventoryLocation
Expand Down Expand Up @@ -90,27 +86,31 @@ public function init(): void
}

/**
* @inheritDoc
* @return array
*/
public function isValid(): bool
protected function defineRules(): array
{
return $this->validate();
$rules = parent::defineRules();

$rules[] = [['inventoryItemId'], 'safe'];

return $rules;
}

/**
* @inheritDoc
*/
public function getInventoryMovementHash(): string
public function isValid(): bool
{
return $this->_inventoryMovementHash;
return $this->validate();
}

/**
* @inheritDoc
*/
public function getInventoryItem(): InventoryItem
public function getInventoryMovementHash(): string
{
return $this->inventoryItem;
return $this->_inventoryMovementHash;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/base/InventoryMovementInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface InventoryMovementInterface
/**
* @return InventoryItem
*/
public function getInventoryItem(): InventoryItem;
public function getInventoryItem(): ?InventoryItem;

/**
* @return InventoryLocation
Expand Down
15 changes: 14 additions & 1 deletion src/base/Purchasable.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,20 @@ private function _getTeller(): Teller
return Plugin::getInstance()->getCurrencies()->getTeller($this->getStore()->getCurrency());
}

/**
* @inheritdoc
*/
public function __unset($name)
{
// Allow clearing of specific memoized properties
if (in_array($name, ['stock', 'shippingCategory', 'taxCategory'])) {
$this->{'_' . $name} = null;
return;
}

parent::__unset($name);
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -949,7 +963,6 @@ public function getStock(): int
return $this->_stock;
}


/**
* Returns the total stock across all locations this purchasable is tracked in.
* @return Collection<InventoryLevel>
Expand Down
5 changes: 5 additions & 0 deletions src/base/StoreTrait.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\commerce\base;

Expand Down
2 changes: 1 addition & 1 deletion src/collections/UpdateInventoryLevelCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static function make($items = [])
public function getPurchasables(): array
{
return $this->map(function(UpdateInventoryLevel|UpdateInventoryLevelInTransfer $updateInventoryLevel) {
return $updateInventoryLevel->inventoryItem->getPurchasable();
return $updateInventoryLevel->getInventoryItem()->getPurchasable();
})->all();
}
}
77 changes: 32 additions & 45 deletions src/controllers/InventoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,6 @@ public function actionUpdateLevels(): Response
$note = Craft::$app->getRequest()->getRequiredParam('note');
$inventoryLocationId = (int)Craft::$app->getRequest()->getRequiredParam('inventoryLocationId');
$inventoryItemIds = Craft::$app->getRequest()->getRequiredParam('ids');
$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);
$type = Craft::$app->getRequest()->getRequiredParam('type');

// We don't add zero amounts as transactions movements
Expand All @@ -514,17 +513,16 @@ public function actionUpdateLevels(): Response
$errors = [];
$updateInventoryLevels = UpdateInventoryLevelCollection::make();
foreach ($inventoryItemIds as $inventoryItemId) {
$inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId);

$updateInventoryLevels->push(new UpdateInventoryLevel([
'type' => $type,
'updateAction' => $updateAction,
'inventoryItem' => $inventoryItem,
'inventoryLocation' => $inventoryLocation,
'quantity' => $quantity,
'note' => $note,
])
);
// Verbosely set property to show usages
$updateInventoryLevel = new UpdateInventoryLevel();
$updateInventoryLevel->type = $type;
$updateInventoryLevel->updateAction = $updateAction;
$updateInventoryLevel->inventoryItemId = $inventoryItemId;
$updateInventoryLevel->inventoryLocationId = $inventoryLocationId;
$updateInventoryLevel->quantity = $quantity;
$updateInventoryLevel->note = $note;

$updateInventoryLevels->push($updateInventoryLevel);
}


Expand All @@ -540,7 +538,8 @@ public function actionUpdateLevels(): Response

$resultingInventoryLevels = [];
foreach ($updateInventoryLevels as $updateInventoryLevel) {
$resultingInventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($updateInventoryLevel->inventoryItem, $updateInventoryLevel->inventoryLocation);
/** @var UpdateInventoryLevel $updateInventoryLevel */
$resultingInventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($updateInventoryLevel->inventoryItemId, $updateInventoryLevel->inventoryLocationId);
}

return $this->asSuccess(Craft::t('commerce', 'Inventory updated.'), [
Expand All @@ -565,12 +564,9 @@ public function actionEditUpdateLevelsModal(): Response
$quantity = (int)$this->request->getParam('quantity', 0);
$type = $this->request->getRequiredParam('type');

$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);

$inventoryLevels = [];
foreach ($inventoryItemIds as $inventoryItemId) {
$item = Plugin::getInstance()->getInventory()->getInventoryItemById((int)$inventoryItemId);
$inventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($item, $inventoryLocation);
$inventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel((int)$inventoryItemId, $inventoryLocationId);
}

$params = [
Expand Down Expand Up @@ -614,17 +610,14 @@ public function actionSaveInventoryMovement(): Response
return $this->asSuccess(Craft::t('commerce', 'No inventory movements made.'));
}

$inventoryMovement = new InventoryManualMovement(
[
'inventoryItem' => Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId),
'fromInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId),
'toInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId),
'fromInventoryTransactionType' => InventoryTransactionType::from($fromInventoryTransactionType),
'toInventoryTransactionType' => InventoryTransactionType::from($toInventoryTransactionType),
'quantity' => $quantity,
'note' => $note,
]
);
$inventoryMovement = new InventoryManualMovement();
$inventoryMovement->inventoryItemId = $inventoryItemId;
$inventoryMovement->fromInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId);
$inventoryMovement->toInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId);
$inventoryMovement->fromInventoryTransactionType = InventoryTransactionType::from($fromInventoryTransactionType);
$inventoryMovement->toInventoryTransactionType = InventoryTransactionType::from($toInventoryTransactionType);
$inventoryMovement->quantity = $quantity;
$inventoryMovement->note = $note;

if ($inventoryMovement->validate()) {
/** @var InventoryMovementCollection $inventoryMovementCollection */
Expand Down Expand Up @@ -665,19 +658,16 @@ public function actionEditMovementModal(): Response
$toInventoryTransactionType = $toInventoryTransactionType->value;
}

$inventoryMovement = new InventoryManualMovement(
[
'inventoryItem' => Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId),
'fromInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId),
'toInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId),
'fromInventoryTransactionType' => InventoryTransactionType::from($fromInventoryTransactionType),
'toInventoryTransactionType' => InventoryTransactionType::from($toInventoryTransactionType),
'quantity' => $quantity,
'note' => $note,
]
);

$fromLevel = Plugin::getInstance()->getInventory()->getInventoryLevel($inventoryMovement->inventoryItem, $inventoryMovement->fromInventoryLocation);
$inventoryMovement = new InventoryManualMovement();
$inventoryMovement->inventoryItemId = $inventoryItemId;
$inventoryMovement->fromInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId);
$inventoryMovement->toInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId);
$inventoryMovement->fromInventoryTransactionType = InventoryTransactionType::from($fromInventoryTransactionType);
$inventoryMovement->toInventoryTransactionType = InventoryTransactionType::from($toInventoryTransactionType);
$inventoryMovement->quantity = $quantity;
$inventoryMovement->note = $note;

$fromLevel = Plugin::getInstance()->getInventory()->getInventoryLevel($inventoryMovement->inventoryItemId, $inventoryMovement->fromInventoryLocation);
$fromTotal = $fromLevel->{$fromInventoryTransactionType . 'Total'};

$movableTo = $movableTo->toArray();
Expand Down Expand Up @@ -705,10 +695,7 @@ public function actionUnfulfilledOrders(): Response
$inventoryLocationId = Craft::$app->getRequest()->getParam('inventoryLocationId');
$inventoryItemId = Craft::$app->getRequest()->getParam('inventoryItemId');

$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);
$inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId);

$orders = Plugin::getInstance()->getInventory()->getUnfulfilledOrders($inventoryItem, $inventoryLocation);
$orders = Plugin::getInstance()->getInventory()->getUnfulfilledOrders($inventoryItemId, $inventoryLocationId);

$title = Craft::t('commerce', '{count} Unfulfilled Orders', [
'count' => count($orders),
Expand Down
Loading

0 comments on commit ca0f88b

Please sign in to comment.