본문으로 건너뛰기

취소복원 시 재고 부족으로 복원이 보류되면 마일리지도 함께 보류되도록 개선

PHP 8 · GODO26
변경 파일 수: 1개
변경 파일 목록
1
변경 파일 코드
추가삭제
Component/Order/ReOrderCalculation.php+82
변경 전ReOrderCalculation.php
public function setOrderRestore($orderNo, $claimStatus)
{
$exceptMsg = [];
 
 
 
 
// Original 존재 확인
$count = $this->getOrderOriginalCount($orderNo, $claimStatus);
if ($count < 1) {
$exceptMsg[] = $stockResult['desc'][$getKey];
}
 
 
 
 
 
 
 
 
 
$giftFl = false; // 사은품
$cashFl = false; // 현금영수증
if ($claimStatus == 'c') {
return true;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* getSelectOrderGoodsAddData
* 상품 추가 데이터
 
변경 후ReOrderCalculation.php
public function setOrderRestore($orderNo, $claimStatus)
{
$exceptMsg = [];
 
// 실제 차감 전 복원 가능 여부 사전검증
$this->assertOrderRestoreAvailable($orderNo, $claimStatus);
 
// Original 존재 확인
$count = $this->getOrderOriginalCount($orderNo, $claimStatus);
if ($count < 1) {
$exceptMsg[] = $stockResult['desc'][$getKey];
}
 
// 재고 차감 실패(재고 부족 등) 시 마일리지/예치금 차감 이전에 중단한다.
// setMemberMileage 는 별도 커밋되어 이후 throw 로 롤백되지 않으므로, 반드시 차감 전에 throw 해야 한다.
if (!empty($exceptMsg)) {
$message = '<b>' . __('취소복원이 불가합니다. 복원 불가 사유를 확인해주세요.') . '</b><br /><br />'
. implode('<br />', $exceptMsg);
throw new Exception($message);
}
 
$giftFl = false; // 사은품
$cashFl = false; // 현금영수증
if ($claimStatus == 'c') {
return true;
}
 
/**
* 주문 취소 복원 사전검증 (READ-ONLY)
*
* setOrderRestore 는 예치금/마일리지 차감 시 Mileage::setMemberMileage 내부 트랜잭션이
* 외부 DB::transaction 과 중첩 커밋되어 롤백이 불가능하다. 그 결과 회원 보유분이 부족한 경우
* 일부만 반영된 상태 불일치가 발생할 수 있으므로, 실제 차감 전에 회원의 예치금/마일리지로
* 복원이 가능한지 먼저 확인하고 불가 시 throw
*
* @throws Exception 복원 불가 사유가 있을 경우
*/
private function assertOrderRestoreAvailable(string $orderNo, string $claimStatus): void
{
try {
$exceptMsg = $this->precheckRestoreAddPayment($orderNo, $claimStatus);
} catch (\Throwable $e) {
\Logger::channel('order')->warning('Order restore precheck failed', [
'orderNo' => $orderNo,
'claimStatus' => $claimStatus,
'error' => $e->getMessage()
]);
return;
}
 
if (empty($exceptMsg)) {
return;
}
 
$message = '<b>' . __('취소복원이 불가합니다. 복원 불가 사유를 확인해주세요.') . '</b><br /><br />'
. implode('<br />', $exceptMsg);
throw new Exception($message);
}
 
/**
* 예치금/마일리지 복원 가능 여부 사전검증. 원본과 현재 주문의 사용 차액을 회원 보유분으로 차감 가능한지 확인
*
* @return array 복원 불가 사유 메시지 배열 (정상 시 빈 배열)
*/
private function precheckRestoreAddPayment(string $orderNo, string $claimStatus): array
{
$original = $this->getOrderOriginalDepositMileageData($orderNo, $claimStatus);
$current = $this->getOrderDepositMileageData($orderNo);
 
// precheck 는 setOrderRestore 진입 직후(member 초기화 이전)에 호출되므로 직접 로드한다.
if (!is_object($this->member)) {
$this->member = \App::load('\\Component\\Member\\Member');
}
 
$memInfo = [];
if (is_array($original) && !empty($original['memNo'])) {
$memInfo = $this->member->getMemberInfo($original['memNo']);
}
 
$exceptMsg = [];
$checks = [
['field' => 'useDeposit', 'hold' => 'deposit', 'msg' => '고객이 보유한 예치금 부족'],
['field' => 'useMileage', 'hold' => 'mileage', 'msg' => '고객이 보유한 마일리지 부족'],
];
foreach ($checks as $check) {
$diff = gd_isset($current[$check['field']], 0) - gd_isset($original[$check['field']], 0);
if ($diff === 0) {
continue;
}
if (empty($memInfo) || (gd_isset($memInfo[$check['hold']], 0) - abs($diff) < 0)) {
$exceptMsg[] = $check['msg'];
}
}
 
return $exceptMsg;
}
 
/**
* getSelectOrderGoodsAddData
* 상품 추가 데이터