Stock/Prioritizer/PrioritizeHelper.php
public function getUnitCandidates(StockAssignmentInterface $assignment, $quantity)
    {
        $subject = $assignment->getStockUnit()->getSubject();

        // Find the subject's ready stock units
        if (empty($units = $this->unitResolver->findReady($subject))) {
            return [];
        };

        $sale = $assignment->getSaleItem()->getSale();

        $candidates = [];

        foreach ($units as $unit) {
            $this->unitResolver->getStockUnitCache()->add($unit);

            $candidate = UnitCandidate::build($unit, $sale);

            // Skip if no reservable and no releasable quantity
            if ((0 >= $candidate->reservable) && (0 >= $candidate->releasable)) {
                continue;
            }

            $add = false;
            $diff = 0;

            if (0 < $candidate->reservable) {
                // Unit has enough reservable quantity
                if (empty($candidates) && 0 >= $diff = $quantity - $candidate->reservable) {
                    return [$candidate];
                }

                $add = true;
            }

            if (null !== $candidate->getCombination(max($diff, $candidate->releasable))) {
                $add = true;
            }

            if ($add) {
                $candidates[] = $candidate;
            }
        }

        if (empty($candidates)) {
            return [];
        }

        // Sort candidates
        usort($candidates, function (UnitCandidate $a, UnitCandidate $b) use ($quantity) {
            // TODO sort by (reservable + releasable) DESC

            // TODO Simplify. Prefer:
            // - 'shippable' enough
            // - 'reservable' eq/positive/closest
            // - 'releasable' eq/positive/closest

            // Prefer units with shippable >= quantity, reservable >= quantity or releasable >= quantity
            foreach (['shippable', 'reservable', 'releasable'] as $property) {
                if (false !== $r = $this->ceilComparison($a, $b, $property, $quantity)) {
                    return $r;
                }
            }
            // Prefer units with shippable == quantity, reservable == quantity or releasable == quantity
            foreach (['reservable', 'releasable'] as $property) { // 'shippable' ?
                if (false !== $r = $this->equalComparison($a, $b, $property, $quantity)) {
                    return $r;
                }
            }

            // TODO (temporary)
            foreach (['shippable', 'reservable', 'releasable'] as $property) {
                if ($a->{$property} != $b->{$property}) {
                    return $b->{$property} - $a->{$property};
                }
            }
            return 0;

            // Prefer units with assignments combination's releasable quantity (sum) that
            // equals or is greater than (prefer closest) aimed quantity.
            if ($a->combination->sum == $b->combination->sum) {
                return 0;
            }
            if (0 <= $a->combination->sum) {
                return intval(0 > $b->combination->sum ? -1 : $a->combination->sum - $b->combination->sum);
            }

            return intval(0 < $b->combination->sum ? 1 : $b->combination->sum - $a->combination->sum);
        });

        return $candidates;
    }
public function getUnitCandidates(StockAssignmentInterface $assignment, $quantity)
    {
        $subject = $assignment->getStockUnit()->getSubject();

        // Find the subject's ready stock units
        if (empty($units = $this->unitResolver->findReady($subject))) {
            return [];
        };

        $sale = $assignment->getSaleItem()->getSale();

        $candidates = [];

        foreach ($units as $unit) {
            $this->unitResolver->getStockUnitCache()->add($unit);

            $candidate = UnitCandidate::build($unit, $sale);

            // Skip if no reservable and no releasable quantity
            if ((0 >= $candidate->reservable) && (0 >= $candidate->releasable)) {
                continue;
            }

            $add = false;
            $diff = 0;

            if (0 < $candidate->reservable) {
                // Unit has enough reservable quantity
                if (empty($candidates) && 0 >= $diff = $quantity - $candidate->reservable) {
                    return [$candidate];
                }

                $add = true;
            }

            if (null !== $candidate->getCombination(max($diff, $candidate->releasable))) {
                $add = true;
            }

            if ($add) {
                $candidates[] = $candidate;
            }
        }

        if (empty($candidates)) {
            return [];
        }

        // Sort candidates
        usort($candidates, function (UnitCandidate $a, UnitCandidate $b) use ($quantity) {
            // TODO sort by (reservable + releasable) DESC

            // TODO Simplify. Prefer:
            // - 'shippable' enough
            // - 'reservable' eq/positive/closest
            // - 'releasable' eq/positive/closest

            // Prefer units with shippable >= quantity, reservable >= quantity or releasable >= quantity
            foreach (['shippable', 'reservable', 'releasable'] as $property) {
                if (false !== $r = $this->ceilComparison($a, $b, $property, $quantity)) {
                    return $r;
                }
            }
            // Prefer units with shippable == quantity, reservable == quantity or releasable == quantity
            foreach (['reservable', 'releasable'] as $property) { // 'shippable' ?
                if (false !== $r = $this->equalComparison($a, $b, $property, $quantity)) {
                    return $r;
                }
            }

            // TODO (temporary)
            foreach (['shippable', 'reservable', 'releasable'] as $property) {
                if ($a->{$property} != $b->{$property}) {
                    return $b->{$property} - $a->{$property};
                }
            }
            return 0;

            // Prefer units with assignments combination's releasable quantity (sum) that
            // equals or is greater than (prefer closest) aimed quantity.
            if ($a->combination->sum == $b->combination->sum) {
                return 0;
            }
            if (0 <= $a->combination->sum) {
                return intval(0 > $b->combination->sum ? -1 : $a->combination->sum - $b->combination->sum);
            }

            return intval(0 < $b->combination->sum ? 1 : $b->combination->sum - $a->combination->sum);
        });

        return $candidates;
    }
public function getUnitCandidates ( StockAssignmentInterface $ assignment , $ quantity ) { $ subject = $ assignment -> getStockUnit ( ) -> getSubject ( ) ; // Find the subject's ready stock units if ( empty ( $ units = $ this -> unitResolver -> findReady ( $ subject ) ) ) { return [ ] ; } ; $ sale = $ assignment -> getSaleItem ( ) -> getSale ( ) ; $ candidates = [ ] ; foreach ( $ units as $ unit ) { $ this -> unitResolver -> getStockUnitCache ( ) -> add ( $ unit ) ; $ candidate = UnitCandidate :: build ( $ unit , $ sale ) ; // Skip if no reservable and no releasable quantity if ( ( 0 >= $ candidate -> reservable ) && ( 0 >= $ candidate -> releasable ) ) { continue ; } $ add = false ; $ diff = 0 ; if ( 0 < $ candidate -> reservable ) { // Unit has enough reservable quantity if ( empty ( $ candidates ) && 0 >= $ diff = $ quantity - $ candidate -> reservable ) { return [ $ candidate ] ; } $ add = true ; } if ( null !== $ candidate -> getCombination ( max ( $ diff , $ candidate -> releasable ) ) ) { $ add = true ; } if ( $ add ) { $ candidates [ ] = $ candidate ; } } if ( empty ( $ candidates ) ) { return [ ] ; } // Sort candidates usort ( $ candidates , function ( UnitCandidate $ a , UnitCandidate $ b ) use ( $ quantity ) { // TODO sort by (reservable + releasable) DESC // TODO Simplify. Prefer: // - 'shippable' enough // - 'reservable' eq/positive/closest // - 'releasable' eq/positive/closest // Prefer units with shippable >= quantity, reservable >= quantity or releasable >= quantity foreach ( [ 'shippable' , 'reservable' , 'releasable' ] as $ property ) { if ( false !== $ r = $ this -> ceilComparison ( $ a , $ b , $ property , $ quantity ) ) { return $ r ; } } // Prefer units with shippable == quantity, reservable == quantity or releasable == quantity foreach ( [ 'reservable' , 'releasable' ] as $ property ) { // 'shippable' ? if ( false !== $ r = $ this -> equalComparison ( $ a , $ b , $ property , $ quantity ) ) { return $ r ; } } // TODO (temporary) foreach ( [ 'shippable' , 'reservable' , 'releasable' ] as $ property ) { if ( $ a -> { $ property } != $ b -> { $ property } ) { return $ b -> { $ property } - $ a -> { $ property } ; } } return 0 ; // Prefer units with assignments combination's releasable quantity (sum) that // equals or is greater than (prefer closest) aimed quantity. if ( $ a -> combination -> sum == $ b -> combination -> sum ) { return 0 ; } if ( 0 <= $ a -> combination -> sum ) { return intval ( 0 > $ b -> combination -> sum ? - 1 : $ a -> combination -> sum - $ b -> combination -> sum ) ; } return intval ( 0 < $ b -> combination -> sum ? 1 : $ b -> combination -> sum - $ a -> combination -> sum ) ; } ) ; return $ candidates ; }
Finds the best stock unit to move/merge assignment(s) into for the given quantity.

@param StockAssignmentInterface $assignment
@param float                    $quantity

@return UnitCandidate[]
Finds the best stock unit to move / merge assignment ( s ) into for the given quantity .