Add HL3D branding, Etsy Live/Draft paging and Projects lifecycle
Deploy HickLab3D Dashboard / Deploy to production (push) Failing after 23s

Replace the old touchmark/PNG identity with the supplied lockup and
monogram, segmented role-aware navigation, Live/Draft listing filters
with generation-based cache invalidation, and admin Projects covering
immutable file revisions, listing live pointers, and exact-decimal
filament/packaging/shipping costing. Additive schema only; no Etsy
publication. Isolated clone tests: 301 tests, 1162 assertions.
This commit is contained in:
2026-11-08 12:50:56 +00:00
parent c8c5822166
commit d4928789c4
83 changed files with 5808 additions and 84 deletions
+153
View File
@@ -0,0 +1,153 @@
<?php
namespace App\Support;
use InvalidArgumentException;
use OverflowException;
/**
* Exact decimal fixed-point arithmetic using bounded native integers.
*
* Neither the bcmath nor gmp extensions are available in this application's
* runtime, so costing math is done by scaling decimal strings into integers
* (never floats) and checking every operation for overflow against the
* platform's native integer range.
*/
class FixedPoint
{
private const MAX_INT = PHP_INT_MAX;
private const MIN_INT = PHP_INT_MIN;
/**
* Parse a decimal string (or int/numeric string) into an integer scaled by 10^$scale.
*/
public static function toScaled(string $decimal, int $scale, ?int $maxAbs = null, bool $allowNegative = true): int
{
$decimal = trim($decimal);
if ($decimal === '' || ! preg_match('/^-?\d+(\.\d+)?$/', $decimal)) {
throw new InvalidArgumentException("Invalid decimal value: {$decimal}");
}
$negative = $decimal[0] === '-';
if ($negative) {
if (! $allowNegative) {
throw new InvalidArgumentException("Negative values are not allowed: {$decimal}");
}
$decimal = substr($decimal, 1);
}
[$whole, $fraction] = array_pad(explode('.', $decimal, 2), 2, '');
if (strlen($fraction) > $scale) {
throw new InvalidArgumentException("Value has more than {$scale} decimal places: {$decimal}");
}
$fraction = str_pad($fraction, $scale, '0');
$whole = $whole === '' ? '0' : $whole;
$combined = ltrim($whole.$fraction, '0');
$combined = $combined === '' ? '0' : $combined;
if (strlen($combined) > 18) {
throw new InvalidArgumentException("Value out of bounds: {$decimal}");
}
$value = (int) $combined;
if ($value < 0 || $combined !== (string) $value) {
throw new InvalidArgumentException("Value out of bounds: {$decimal}");
}
if ($maxAbs !== null && $value > $maxAbs * (10 ** $scale)) {
throw new InvalidArgumentException("Value exceeds the allowed maximum: {$decimal}");
}
return $negative ? -$value : $value;
}
public static function add(int $a, int $b): int
{
if (($b > 0 && $a > self::MAX_INT - $b) || ($b < 0 && $a < self::MIN_INT - $b)) {
throw new OverflowException('Fixed-point addition overflowed.');
}
return $a + $b;
}
public static function subtract(int $a, int $b): int
{
return self::add($a, -$b);
}
public static function multiply(int $a, int $b): int
{
if ($a === 0 || $b === 0) {
return 0;
}
$result = $a * $b;
if (! is_int($result) || intdiv($result, $b) !== $a) {
throw new OverflowException('Fixed-point multiplication overflowed.');
}
return $result;
}
/**
* Divide a scaled value by a plain positive integer (e.g. batch units), rounding half away from zero.
*/
public static function divideByInt(int $value, int $divisor): int
{
if ($divisor === 0) {
throw new InvalidArgumentException('Cannot divide by zero.');
}
return self::roundDivide($value, $divisor);
}
/**
* Rescale a value from one decimal scale to another, rounding half away from zero.
*/
public static function rescale(int $value, int $fromScale, int $toScale): int
{
if ($toScale === $fromScale) {
return $value;
}
if ($toScale > $fromScale) {
$factor = 10 ** ($toScale - $fromScale);
$result = $value * $factor;
if ($factor !== 0 && intdiv($result, $factor) !== $value) {
throw new OverflowException('Fixed-point rescale overflowed.');
}
return $result;
}
return self::roundDivide($value, 10 ** ($fromScale - $toScale));
}
public static function format(int $scaled, int $scale): string
{
$negative = $scaled < 0;
$abs = (string) abs($scaled);
$abs = str_pad($abs, $scale + 1, '0', STR_PAD_LEFT);
$whole = substr($abs, 0, strlen($abs) - $scale);
$fraction = $scale > 0 ? substr($abs, strlen($abs) - $scale) : '';
$formatted = $scale > 0 ? "{$whole}.{$fraction}" : $whole;
return ($negative && $scaled !== 0 ? '-' : '').$formatted;
}
private static function roundDivide(int $value, int $divisor): int
{
$sign = ($value < 0) !== ($divisor < 0) ? -1 : 1;
$numerator = abs($value);
$denominator = abs($divisor);
$quotient = intdiv($numerator, $denominator);
$remainder = $numerator % $denominator;
if ($remainder * 2 >= $denominator) {
$quotient++;
}
return $sign * $quotient;
}
}