구간별 배송비의 종료값이 구간에 포함되지 않아 경계값이 무료배송으로 새고, 상품 옵션의 g/cm³ 저장값을 정책의 kg/L 로 환산하지 않아 금액이 1000배로 청구되던 문제를 수정한다. - 구간 매칭을 종료값 오름차순 사다리로 교체 — 시작값은 표시 전용이 되어 기존 저장 데이터의 두 형태 모두에서 정확히 계산된다 - 단위 환산을 배송비 계산 한 지점으로 모으고, 부피무게와 실무게를 같은 kg 단위로 비교하도록 교정 - 계산이 조용히 0원이 되는 설정(구간 미등록·단위값/기준금액 누락· 중간 구간 무제한·계산 API 폴백 0원)을 저장 시점에 차단하고, 런타임 잔여 경로에는 경고 로그를 남긴다 - 연속성 규칙을 정책 타입별로 분리해 소수 구간(2.5kg) 저장을 허용 - 상품 옵션 무게/부피 응답 왕복, 주문 총 무게/부피 실값 기록
180 lines
4.7 KiB
PHP
180 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace Modules\Sirsoft\Ecommerce\Enums;
|
|
|
|
/**
|
|
* 배송비 부과정책 Enum
|
|
*/
|
|
enum ChargePolicyEnum: string
|
|
{
|
|
case FREE = 'free'; // 무료
|
|
case FIXED = 'fixed'; // 고정
|
|
case CONDITIONAL_FREE = 'conditional_free'; // 조건부 무료
|
|
case RANGE_AMOUNT = 'range_amount'; // 구간별(금액)
|
|
case RANGE_QUANTITY = 'range_quantity'; // 구간별(수량)
|
|
case RANGE_WEIGHT = 'range_weight'; // 구간별(무게)
|
|
case RANGE_VOLUME = 'range_volume'; // 구간별(부피)
|
|
case RANGE_VOLUME_WEIGHT = 'range_volume_weight'; // 구간별(부피+무게)
|
|
case API = 'api'; // 계산 API
|
|
case PER_QUANTITY = 'per_quantity'; // 수량당
|
|
case PER_WEIGHT = 'per_weight'; // 무게당
|
|
case PER_VOLUME = 'per_volume'; // 부피당
|
|
case PER_VOLUME_WEIGHT = 'per_volume_weight'; // 부피무게당
|
|
case PER_AMOUNT = 'per_amount'; // 금액당
|
|
|
|
/**
|
|
* 다국어 라벨을 반환합니다.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function label(): string
|
|
{
|
|
return __('sirsoft-ecommerce::enums.charge_policy.'.$this->value);
|
|
}
|
|
|
|
/**
|
|
* 프론트엔드용 라벨 키를 반환합니다.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getLabel(): string
|
|
{
|
|
return $this->label();
|
|
}
|
|
|
|
/**
|
|
* 모든 값 배열을 반환합니다.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function values(): array
|
|
{
|
|
return array_column(self::cases(), 'value');
|
|
}
|
|
|
|
/**
|
|
* 프론트엔드용 옵션 배열을 반환합니다.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function toSelectOptions(): array
|
|
{
|
|
return array_map(fn ($case) => [
|
|
'value' => $case->value,
|
|
'label' => $case->label(),
|
|
], self::cases());
|
|
}
|
|
|
|
/**
|
|
* 기본 배송비 필드가 필요한 정책인지 확인합니다.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function requiresBaseFee(): bool
|
|
{
|
|
return in_array($this, [
|
|
self::FIXED,
|
|
self::CONDITIONAL_FREE,
|
|
// API 정책의 base_fee 는 외부 API 장애 시의 폴백 배송비다.
|
|
// 0 으로 강제되면 장애가 곧 무음 무료배송이 된다.
|
|
self::API,
|
|
self::PER_QUANTITY,
|
|
self::PER_WEIGHT,
|
|
self::PER_VOLUME,
|
|
self::PER_VOLUME_WEIGHT,
|
|
self::PER_AMOUNT,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 구간 경계값이 이산형(정수)인 정책인지 확인합니다.
|
|
*
|
|
* 수량은 정수 단위라 "5개 다음은 6개"(max + 1)로 이어지고, 금액·무게·부피는
|
|
* 연속값이라 "5kg 다음은 5kg 초과"(다음 min = max)로 이어집니다.
|
|
*
|
|
* @return bool 이산형 여부
|
|
*/
|
|
public function hasDiscreteRangeValues(): bool
|
|
{
|
|
return $this === self::RANGE_QUANTITY;
|
|
}
|
|
|
|
/**
|
|
* 무료 기준금액 필드가 필요한 정책인지 확인합니다.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function requiresFreeThreshold(): bool
|
|
{
|
|
return $this === self::CONDITIONAL_FREE;
|
|
}
|
|
|
|
/**
|
|
* 구간 설정이 필요한 정책인지 확인합니다.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function requiresRanges(): bool
|
|
{
|
|
return in_array($this, [
|
|
self::RANGE_AMOUNT,
|
|
self::RANGE_QUANTITY,
|
|
self::RANGE_WEIGHT,
|
|
self::RANGE_VOLUME,
|
|
self::RANGE_VOLUME_WEIGHT,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* API 엔드포인트가 필요한 정책인지 확인합니다.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function requiresApiEndpoint(): bool
|
|
{
|
|
return $this === self::API;
|
|
}
|
|
|
|
/**
|
|
* 구간별 정책 목록을 반환합니다.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function rangePolicies(): array
|
|
{
|
|
return [
|
|
self::RANGE_AMOUNT,
|
|
self::RANGE_QUANTITY,
|
|
self::RANGE_WEIGHT,
|
|
self::RANGE_VOLUME,
|
|
self::RANGE_VOLUME_WEIGHT,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 단위당 배송비 설정(unit_value)이 필요한 정책인지 확인합니다.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function requiresUnitValue(): bool
|
|
{
|
|
return in_array($this, self::perUnitPolicies());
|
|
}
|
|
|
|
/**
|
|
* 단위당 정책 목록을 반환합니다.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function perUnitPolicies(): array
|
|
{
|
|
return [
|
|
self::PER_QUANTITY,
|
|
self::PER_WEIGHT,
|
|
self::PER_VOLUME,
|
|
self::PER_VOLUME_WEIGHT,
|
|
self::PER_AMOUNT,
|
|
];
|
|
}
|
|
}
|