dbmsv3 init...1

This commit is contained in:
choi.jh 2025-10-24 10:35:12 +09:00
parent aa749599c2
commit 43ce84e21c
16 changed files with 377 additions and 71 deletions

File diff suppressed because one or more lines are too long

View File

@ -48,7 +48,7 @@ class ServiceEntity extends CustomerEntity
//기본기능용
public function getCustomTitle(mixed $title = null): string
{
return sprintf("[%s]%s", $this->getCode(), $title ? $title : $this->getServerEntity()->getIP());
return sprintf("[%s]%s", $this->getCode(), $this->getTitle());
}
final public function getCode(): string
{
@ -69,7 +69,7 @@ class ServiceEntity extends CustomerEntity
//청구금액->기본:상면비+회선비+서버금액(price)+서버파트연결(월비용)-할인액
final public function getSale(): int
{
return $this->attributes['sale'];
return $this->attributes['sale'] ?? 0;
}
final public function getAmount(): int
{

View File

@ -2,7 +2,6 @@
namespace App\Helpers\Customer;
use App\Entities\CommonEntity;
use App\Models\Customer\ServiceModel;
class ServiceHelper extends CustomerHelper
@ -20,9 +19,6 @@ class ServiceHelper extends CustomerHelper
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras);
break;
case 'serverinfo_uid':
if ($value === null && array_key_exists('entity', $viewDatas)) {
$value = $viewDatas['entity']->getServerEntity()->getPK();
}
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' select-field' : 'select-field';
$attributes = ['data-price' => 'price'];
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras, $attributes);

View File

@ -7,6 +7,7 @@ return [
'serverinfo_uid' => "서버",
'site' => "사이트",
'code' => "코드",
'title' => "서비스명",
'location' => "위치",
'rack' => "상면비",
'line' => "회선비",

View File

@ -9,7 +9,7 @@ class ServiceModel extends CustomerModel
{
const TABLE = "serviceinfo";
const PK = "uid";
const TITLE = "code";
const TITLE = "title";
protected $table = self::TABLE;
// protected $useAutoIncrement = false;
protected $primaryKey = self::PK;
@ -21,6 +21,7 @@ class ServiceModel extends CustomerModel
"serverinfo_uid",
"payment_uid",
"code",
"title",
"site",
"location",
"rack",
@ -68,6 +69,7 @@ class ServiceModel extends CustomerModel
case "end_at":
$rule = "permit_empty|valid_date";
break;
case 'title':
case "history":
$rule = "permit_empty|trim|string";
break;

View File

@ -0,0 +1,26 @@
<?php
namespace App\Processor;
use App\Services\MyLogService;
use CodeIgniter\Database\BaseConnection;
abstract class CommonProcessor
{
final protected $db = null;
final protected ?MyLogService $logService = null;
protected function __construct(BaseConnection $db)
{
$this->db = $db;
$this->logService = new MyLogService();
}
final protected function setLog(string $title, string $status, ?string $context = null): void
{
$this->logService->create([
'title' => $title,
'status' => $status,
'context' => $context
]);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Processors\Customer\Service;
use App\Processor\ServiceInterface;
use App\Processors\Customer\ServiceContext;
use App\Processors\Customer\ServiceProcessor;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
use App\Services\PaymentService;
use CodeIgniter\Database\BaseConnection;
class CreateProcessor extends ServiceProcessor implements ServiceInterface
{
public function __construct(
BaseConnection $db,
ServiceService $serviceService,
ServerService $serverService,
PaymentService $paymentService,
) {
parent::__construct($db, $serviceService, $serverService, $paymentService);
}
public function process(ServiceContext $ctx): ServiceContext
{
if (!isset($ctx->formDatas['serverinfo_uid'])) {
throw new \Exception('서버가 지정되지 않았습니다.');
}
// 1) 서비스 생성
$entity = $this->serviceService->getModel()->create($ctx->formDatas);
// 2) 서버 연결
$serverEntity = $this->attachServer($entity);
// 3) 금액 계산
$amount = $this->serviceService->getCalculatedAmount($entity);
$entity = $this->serviceService->getModel()->modify($entity, ['amount' => $amount]);
// 4) 결제 생성
$paymentEntity = $this->createPayment($entity, $serverEntity);
// 5) 서비스 링크 갱신(FK 반영)
$entity = $this->serviceService->getModel()->modify($entity, [
'serverinfo_id' => $serverEntity->getPK(),
'payment_uid' => $paymentEntity->getPK(),
]);
// 6) 로그 (필요 시 이벤트로 대체)
$this->setLog($entity);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
throw new \Exception('트랜잭션 실패');
}
return $entity;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Processors\Customer;
use App\Processor\Customer\ServiceInterface;
use App\Processors\Customer\ServiceContext;
class ServiceComposite implements ServiceInterface
{
private array $pipes;
public function __construct(array $pipes)
{
$this->pipes = $pipes;
}
public function process(ServiceContext $ctx): ServiceContext
{
foreach ($this->pipes as $pipe) {
$ctx = $pipe->process($ctx);
}
return $ctx;
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Processors\Customer;
use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerEntity;
use App\Entities\PaymentEntity;
class ServiceContext
{
public array $formDatas = [];
public ?ServiceEntity $serviceEntity = null;
public ?ServerEntity $serverEntity = null;
public ?PaymentEntity $paymentEntity = null;
public function __construct(array $formDatas)
{
$this->formDatas = $formDatas;
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Processor\Customer;
use App\Processors\Customer\ServiceContext;
interface ServiceInterface
{
/** 모든 프로세서는 같은 함수로 동작 */
public function process(ServiceContext $ctx): ServiceContext;
}

View File

@ -0,0 +1,112 @@
<?php
namespace App\Processors\Customer;
use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerEntity;
use App\Entities\PaymentEntity;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
use App\Services\MyLogService;
use App\Services\PaymentService;
use CodeIgniter\Database\BaseConnection;
use DateTimeImmutable;
use DateTimeZone;
use RuntimeException;
class ServiceV1Processor
{
public function __construct(
private BaseConnection $db,
private ServiceService $serviceService,
private ServerService $serverService,
private PaymentService $paymentService,
private MyLogService $logService,
) {}
/** 1) 서비스 생성 */
private function createService(array $formDatas): ServiceEntity
{
return $this->serviceService->getModel()->create($formDatas);
}
/** 2) 서버 연결 */
private function attachServer(ServiceEntity $entity): ServerEntity
{
$serverEntity = $this->serverService->getEntity($entity->getServerInfoUID());
if (!$serverEntity instanceof ServerEntity) {
throw new RuntimeException(sprintf(
'[%s]에 대한 서버정보를 찾을 수 없습니다.',
$entity->getServerInfoUID()
));
}
return $this->serverService->getModel()->modify($serverEntity, [
'clientinfo_uid' => $entity->getClientInfoUID(),
'serviceinfo_uid' => $entity->getPK(),
'status' => STATUS['OCCUPIED'],
]);
}
/** 3) 금액 계산 */
private function calculateAmount(ServiceEntity $entity, ServerEntity $serverEntity): ServiceEntity
{
$amount = $this->serviceService->getCalculatedAmount($entity, $serverEntity);
return $this->serviceService->getModel()->modify($entity, ['amount' => $amount]);
}
/** 4) 결제 생성 */
private function createPayment(ServiceEntity $entity, ServerEntity $serverEntity): PaymentEntity
{
$billingAt = new DateTimeImmutable($entity->getBillingAt() ?? 'now', new DateTimeZone('Asia/Tokyo'));
$title = sprintf('[%s/%s] %s 서비스비용', $serverEntity->getCode(), $serverEntity->getIP(), $billingAt->format('Y년 n월'));
return $this->paymentService->getModel()->create([
'clientinfo_uid' => $entity->getClientInfoUID(),
'serviceinfo_uid' => $entity->getPK(),
'serverinfo_uid' => $entity->getServerInfoUID(),
'title' => $title,
'amount' => $entity->getAmount(),
'billing' => PAYMENT['BILLING']['MONTH'],
'billing_at' => $billingAt->format('Y-m-d'),
]);
}
/** 5) 서비스 링크 갱신(FK 반영) */
private function updateLinks(ServiceEntity $entity, ServerEntity $serverEntity, PaymentEntity $paymentEntity): ServiceEntity
{
return $this->serviceService->getModel()->modify($entity, [
'serverinfo_id' => $serverEntity->getPK(),
'payment_uid' => $paymentEntity->getPK(),
]);
}
/** 6) 로그 */
private function stepLog(ServiceEntity $entity): void
{
$this->logService->create([
'title' => sprintf('[%s] 서비스정보 추가', $entity->getCustomTitle()),
'status' => $entity->getStatus(),
]);
}
/** 최종 결과만 필요할 때 */
public function create(array $formDatas): ServiceEntity
{
$this->db->transStart();
if (!isset($formDatas['serverinfo_uid'])) {
throw new RuntimeException('서버가 지정되지 않았습니다.');
}
// 1) 서비스 생성
$entity = $this->createService($formDatas);
// 2) 서버 연결
$serverEntity = $this->attachServer($entity);
// 3) 금액 계산
$entity = $this->calculateAmount($entity, $serverEntity);
// 4) 결제 생성
$paymentEntity = $this->createPayment($entity, $serverEntity);
// 5) 서비스 링크 갱신(FK 반영)
$entity = $this->updateLinks($entity, $serverEntity, $paymentEntity);
// 6) 로그 (필요 시 이벤트로 대체)
$this->stepLog($entity);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
throw new RuntimeException('트랜잭션 실패');
}
return $entity;
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Processors\Customer;
use App\Entities\Customer\ServiceEntity;
use App\Processors\Customer\{ServiceInterface, ServiceComposite, ServiceContext};
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
use App\Services\PaymentService;
use App\Services\MyLogService;
use CodeIgniter\Database\BaseConnection;
use RuntimeException;
final class ServiceV2Processor
{
public function __construct(
private BaseConnection $db,
private ServiceService $serviceService,
private ServerService $serverService,
private PaymentService $paymentService,
private MyLogService $logService,
) {}
public function create(array $formDatas): ServiceEntity
{
$pipeline = new ServiceComposite([
new \App\Processors\Service\CreateServiceProcessor($this->serviceService),
new \App\Processors\Server\ServerAttachProcessor($this->serverService),
new \App\Processors\Payment\PaymentCreateProcessor($this->serviceService, $this->paymentService),
new \App\Processors\Log\LogProcessor($this->logService, '서비스정보 추가'),
]);
return $this->runPipeline($pipeline, $formDatas);
}
public function modify(array $formDatas, ServiceEntity $serviceEntity): ServiceEntity
{
$ctx = new ServiceContext($formDatas);
$ctx->serviceEntity = $serviceEntity;
$pipeline = new ServiceComposite([
new \App\Processors\Server\ServerUnsetProcessor($this->serverService),
new \App\Processors\Service\ServiceModifyProcessor($this->serviceService),
new \App\Processors\Server\ServerAttachProcessor($this->serverService),
new \App\Processors\Payment\PaymentUpdateProcessor($this->serviceService, $this->paymentService),
new \App\Processors\Log\LogProcessor($this->logService, '서비스정보 수정'),
]);
return $this->runPipeline($pipeline, $formDatas, $ctx);
}
public function delete(ServiceEntity $serviceEntity): bool
{
$ctx = new ServiceContext([]);
$ctx->serviceEntity = $serviceEntity;
$pipeline = new ServiceComposite([
new \App\Processors\Server\ServerUnsetProcessor($this->serverService),
new \App\Processors\Payment\PaymentCancelProcessor($this->paymentService),
new \App\Processors\Service\ServiceDeleteProcessor($this->serviceService),
new \App\Processors\Log\LogProcessor($this->logService, '서비스정보 삭제'),
]);
$this->runPipeline($pipeline, [], $ctx);
return true;
}
private function runPipeline(ServiceComposite $pipeline, array $formDatas, ?ServiceContext $ctx = null): ServiceEntity
{
$this->db->transStart();
$ctx ??= new ServiceContext($formDatas);
$ctx = $pipeline->process($ctx);
$this->db->transComplete();
if ($this->db->transStatus() === false) {
throw new RuntimeException('트랜잭션 실패');
}
return $ctx->serviceEntity;
}
}

View File

@ -24,10 +24,17 @@ abstract class CommonService
}
abstract public function getFormFields(): array;
abstract public function getFormFilters(): array;
final public function getModel(): mixed
{
if (!$this->_model instanceof CommonModel) {
throw new \Exception(__METHOD__ . "에서 오류발생:Model이 정의되지 않았습니다. ");
}
return $this->_model;
}
final public function getHelper(): mixed
{
if (!$this->_helper) {
throw new \Exception("Helper가 정의되지 않았습니다. " . __METHOD__);
if (!$this->_helper instanceof CommonHelper) {
throw new \Exception(__METHOD__ . "에서 오류발생:Helper가 정의되지 않았습니다. ");
}
return $this->_helper;
}
@ -45,13 +52,6 @@ abstract class CommonService
}
$this->_control[$key] = $values;
}
final protected function getModel(): mixed
{
if (!$this->_model) {
throw new \Exception("Model이 정의되지 않았습니다. " . __METHOD__);
}
return $this->_model;
}
final protected function addClassName(string $className): void
{
$this->_classNames[] = $className;

View File

@ -7,16 +7,16 @@ use App\Entities\Equipment\ServerEntity;
use App\Entities\PaymentEntity;
use App\Helpers\Customer\ServiceHelper;
use App\Models\Customer\ServiceModel;
use App\Services\Equipment\ServerPartService;
use App\Processors\Customer\ServiceV1Processor as ServiceProcessor;
use App\Services\Equipment\ServerService;
use App\Services\PaymentService;
use DateTime;
class ServiceService extends CustomerService
{
private ?ServerService $_serverService = null;
private ?PaymentService $_paymentService = null;
private ?ServerPartService $_serverPartService = null;
public function __construct()
{
parent::__construct(new ServiceModel(), new ServiceHelper());
@ -31,6 +31,7 @@ class ServiceService extends CustomerService
'serverinfo_uid',
"rack",
"line",
"title",
"start_at",
"billing_at",
"status",
@ -135,13 +136,6 @@ class ServiceService extends CustomerService
}
return $this->_serverService;
}
final public function getServerPartService(): ServerPartService
{
if (!$this->_serverPartService) {
$this->_serverPartService = new ServerPartService();
}
return $this->_serverPartService;
}
//interval을 기준으로 최근 신규 서비스정보 가져오기
final public function getNewServiceEntities(int $interval, string $status = ServiceEntity::DEFAULT_STATUS): array
{
@ -186,15 +180,11 @@ class ServiceService extends CustomerService
return $date->format('Y-m-d');
}
//총 서비스금액 설정
private function getCaculatedAmount(ServiceEntity $entity): int
public function getCalculatedAmount(ServiceEntity $entity, ServerEntity $serverEntity): int
{
$serverAmount = $this->getServerService()->getCaculatedAmount($entity->getServerEntity());
//총서비스금액 계산
//기본:상면비+회선비+서버금액(price)+서버파트연결(월비용)-할인액
$caculatedAmount = $entity->getRack() + $entity->getLine() + $serverAmount - $entity->getSale();
// echo "총서비스금액: {$caculatedAmount} - 할인액: {$entity->getSale()} = 최종금액: " . ($caculatedAmount - $entity->getSale()) . "\n";
// exit;
return $caculatedAmount;
return $entity->getRack() + $entity->getLine() + $this->getServerService()->getCalculatedAmount($serverEntity) - $entity->getSale();
}
public function setAmount(int $uid): PaymentEntity
{
@ -202,7 +192,7 @@ class ServiceService extends CustomerService
if (!$entity instanceof ServiceEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생: [{$uid}]에 대한 서비스정보를 찾을수 없습니다.");
}
parent::modify($entity, ['amount' => $this->getCaculatedAmount($entity)]);;
parent::modify($entity, ['amount' => $this->getCalculatedAmount($entity, $entity->getServerEntity())]);
//결제정보 수정
return $this->getPaymentService()->modifyService($entity);
}
@ -226,25 +216,14 @@ class ServiceService extends CustomerService
if (!array_key_exists('serverinfo_uid', $formDatas)) {
throw new \Exception(__METHOD__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
}
//서비스 정보 생성
$entity = parent::create($formDatas);
//지정된 서버정보에 서비스 설정
$serverEntity = $this->getServerService()->setService($entity, $entity->getServerInfoUID());
//서비스 총금액 설정
$paymentEntity = $this->setAmount($entity->getPK());
//결제정보 등록
$paymentEntity = $this->getPaymentService()->createService($entity);
//추가 필수정보 수정용
$entity = parent::modify($entity, [
'serverinfo_id' => $serverEntity->getPK(),
'payment_uid' => $paymentEntity->getPK()
]);
//Log정보 등록
$this->getMylogService()->create([
'title' => "[{$entity->getCustomTitle()}] 서비스정보 추가",
'status' => $entity->getStatus(),
]);
return $entity;
$processor = new ServiceProcessor(
\Config\Database::connect(),
$this,
$this->getServerService(),
$this->getPaymentservice(),
$this->getMyLogService()
);
return $processor->create($formDatas);
}
//수정
public function modify(mixed $entity, array $formDatas): ServiceEntity

View File

@ -181,7 +181,7 @@ class ServerService extends EquipmentService
}
//총 서버금액 설정()
//기본:서버금액(price)+서버파트연결(월비용)
final public function getCaculatedAmount(ServerEntity $entity): int
final public function getCalculatedAmount(ServerEntity $entity): int
{
$caculatedAmount = $entity->getPrice();
//해당 서비스(서버) 관련 결제방식(Billing)이 Month인 ServerPart 전체를 다시 검사하여 월청구액을 합산한다.

View File

@ -1,13 +1,13 @@
const serverSelect = document.querySelector("select[name=serverinfo_uid]");
const rackSelect = document.querySelector("select[name=rack]");
const lineSelect = document.querySelector("select[name=line]");
const lineSelect = document.querySelector("select[name=line]");
const titleInput = document.querySelector("input[name=title]");
const amountInput = document.querySelector("input[name=amount]");
function getTotalPrice() {
const serverPrice = serverSelect?.options[serverSelect.selectedIndex]?.getAttribute("data-price") || 0;
const rackPrice = rackSelect?.options[rackSelect.selectedIndex]?.value || 0;
const linePrice = lineSelect?.options[lineSelect.selectedIndex]?.value || 0;
return Number(serverPrice) + Number(rackPrice) + Number(linePrice);
}
@ -25,6 +25,9 @@ if (lineSelect) lineSelect.addEventListener("change", updateAmount);
if (serverSelect) {
$(serverSelect).on("select2:select", function () {
updateAmount();
if (titleInput) {
titleInput.value = serverSelect?.options[serverSelect.selectedIndex]?.text || "";
}
});
}