protected function moveAssignment(
        Stock\StockAssignmentInterface $assignment,
        Stock\StockUnitInterface $targetUnit,
        $quantity
    ) {
        /**
         * TODO Refactor with:
         * @see \Ekyna\Component\Commerce\Stock\Dispatcher\StockAssignmentDispatcher::moveAssignments()
         */

        // Don't move shipped quantity
        $quantity = min($quantity, $assignment->getSoldQuantity() - $assignment->getShippedQuantity());
        if (0 >= $quantity) { // TODO Packaging format
            return 0;
        }

        $sourceUnit = $assignment->getStockUnit();
        $saleItem = $assignment->getSaleItem();

        // Debit source unit's sold quantity
        $this->logger->unitSold($sourceUnit, -$quantity);
        $sourceUnit->setSoldQuantity($sourceUnit->getSoldQuantity() - $quantity);
        $this->manager->persist($sourceUnit);

        // Credit target unit
        $this->logger->unitSold($targetUnit, $quantity);
        $targetUnit->setSoldQuantity($targetUnit->getSoldQuantity() + $quantity);
        $this->manager->persist($targetUnit);

        // Merge assignment lookup
        $merge = null;
        foreach ($targetUnit->getStockAssignments() as $m) {
            if ($m->getSaleItem() === $saleItem) {
                $merge = $m;
                break;
            }
        }

        if ($quantity == $assignment->getSoldQuantity()) {
            if (null !== $merge) {
                // Credit quantity to mergeable assignment
                $this->logger->assignmentSold($merge, $quantity);
                $merge->setSoldQuantity($merge->getSoldQuantity() + $quantity);
                $this->manager->persist($merge);

                // Debit quantity from source assignment
                $this->logger->assignmentSold($assignment, 0, false); // TODO log removal ?
                $assignment
                    ->setSoldQuantity(0)
                    ->setSaleItem(null)
                    ->setStockUnit(null);
                $this->manager->remove($assignment);
            } else {
                // Move source assignment to target unit
                $this->logger->assignmentUnit($assignment, $targetUnit);
                $assignment->setStockUnit($targetUnit);
                $this->manager->persist($assignment);
            }
        } else {
            // Debit quantity from source assignment
            $this->logger->assignmentSold($assignment, -$quantity);
            $assignment->setSoldQuantity($assignment->getSoldQuantity() - $quantity);
            $this->manager->persist($assignment);

            if (null !== $merge) {
                // Credit quantity to mergeable assignment
                $this->logger->assignmentSold($merge, $quantity);
                $merge->setSoldQuantity($merge->getSoldQuantity() + $quantity);
                $this->manager->persist($merge);
            } else {
                // Credit quantity to new assignment
                $create = $this->saleFactory->createStockAssignmentForItem($saleItem);
                $this->logger->assignmentSold($create, $quantity, false);
                $create
                    ->setSoldQuantity($quantity)
                    ->setSaleItem($saleItem)
                    ->setStockUnit($targetUnit);

                $this->manager->persist($create);
            }
        }

        return $quantity;
    }