| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- <?php
- namespace Longyi\FreeGift\Services;
- use Longyi\FreeGift\Config\Gift;
- use Longyi\FreeGift\Repositories\FreeGiftItemRepository;
- use Webkul\Checkout\Contracts\Cart as CartContract;
- /**
- * 单次请求内的赠品注册表(按购物车维度)。
- *
- * 对应 Amasty 的 Model\Registry,但这里额外负责:
- * - 首次访问时从 free_gift_items 回填状态(reservedQty / is_item_deleted)
- * - 规则重算结束后把结果写回 free_gift_items
- */
- class GiftRegistry
- {
- /**
- * @var array<int, GiftItemsGroup>
- */
- protected array $groups = [];
- /**
- * @var array<int, bool>
- */
- protected array $hydrated = [];
- public function __construct(
- protected FreeGiftItemRepository $giftItemRepository
- ) {}
- /**
- * 取(或初始化)某个购物车的赠品分组。
- */
- public function group(int $cartId): GiftItemsGroup
- {
- if (! isset($this->groups[$cartId])) {
- $this->groups[$cartId] = new GiftItemsGroup();
- }
- if (! isset($this->hydrated[$cartId])) {
- $this->hydrate($cartId);
- $this->hydrated[$cartId] = true;
- }
- return $this->groups[$cartId];
- }
- /**
- * 用购物车里的真实赠品行刷新 reservedQty。
- *
- * free_gift_items 只是缓存,cart_items 才是真相;每次重算都以购物车为准,
- * 避免用户在另一个标签页删了东西导致数量对不上。
- */
- public function syncReservedQty(CartContract $cart, GiftItemsGroup $group): void
- {
- $reserved = [];
- foreach ($cart->all_items as $cartItem) {
- $ruleId = $cartItem->additional[Gift::CART_ITEM_FLAG] ?? null;
- if (! $ruleId) {
- continue;
- }
- $key = ((int) $ruleId).':'.$cartItem->sku;
- $reserved[$key] = ($reserved[$key] ?? 0) + (float) $cartItem->quantity;
- }
- foreach ($group->getItems() as $item) {
- $item->setReservedQty($reserved[$item->getKey()] ?? 0);
- unset($reserved[$item->getKey()]);
- }
- // 购物车里存在但注册表里没有的赠品行(规则被删掉等)交给 syncGiftItems 清理
- }
- /**
- * 把注册表写回 free_gift_items。
- */
- public function persist(int $cartId): void
- {
- if (! isset($this->groups[$cartId])) {
- return;
- }
- foreach ($this->groups[$cartId]->getItems() as $item) {
- // 规则已经不再命中,且购物车里也没有残留 → 直接删掉状态行
- if ($item->getAllowedQty() < 1) {
- if ($item->getId()) {
- $this->giftItemRepository->delete($item->getId());
- $item->setId(null);
- }
- continue;
- }
- $data = [
- 'cart_id' => $cartId,
- 'cart_item_id' => $item->getCartItemId(),
- 'product_id' => $item->getProductId(),
- 'sku' => $item->getSku(),
- 'rule_id' => $item->getRuleId(),
- 'rule_type' => $item->getRuleType(),
- 'allowed_qty' => $item->getAllowedQty(),
- 'reserved_qty' => $item->getReservedQty(),
- 'discount_amount' => $item->getDiscount(),
- 'auto_add' => $item->isAutoAdd(),
- 'is_item_deleted' => $item->isDeleted(),
- ];
- if ($item->getId()) {
- $this->giftItemRepository->update($data, $item->getId());
- } else {
- $row = $this->giftItemRepository->create($data);
- $item->setId((int) $row->id);
- }
- }
- }
- /**
- * 丢弃某个购物车的注册表缓存(购物车被清空 / 合并时使用)。
- */
- public function forget(int $cartId): void
- {
- unset($this->groups[$cartId], $this->hydrated[$cartId]);
- }
- /**
- * 从 free_gift_items 回填。
- */
- protected function hydrate(int $cartId): void
- {
- foreach ($this->giftItemRepository->getByCart($cartId) as $row) {
- $item = new GiftItem(
- (string) $row->sku,
- (int) $row->rule_id,
- $row->discount_amount,
- (int) $row->rule_type,
- (bool) $row->auto_add
- );
- $item->setId((int) $row->id)
- ->setProductId($row->product_id ? (int) $row->product_id : null)
- ->setCartItemId($row->cart_item_id ? (int) $row->cart_item_id : null)
- ->setReservedQty((float) $row->reserved_qty)
- ->setStoredQty((float) $row->allowed_qty)
- ->setDeleted((bool) $row->is_item_deleted);
- $this->groups[$cartId]->put($item);
- }
- }
- }
|