dbmsv4 init...5
This commit is contained in:
parent
4a1b40c39f
commit
43dd7caf02
@ -180,34 +180,6 @@ abstract class CommonForm
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 2) 숫자/FK 필드 정규화
|
|
||||||
* - 폼에서 미선택은 보통 ''로 들어옴 -> NULL로 변환
|
|
||||||
* - 숫자 문자열은 int 캐스팅 (선택)
|
|
||||||
*
|
|
||||||
* 주의:
|
|
||||||
* - "빈값을 0으로 취급" 같은 정책이 있다면 여기에서 조정해야 함.
|
|
||||||
*/
|
|
||||||
protected function normalizeNumericEmptyToNull(array $data, array $numericFields): array
|
|
||||||
{
|
|
||||||
foreach ($numericFields as $f) {
|
|
||||||
if (!array_key_exists($f, $data)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($data[$f] === '') {
|
|
||||||
$data[$f] = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($data[$f]) && ctype_digit($data[$f])) {
|
|
||||||
$data[$f] = (int) $data[$f];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3) role.* 같은 배열 원소 규칙이 있을 때, 부모 배열 존재/타입 보정
|
* 3) role.* 같은 배열 원소 규칙이 있을 때, 부모 배열 존재/타입 보정
|
||||||
*/
|
*/
|
||||||
@ -259,38 +231,6 @@ abstract class CommonForm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 4) 검증 rule에 따라 "numeric(특히 FK)"로 취급할 필드를 수집
|
|
||||||
* - getFormRule()에서 permit_empty|numeric 로 정의되는 필드를 공통 처리하기 위함
|
|
||||||
*
|
|
||||||
* 구현 전략:
|
|
||||||
* - formRules에서 rule 문자열에 'numeric'가 포함된 필드를 모음
|
|
||||||
* - wildcard(role.*) 제외
|
|
||||||
*/
|
|
||||||
protected function collectNumericFieldsFromRules(array $formRules): array
|
|
||||||
{
|
|
||||||
$numericFields = [];
|
|
||||||
|
|
||||||
foreach ($formRules as $field => $rule) {
|
|
||||||
$fieldName = (string) $field;
|
|
||||||
|
|
||||||
if (str_contains($fieldName, '.*')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// getValidationRule hook 적용 (필드명/룰이 바뀔 수 있으니)
|
|
||||||
[$fieldName, $ruleStr] = $this->getValidationRule($fieldName, (string) $rule);
|
|
||||||
|
|
||||||
if (is_string($ruleStr) && str_contains($ruleStr, 'numeric')) {
|
|
||||||
$numericFields[] = $fieldName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 중복 제거
|
|
||||||
return array_values(array_unique($numericFields));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* Validation
|
* Validation
|
||||||
* --------------------------------------------------------------------- */
|
* --------------------------------------------------------------------- */
|
||||||
@ -299,13 +239,8 @@ abstract class CommonForm
|
|||||||
* 데이터를 검증하고 유효하지 않을 경우 예외를 발생시킵니다.
|
* 데이터를 검증하고 유효하지 않을 경우 예외를 발생시킵니다.
|
||||||
* 2025 CI4 표준: 규칙 배열 내에 label을 포함하여 한글 메시지 출력을 보장합니다.
|
* 2025 CI4 표준: 규칙 배열 내에 label을 포함하여 한글 메시지 출력을 보장합니다.
|
||||||
*/
|
*/
|
||||||
final public function validate(array &$formDatas): void
|
public function validate_process(array &$formDatas, $isDebug = false): array
|
||||||
{
|
{
|
||||||
log_message('debug', '>>> CommonForm::validate CALLED: ' . static::class . ', formAction:' . $this->formAction);
|
|
||||||
try {
|
|
||||||
// 0) 데이터 구조 정리 (null 변환 X)
|
|
||||||
$formDatas = $this->sanitizeFormDatas($formDatas);
|
|
||||||
|
|
||||||
// 1) 전체 라벨/룰
|
// 1) 전체 라벨/룰
|
||||||
$allFormFields = $this->getFormFields(); // ['field' => '라벨', ...]
|
$allFormFields = $this->getFormFields(); // ['field' => '라벨', ...]
|
||||||
$allFormRules = $this->getFormRules(); // ['field' => 'rules', ...]
|
$allFormRules = $this->getFormRules(); // ['field' => 'rules', ...]
|
||||||
@ -313,54 +248,61 @@ abstract class CommonForm
|
|||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 지정된 Form RULE이 없습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 지정된 Form RULE이 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) 액션별 "검증 대상 필드" 결정
|
|
||||||
$formRules = $allFormRules;
|
|
||||||
$formFields = $allFormFields;
|
|
||||||
if ($this->formAction === 'modify') {
|
if ($this->formAction === 'modify') {
|
||||||
// (1) formDatas에 실제로 넘어온 필드만
|
// (1) formDatas에 실제로 넘어온 필드만
|
||||||
$targetFields = array_keys($formDatas);
|
$targetFields = array_keys($formDatas);
|
||||||
|
if ($isDebug) {
|
||||||
// (2) 내부 제어용 키 제거(프로젝트에 맞게 추가/삭제)
|
log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate targetFields Begin DEBUG");
|
||||||
$exclude = ['_method', 'csrf_test_name', 'submit', 'token', 'action'];
|
log_message('debug', var_export($targetFields, true));
|
||||||
$targetFields = array_values(array_diff($targetFields, $exclude));
|
|
||||||
|
|
||||||
// (3) wildcard(role.*) 같은 규칙이 있으면 부모 기반으로 같이 포함
|
|
||||||
// - formDatas에 role이 있으면 role.* 규칙도 함께 검사되도록 추가
|
|
||||||
foreach ($allFormRules as $ruleField => $_ruleStr) {
|
|
||||||
$ruleField = (string) $ruleField;
|
|
||||||
if (!str_contains($ruleField, '.*')) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$parent = str_replace('.*', '', $ruleField);
|
// // (2) 내부 제어용 키 제거(프로젝트에 맞게 추가/삭제)
|
||||||
if (in_array($parent, $targetFields, true)) {
|
// $exclude = ['_method', 'csrf_test_name', 'submit', 'token', 'action'];
|
||||||
$targetFields[] = $ruleField; // e.g. 'role.*'
|
// $targetFields = array_values(array_diff($targetFields, $exclude));
|
||||||
|
// // (3) wildcard(role.*) 같은 규칙이 있으면 부모 기반으로 같이 포함
|
||||||
|
// // - formDatas에 role이 있으면 role.* 규칙도 함께 검사되도록 추가
|
||||||
|
// foreach ($allFormRules as $ruleField => $_ruleStr) {
|
||||||
|
// $ruleField = (string) $ruleField;
|
||||||
|
// if (!str_contains($ruleField, '.*')) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// $parent = str_replace('.*', '', $ruleField);
|
||||||
|
// if (in_array($parent, $targetFields, true)) {
|
||||||
|
// $targetFields[] = $ruleField; // e.g. 'role.*'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // (4) 실제로 룰이 정의된 필드만 남김
|
||||||
|
// $targetFields = array_values(array_intersect($targetFields, array_keys($allFormRules)));
|
||||||
|
if ($isDebug) {
|
||||||
|
log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate targetFields End DEBUG");
|
||||||
|
log_message('debug', var_export($targetFields, true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// (4) 실제로 룰이 정의된 필드만 남김
|
|
||||||
$targetFields = array_values(array_intersect($targetFields, array_keys($allFormRules)));
|
|
||||||
|
|
||||||
// 최종: modify에서는 "타겟만" 룰/라벨 세팅
|
// 최종: modify에서는 "타겟만" 룰/라벨 세팅
|
||||||
$formRules = $this->getFormRules($targetFields);
|
|
||||||
$formFields = $this->getFormFields($targetFields);
|
$formFields = $this->getFormFields($targetFields);
|
||||||
|
$formRules = $this->getFormRules($targetFields);
|
||||||
// throw new RuntimeException(static::class . "->targetFields" . implode(",", $targetFields) . "\nformRules:" . implode(",", array_keys($formRules)) . "\nformFields:" . implode(",", array_keys($formFields)));
|
// throw new RuntimeException(static::class . "->targetFields" . implode(",", $targetFields) . "\nformRules:" . implode(",", array_keys($formRules)) . "\nformFields:" . implode(",", array_keys($formFields)));
|
||||||
|
}//modify
|
||||||
|
// 2) 액션별 "검증 대상 필드" 결정
|
||||||
|
// $formFields = $allFormFields;
|
||||||
|
// $formRules = $allFormRules;
|
||||||
|
return array($formFields, $formRules, $allFormFields);
|
||||||
}
|
}
|
||||||
|
final public function validate(array &$formDatas, $isDebug = false): void
|
||||||
|
{
|
||||||
|
log_message('debug', '>>> CommonForm::validate CALLED: ' . static::class . ', formAction:' . $this->formAction);
|
||||||
|
try {
|
||||||
|
// 0) 데이터 구조 정리 (null 변환 X)
|
||||||
|
$formDatas = $this->sanitizeFormDatas($formDatas);
|
||||||
|
list($formFields, $formRules, $allFormFields) = $this->validate_process($formDatas, $isDebug);
|
||||||
if (empty($formRules)) {
|
if (empty($formRules)) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 검증할 대상 RULE이 없습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 검증할 대상 RULE이 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) wildcard(role.*) 부모 배열 보정
|
// 3) wildcard(role.*) 부모 배열 보정
|
||||||
$this->ensureParentArrayForWildcardRules($formDatas, $formRules);
|
$this->ensureParentArrayForWildcardRules($formDatas, $formRules);
|
||||||
|
|
||||||
// 4) numeric(FK 포함) 필드: '' -> null, 숫자 문자열 -> int
|
|
||||||
$numericFields = $this->collectNumericFieldsFromRules($formRules);
|
|
||||||
$formDatas = $this->normalizeNumericEmptyToNull($formDatas, $numericFields);
|
|
||||||
|
|
||||||
// 5) dynamicRules 구성
|
// 5) dynamicRules 구성
|
||||||
$dynamicRules = [];
|
$dynamicRules = [];
|
||||||
foreach ($formRules as $field => $rule) {
|
foreach ($formRules as $field => $rule) {
|
||||||
[$fieldName, $ruleStr] = $this->getValidationRule((string) $field, (string) $rule);
|
[$fieldName, $ruleStr] = $this->getValidationRule((string) $field, (string) $rule);
|
||||||
|
|
||||||
// label 결정
|
// label 결정
|
||||||
if (isset($formFields[$fieldName])) {
|
if (isset($formFields[$fieldName])) {
|
||||||
$label = $formFields[$fieldName];
|
$label = $formFields[$fieldName];
|
||||||
@ -370,13 +312,18 @@ abstract class CommonForm
|
|||||||
} else {
|
} else {
|
||||||
$label = $fieldName;
|
$label = $fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dynamicRules[$fieldName] = [
|
$dynamicRules[$fieldName] = [
|
||||||
'label' => $label,
|
'label' => $label,
|
||||||
'rules' => $ruleStr,
|
'rules' => $ruleStr,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($isDebug) {
|
||||||
|
log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate dynamicRules DEBUG");
|
||||||
|
log_message('debug', var_export($formDatas, true));
|
||||||
|
log_message('debug', var_export($dynamicRules, true));
|
||||||
|
}
|
||||||
|
|
||||||
$this->_validation->setRules($dynamicRules);
|
$this->_validation->setRules($dynamicRules);
|
||||||
if (!$this->_validation->run($formDatas)) {
|
if (!$this->_validation->run($formDatas)) {
|
||||||
$errors = $this->_validation->getErrors();
|
$errors = $this->_validation->getErrors();
|
||||||
@ -394,7 +341,7 @@ abstract class CommonForm
|
|||||||
if ($e instanceof RuntimeException) {
|
if ($e instanceof RuntimeException) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
throw new RuntimeException("유효성 검사 중 시스템 오류 발생: " . $e->getMessage());
|
// throw new RuntimeException("유효성 검사 중 시스템 오류 발생: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,9 @@ class ServiceForm extends CustomerForm
|
|||||||
'status'
|
'status'
|
||||||
];
|
];
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
|
case 'modify':
|
||||||
|
$fields = [...$fields, 'amount'];
|
||||||
|
break;
|
||||||
case 'view':
|
case 'view':
|
||||||
$fields = [...$fields, 'created_at'];
|
$fields = [...$fields, 'created_at'];
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -232,6 +232,10 @@ abstract class CommonService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//생성용
|
//생성용
|
||||||
|
protected function create_process_validate(CommonForm &$actionForm, array $formDatas)
|
||||||
|
{
|
||||||
|
$actionForm->validate($formDatas); // ✅ 여기서 검증
|
||||||
|
}
|
||||||
protected function create_process(array $formDatas): CommonEntity
|
protected function create_process(array $formDatas): CommonEntity
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -240,7 +244,7 @@ abstract class CommonService
|
|||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
|
||||||
}
|
}
|
||||||
$actionForm->form_init_process('create', $formDatas);
|
$actionForm->form_init_process('create', $formDatas);
|
||||||
$actionForm->validate($formDatas); // ✅ 여기서 검증
|
$this->create_process_validate($actionForm, $formDatas);
|
||||||
// 검증 통과 후 엔티티 반영용
|
// 검증 통과 후 엔티티 반영용
|
||||||
foreach ($formDatas as $field => $value) {
|
foreach ($formDatas as $field => $value) {
|
||||||
$formDatas = $this->fieldhook_process($field, $value, $formDatas);
|
$formDatas = $this->fieldhook_process($field, $value, $formDatas);
|
||||||
@ -273,6 +277,10 @@ abstract class CommonService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//수정용
|
//수정용
|
||||||
|
protected function modify_process_validate(CommonForm &$actionForm, array $formDatas)
|
||||||
|
{
|
||||||
|
$actionForm->validate($formDatas); // ✅ 여기서 검증
|
||||||
|
}
|
||||||
protected function modify_process($entity, array $formDatas): CommonEntity
|
protected function modify_process($entity, array $formDatas): CommonEntity
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -281,7 +289,7 @@ abstract class CommonService
|
|||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다.");
|
||||||
}
|
}
|
||||||
$actionForm->form_init_process('modify', $formDatas);
|
$actionForm->form_init_process('modify', $formDatas);
|
||||||
$actionForm->validate($formDatas); // ✅ 여기서 검증
|
$this->modify_process_validate($actionForm, $formDatas);
|
||||||
// 검증 통과 후 엔티티 반영
|
// 검증 통과 후 엔티티 반영
|
||||||
foreach ($formDatas as $field => $value) {
|
foreach ($formDatas as $field => $value) {
|
||||||
$formDatas = $this->fieldhook_process($field, $value, $formDatas);
|
$formDatas = $this->fieldhook_process($field, $value, $formDatas);
|
||||||
|
|||||||
@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Services\Customer;
|
namespace App\Services\Customer;
|
||||||
|
|
||||||
|
use App\Entities\CommonEntity;
|
||||||
|
use App\Entities\Customer\ServiceEntity;
|
||||||
|
use App\Forms\CommonForm;
|
||||||
|
use App\Forms\Customer\ServiceForm;
|
||||||
|
use App\Helpers\Customer\ServiceHelper;
|
||||||
|
use App\Models\Customer\ServiceModel;
|
||||||
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use DateTimeImmutable;
|
|
||||||
use App\Entities\CommonEntity;
|
|
||||||
use App\Forms\Customer\ServiceForm;
|
|
||||||
use App\Models\Customer\ServiceModel;
|
|
||||||
use App\Helpers\Customer\ServiceHelper;
|
|
||||||
use App\Entities\Customer\ServiceEntity;
|
|
||||||
|
|
||||||
class ServiceService extends CustomerService
|
class ServiceService extends CustomerService
|
||||||
{
|
{
|
||||||
@ -61,46 +62,31 @@ class ServiceService extends CustomerService
|
|||||||
return $date->format('Y-m-d');
|
return $date->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCalculatedAmount(int $rack_price, int $line_price, int $sale_price, int $serverinfo_uid): int
|
final public function updateBillingAt(int $uid, string $billing_at): CommonEntity
|
||||||
{
|
|
||||||
$server_amount = service('equipment_serverservice')->getCalculatedAmount($serverinfo_uid);
|
|
||||||
return (int) $server_amount + $rack_price + $line_price - $sale_price;
|
|
||||||
}
|
|
||||||
|
|
||||||
final protected function updateAmount(ServiceEntity $entity): ServiceEntity
|
|
||||||
{
|
|
||||||
$serverUid = $entity->getServerInfoUid();
|
|
||||||
// ✅ 서버 미지정(해지/분리 상태) 방어: 계산 시도 자체를 막는다
|
|
||||||
if (empty($serverUid)) { // null, 0, '' 모두 방어
|
|
||||||
throw new RuntimeException(
|
|
||||||
static::class . '->' . __FUNCTION__
|
|
||||||
. " 오류: 서비스({$entity->getPK()})에 serverinfo_uid가 없습니다. (해지/분리 상태)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$entity->amount = $this->getCalculatedAmount(
|
|
||||||
$entity->getRack(),
|
|
||||||
$entity->getLine(),
|
|
||||||
$entity->getSale(),
|
|
||||||
(int) $serverUid
|
|
||||||
);
|
|
||||||
// dd($entity);
|
|
||||||
if (!$this->model->save($entity)) {
|
|
||||||
throw new RuntimeException("금액 업데이트 중 DB 저장 오류: " . implode(', ', $this->model->errors()));
|
|
||||||
}
|
|
||||||
return $entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function updateBillingAt($uid, string $billing_at): ServiceEntity
|
|
||||||
{
|
{
|
||||||
$entity = $this->getEntity($uid);
|
$entity = $this->getEntity($uid);
|
||||||
if (!$entity instanceof ServiceEntity) {
|
if (!$entity instanceof ServiceEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:{$uid}에 해당하는 서비스정보를 찾을 수 업습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:{$uid}에 해당하는 서비스정보를 찾을 수 업습니다.");
|
||||||
}
|
}
|
||||||
|
$formDatas = ['billing_at' => $billing_at];
|
||||||
|
return parent::modify_process($entity, $formDatas);
|
||||||
|
}
|
||||||
|
|
||||||
$entity->billing_at = $billing_at;
|
//서비스 관련 총 금액
|
||||||
if (!$this->model->save($entity)) {
|
private function getCalculatedAmount(ServiceEntity $entity): int
|
||||||
$errors = $this->model->errors();
|
{
|
||||||
throw new RuntimeException("금액 업데이트 중 DB 저장 오류: " . implode(', ', $errors));
|
//서버 관련 금액
|
||||||
|
$server_amount = service('equipment_serverservice')->getCalculatedAmount($entity->getServerInfoUid());
|
||||||
|
return (int) $server_amount + (int) $entity->getRack() + (int) $entity->getLine() - $entity->getSale();
|
||||||
|
}
|
||||||
|
|
||||||
|
//서비스 금액 설정
|
||||||
|
final public function recalcAmount(ServiceEntity $entity): ServiceEntity
|
||||||
|
{
|
||||||
|
$formDatas = ['amount' => $this->getCalculatedAmount($entity)];
|
||||||
|
$entity = parent::modify_process($entity, $formDatas);
|
||||||
|
if (!$entity instanceof ServiceEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
}
|
}
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
@ -110,74 +96,74 @@ class ServiceService extends CustomerService
|
|||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ (internal) payment까지 동기화하는 일반용 로직 (트랜잭션 없음)
|
|
||||||
final public function recalcAmountAndSyncPaymentInternal(ServiceEntity $old, ServiceEntity $current): ServiceEntity
|
|
||||||
{
|
|
||||||
$current = $this->updateAmount($current);
|
|
||||||
service('paymentservice')->setByService($old, $current);
|
|
||||||
return $current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ (internal) amount만 재계산 (해지 시 0원될 수 있으나 payment 건드리지 않음)
|
|
||||||
final public function recalcAmountInternal(ServiceEntity $current): ServiceEntity
|
|
||||||
{
|
|
||||||
return $this->updateAmount($current);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ (public) dbTransaction 보류: 내부 로직만 호출
|
|
||||||
final public function recalcAmountAndSyncPayment(ServiceEntity $serviceEntity): ServiceEntity
|
|
||||||
{
|
|
||||||
$old = clone $serviceEntity;
|
|
||||||
return $this->recalcAmountAndSyncPaymentInternal($old, $serviceEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
final public function recalcAmountAndSyncPaymentByOld(ServiceEntity $old, ServiceEntity $current): ServiceEntity
|
|
||||||
{
|
|
||||||
return $this->recalcAmountAndSyncPaymentInternal($old, $current);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function create_process(array $formDatas): ServiceEntity
|
protected function create_process(array $formDatas): ServiceEntity
|
||||||
{
|
{
|
||||||
if (empty($formDatas['site'])) {
|
if (!array_key_exists('site', $formDatas) || empty($formDatas['site'])) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 사이트가 지정되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 사이트가 지정되지 않았습니다.");
|
||||||
}
|
}
|
||||||
if (empty($formDatas['serverinfo_uid'])) {
|
if (!array_key_exists('serverinfo_uid', $formDatas) || empty($formDatas['serverinfo_uid'])) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$formDatas['code'] = $formDatas['site'] . "_s" . uniqid();
|
$formDatas['code'] = $formDatas['site'] . "_s" . uniqid();
|
||||||
$formDatas['amount'] = 0;
|
$formDatas['amount'] = 0;
|
||||||
|
|
||||||
$entity = parent::create_process($formDatas);
|
$entity = parent::create_process($formDatas);
|
||||||
if (!$entity instanceof ServiceEntity) {
|
if (!$entity instanceof ServiceEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
}
|
}
|
||||||
|
//서버 설정
|
||||||
service('equipment_serverservice')->attatchToService($entity, $entity->getServerInfoUid());
|
service('equipment_serverservice')->attatchToService($entity, $entity->getServerInfoUid());
|
||||||
|
//서비스 금액 설정
|
||||||
return $this->recalcAmountAndSyncPayment($entity);
|
$entity = $this->recalcAmount($entity);
|
||||||
|
//결제 추가
|
||||||
|
service('paymentservice')->createByService($entity);
|
||||||
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function modify_process_validate(CommonForm &$actionForm, array $formDatas)
|
||||||
|
{
|
||||||
|
$actionForm->validate($formDatas, true); // ✅ 여기서 검증
|
||||||
|
}
|
||||||
protected function modify_process($entity, array $formDatas): ServiceEntity
|
protected function modify_process($entity, array $formDatas): ServiceEntity
|
||||||
{
|
{
|
||||||
if (empty($formDatas['serverinfo_uid'])) {
|
if (empty($formDatas['serverinfo_uid'])) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
|
||||||
}
|
}
|
||||||
|
//기존 정보 저장
|
||||||
$oldEntity = clone $entity;
|
$oldEntity = clone $entity;
|
||||||
$formDatas['code'] = $entity->getCode();
|
|
||||||
$formDatas['amount'] = 0;
|
|
||||||
|
|
||||||
$entity = parent::modify_process($entity, $formDatas);
|
$entity = parent::modify_process($entity, $formDatas);
|
||||||
if (!$entity instanceof ServiceEntity) {
|
if (!$entity instanceof ServiceEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
}
|
}
|
||||||
|
//서버 설정
|
||||||
if ($oldEntity->getServerInfoUid() !== $entity->getServerInfoUid()) {
|
if ($oldEntity->getServerInfoUid() !== $entity->getServerInfoUid()) {
|
||||||
service('equipment_serverservice')->modifyByService($oldEntity, $entity);
|
service('equipment_serverservice')->modifyByService($oldEntity, $entity);
|
||||||
}
|
}
|
||||||
|
//서비스 금액 설정
|
||||||
|
$entity = $this->recalcAmount($entity);
|
||||||
|
//결제비 설정
|
||||||
|
service('paymentservice')->modifyByService($oldEntity, $entity);
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->recalcAmountAndSyncPaymentByOld($oldEntity, $entity);
|
protected function delete_process($entity): ServiceEntity
|
||||||
|
{
|
||||||
|
if (!$entity instanceof ServiceEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
|
}
|
||||||
|
|
||||||
|
//기존정보 우선 저장
|
||||||
|
$oldEntity = clone $entity;
|
||||||
|
|
||||||
|
$entity = parent::delete_process($entity);
|
||||||
|
if (!$entity instanceof ServiceEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
|
}
|
||||||
|
if ($oldEntity->getServerInfoUid()) {
|
||||||
|
service('equipment_serverservice')->deatchFromService($oldEntity->getServerInfoUid());
|
||||||
|
}
|
||||||
|
return $oldEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function history(string|int $uid, string $history): CommonEntity
|
public function history(string|int $uid, string $history): CommonEntity
|
||||||
|
|||||||
@ -93,55 +93,18 @@ class ServerPartService extends EquipmentService
|
|||||||
return $formDatas;
|
return $formDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//서비스 금액 재계산용
|
||||||
* ✅ MONTH 파트 변경 시:
|
private function recalcAmount(ServerPartEntity $entity): void
|
||||||
* - "서비스가 유지중"이면: (serverinfo_uid 기준) 현재 서버가 붙은 서비스로 amount 재계산 + 월 Payment upsert
|
{
|
||||||
* - "서버가 서비스에서 분리된 상태(server.serviceinfo_uid==null)"이면: 월 미납 결제 status=TERMINATED (amount 재계산 금지)
|
//월비용 서버파트 정보일 경우 서버금액 재계산
|
||||||
*
|
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH'] && $entity->getServerInfoUid()) {
|
||||||
* 핵심: ServerPartService는 'serviceUid'가 아니라 'serverUid'를 기준으로 판단한다.
|
$serverEntity = service('equipment_serverservice')->getEntity($entity->getServerInfoUid());
|
||||||
*/
|
if ($serverEntity instanceof ServerEntity) {
|
||||||
private function syncMonthlyServiceAndPaymentByServer(
|
service('equipment_serverservice')->recalcAmount($serverEntity);
|
||||||
int $serverUid,
|
|
||||||
?ServiceEntity $oldServiceSnapshot = null,
|
|
||||||
bool $serverDetached = false
|
|
||||||
): void {
|
|
||||||
$server = service('equipment_serverservice')->getEntity($serverUid);
|
|
||||||
if (!$server instanceof ServerEntity) {
|
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$serverUid} 서버정보를 찾을수 없습니다.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 해지 케이스
|
|
||||||
if ($serverDetached) {
|
|
||||||
if ($oldServiceSnapshot instanceof ServiceEntity) {
|
|
||||||
service('paymentservice')->terminateUnpaidMonthlyByService($oldServiceSnapshot);
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$serviceUid = $server->getServiceInfoUid();
|
|
||||||
if (!$serviceUid) {
|
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 서비스가 정의되지 않은 서버정보입니다.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$svcService = service('customer_serviceservice');
|
|
||||||
$current = $svcService->getEntity($serviceUid);
|
|
||||||
if (!$current instanceof ServiceEntity) {
|
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$serviceUid} 서비스정보를 찾을수 없습니다.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ 핵심 추가: 메인서버만 amount/payment 동기화 허용
|
|
||||||
if ((int) $current->getServerInfoUid() !== (int) $serverUid) {
|
|
||||||
// 대체서버(alternative)에서는 서비스금액/결제 동기화 금지
|
|
||||||
return; // 또는 정책상 필요하면 예외로 변경 가능
|
|
||||||
// throw new RuntimeException("메인서버가 아닌 서버({$serverUid})에서 월동기화 금지");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ 일반 케이스: amount + payment upsert
|
|
||||||
$old = $oldServiceSnapshot instanceof ServiceEntity ? $oldServiceSnapshot : clone $current;
|
|
||||||
$svcService->recalcAmountAndSyncPaymentInternal($old, $current);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function create_process(array $formDatas): CommonEntity
|
protected function create_process(array $formDatas): CommonEntity
|
||||||
{
|
{
|
||||||
$serverEntity = service('equipment_serverservice')->getEntity($formDatas['serverinfo_uid']);
|
$serverEntity = service('equipment_serverservice')->getEntity($formDatas['serverinfo_uid']);
|
||||||
@ -162,7 +125,7 @@ class ServerPartService extends EquipmentService
|
|||||||
// ✅ 서버가 서비스에 붙어 있을 때만 결제/동기화
|
// ✅ 서버가 서비스에 붙어 있을 때만 결제/동기화
|
||||||
if ($entity->getServiceInfoUid()) {
|
if ($entity->getServiceInfoUid()) {
|
||||||
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH']) {
|
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH']) {
|
||||||
$this->syncMonthlyServiceAndPaymentByServer((int) $entity->getServerInfoUid());
|
$this->recalcAmount($entity);
|
||||||
}
|
}
|
||||||
if ($entity->getBilling() == PAYMENT['BILLING']['ONETIME']) {
|
if ($entity->getBilling() == PAYMENT['BILLING']['ONETIME']) {
|
||||||
service('paymentservice')->createByServerPart($entity);
|
service('paymentservice')->createByServerPart($entity);
|
||||||
@ -178,45 +141,34 @@ class ServerPartService extends EquipmentService
|
|||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$formDatas['serverinfo_uid']}에 해당하는 서버정보을 찾을수 없습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$formDatas['serverinfo_uid']}에 해당하는 서버정보을 찾을수 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$formDatas = $this->getFormDatasForServerPart($formDatas, $serverEntity);
|
//기존정보 우선 저장
|
||||||
|
|
||||||
$oldEntity = clone $entity;
|
$oldEntity = clone $entity;
|
||||||
|
|
||||||
$entity = parent::modify_process($entity, $formDatas);
|
$entity = parent::modify_process($entity, $this->getFormDatasForServerPart($formDatas, $serverEntity));
|
||||||
if (!$entity instanceof ServerPartEntity) {
|
if (!$entity instanceof ServerPartEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Return Type은 ServerPartEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Return Type은 ServerPartEntity만 가능");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getPartService($entity->getType())->modifyServerPart($oldEntity, $entity);
|
$this->getPartService($entity->getType())->modifyServerPart($oldEntity, $entity);
|
||||||
|
|
||||||
// ✅ MONTH 동기화는 serviceinfo_uid가 아니라 serverinfo_uid 기준
|
// ✅ 월별용 처리 (서버파트가 변경되었으므로 서버파트의 Billing이 MONTH이면 서비스/결제 동기화)
|
||||||
$serverUidsToSync = [];
|
|
||||||
|
|
||||||
if ($oldEntity->getBilling() == PAYMENT['BILLING']['MONTH'] && $oldEntity->getServerInfoUid()) {
|
|
||||||
$serverUidsToSync[(int) $oldEntity->getServerInfoUid()] = true;
|
|
||||||
}
|
|
||||||
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH'] && $entity->getServerInfoUid()) {
|
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH'] && $entity->getServerInfoUid()) {
|
||||||
$serverUidsToSync[(int) $entity->getServerInfoUid()] = true;
|
$this->recalcAmount($entity);
|
||||||
}
|
}
|
||||||
|
// ✅ 일회성용 처리
|
||||||
foreach (array_keys($serverUidsToSync) as $serverUid) {
|
|
||||||
$this->syncMonthlyServiceAndPaymentByServer((int) $serverUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($entity->getBilling() == PAYMENT['BILLING']['ONETIME']) {
|
if ($entity->getBilling() == PAYMENT['BILLING']['ONETIME']) {
|
||||||
service('paymentservice')->modifyByServerPart($oldEntity, $entity);
|
service('paymentservice')->modifyByServerPart($oldEntity, $entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function delete_process($entity): CommonEntity
|
protected function delete_process($entity): ServerPartEntity
|
||||||
{
|
{
|
||||||
if (!$entity instanceof ServerPartEntity) {
|
if (!$entity instanceof ServerPartEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: ServerPartEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: ServerPartEntity만 가능");
|
||||||
}
|
}
|
||||||
|
|
||||||
$old = clone $entity;
|
//기존정보 우선 저장
|
||||||
|
$oldEntity = clone $entity;
|
||||||
|
|
||||||
$this->getPartService($entity->getType())->detachFromServerPart($entity);
|
$this->getPartService($entity->getType())->detachFromServerPart($entity);
|
||||||
|
|
||||||
@ -224,12 +176,10 @@ class ServerPartService extends EquipmentService
|
|||||||
if (!$entity instanceof ServerPartEntity) {
|
if (!$entity instanceof ServerPartEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Return Type은 ServerPartEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Return Type은 ServerPartEntity만 가능");
|
||||||
}
|
}
|
||||||
|
// ✅서버파트가 삭제되었으므로 서버파트의 Billing이 MONTH이면 서비스/결제 동기화
|
||||||
// ✅ MONTH면 서버 기준으로 서비스/결제 동기화
|
if ($oldEntity->getBilling() == PAYMENT['BILLING']['MONTH'] && $oldEntity->getServerInfoUid()) {
|
||||||
if ($old->getBilling() == PAYMENT['BILLING']['MONTH'] && $old->getServerInfoUid()) {
|
$this->recalcAmount($oldEntity);
|
||||||
$this->syncMonthlyServiceAndPaymentByServer((int) $old->getServerInfoUid());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ ONETIME 미납 결제 삭제는 "보류" (여기서는 아무것도 안함)
|
// ✅ ONETIME 미납 결제 삭제는 "보류" (여기서는 아무것도 안함)
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
@ -268,37 +218,21 @@ class ServerPartService extends EquipmentService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* ✅ 서버 해지/분리 시 서버파트 회수 처리
|
* ✅ 서버 해지/분리 시 서버파트 회수 처리
|
||||||
* - BASE 제외 전부 삭제(정책상 OK)
|
|
||||||
* - MONTH 삭제가 있었다면:
|
|
||||||
* - server.serviceinfo_uid == null 인 상태에서만 TERMINATED 처리 (amount 재계산 금지)
|
|
||||||
* - ONETIME 미납 삭제는 보류
|
|
||||||
*
|
|
||||||
* @param ServiceEntity|null $oldServiceEntity 분리 전 서비스 스냅샷(권장: TERMINATED 매칭용)
|
|
||||||
*/
|
*/
|
||||||
public function detachFromServer(ServerEntity $serverEntity, ?ServiceEntity $oldServiceEntity = null): void
|
public function detachFromServer(ServerEntity $serverEntity): void
|
||||||
{
|
{
|
||||||
$monthlyChanged = false;
|
|
||||||
foreach ($this->getEntities(['serverinfo_uid' => $serverEntity->getPK(), "billing !=" => PAYMENT['BILLING']['BASE']]) as $entity) {
|
foreach ($this->getEntities(['serverinfo_uid' => $serverEntity->getPK(), "billing !=" => PAYMENT['BILLING']['BASE']]) as $entity) {
|
||||||
if (!$entity instanceof ServerPartEntity)
|
if (!$entity instanceof ServerPartEntity) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
//파트정보 해지
|
||||||
$this->getPartService($entity->getType())->detachFromServerPart($entity);
|
$this->getPartService($entity->getType())->detachFromServerPart($entity);
|
||||||
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH']) {
|
//서버파트 해지
|
||||||
$monthlyChanged = true;
|
|
||||||
}
|
|
||||||
parent::delete_process($entity);
|
parent::delete_process($entity);
|
||||||
}
|
//서비스금액 재계산
|
||||||
if (!$monthlyChanged) {
|
if ($entity->getBilling() == PAYMENT['BILLING']['MONTH'] && $entity->getServerInfoUid()) {
|
||||||
return;
|
$this->recalcAmount($entity);
|
||||||
}
|
}
|
||||||
// ✅ 분리 완료 후(server.serviceinfo_uid == null)에서만 TERMINATED 처리
|
}
|
||||||
$serverDetached = ($serverEntity->getServiceInfoUid() === null);
|
|
||||||
if ($serverDetached) {
|
|
||||||
if ($oldServiceEntity instanceof ServiceEntity) {
|
|
||||||
$this->syncMonthlyServiceAndPaymentByServer((int) $serverEntity->getPK(), $oldServiceEntity, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// ✅ (이 케이스는 정상 플로우에서는 거의 없지만) 서비스 유지중이면 정상 upsert
|
|
||||||
$this->syncMonthlyServiceAndPaymentByServer((int) $serverEntity->getPK());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,12 @@ class ServerService extends EquipmentService
|
|||||||
return ServerEntity::class;
|
return ServerEntity::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getEntity_process(mixed $entity): ServerEntity
|
||||||
|
{
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final public function getTotalServiceCount(array $where = []): array
|
final public function getTotalServiceCount(array $where = []): array
|
||||||
{
|
{
|
||||||
$totalCounts = [
|
$totalCounts = [
|
||||||
@ -100,18 +106,29 @@ class ServerService extends EquipmentService
|
|||||||
if (!$entity instanceof ServerEntity) {
|
if (!$entity instanceof ServerEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid} 서버 정보를 찾을수 없습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid} 서버 정보를 찾을수 없습니다.");
|
||||||
}
|
}
|
||||||
$serverPartService = service('equipment_serverpartservice');
|
|
||||||
$caculatedAmount = $entity->getPrice();
|
$caculatedAmount = $entity->getPrice();
|
||||||
foreach ($serverPartService->getEntities(['serverinfo_uid' => $entity->getPK(), 'billing' => PAYMENT['BILLING']['MONTH']]) as $serverPartEntity) {
|
foreach (service('equipment_serverpartservice')->getEntities(['serverinfo_uid' => $entity->getPK(), 'billing' => PAYMENT['BILLING']['MONTH']]) as $serverPartEntity) {
|
||||||
log_message('debug', $serverPartEntity->getCustomTitle() . '::' . $serverPartEntity->getCalculatedAmount());
|
log_message('debug', $serverPartEntity->getCustomTitle() . '::' . $serverPartEntity->getCalculatedAmount());
|
||||||
$caculatedAmount += $serverPartEntity->getCalculatedAmount();
|
$caculatedAmount += $serverPartEntity->getCalculatedAmount();
|
||||||
}
|
}
|
||||||
return $caculatedAmount;
|
return $caculatedAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getEntity_process(mixed $entity): ServerEntity
|
public function recalcAmount(ServerEntity $entity): void
|
||||||
{
|
{
|
||||||
return $entity;
|
if ($entity->getServiceInfoUid()) {
|
||||||
|
$serviceEntity = service('customer_serviceservice')->getEntity($entity->getServiceInfoUid());
|
||||||
|
if (!$serviceEntity instanceof ServiceEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$entity->getServiceInfoUid()} 서비스정보를 찾을수 없습니다.");
|
||||||
|
}
|
||||||
|
// ✅ 핵심 추가: 서비스금액 변경 및 payment Sync용
|
||||||
|
if ($serviceEntity->getServerInfoUid() === $entity->getServiceInfoUid()) {
|
||||||
|
$oldServiceEntity = clone $serviceEntity;
|
||||||
|
$serviceEntity = service('customer_serviceservice')->recalcAmount($serviceEntity);
|
||||||
|
//결제비 설정
|
||||||
|
service('paymentservice')->modifyByService($oldServiceEntity, $serviceEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function create_process(array $formDatas): ServerEntity
|
protected function create_process(array $formDatas): ServerEntity
|
||||||
@ -120,22 +137,14 @@ class ServerService extends EquipmentService
|
|||||||
if (!$entity instanceof ServerEntity) {
|
if (!$entity instanceof ServerEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServerEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServerEntity만 가능");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if ($entity->getIP()) {
|
if ($entity->getIP()) {
|
||||||
service('part_ipservice')->attachToServer($entity);
|
service('part_ipservice')->attachToServer($entity);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
|
||||||
log_message('debug', static::class . '->' . __FUNCTION__ . '에서:' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($entity->getSwitchInfoUid()) {
|
if ($entity->getSwitchInfoUid()) {
|
||||||
service('part_switchservice')->attachToServer($entity);
|
service('part_switchservice')->attachToServer($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
service('equipment_chassisservice')->attachToServer($entity);
|
service('equipment_chassisservice')->attachToServer($entity);
|
||||||
service('equipment_serverpartservice')->attachToServer($entity);
|
service('equipment_serverpartservice')->attachToServer($entity);
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,23 +154,21 @@ class ServerService extends EquipmentService
|
|||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생: 샷시정보가 정의되지 않았습니다.');
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생: 샷시정보가 정의되지 않았습니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//기존정보 저장
|
||||||
$oldEntity = clone $entity;
|
$oldEntity = clone $entity;
|
||||||
|
|
||||||
$entity = parent::modify_process($entity, $formDatas);
|
$entity = parent::modify_process($entity, $formDatas);
|
||||||
if (!$entity instanceof ServerEntity) {
|
if (!$entity instanceof ServerEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServerEntity만 가능");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServerEntity만 가능");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oldEntity->getIP() !== $entity->getIP()) {
|
if ($oldEntity->getIP() !== $entity->getIP()) {
|
||||||
try {
|
|
||||||
if ($oldEntity->getIP()) {
|
if ($oldEntity->getIP()) {
|
||||||
service('part_ipservice')->detachFromServer($oldEntity);
|
service('part_ipservice')->detachFromServer($oldEntity);
|
||||||
}
|
}
|
||||||
if ($entity->getIP()) {
|
if ($entity->getIP()) {
|
||||||
service('part_ipservice')->attachToServer($entity);
|
service('part_ipservice')->attachToServer($entity);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
|
||||||
log_message('debug', static::class . '->' . __FUNCTION__ . '에서:' . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oldEntity->getSwitchInfoUid() !== $entity->getSwitchInfoUid()) {
|
if ($oldEntity->getSwitchInfoUid() !== $entity->getSwitchInfoUid()) {
|
||||||
@ -179,22 +186,51 @@ class ServerService extends EquipmentService
|
|||||||
service('equipment_chassisservice')->attachToServer($entity);
|
service('equipment_chassisservice')->attachToServer($entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//가격 변동이 있는 경우
|
//가격 변동이 있는 경우
|
||||||
if ($oldEntity->getPrice() !== $entity->getPrice()) {
|
if ($oldEntity->getPrice() !== $entity->getPrice()) {
|
||||||
// ✅ 서비스 유지중이면 정상 동기화 (해지 시는 detachFromService에서 따로 처리)
|
$this->recalcAmount($entity);
|
||||||
if ($entity->getServiceInfoUid() !== null) {
|
|
||||||
$serviceService = service('customer_serviceservice');
|
|
||||||
$serviceEntity = $serviceService->getEntity($entity->getServiceInfoUid());
|
|
||||||
if (!$serviceEntity instanceof ServiceEntity) {
|
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$entity->getServiceInfoUid()}에 해당하는 서비스정보을 찾을수 없습니다.");
|
|
||||||
}
|
|
||||||
$serviceService->recalcAmountAndSyncPayment($serviceEntity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function delete_process($entity): ServerEntity
|
||||||
|
{
|
||||||
|
if (!$entity instanceof ServerEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
|
}
|
||||||
|
|
||||||
|
//기존정보 우선 저장
|
||||||
|
$oldEntity = clone $entity;
|
||||||
|
|
||||||
|
//서버정보
|
||||||
|
$entity = parent::delete_process($entity);
|
||||||
|
if (!$entity instanceof ServerEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
|
}
|
||||||
|
|
||||||
|
//서비스연결이 유지된 상태인경우
|
||||||
|
if ($entity->getServiceInfoUid() !== null) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:{$entity->getTitle()} 서버는 아직 서비스와 연결된 상태입니다.");
|
||||||
|
}
|
||||||
|
//IP정보
|
||||||
|
if ($oldEntity->getIP()) {
|
||||||
|
service('part_ipservice')->detachFromServer($oldEntity);
|
||||||
|
}
|
||||||
|
//Switch정보
|
||||||
|
if ($oldEntity->getSwitchInfoUid()) {
|
||||||
|
if (is_int($oldEntity->getSwitchInfoUid())) { //null이거나 공백인경우
|
||||||
|
service('part_switchservice')->detachFromServer($oldEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//샷시정보
|
||||||
|
if ($oldEntity->getChassisInfoUid()) {
|
||||||
|
service('equipment_chassisservice')->detachFromServer($oldEntity);
|
||||||
|
}
|
||||||
|
//파트정보
|
||||||
|
service('equipment_serverpartservice')->detachFromServer($oldEntity);
|
||||||
|
return $oldEntity;
|
||||||
|
}
|
||||||
|
|
||||||
public function setSearchWord(string $word): void
|
public function setSearchWord(string $word): void
|
||||||
{
|
{
|
||||||
$this->model->orLike($this->model->getTable() . '.ip', $word, 'both');
|
$this->model->orLike($this->model->getTable() . '.ip', $word, 'both');
|
||||||
@ -208,11 +244,9 @@ class ServerService extends EquipmentService
|
|||||||
if (!$entity instanceof ServerEntity) {
|
if (!$entity instanceof ServerEntity) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 서버정보을 찾을수 없습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 서버정보을 찾을수 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$formDatas['serviceinfo_uid'] = $serviceEntity->getPK();
|
$formDatas['serviceinfo_uid'] = $serviceEntity->getPK();
|
||||||
$formDatas["clientinfo_uid"] = $serviceEntity->getClientInfoUid();
|
$formDatas["clientinfo_uid"] = $serviceEntity->getClientInfoUid();
|
||||||
$formDatas['status'] = $formDatas['status'] ?? STATUS['OCCUPIED'];
|
$formDatas['status'] = $formDatas['status'] ?? STATUS['OCCUPIED'];
|
||||||
|
|
||||||
parent::modify_process($entity, $formDatas);
|
parent::modify_process($entity, $formDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -93,41 +93,6 @@ class PaymentService extends CommonService
|
|||||||
return $walletService;
|
return $walletService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 서비스 해지(서버 분리) 시: 월 미납 청구는 "삭제/0원수정" 금지, 상태만 TERMINATED
|
|
||||||
public function terminateUnpaidMonthlyByService(ServiceEntity $oldServiceEntity): void
|
|
||||||
{
|
|
||||||
$entity = $this->getEntity([
|
|
||||||
'serviceinfo_uid' => $oldServiceEntity->getPK(),
|
|
||||||
'billing' => PAYMENT['BILLING']['MONTH'],
|
|
||||||
'billing_at' => $oldServiceEntity->getBillingAt(),
|
|
||||||
'status' => STATUS['UNPAID'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$entity instanceof PaymentEntity) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// amount/title 건드리지 않고 status만 변경
|
|
||||||
parent::modify_process($entity, ['status' => STATUS['TERMINATED']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//서비스정보로 결제정보 생성 또는 수정 (일반 운영용: upsert 유지)
|
|
||||||
public function setByService(ServiceEntity $oldServiceEntity, ServiceEntity $serviceEntity): PaymentEntity
|
|
||||||
{
|
|
||||||
$formDatas = $this->getFormDatasFromService($serviceEntity);
|
|
||||||
$entity = $this->getEntity([
|
|
||||||
'serviceinfo_uid' => $oldServiceEntity->getPK(),
|
|
||||||
'billing' => PAYMENT['BILLING']['MONTH'],
|
|
||||||
'billing_at' => $oldServiceEntity->getBillingAt(),
|
|
||||||
'status' => STATUS['UNPAID']
|
|
||||||
]);
|
|
||||||
//매칭되는게 있으면
|
|
||||||
if ($entity instanceof PaymentEntity) {
|
|
||||||
return $this->modify_process($entity, $formDatas);
|
|
||||||
}
|
|
||||||
return $this->create_process($formDatas);
|
|
||||||
}
|
|
||||||
|
|
||||||
//일회성,선결제,쿠폰,포인트 입력 관련
|
//일회성,선결제,쿠폰,포인트 입력 관련
|
||||||
protected function create_process(array $formDatas): PaymentEntity
|
protected function create_process(array $formDatas): PaymentEntity
|
||||||
{
|
{
|
||||||
@ -251,6 +216,23 @@ class PaymentService extends CommonService
|
|||||||
$formDatas = $this->getFormDatasFromService($serviceEntity);
|
$formDatas = $this->getFormDatasFromService($serviceEntity);
|
||||||
return $this->create_process($formDatas);
|
return $this->create_process($formDatas);
|
||||||
}
|
}
|
||||||
|
//서비스정보로 결제정보 생성 또는 수정 (일반 운영용: upsert 유지)
|
||||||
|
public function modifyByService(ServiceEntity $oldServiceEntity, ServiceEntity $serviceEntity): PaymentEntity
|
||||||
|
{
|
||||||
|
$entity = $this->getEntity([
|
||||||
|
'serviceinfo_uid' => $oldServiceEntity->getPK(),
|
||||||
|
'billing' => PAYMENT['BILLING']['MONTH'],
|
||||||
|
'billing_at' => $oldServiceEntity->getBillingAt(),
|
||||||
|
'status' => STATUS['UNPAID']
|
||||||
|
]);
|
||||||
|
if (!$entity instanceof PaymentEntity) {
|
||||||
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 ServiceEntity만 가능");
|
||||||
|
}
|
||||||
|
//매칭되는게 있으면(기존 서비스인경우) 아니면 신규등록
|
||||||
|
$formDatas = $this->getFormDatasFromService($serviceEntity);
|
||||||
|
return $this->modify_process($entity, $formDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//서버파트별 일회성 관련
|
//서버파트별 일회성 관련
|
||||||
private function getFormDatasFromServerPart(ServerPartEntity $serverPartEntity, array $formDatas = []): array
|
private function getFormDatasFromServerPart(ServerPartEntity $serverPartEntity, array $formDatas = []): array
|
||||||
@ -287,15 +269,26 @@ class PaymentService extends CommonService
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (!$entity instanceof PaymentEntity) {
|
if (!$entity instanceof PaymentEntity) {
|
||||||
log_message('error', sprintf(
|
|
||||||
"\n------Last Query (%s)-----\nQuery: %s\n------------------------------\n",
|
|
||||||
static::class . '->' . __FUNCTION__,
|
|
||||||
$this->model->getLastQuery() ?? "No Query Available",
|
|
||||||
));
|
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 기존 서버파트정보의 {$oldServerPartEntity->getTitle()}에 해당하는 결제정보가 존재하지 않습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 기존 서버파트정보의 {$oldServerPartEntity->getTitle()}에 해당하는 결제정보가 존재하지 않습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$formDatas = $this->getFormDatasFromServerPart($serverPartEntity);
|
$formDatas = $this->getFormDatasFromServerPart($serverPartEntity);
|
||||||
return parent::modify_process($entity, $formDatas);
|
return parent::modify_process($entity, $formDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ 서비스 해지(서버 분리) 시: 월비용 파트정보는 고객만 연결
|
||||||
|
public function terminateByServerPart(ServiceEntity $oldServiceEntity): void
|
||||||
|
{
|
||||||
|
$entity = $this->getEntity([
|
||||||
|
'serviceinfo_uid' => $oldServiceEntity->getPK(),
|
||||||
|
'billing' => PAYMENT['BILLING']['MONTH'],
|
||||||
|
'billing_at' => $oldServiceEntity->getBillingAt(),
|
||||||
|
'status' => STATUS['UNPAID'],
|
||||||
|
]);
|
||||||
|
if (!$entity instanceof PaymentEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//매칭되는게 있으면(기존 파트정보서비스인경우)
|
||||||
|
parent::modify_process($entity, ['status' => STATUS['TERMINATED']]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user