|
@@ -197,7 +197,7 @@ class GiftProcessor
|
|
|
|
|
|
|
|
// 规则已不再成立 → 把赠品从购物车里摘掉
|
|
// 规则已不再成立 → 把赠品从购物车里摘掉
|
|
|
if ($gift->getAllowedQty() < 1) {
|
|
if ($gift->getAllowedQty() < 1) {
|
|
|
- $this->cartItemRepository->delete($cartItem->id);
|
|
|
|
|
|
|
+ $this->deleteCartItemRow($cart, $cartItem->id);
|
|
|
|
|
|
|
|
$gift->setCartItemId(null)->setReservedQty(0);
|
|
$gift->setCartItemId(null)->setReservedQty(0);
|
|
|
|
|
|
|
@@ -208,12 +208,19 @@ class GiftProcessor
|
|
|
if ($gift->getAllowedQty() < $gift->getReservedQty()) {
|
|
if ($gift->getAllowedQty() < $gift->getReservedQty()) {
|
|
|
$qty = $gift->getAllowedQty();
|
|
$qty = $gift->getAllowedQty();
|
|
|
|
|
|
|
|
- $cartItem = $this->cartItemRepository->update([
|
|
|
|
|
|
|
+ $cartItem = $this->updateCartItemRow($cartItem->id, [
|
|
|
'quantity' => $qty,
|
|
'quantity' => $qty,
|
|
|
'total' => (float) $cartItem->base_price * $qty,
|
|
'total' => (float) $cartItem->base_price * $qty,
|
|
|
'base_total' => (float) $cartItem->base_price * $qty,
|
|
'base_total' => (float) $cartItem->base_price * $qty,
|
|
|
'additional' => array_merge($cartItem->additional ?? [], ['quantity' => $qty]),
|
|
'additional' => array_merge($cartItem->additional ?? [], ['quantity' => $qty]),
|
|
|
- ], $cartItem->id);
|
|
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // 行已被本轮其它步骤删掉(快照失效)→ 作废指针,交给后续流程重建
|
|
|
|
|
+ if (! $cartItem) {
|
|
|
|
|
+ $gift->setCartItemId(null)->setReservedQty(0);
|
|
|
|
|
+
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
$gift->setReservedQty($qty);
|
|
$gift->setReservedQty($qty);
|
|
|
}
|
|
}
|
|
@@ -270,18 +277,18 @@ class GiftProcessor
|
|
|
if (! $cartItem) {
|
|
if (! $cartItem) {
|
|
|
$gift->setReservedQty(max(0, $gift->getReservedQty() - $excess));
|
|
$gift->setReservedQty(max(0, $gift->getReservedQty() - $excess));
|
|
|
} elseif ((float) $cartItem->quantity - $excess < 1) {
|
|
} elseif ((float) $cartItem->quantity - $excess < 1) {
|
|
|
- $this->cartItemRepository->delete($cartItem->id);
|
|
|
|
|
|
|
+ $this->deleteCartItemRow($cart, $cartItem->id);
|
|
|
|
|
|
|
|
$gift->setCartItemId(null)->setReservedQty(0);
|
|
$gift->setCartItemId(null)->setReservedQty(0);
|
|
|
} else {
|
|
} else {
|
|
|
$qty = (float) $cartItem->quantity - $excess;
|
|
$qty = (float) $cartItem->quantity - $excess;
|
|
|
|
|
|
|
|
- $this->cartItemRepository->update([
|
|
|
|
|
|
|
+ $this->updateCartItemRow($cartItem->id, [
|
|
|
'quantity' => $qty,
|
|
'quantity' => $qty,
|
|
|
'total' => (float) $cartItem->base_price * $qty,
|
|
'total' => (float) $cartItem->base_price * $qty,
|
|
|
'base_total' => (float) $cartItem->base_price * $qty,
|
|
'base_total' => (float) $cartItem->base_price * $qty,
|
|
|
'additional' => array_merge($cartItem->additional ?? [], ['quantity' => $qty]),
|
|
'additional' => array_merge($cartItem->additional ?? [], ['quantity' => $qty]),
|
|
|
- ], $cartItem->id);
|
|
|
|
|
|
|
+ ]);
|
|
|
|
|
|
|
|
$gift->setReservedQty($qty);
|
|
$gift->setReservedQty($qty);
|
|
|
}
|
|
}
|
|
@@ -615,7 +622,7 @@ class GiftProcessor
|
|
|
|
|
|
|
|
$qty = (float) $cartItem->quantity;
|
|
$qty = (float) $cartItem->quantity;
|
|
|
|
|
|
|
|
- $this->cartItemRepository->update([
|
|
|
|
|
|
|
+ $this->updateCartItemRow($cartItem->id, [
|
|
|
'price' => $price,
|
|
'price' => $price,
|
|
|
'price_incl_tax' => $price,
|
|
'price_incl_tax' => $price,
|
|
|
'base_price' => $price,
|
|
'base_price' => $price,
|
|
@@ -624,7 +631,89 @@ class GiftProcessor
|
|
|
'total_incl_tax' => $price * $qty,
|
|
'total_incl_tax' => $price * $qty,
|
|
|
'base_total' => $price * $qty,
|
|
'base_total' => $price * $qty,
|
|
|
'base_total_incl_tax' => $price * $qty,
|
|
'base_total_incl_tax' => $price * $qty,
|
|
|
- ], $cartItem->id);
|
|
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 安全更新购物车行。
|
|
|
|
|
+ *
|
|
|
|
|
+ * findGiftCartItem() 认领的是 $cart->all_items 这份「本轮快照」,而 Repository
|
|
|
|
|
+ * 的 delete() 不会刷新该关联:同一轮里先删后写的场景(syncGiftItems 删行之后,
|
|
|
|
|
+ * shrinkOneOfGroups / applyGiftPrice 又用旧快照认领到同一行)会让 update() 打到
|
|
|
|
|
+ * 已删除的 id —— Prettus 的 update() 内部是 findOrFail(),于是抛
|
|
|
|
|
+ * ModelNotFoundException(No query results for model [CartItem] xx)。这里先确认
|
|
|
|
|
+ * 行仍存在,悬空则跳过并返回 null。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int|string $cartItemId
|
|
|
|
|
+ * @return \Webkul\Checkout\Contracts\CartItem|null
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function updateCartItemRow($cartItemId, array $payload)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! $cartItemId || ! $this->cartItemRepository->find($cartItemId)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $this->cartItemRepository->update($payload, $cartItemId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 安全删除购物车行,并把该行从 $cart 的内存关联里剔除。
|
|
|
|
|
+ *
|
|
|
|
|
+ * Prettus 的 delete() 内部会 clone 查询结果,行不存在时 clone null 会致命报错,
|
|
|
|
|
+ * 所以先确认存在。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 更要紧的是「删完同步快照」:findGiftCartItem() / removeOrphanGiftRows() 认领的
|
|
|
|
|
+ * 都是 $cart->all_items 这份本轮快照,而 Repository 的删除不会刷新它。同一轮里
|
|
|
|
|
+ * 删完之后立刻还会再扫一遍(removeOrphanGiftRows),旧快照仍能看到已删的行,
|
|
|
|
|
+ * 于是又删/又写一次 —— delete 抛 `__clone method called on non-object`,
|
|
|
|
|
+ * update 抛 ModelNotFoundException。删完立刻把行从快照里摘掉,后续扫描就看不到它。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param \Webkul\Checkout\Contracts\Cart $cart
|
|
|
|
|
+ * @param int|string $cartItemId
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function deleteCartItemRow($cart, $cartItemId): void
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! $cartItemId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($this->cartItemRepository->find($cartItemId)) {
|
|
|
|
|
+ $this->cartItemRepository->delete($cartItemId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $this->forgetCartItemFromSnapshot($cart, $cartItemId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 把某一行从 $cart 已加载的 items / all_items 关联里剔除。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 只动内存里已经加载的关系(不触发重新查询);没加载过的关系不动,
|
|
|
|
|
+ * 它下次被访问时会回库拿最新数据。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param \Webkul\Checkout\Contracts\Cart $cart
|
|
|
|
|
+ * @param int|string $cartItemId
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function forgetCartItemFromSnapshot($cart, $cartItemId): void
|
|
|
|
|
+ {
|
|
|
|
|
+ if (! $cart || ! $cartItemId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach (['items', 'all_items'] as $relation) {
|
|
|
|
|
+ if (! $cart->relationLoaded($relation)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $items = $cart->getRelation($relation);
|
|
|
|
|
+
|
|
|
|
|
+ if (! $items instanceof \Illuminate\Support\Collection) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $cart->setRelation($relation, $items
|
|
|
|
|
+ ->reject(fn ($item) => (int) $item->id === (int) $cartItemId)
|
|
|
|
|
+ ->values());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -655,7 +744,7 @@ class GiftProcessor
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- $this->cartItemRepository->delete($cartItem->id);
|
|
|
|
|
|
|
+ $this->deleteCartItemRow($cart, $cartItem->id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|