Skip to content

Commit dfd4460

Browse files
committed
Merge branch '5.3' into feature/pt-2315-add-coupon-code-order-condition-rule
# Conflicts: # CHANGELOG-WIP.md [ci skip]
2 parents 7aa9cab + c8105c9 commit dfd4460

21 files changed

+536
-189
lines changed

CHANGELOG-WIP.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Store Management
44
- Order conditions can now have a “Coupon Code” rule. ([#3776](https://github.com/craftcms/commerce/discussions/3776))
55
- Order conditions can now have a “Payment Gateway” rule. ([#3722](https://github.com/craftcms/commerce/discussions/3722))
6+
- Variant conditions can now have a “Product” rule.
67

78
### Administration
89
- Added support for `to`, `bcc`, and `cc` email fields to support environment variables. ([#3738](https://github.com/craftcms/commerce/issues/3738))
@@ -12,6 +13,11 @@
1213
- Added an `originalCart` value to the `commerce/update-cart` failed ajax response. ([#430](https://github.com/craftcms/commerce/issues/430))
1314

1415
### Extensibility
16+
- Added `craft\commerce\base\InventoryItemTrait`.
17+
- Added `craft\commerce\base\InventoryLocationTrait`.
1518
- Added `craft\commerce\elements\conditions\orders\CouponCodeConditionRule`.
19+
- Added `craft\commerce\elements\conditions\variants\ProductConditionRule`.
1620
- Added `craft\commerce\elements\db\OrderQuery::$couponCode`.
17-
- Added `craft\commerce\elements\db\OrderQuery::couponCode()`.
21+
- Added `craft\commerce\elements\db\OrderQuery::couponCode()`.
22+
- Added `craft\commerce\services\Inventory::updateInventoryLevel()`.
23+
- Added `craft\commerce\services\Inventory::updatePurchasableInventoryLevel()`.

src/base/InventoryItemTrait.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* @link https://craftcms.com/
4+
* @copyright Copyright (c) Pixel & Tonic, Inc.
5+
* @license https://craftcms.github.io/license/
6+
*/
7+
8+
namespace craft\commerce\base;
9+
10+
use craft\commerce\models\InventoryItem;
11+
use craft\commerce\Plugin;
12+
13+
/**
14+
* Inventory Item Trait
15+
*
16+
* @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
17+
* @since 5.3.0
18+
*/
19+
trait InventoryItemTrait
20+
{
21+
/**
22+
* @var int|null The inventory item ID
23+
*/
24+
public ?int $inventoryItemId = null;
25+
26+
/**
27+
* @var InventoryItem|null The inventory item
28+
* @see getInventoryItem()
29+
* @see setInventoryItem()
30+
*/
31+
private ?InventoryItem $_inventoryItem = null;
32+
33+
/**
34+
* @param InventoryItem|null $inventoryItem
35+
* @return void
36+
*/
37+
public function setInventoryItem(?InventoryItem $inventoryItem): void
38+
{
39+
$this->_inventoryItem = $inventoryItem;
40+
$this->inventoryItemId = $inventoryItem?->id ?? null;
41+
}
42+
43+
/**
44+
* @return InventoryItem|null
45+
* @throws \yii\base\InvalidConfigException
46+
*/
47+
public function getInventoryItem(): ?InventoryItem
48+
{
49+
if (isset($this->_inventoryItem)) {
50+
return $this->_inventoryItem;
51+
}
52+
53+
if ($this->inventoryItemId) {
54+
$this->_inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($this->inventoryItemId);
55+
56+
return $this->_inventoryItem;
57+
}
58+
59+
return null;
60+
}
61+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* @link https://craftcms.com/
4+
* @copyright Copyright (c) Pixel & Tonic, Inc.
5+
* @license https://craftcms.github.io/license/
6+
*/
7+
8+
namespace craft\commerce\base;
9+
10+
use craft\commerce\models\InventoryLocation;
11+
use craft\commerce\Plugin;
12+
13+
/**
14+
* Inventory Location Trait
15+
*
16+
* @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
17+
* @since 5.3.0
18+
*/
19+
trait InventoryLocationTrait
20+
{
21+
/**
22+
* @var int|null The inventory item ID
23+
*/
24+
public ?int $inventoryLocationId = null;
25+
26+
/**
27+
* @var InventoryLocation|null The inventory item
28+
* @see getInventoryLocation()
29+
* @see setInventoryLocation()
30+
*/
31+
private ?InventoryLocation $_inventoryLocation = null;
32+
33+
/**
34+
* @param InventoryLocation|null $inventoryLocation
35+
* @return void
36+
*/
37+
public function setInventoryLocation(?InventoryLocation $inventoryLocation): void
38+
{
39+
$this->_inventoryLocation = $inventoryLocation;
40+
$this->inventoryLocationId = $inventoryLocation?->id ?? null;
41+
}
42+
43+
/**
44+
* @return InventoryLocation|null
45+
* @throws \yii\base\InvalidConfigException
46+
*/
47+
public function getInventoryLocation(): ?InventoryLocation
48+
{
49+
if (isset($this->_inventoryLocation)) {
50+
return $this->_inventoryLocation;
51+
}
52+
53+
if ($this->inventoryLocationId) {
54+
$this->_inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($this->inventoryLocationId);
55+
56+
return $this->_inventoryLocation;
57+
}
58+
59+
return null;
60+
}
61+
}

src/base/InventoryMovement.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
namespace craft\commerce\base;
99

1010
use craft\commerce\enums\InventoryTransactionType;
11-
use craft\commerce\models\InventoryItem;
1211
use craft\commerce\models\InventoryLocation;
1312

1413
/**
@@ -18,10 +17,7 @@
1817
*/
1918
abstract class InventoryMovement extends Model implements InventoryMovementInterface
2019
{
21-
/**
22-
* @var InventoryItem The inventory item
23-
*/
24-
public InventoryItem $inventoryItem;
20+
use InventoryItemTrait;
2521

2622
/**
2723
* @var InventoryLocation
@@ -90,27 +86,31 @@ public function init(): void
9086
}
9187

9288
/**
93-
* @inheritDoc
89+
* @return array
9490
*/
95-
public function isValid(): bool
91+
protected function defineRules(): array
9692
{
97-
return $this->validate();
93+
$rules = parent::defineRules();
94+
95+
$rules[] = [['inventoryItemId'], 'safe'];
96+
97+
return $rules;
9898
}
9999

100100
/**
101101
* @inheritDoc
102102
*/
103-
public function getInventoryMovementHash(): string
103+
public function isValid(): bool
104104
{
105-
return $this->_inventoryMovementHash;
105+
return $this->validate();
106106
}
107107

108108
/**
109109
* @inheritDoc
110110
*/
111-
public function getInventoryItem(): InventoryItem
111+
public function getInventoryMovementHash(): string
112112
{
113-
return $this->inventoryItem;
113+
return $this->_inventoryMovementHash;
114114
}
115115

116116
/**

src/base/InventoryMovementInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ interface InventoryMovementInterface
2121
/**
2222
* @return InventoryItem
2323
*/
24-
public function getInventoryItem(): InventoryItem;
24+
public function getInventoryItem(): ?InventoryItem;
2525

2626
/**
2727
* @return InventoryLocation

src/base/Purchasable.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,20 @@ private function _getTeller(): Teller
383383
return Plugin::getInstance()->getCurrencies()->getTeller($this->getStore()->getCurrency());
384384
}
385385

386+
/**
387+
* @inheritdoc
388+
*/
389+
public function __unset($name)
390+
{
391+
// Allow clearing of specific memoized properties
392+
if (in_array($name, ['stock', 'shippingCategory', 'taxCategory'])) {
393+
$this->{'_' . $name} = null;
394+
return;
395+
}
396+
397+
parent::__unset($name);
398+
}
399+
386400
/**
387401
* @inheritdoc
388402
*/
@@ -949,7 +963,6 @@ public function getStock(): int
949963
return $this->_stock;
950964
}
951965

952-
953966
/**
954967
* Returns the total stock across all locations this purchasable is tracked in.
955968
* @return Collection<InventoryLevel>

src/base/StoreTrait.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
<?php
2+
/**
3+
* @link https://craftcms.com/
4+
* @copyright Copyright (c) Pixel & Tonic, Inc.
5+
* @license https://craftcms.github.io/license/
6+
*/
27

38
namespace craft\commerce\base;
49

src/collections/UpdateInventoryLevelCollection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static function make($items = [])
4848
public function getPurchasables(): array
4949
{
5050
return $this->map(function(UpdateInventoryLevel|UpdateInventoryLevelInTransfer $updateInventoryLevel) {
51-
return $updateInventoryLevel->inventoryItem->getPurchasable();
51+
return $updateInventoryLevel->getInventoryItem()->getPurchasable();
5252
})->all();
5353
}
5454
}

src/controllers/InventoryController.php

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,6 @@ public function actionUpdateLevels(): Response
503503
$note = Craft::$app->getRequest()->getRequiredParam('note');
504504
$inventoryLocationId = (int)Craft::$app->getRequest()->getRequiredParam('inventoryLocationId');
505505
$inventoryItemIds = Craft::$app->getRequest()->getRequiredParam('ids');
506-
$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);
507506
$type = Craft::$app->getRequest()->getRequiredParam('type');
508507

509508
// We don't add zero amounts as transactions movements
@@ -514,17 +513,16 @@ public function actionUpdateLevels(): Response
514513
$errors = [];
515514
$updateInventoryLevels = UpdateInventoryLevelCollection::make();
516515
foreach ($inventoryItemIds as $inventoryItemId) {
517-
$inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId);
518-
519-
$updateInventoryLevels->push(new UpdateInventoryLevel([
520-
'type' => $type,
521-
'updateAction' => $updateAction,
522-
'inventoryItem' => $inventoryItem,
523-
'inventoryLocation' => $inventoryLocation,
524-
'quantity' => $quantity,
525-
'note' => $note,
526-
])
527-
);
516+
// Verbosely set property to show usages
517+
$updateInventoryLevel = new UpdateInventoryLevel();
518+
$updateInventoryLevel->type = $type;
519+
$updateInventoryLevel->updateAction = $updateAction;
520+
$updateInventoryLevel->inventoryItemId = $inventoryItemId;
521+
$updateInventoryLevel->inventoryLocationId = $inventoryLocationId;
522+
$updateInventoryLevel->quantity = $quantity;
523+
$updateInventoryLevel->note = $note;
524+
525+
$updateInventoryLevels->push($updateInventoryLevel);
528526
}
529527

530528

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

541539
$resultingInventoryLevels = [];
542540
foreach ($updateInventoryLevels as $updateInventoryLevel) {
543-
$resultingInventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($updateInventoryLevel->inventoryItem, $updateInventoryLevel->inventoryLocation);
541+
/** @var UpdateInventoryLevel $updateInventoryLevel */
542+
$resultingInventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($updateInventoryLevel->inventoryItemId, $updateInventoryLevel->inventoryLocationId);
544543
}
545544

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

568-
$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);
569-
570567
$inventoryLevels = [];
571568
foreach ($inventoryItemIds as $inventoryItemId) {
572-
$item = Plugin::getInstance()->getInventory()->getInventoryItemById((int)$inventoryItemId);
573-
$inventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel($item, $inventoryLocation);
569+
$inventoryLevels[] = Plugin::getInstance()->getInventory()->getInventoryLevel((int)$inventoryItemId, $inventoryLocationId);
574570
}
575571

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

617-
$inventoryMovement = new InventoryManualMovement(
618-
[
619-
'inventoryItem' => Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId),
620-
'fromInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId),
621-
'toInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId),
622-
'fromInventoryTransactionType' => InventoryTransactionType::from($fromInventoryTransactionType),
623-
'toInventoryTransactionType' => InventoryTransactionType::from($toInventoryTransactionType),
624-
'quantity' => $quantity,
625-
'note' => $note,
626-
]
627-
);
613+
$inventoryMovement = new InventoryManualMovement();
614+
$inventoryMovement->inventoryItemId = $inventoryItemId;
615+
$inventoryMovement->fromInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId);
616+
$inventoryMovement->toInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId);
617+
$inventoryMovement->fromInventoryTransactionType = InventoryTransactionType::from($fromInventoryTransactionType);
618+
$inventoryMovement->toInventoryTransactionType = InventoryTransactionType::from($toInventoryTransactionType);
619+
$inventoryMovement->quantity = $quantity;
620+
$inventoryMovement->note = $note;
628621

629622
if ($inventoryMovement->validate()) {
630623
/** @var InventoryMovementCollection $inventoryMovementCollection */
@@ -665,19 +658,16 @@ public function actionEditMovementModal(): Response
665658
$toInventoryTransactionType = $toInventoryTransactionType->value;
666659
}
667660

668-
$inventoryMovement = new InventoryManualMovement(
669-
[
670-
'inventoryItem' => Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId),
671-
'fromInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId),
672-
'toInventoryLocation' => Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId),
673-
'fromInventoryTransactionType' => InventoryTransactionType::from($fromInventoryTransactionType),
674-
'toInventoryTransactionType' => InventoryTransactionType::from($toInventoryTransactionType),
675-
'quantity' => $quantity,
676-
'note' => $note,
677-
]
678-
);
679-
680-
$fromLevel = Plugin::getInstance()->getInventory()->getInventoryLevel($inventoryMovement->inventoryItem, $inventoryMovement->fromInventoryLocation);
661+
$inventoryMovement = new InventoryManualMovement();
662+
$inventoryMovement->inventoryItemId = $inventoryItemId;
663+
$inventoryMovement->fromInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($fromInventoryLocationId);
664+
$inventoryMovement->toInventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($toInventoryLocationId);
665+
$inventoryMovement->fromInventoryTransactionType = InventoryTransactionType::from($fromInventoryTransactionType);
666+
$inventoryMovement->toInventoryTransactionType = InventoryTransactionType::from($toInventoryTransactionType);
667+
$inventoryMovement->quantity = $quantity;
668+
$inventoryMovement->note = $note;
669+
670+
$fromLevel = Plugin::getInstance()->getInventory()->getInventoryLevel($inventoryMovement->inventoryItemId, $inventoryMovement->fromInventoryLocation);
681671
$fromTotal = $fromLevel->{$fromInventoryTransactionType . 'Total'};
682672

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

708-
$inventoryLocation = Plugin::getInstance()->getInventoryLocations()->getInventoryLocationById($inventoryLocationId);
709-
$inventoryItem = Plugin::getInstance()->getInventory()->getInventoryItemById($inventoryItemId);
710-
711-
$orders = Plugin::getInstance()->getInventory()->getUnfulfilledOrders($inventoryItem, $inventoryLocation);
698+
$orders = Plugin::getInstance()->getInventory()->getUnfulfilledOrders($inventoryItemId, $inventoryLocationId);
712699

713700
$title = Craft::t('commerce', '{count} Unfulfilled Orders', [
714701
'count' => count($orders),

0 commit comments

Comments
 (0)