$g ) { $sel_by_group[ $gid ] = array(); foreach ( $g['options'] as $oid => $o ) { $opt_index[ $oid ] = $o; if ( isset( $selected[ $oid ] ) ) { $sel_by_group[ $gid ][] = $oid; } } } $resolved = array(); foreach ( array_keys( $selected ) as $oid ) { if ( ! isset( $opt_index[ $oid ] ) ) { continue; } $o = $opt_index[ $oid ]; $assignment_id = isset( $groups[ $o['group_id'] ] ) ? (int) $groups[ $o['group_id'] ]['assignment_id'] : 0; $resolved[ $oid ] = self::resolve_option_price( $o, isset( $rules[ $oid ] ) ? $rules[ $oid ] : array(), $assignment_id, $selected ); } $lines = array(); $total = 0.0; foreach ( $groups as $gid => $g ) { $sel = $sel_by_group[ $gid ]; if ( empty( $sel ) ) { continue; } $free_n = (int) $g['included_free']; $policy = ( 'cheapest_free' === $g['free_policy'] ) ? 'cheapest_free' : 'expensive_free'; $pool = array(); foreach ( $sel as $oid ) { if ( empty( $opt_index[ $oid ]['exclude_from_allowance'] ) ) { $pool[] = $oid; } } $free_set = array(); if ( $free_n > 0 && $pool ) { usort( $pool, function ( $a, $b ) use ( $resolved, $policy ) { $pa = isset( $resolved[ $a ] ) ? $resolved[ $a ] : 0; $pb = isset( $resolved[ $b ] ) ? $resolved[ $b ] : 0; return ( 'cheapest_free' === $policy ) ? ( $pa <=> $pb ) : ( $pb <=> $pa ); } ); foreach ( array_slice( $pool, 0, $free_n ) as $oid ) { $free_set[ $oid ] = true; } } foreach ( $sel as $oid ) { $rd = isset( $resolved[ $oid ] ) ? $resolved[ $oid ] : 0.0; $is_free = isset( $free_set[ $oid ] ); $charged = $is_free ? 0.0 : $rd; $total += $charged; $lines[] = array( 'option_id' => $oid, 'group_id' => $gid, 'label' => $opt_index[ $oid ]['label'], 'resolved_delta' => round( $rd, 4 ), 'charged_delta' => round( $charged, 4 ), 'free' => $is_free, ); } } $errors = self::validate( $groups, $sel_by_group, $opt_index ); return array( 'total_delta' => round( $total, 4 ), 'lines' => $lines, 'valid' => empty( $errors ), 'errors' => $errors, ); } private static function resolve_option_price( array $option, array $rules, $assignment_id, array $selected ) { $best = null; $best_score = -1; foreach ( $rules as $r ) { $scope = (int) $r['scope_assignment_id']; if ( 0 !== $scope && $scope !== (int) $assignment_id ) { continue; } $wg = (int) $r['when_group_id']; if ( 0 !== $wg ) { $wo = (int) $r['when_option_id']; if ( 0 === $wo || ! isset( $selected[ $wo ] ) ) { continue; } } $score = ( 0 !== $scope ? 2 : 0 ) + ( 0 !== $wg ? 1 : 0 ); if ( $score > $best_score ) { $best = $r; $best_score = $score; } } return null !== $best ? (float) $best['price_delta'] : (float) $option['price_delta']; } private static function validate( array $groups, array $sel_by_group, array $opt_index ) { $errors = array(); foreach ( $groups as $gid => $g ) { $n = isset( $sel_by_group[ $gid ] ) ? count( $sel_by_group[ $gid ] ) : 0; $min = (int) $g['min_select']; $max = (int) $g['max_select']; if ( $min > 0 && $n < $min ) { $errors[] = sprintf( _n( 'Choose at least %1$d option for “%2$s”.', 'Choose at least %1$d options for “%2$s”.', $min, 'ai-eshop-optimizer' ), $min, $g['name'] ); } if ( $max > 0 && $n > $max ) { $errors[] = sprintf( _n( 'Choose at most %1$d option for “%2$s”.', 'Choose at most %1$d options for “%2$s”.', $max, 'ai-eshop-optimizer' ), $max, $g['name'] ); } $sel = isset( $sel_by_group[ $gid ] ) ? $sel_by_group[ $gid ] : array(); foreach ( $sel as $oid ) { if ( isset( $opt_index[ $oid ] ) && empty( $opt_index[ $oid ]['available'] ) ) { $errors[] = sprintf( __( '“%s” is sold out.', 'ai-eshop-optimizer' ), $opt_index[ $oid ]['label'] ); } } } return $errors; } }