dbmsv3/app/Services/PaymentService.php
2025-10-27 17:15:47 +09:00

324 lines
14 KiB
PHP

<?php
namespace App\Services;
use App\Entities\Customer\ClientEntity;
use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerEntity;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\PaymentEntity;
use App\Helpers\PaymentHelper;
use App\Interfaces\PaymentInterface;
use App\Models\PaymentModel;
use App\Services\CommonService;
use App\Services\Customer\AccountService;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerPartService;
use App\Services\Equipment\ServerService;
use DateTimeImmutable;
use DateTimeZone;
class PaymentService extends CommonService implements PaymentInterface
{
private ?ServiceService $_serviceService = null;
private ?ServerService $_serverService = null;
private ?ServerPartService $_serverPartService = null;
private ?AccountService $_accountService = null;
public function __construct()
{
parent::__construct(new PaymentModel(), new PaymentHelper());
$this->addClassName('Payment');
}
final public function getFormFields(): array
{
return [
"serviceinfo_uid",
"title",
"amount",
"billing",
"billing_at",
"content"
];
}
final public function getFormFilters(): array
{
return [
'clientinfo_uid',
"serviceinfo_uid",
'billing',
'pay',
'status',
'user_uid',
];
}
final public function getIndexFields(): array
{
return [
'clientinfo_uid',
"serviceinfo_uid",
'billing',
'title',
'amount',
'billing_at',
'pay',
'status',
'updated_at',
'countdown',
'user_uid',
];
}
final public function getBatchjobFields(): array
{
return [];
}
final public function getBatchjobButtons(): array
{
return [
'batchjob' => '결제 처리',
'invoice' => '청구서 발행',
];
}
final public function getServiceService(): ServiceService
{
if ($this->_serviceService === null) {
$this->_serviceService = new ServiceService();
}
return $this->_serviceService;
}
public function getServerService(): ServerService
{
if (!$this->_serverService) {
$this->_serverService = new ServerService();
}
return $this->_serverService;
}
final public function getServerPartService(): ServerPartService
{
if (!$this->_serverPartService) {
$this->_serverPartService = new ServerPartService();
}
return $this->_serverPartService;
}
final public function getAccountService(): AccountService
{
if (!$this->_accountService) {
$this->_accountService = new AccountService();
}
return $this->_accountService;
}
//총 미납건수, 금액
final public function getUnPaids(string $group, array $where = []): array
{
$builder = $this->getModel()->groupBy($group)
->select("{$group},COUNT(uid) as cnt, SUM(amount) as amount")
->where(['status' => STATUS['UNPAID']])
->where($where)
->builder();
// echo $builder->getCompiledSelect(false); //초기화 없이 SQL만 보고 싶을 때: getCompiledSelect(false) ← 꼭 false!
$unPaids = [];
foreach ($builder->get()->getResult() as $row) {
$unPaids[$row->$group] = ['cnt' => $row->cnt, 'amount' => $row->amount];
}
return $unPaids;
}
//Service관련(월과금)
//서비스생성
public function createForService(ServiceEntity $serviceEntity, int $amount): PaymentEntity
{
$billingAt = new DateTimeImmutable($serviceEntity->getBillingAt(), new DateTimeZone('Asia/Tokyo'));
return $this->getModel()->create([
'clientinfo_uid' => $serviceEntity->getClientInfoUID(),
'serviceinfo_uid' => $serviceEntity->getPK(),
'serverinfo_uid' => $serviceEntity->getServerInfoUID(), //서버정보 번호
'title' => sprintf('[%s] %s 서비스비용', $serviceEntity->getTitle(), $billingAt->format('Y년 n월')),
'amount' => $amount,
'billing' => PAYMENT['BILLING']['MONTH'],
'billing_at' => $billingAt->format('Y-m-d'),
]);
}
//서비스수정
public function updateForService(ServiceEntity $serviceEntity, string $payment_uid, int $amount): PaymentEntity
{
$paymentEntity = $this->getEntity($payment_uid);
if (!$paymentEntity instanceof PaymentEntity) {
throw new \Exception("[{$payment_uid}]에 대한 결제정보를 찾을 수 없습니다.");
}
$billingAt = new DateTimeImmutable($serviceEntity->getBillingAt(), new DateTimeZone('Asia/Tokyo'));
return $this->getModel()->modify($paymentEntity, [
'clientinfo_uid' => $serviceEntity->getClientInfoUID(),
'serviceinfo_uid' => $serviceEntity->getPK(),
'serverinfo_uid' => $serviceEntity->getServerInfoUID(),
'title' => sprintf('[%s] %s 서비스비용', $serviceEntity->getTitle(), $billingAt->format('Y년 n월')),
'amount' => $amount,
'billing' => PAYMENT['BILLING']['MONTH'],
'billing_at' => $billingAt->format('Y-m-d'),
]);
}
//서비스해지
public function unlinkFromService(string $payment_uid): PaymentEntity
{
$paymentEntity = $this->getEntity($payment_uid);
if (!$paymentEntity instanceof PaymentEntity) {
throw new \Exception("[{$payment_uid}]에 대한 결제정보를 찾을 수 없습니다.");
}
return $this->getModel()->modify($paymentEntity, [
'serviceinfo_uid' => null,
'serverinfo_uid' => null,
]);
}
//서버파트(일회성과금)
final public function createForServerPart(ServerPartEntity $serverPartEntity, int $amount): PaymentEntity
{
$formDatas = [];
$formDatas['clientinfo_uid'] = $serverPartEntity->getClientInfoUID();
$formDatas['serviceinfo_uid'] = $serverPartEntity->getServiceInfoUID();
//서버연결정보 수정시에 필요함
$formDatas['serverinfo_uid'] = $serverPartEntity->getServerInfoUID();
//타이틀은 기타의 경우 직접작성한 제목을 등록하고 아닌경우는 Part의 Title을 사용한다.
$formDatas['title'] = $serverPartEntity->getTitle();
$formDatas['amount'] = $serverPartEntity->getTotalAmount(); //단가*cnt
$formDatas['billing'] = $serverPartEntity->getBilling();
//당일결체일로 설정
$formDatas['billing_at'] = date("Y-m-d");
return parent::create($formDatas);
}
final public function updateForServerPart(ServerPartEntity $serverPartEntity): PaymentEntity
{
if ($serverPartEntity->getPaymentUID() === null) {
throw new \Exception(__METHOD__ . "에서 오류발생:일회성서비스정보에 결제정보가 정의되지 않았습니다.");
}
$entity = $this->getEntity($serverPartEntity->getPaymentUID());
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보를 찾을수 없습니다.");
}
if ($entity->getStatus() === STATUS['PAID']) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제완료된 서비스는 수정할수 없습니다.");
}
$formDatas = [];
$formDatas['clientinfo_uid'] = $serverPartEntity->getClientInfoUID();
$formDatas['serviceinfo_uid'] = $serverPartEntity->getServiceInfoUID();
//서버연결정보 수정시에 필요함
$formDatas['serverinfo_uid'] = $serverPartEntity->getServerInfoUID();
//타이틀은 기타의 경우 직접작성한 제목을 등록하고 아닌경우는 Part의 Title을 사용한다.
$formDatas['title'] = $serverPartEntity->getTitle();
$formDatas['amount'] = $serverPartEntity->getTotalAmount(); //단가*cnt
$formDatas['billing'] = $serverPartEntity->getBilling();
return parent::modify($entity, $formDatas);
}
final public function deleteServerPart(ServerPartEntity $serverPartEntity): void
{
if ($serverPartEntity->getPaymentUID() === null) {
throw new \Exception(__METHOD__ . "에서 오류발생:일회성서비스정보에 결제정보가 정의되지 않았습니다.");
}
$entity = $this->getEntity($serverPartEntity->getPaymentUID());
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보를 찾을수 없습니다.");
}
if ($entity->getStatus() === STATUS['PAID']) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제완료된 서비스는 수정할수 없습니다.");
}
parent::delete($entity);
}
//Invoice 관련
public function getInvoiceData(ClientEntity $clientEntity, ServiceEntity $serviceEntity, PaymentEntity $entity, array $rows): array
{
if (!array_key_exists($clientEntity->getPK(), $rows)) {
$rows[$clientEntity->getPK()] = [
'name' => $clientEntity->getName(),
'total_amount' => 0,
'services' => [],
];
}
if (!array_key_exists($serviceEntity->getPK(), $rows[$clientEntity->getPK()]['services'])) {
$serverEntity = $this->getServerService()->getEntity($serviceEntity->getServerInfoUID());
if (!$serverEntity instanceof ServerEntity) {
dd($serverEntity);
throw new \Exception("[{$serviceEntity->getServerInfoUID()}]에 대한 서버정보를 찾을 수 없습니다.");
}
$rows[$clientEntity->getPK()]['services'][$serviceEntity->getPK()] = [
'ip' => $serverEntity->getIP(),
'billing_at' => $serviceEntity->getBillingAt(),
'items' => [],
];
}
//entities에 총 결제금액 설정
$rows[$clientEntity->getPK()]['services'][$serviceEntity->getPK()]['items'][] = ['title' => $entity->getTitle(), 'amount' => $entity->getAmount()];
$rows[$clientEntity->getPK()]['total_amount'] += $entity->getAmount();
return $rows;
}
//기본 기능부분
//FieldForm관련용
final public function getFormOption(string $field, array $options = []): array
{
switch ($field) {
case 'serviceinfo_uid':
$options = $this->getServiceService()->getEntities();
break;
default:
$options = parent::getFormOption($field, $options);
break;
}
return $options;
}
//Action 기능
//일회성용 결제처리 등록(일회성은 예치금에 관련된것만 등록한다.)
public function create(array $formDatas): PaymentEntity
{
if (!array_key_exists('serviceinfo_uid', $formDatas)) {
throw new \Exception("서비스정보가 없습니다.");
}
//서비스정보 가져오기
$serviceEntity = $this->getServiceService()->getEntity($formDatas['serviceinfo_uid']);
if (!$serviceEntity instanceof ServiceEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생: 서비스정보[{$formDatas['serviceinfo_uid']}]를 찾을수 없습니다.");
}
//결제 완료 처리 후 추가정보 처리
$formDatas['clientinfo_uid'] = $serviceEntity->getClientInfoUID();
$entity = parent::create($formDatas);
//Log처리
$this->getMylogService()->create([
'title' => "[{$entity->getTitle()}] 일회성 결제",
'status' => $entity->getStatus()
]);
return $entity;
}
//월과금용 일괄결제처리(결제는 무조건 예치금으로만 처리)
public function batchjob(mixed $entity, array $formDatas): mixed
{
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보가 정의되지 않았습니다.");
}
//결제 완료 처리 후 추가정보 처리
$formDatas['status'] = STATUS['PAID'];
$entity = parent::batchjob($entity, $formDatas);
//Log처리
$this->getMylogService()->create([
'title' => "[{$entity->getTitle()}] 월과금 결제",
'status' => $entity->getStatus()
]);
//예치금처리
$this->getAccountService()->setPaymentPaid($entity);
return $entity;
}
//결제정보 삭제
public function delete(mixed $entity): PaymentEntity
{
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보가 정의되지 않았습니다.");
}
if ($entity->getStatus() === STATUS['PAID']) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제완료된 서비스는 삭제할수 없습니다.");
}
return parent::delete($entity);
}
//List 검색용
//OrderBy 처리
final public function setOrderBy(mixed $field = null, mixed $value = null): void
{
$this->getModel()->orderBy('billing_at ASC');
parent::setOrderBy($field, $value);
}
}