code: public static function build(StockUnitInterface $unit, SaleInterface $sale)
      {
          $releasable = 0;
          $map = [];
          foreach ($unit->getStockAssignments() as $a) {
              // Ignore assignments from the same sale (Should be impossible)
              /** @var \Ekyna\Component\Commerce\Shipment\Model\ShipmentSubjectInterface $s */
              if ($sale === $s = $a->getSaleItem()->getSale()) {
                  continue;
              }
  
              // Ignore assignments from preparation sales
              if ($s->getShipmentState() === ShipmentStates::STATE_PREPARATION) {
                  continue;
              }
  
              if (0 < $d = $a->getSoldQuantity() - $a->getShippedQuantity()) {
                  $releasable += $d;
                  $map[$a->getId()] = $d;
              }
          }
  
          arsort($map, \SORT_NUMERIC);
  
          $candidate = new static;
  
          $candidate->unit = $unit;
          $candidate->shippable = $unit->getShippableQuantity();
          $candidate->reservable = $unit->getReservableQuantity();
          $candidate->releasable = $releasable;
          $candidate->map = $map;
  
          return $candidate;
      }
docs: Builds a new unit candidate.
  
  @param StockUnitInterface $unit
  @param SaleInterface      $sale
  
  @return UnitCandidate