update rm deadcode
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Models\Addon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AddonQuantityValidator
|
||||
{
|
||||
/**
|
||||
* @param array<int, array{addon_id?: int, qty?: int}> $raw
|
||||
* @param Collection<int, Addon> $activeAddons Keyed by addon id.
|
||||
* @param array<int, int> $existingQtyByAddonId Already-owned qty per addon id, for capping total against max.
|
||||
* @return list<array{addon_id: int, code: string, name: string, qty: int, price: float, subtotal: float}>
|
||||
*
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public static function resolve(array $raw, Collection $activeAddons, array $existingQtyByAddonId = []): array
|
||||
{
|
||||
$resolved = [];
|
||||
|
||||
foreach ($raw as $entry) {
|
||||
$addonId = $entry['addon_id'] ?? null;
|
||||
if (!$addonId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$addon = $activeAddons->get($addonId);
|
||||
if (!$addon) {
|
||||
throw ValidationException::withMessages([
|
||||
'addons' => ['Addon không tồn tại hoặc không áp dụng cho sản phẩm này.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$qty = (int) ($entry['qty'] ?? 1);
|
||||
|
||||
if ($qty < $addon->min) {
|
||||
throw ValidationException::withMessages([
|
||||
'addons' => ["Số lượng addon {$addon->name} phải lớn hơn hoặc bằng {$addon->min}."],
|
||||
]);
|
||||
}
|
||||
|
||||
$totalQty = ($existingQtyByAddonId[$addonId] ?? 0) + $qty;
|
||||
|
||||
if ($addon->max > 0 && $totalQty > $addon->max) {
|
||||
throw ValidationException::withMessages([
|
||||
'addons' => ["Số lượng addon {$addon->name} không được vượt quá {$addon->max}."],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($addon->step > 0 && $qty % $addon->step !== 0) {
|
||||
throw ValidationException::withMessages([
|
||||
'addons' => ["Số lượng addon {$addon->name} phải là bội số của {$addon->step}."],
|
||||
]);
|
||||
}
|
||||
|
||||
$resolved[] = [
|
||||
'addon_id' => $addon->id,
|
||||
'code' => strtolower((string) $addon->code),
|
||||
'name' => $addon->name,
|
||||
'qty' => $qty,
|
||||
'price' => $addon->price,
|
||||
'subtotal' => $addon->price * $qty,
|
||||
];
|
||||
}
|
||||
|
||||
return $resolved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
final class PowerCliCertificatePolicy
|
||||
{
|
||||
public static function configurationLine(): string
|
||||
{
|
||||
$action = config('vmware.tls_verify', true) ? 'Fail' : 'Ignore';
|
||||
|
||||
return "Set-PowerCLIConfiguration -InvalidCertificateAction {$action} -Scope Session -Confirm:\$false | Out-Null";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
final class PowerShellEscaper
|
||||
{
|
||||
public static function singleQuote(string $value): string
|
||||
{
|
||||
return "'" . str_replace("'", "''", $value) . "'";
|
||||
}
|
||||
|
||||
public static function encodedCommand(string $script): string
|
||||
{
|
||||
return base64_encode(mb_convert_encoding($script, 'UTF-16LE', 'UTF-8'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Helpers\OrderHelper;
|
||||
use App\Models\Addon;
|
||||
use App\Models\Service;
|
||||
|
||||
class RenewalPricing
|
||||
{
|
||||
/** @return list<int> */
|
||||
public static function validMonths(string $billingCycle): array
|
||||
{
|
||||
$cycleMonths = OrderHelper::cycleToMonths($billingCycle);
|
||||
|
||||
if ($cycleMonths > 24) {
|
||||
return [$cycleMonths];
|
||||
}
|
||||
|
||||
$maxMultiple = intdiv(24, $cycleMonths);
|
||||
|
||||
return array_map(static fn (int $n): int => $n * $cycleMonths, range(1, $maxMultiple));
|
||||
}
|
||||
|
||||
public static function addonTotal(Service $service, int $cycles): int
|
||||
{
|
||||
return (int) array_sum(array_column(self::addonInvoiceItems($service, $cycles, 0), 'total_price'));
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public static function addonInvoiceItems(Service $service, int $cycles, int $months): array
|
||||
{
|
||||
$meta = array_filter(
|
||||
(array) ($service->orderItem?->addons_meta ?? []),
|
||||
static fn ($entry): bool => is_array($entry) && (int) ($entry['qty'] ?? 0) > 0,
|
||||
);
|
||||
|
||||
if ($meta === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$currentPrices = Addon::whereIn('id', array_column($meta, 'addon_id'))->pluck('price', 'id');
|
||||
|
||||
$items = [];
|
||||
foreach ($meta as $entry) {
|
||||
$qty = (int) $entry['qty'];
|
||||
$unitPrice = (int) ($currentPrices[$entry['addon_id'] ?? null] ?? $entry['price'] ?? 0);
|
||||
$totalPrice = $unitPrice * $qty * $cycles;
|
||||
|
||||
if ($totalPrice <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'product_id' => $service->product_id,
|
||||
'type' => 'addon',
|
||||
'description' => 'Addon: ' . ($entry['name'] ?? strtoupper((string) ($entry['code'] ?? ''))) . ' x' . $qty,
|
||||
'months' => $months,
|
||||
'quantity' => $qty,
|
||||
'unit_price' => $unitPrice * $cycles,
|
||||
'total_price' => $totalPrice,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use phpseclib3\Net\SSH2;
|
||||
use RuntimeException;
|
||||
|
||||
final class SshHostKeyVerifier
|
||||
{
|
||||
/** @throws RuntimeException */
|
||||
public static function verify(SSH2 $client, string $host): void
|
||||
{
|
||||
$knownHostsPath = config('vmware.ssh_known_hosts');
|
||||
if (!$knownHostsPath) {
|
||||
if (config('vmware.tls_verify', true)) {
|
||||
throw new RuntimeException("SSH host key verification required for {$host}: set VCENTER_SSH_KNOWN_HOSTS or VCENTER_TLS_VERIFY=false");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_readable($knownHostsPath)) {
|
||||
throw new RuntimeException("SSH known_hosts file not readable: {$knownHostsPath}");
|
||||
}
|
||||
|
||||
$serverKey = (string) $client->getServerPublicHostKey();
|
||||
$serverKeyParts = preg_split('/\s+/', trim($serverKey));
|
||||
$serverKeyValue = $serverKeyParts[1] ?? $serverKey;
|
||||
|
||||
$lines = file($knownHostsPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||||
foreach ($lines as $line) {
|
||||
$parts = preg_split('/\s+/', trim($line));
|
||||
if (count($parts) < 3 || $parts[0] !== $host) {
|
||||
continue;
|
||||
}
|
||||
if (hash_equals($parts[2], $serverKeyValue)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("SSH host key verification failed for {$host}: no matching known_hosts entry");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
final class TlsHttpClientFactory
|
||||
{
|
||||
public static function vCenter(): PendingRequest
|
||||
{
|
||||
return Http::withOptions(['verify' => self::verifyOption('vmware')]);
|
||||
}
|
||||
|
||||
public static function plesk(): PendingRequest
|
||||
{
|
||||
return Http::withOptions(['verify' => self::verifyOption('services.plesk')]);
|
||||
}
|
||||
|
||||
/** @return array<int, mixed> */
|
||||
public static function vCenterCurlOptions(): array
|
||||
{
|
||||
$verify = self::verifyOption('vmware');
|
||||
|
||||
return array_filter([
|
||||
CURLOPT_SSL_VERIFYPEER => $verify !== false,
|
||||
CURLOPT_SSL_VERIFYHOST => $verify === false ? 0 : 2,
|
||||
CURLOPT_CAINFO => is_string($verify) ? $verify : null,
|
||||
], fn ($value) => $value !== null);
|
||||
}
|
||||
|
||||
private static function verifyOption(string $configKey): bool|string
|
||||
{
|
||||
if (!config("{$configKey}.tls_verify", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return config("{$configKey}.ca_bundle") ?: true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user