$data One Omnibus record. * @param int|null $fallback_ts E.g. the post date of a 3.x log post. * @param bool $price_is_regular True for _iwo_price_last_change records. * @param callable $to_gross float $net -> float $gross, using the current tax setup. */ public static function from_record( array $data, ?int $fallback_ts, bool $price_is_regular, callable $to_gross ): ?self { $timestamp = isset( $data['timestamp'] ) && is_numeric( $data['timestamp'] ) && (int) $data['timestamp'] > 0 ? (int) $data['timestamp'] : $fallback_ts; if ( null === $timestamp ) { return null; } $sale = self::number( $data['price_sale'] ?? null ); if ( array_key_exists( 'price_regular', $data ) ) { $effective = self::number( $data['price'] ?? null ); $regular = self::number( $data['price_regular'] ); } elseif ( $price_is_regular ) { $regular = self::number( $data['price'] ?? null ); $effective = null !== $sale && null !== $regular && $sale < $regular ? $sale : $regular; } else { $effective = self::number( $data['price'] ?? null ); $regular = null; } if ( null === $effective ) { return null; } // The gross price Omnibus stored is the effective price incl. VAT at that time. $stored_gross = self::number( $data['price_including_tax'] ?? null ); if ( null !== $stored_gross && $stored_gross > 0 && $effective > 0 ) { $gross = $stored_gross; $tax_ratio = $stored_gross / $effective; } else { $gross = (float) $to_gross( $effective ); $tax_ratio = $effective > 0 ? $gross / $effective : 1.0; } $snapshot = new self(); $snapshot->timestamp = $timestamp; $snapshot->price = round( $gross, 4 ); $snapshot->regular_price = null === $regular ? null : round( $regular * $tax_ratio, 4 ); $snapshot->reduced = null !== $sale && abs( $effective - $sale ) < 0.005 && ( null === $regular || $sale < $regular ); $snapshot->currency = isset( $data['currency'] ) && is_string( $data['currency'] ) && '' !== $data['currency'] ? strtoupper( $data['currency'] ) : null; $snapshot->user_id = isset( $data['user_id'] ) && (int) $data['user_id'] > 0 ? (int) $data['user_id'] : null; return $snapshot; } public function same_price_as( self $other ): bool { return abs( $this->price - $other->price ) < 0.00005 && $this->reduced === $other->reduced && ( null === $this->regular_price ) === ( null === $other->regular_price ) && ( null === $this->regular_price || abs( $this->regular_price - (float) $other->regular_price ) < 0.00005 ); } /** * @param mixed $value */ private static function number( $value ): ?float { if ( is_int( $value ) || is_float( $value ) ) { return (float) $value; } if ( is_string( $value ) ) { $value = trim( str_replace( ',', '.', $value ) ); if ( '' !== $value && is_numeric( $value ) ) { return (float) $value; } } return null; } }