style: Pint 포맷팅 적용

This commit is contained in:
김보곤
2026-02-25 11:45:01 +09:00
parent 68b1622a4e
commit 9a7c548246
199 changed files with 1420 additions and 1083 deletions

View File

@@ -8,6 +8,7 @@
class FixMenuUrlCommand extends Command
{
protected $signature = 'menu:fix-url {name} {new-url} {--tenant=}';
protected $description = '메뉴 URL 수정 (이름으로 검색)';
public function handle(): int
@@ -26,6 +27,7 @@ public function handle(): int
if ($menus->isEmpty()) {
$this->error("'{$name}' 메뉴를 찾을 수 없습니다.");
return 1;
}
@@ -37,6 +39,7 @@ public function handle(): int
}
$this->info("{$menus->count()}건 수정 완료.");
return 0;
}
}

View File

@@ -800,4 +800,4 @@ private function getItemData(): array
],
];
}
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use App\Models\Finance\BankAccount;
use App\Services\BankAccountService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -86,7 +85,7 @@ public function store(Request $request): JsonResponse
// 기본값 설정
$validated['status'] = $validated['status'] ?? 'active';
$validated['account_name'] = $validated['account_name'] ?? $validated['bank_name'] . ' 계좌';
$validated['account_name'] = $validated['account_name'] ?? $validated['bank_name'].' 계좌';
$account = $this->bankAccountService->createAccount($validated);
@@ -156,6 +155,7 @@ public function destroy(Request $request, int $id): JsonResponse|Response
// HTMX 요청인 경우 갱신된 테이블 반환
if ($request->header('HX-Request')) {
$accounts = $this->bankAccountService->getAccounts($request->all(), $request->integer('per_page', 15));
return response(view('finance.accounts.partials.table', compact('accounts')));
}
@@ -184,6 +184,7 @@ public function restore(Request $request, int $id): JsonResponse|Response
// HTMX 요청인 경우 갱신된 테이블 반환
if ($request->header('HX-Request')) {
$accounts = $this->bankAccountService->getAccounts($request->all(), $request->integer('per_page', 15));
return response(view('finance.accounts.partials.table', compact('accounts')));
}
@@ -212,6 +213,7 @@ public function forceDelete(Request $request, int $id): JsonResponse|Response
// HTMX 요청인 경우 갱신된 테이블 반환
if ($request->header('HX-Request')) {
$accounts = $this->bankAccountService->getAccounts($request->all(), $request->integer('per_page', 15));
return response(view('finance.accounts.partials.table', compact('accounts')));
}
@@ -240,6 +242,7 @@ public function toggleActive(Request $request, int $id): JsonResponse|Response
// HTMX 요청인 경우 갱신된 테이블 반환
if ($request->header('HX-Request')) {
$accounts = $this->bankAccountService->getAccounts($request->all(), $request->integer('per_page', 15));
return response(view('finance.accounts.partials.table', compact('accounts')));
}

View File

@@ -42,7 +42,7 @@ public function subscriptions(Request $request): JsonResponse|Response
->orderBy('service_type');
// 테넌트 필터링
if (!$isHeadquarters && !$allTenants) {
if (! $isHeadquarters && ! $allTenants) {
$query->whereHas('member', function ($q) use ($tenantId) {
$q->where('tenant_id', $tenantId);
});
@@ -102,7 +102,7 @@ public function cancelSubscription(int $id): JsonResponse
{
$result = $this->billingService->cancelSubscription($id);
if (!$result) {
if (! $result) {
return response()->json([
'success' => false,
'message' => '구독을 찾을 수 없습니다.',
@@ -121,7 +121,7 @@ public function cancelSubscription(int $id): JsonResponse
public function memberSubscriptions(int $memberId): JsonResponse|Response
{
$member = BarobillMember::with('tenant')->find($memberId);
if (!$member) {
if (! $member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
@@ -157,7 +157,7 @@ public function billingList(Request $request): JsonResponse|Response
$billingMonth = $request->input('billing_month', now()->format('Y-m'));
// 테넌트 필터링
$filterTenantId = (!$isHeadquarters && !$allTenants) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
$summaries = BarobillMonthlySummary::with(['member.tenant'])
->where('billing_month', $billingMonth)
@@ -202,7 +202,7 @@ public function billingStats(Request $request): JsonResponse|Response
$billingMonth = $request->input('billing_month', now()->format('Y-m'));
$filterTenantId = (!$isHeadquarters && !$allTenants) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
$stats = $this->billingService->getMonthlyTotal($billingMonth, $filterTenantId);
if ($request->header('HX-Request')) {
@@ -225,7 +225,7 @@ public function billingStats(Request $request): JsonResponse|Response
public function memberBilling(Request $request, int $memberId): JsonResponse|Response
{
$member = BarobillMember::with('tenant')->find($memberId);
if (!$member) {
if (! $member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
@@ -293,7 +293,7 @@ public function yearlyTrend(Request $request): JsonResponse
$year = $request->input('year', now()->year);
$filterTenantId = (!$isHeadquarters && !$allTenants) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
$trend = $this->billingService->getYearlyTrend($year, $filterTenantId);
return response()->json([
@@ -313,7 +313,7 @@ public function export(Request $request)
$billingMonth = $request->input('billing_month', now()->format('Y-m'));
$filterTenantId = (!$isHeadquarters && !$allTenants) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants) ? $tenantId : null;
$summaries = BarobillMonthlySummary::with(['member.tenant'])
->where('billing_month', $billingMonth)
@@ -336,7 +336,7 @@ public function export(Request $request)
$callback = function () use ($summaries, $total, $isHeadquarters, $allTenants) {
$file = fopen('php://output', 'w');
fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF));
fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
// 헤더
$headerRow = ['사업자번호', '상호', '계좌조회', '카드내역', '홈텍스', '월정액합계', '세금계산서(건)', '세금계산서(원)', '건별합계', '총합계'];
@@ -411,7 +411,7 @@ public function pricingPolicies(Request $request): JsonResponse|Response
public function updatePricingPolicy(Request $request, int $id): JsonResponse
{
$policy = BarobillPricingPolicy::find($id);
if (!$policy) {
if (! $policy) {
return response()->json([
'success' => false,
'message' => '정책을 찾을 수 없습니다.',
@@ -444,7 +444,7 @@ public function updatePricingPolicy(Request $request, int $id): JsonResponse
public function getPricingPolicy(int $id): JsonResponse
{
$policy = BarobillPricingPolicy::find($id);
if (!$policy) {
if (! $policy) {
return response()->json([
'success' => false,
'message' => '정책을 찾을 수 없습니다.',

View File

@@ -94,7 +94,7 @@ public function show(int $id): JsonResponse
{
$config = BarobillConfig::find($id);
if (!$config) {
if (! $config) {
return response()->json([
'success' => false,
'message' => '설정을 찾을 수 없습니다.',
@@ -114,7 +114,7 @@ public function update(Request $request, int $id): JsonResponse
{
$config = BarobillConfig::find($id);
if (!$config) {
if (! $config) {
return response()->json([
'success' => false,
'message' => '설정을 찾을 수 없습니다.',
@@ -167,7 +167,7 @@ public function destroy(int $id): JsonResponse
{
$config = BarobillConfig::find($id);
if (!$config) {
if (! $config) {
return response()->json([
'success' => false,
'message' => '설정을 찾을 수 없습니다.',
@@ -196,7 +196,7 @@ public function toggleActive(int $id): JsonResponse
{
$config = BarobillConfig::find($id);
if (!$config) {
if (! $config) {
return response()->json([
'success' => false,
'message' => '설정을 찾을 수 없습니다.',
@@ -205,14 +205,14 @@ public function toggleActive(int $id): JsonResponse
DB::beginTransaction();
try {
if (!$config->is_active) {
if (! $config->is_active) {
// 활성화하려면 같은 환경의 다른 설정들 비활성화
BarobillConfig::where('environment', $config->environment)
->where('id', '!=', $id)
->update(['is_active' => false]);
}
$config->update(['is_active' => !$config->is_active]);
$config->update(['is_active' => ! $config->is_active]);
DB::commit();
@@ -231,5 +231,4 @@ public function toggleActive(int $id): JsonResponse
], 500);
}
}
}

View File

@@ -25,7 +25,7 @@ public function show(): JsonResponse
// 바로빌 회원사 정보 조회 (담당자 정보 기본값용)
$barobillMember = BarobillMember::where('tenant_id', $tenantId)->first();
if (!$setting) {
if (! $setting) {
// 설정이 없으면 바로빌 회원사 정보를 기본값으로 사용
return response()->json([
'success' => true,
@@ -158,7 +158,7 @@ public function checkService(string $service): JsonResponse
$setting = BarobillSetting::where('tenant_id', $tenantId)->first();
if (!$setting) {
if (! $setting) {
return response()->json([
'success' => true,
'enabled' => false,

View File

@@ -8,7 +8,6 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
/**
* 바로빌 사용량조회 API 컨트롤러
@@ -44,7 +43,7 @@ public function index(Request $request): JsonResponse|Response
$apiEndDate = str_replace('-', '', $endDate);
// 테넌트 필터링
$filterTenantId = (!$isHeadquarters && !$allTenants && $tenantId) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants && $tenantId) ? $tenantId : null;
// 사용량 목록 조회
$usageList = $this->usageService->getUsageList($apiStartDate, $apiEndDate, $filterTenantId);
@@ -117,7 +116,7 @@ public function stats(Request $request): JsonResponse|Response
$apiEndDate = str_replace('-', '', $endDate);
// 테넌트 필터링
$filterTenantId = (!$isHeadquarters && !$allTenants && $tenantId) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants && $tenantId) ? $tenantId : null;
// 사용량 목록 조회 및 통계 집계
$usageList = $this->usageService->getUsageList($apiStartDate, $apiEndDate, $filterTenantId);
@@ -145,7 +144,7 @@ public function show(Request $request, int $memberId): JsonResponse|Response
{
$member = BarobillMember::with('tenant:id,company_name')->find($memberId);
if (!$member) {
if (! $member) {
return response()->json([
'success' => false,
'message' => '회원사를 찾을 수 없습니다.',
@@ -209,7 +208,7 @@ public function export(Request $request)
$apiEndDate = str_replace('-', '', $endDate);
// 테넌트 필터링
$filterTenantId = (!$isHeadquarters && !$allTenants && $tenantId) ? $tenantId : null;
$filterTenantId = (! $isHeadquarters && ! $allTenants && $tenantId) ? $tenantId : null;
// 사용량 목록 조회
$usageList = $this->usageService->getUsageList($apiStartDate, $apiEndDate, $filterTenantId);
@@ -227,7 +226,7 @@ public function export(Request $request)
$file = fopen('php://output', 'w');
// BOM for Excel UTF-8
fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF));
fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
// 헤더
$headerRow = ['사업자번호', '상호', '바로빌ID', '세금계산서(건)', '계좌조회(건)', '카드내역(건)', '홈텍스(건)', '과금액(원)'];

View File

@@ -335,4 +335,4 @@ public function reorder(Request $request): JsonResponse
], 500);
}
}
}
}

View File

@@ -236,7 +236,7 @@ public function destroy(int $id): JsonResponse
*/
public function forceDestroy(int $id): JsonResponse
{
if (!auth()->user()?->is_super_admin) {
if (! auth()->user()?->is_super_admin) {
return response()->json([
'success' => false,
'message' => '슈퍼관리자만 영구 삭제할 수 있습니다.',
@@ -263,7 +263,7 @@ public function forceDestroy(int $id): JsonResponse
*/
public function restore(int $id): JsonResponse
{
if (!auth()->user()?->is_super_admin) {
if (! auth()->user()?->is_super_admin) {
return response()->json([
'success' => false,
'message' => '슈퍼관리자만 복원할 수 있습니다.',

View File

@@ -66,7 +66,7 @@ public function index(Request $request): View
}
// 활성 상태 필터
if ($request->filled('is_active') && !$showTrashed) {
if ($request->filled('is_active') && ! $showTrashed) {
$query->where('is_active', $request->boolean('is_active'));
}
@@ -290,7 +290,7 @@ public function destroy(int $id): JsonResponse
*/
public function forceDestroy(int $id): JsonResponse
{
if (!auth()->user()?->is_super_admin) {
if (! auth()->user()?->is_super_admin) {
return response()->json([
'success' => false,
'message' => '슈퍼관리자만 영구 삭제할 수 있습니다.',
@@ -337,7 +337,7 @@ public function forceDestroy(int $id): JsonResponse
*/
public function restore(int $id): JsonResponse
{
if (!auth()->user()?->is_super_admin) {
if (! auth()->user()?->is_super_admin) {
return response()->json([
'success' => false,
'message' => '슈퍼관리자만 복원할 수 있습니다.',
@@ -535,7 +535,7 @@ public function uploadImage(Request $request): JsonResponse
}
// API 토큰 교환
$tokenService = new \App\Services\ApiTokenService();
$tokenService = new \App\Services\ApiTokenService;
$userId = auth()->id();
$tenantId = session('selected_tenant_id', 1);

View File

@@ -182,6 +182,7 @@ public function destroy(Request $request, int $id): JsonResponse|Response
$month = $request->integer('month', now()->month);
$calendarData = $this->fundScheduleService->getCalendarData($year, $month);
$summary = $this->fundScheduleService->getMonthlySummary($year, $month);
return response(view('finance.fund-schedules.partials.calendar', compact('year', 'month', 'calendarData', 'summary')));
}
@@ -229,6 +230,7 @@ public function updateStatus(Request $request, int $id): JsonResponse|Response
$month = $request->integer('month', now()->month);
$calendarData = $this->fundScheduleService->getCalendarData($year, $month);
$summary = $this->fundScheduleService->getMonthlySummary($year, $month);
return response(view('finance.fund-schedules.partials.calendar', compact('year', 'month', 'calendarData', 'summary')));
}

View File

@@ -266,6 +266,7 @@ public function bulkCopyToTenant(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -288,6 +289,7 @@ public function bulkCopyToTenant(Request $request): JsonResponse
]);
$idMap[$gc->id] = $trashed->id;
$copied++;
continue;
}
@@ -336,4 +338,4 @@ public function bulkCopyToTenant(Request $request): JsonResponse
], 500);
}
}
}
}

View File

@@ -23,7 +23,7 @@ public function search(Request $request): JsonResponse
->where('user_tenants.tenant_id', $tenantId)
->where('user_tenants.is_active', true);
})
->leftJoin('departments', function ($join) use ($tenantId) {
->leftJoin('departments', function ($join) {
$join->on('departments.id', '=', DB::raw('(
SELECT du.department_id FROM department_user du
WHERE du.user_id = users.id AND du.is_primary = 1

View File

@@ -6,8 +6,8 @@
use App\Services\AppVersionService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;
class AppVersionController extends Controller

View File

@@ -77,9 +77,9 @@ public function settings(Request $request): View|Response
$hasBarobillLogin = false;
if ($barobillMember) {
try {
$hasBarobillLogin = !empty($barobillMember->barobill_id) && !empty($barobillMember->barobill_pwd);
$hasBarobillLogin = ! empty($barobillMember->barobill_id) && ! empty($barobillMember->barobill_pwd);
} catch (\Throwable $e) {
$hasBarobillLogin = !empty($barobillMember->barobill_id) && !empty($barobillMember->getRawOriginal('barobill_pwd'));
$hasBarobillLogin = ! empty($barobillMember->barobill_id) && ! empty($barobillMember->getRawOriginal('barobill_pwd'));
}
}
@@ -179,8 +179,8 @@ public function searchTradingPartners(Request $request): JsonResponse
if ($keyword) {
$query->where(function ($q) use ($keyword) {
$q->where('name', 'like', "%{$keyword}%")
->orWhere('biz_no', 'like', "%{$keyword}%")
->orWhere('manager', 'like', "%{$keyword}%");
->orWhere('biz_no', 'like', "%{$keyword}%")
->orWhere('manager', 'like', "%{$keyword}%");
});
}

View File

@@ -21,9 +21,13 @@ class EtaxController extends Controller
* 바로빌 SOAP 설정
*/
private ?string $certKey = null;
private ?string $corpNum = null;
private bool $isTestMode = false;
private ?string $soapUrl = null;
private ?\SoapClient $soapClient = null;
public function __construct()
@@ -35,7 +39,7 @@ public function __construct()
$this->certKey = $activeConfig->cert_key;
$this->corpNum = $activeConfig->corp_num;
$this->isTestMode = $activeConfig->environment === 'test';
$this->soapUrl = $activeConfig->base_url . '/TI.asmx?WSDL';
$this->soapUrl = $activeConfig->base_url.'/TI.asmx?WSDL';
} else {
// 설정이 없으면 기본값 사용
$this->isTestMode = config('services.barobill.test_mode', true);
@@ -57,14 +61,14 @@ public function __construct()
*/
private function initSoapClient(): void
{
if (!empty($this->certKey) || $this->isTestMode) {
if (! empty($this->certKey) || $this->isTestMode) {
try {
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
'allow_self_signed' => true,
],
]);
$this->soapClient = new \SoapClient($this->soapUrl, [
@@ -73,10 +77,10 @@ private function initSoapClient(): void
'exceptions' => true,
'connection_timeout' => 30,
'stream_context' => $context,
'cache_wsdl' => WSDL_CACHE_NONE
'cache_wsdl' => WSDL_CACHE_NONE,
]);
} catch (\Throwable $e) {
Log::error('바로빌 SOAP 클라이언트 생성 실패: ' . $e->getMessage());
Log::error('바로빌 SOAP 클라이언트 생성 실패: '.$e->getMessage());
}
}
}
@@ -135,14 +139,14 @@ private function applyMemberServerMode(BarobillMember $member): void
$baseUrl = $config->base_url ?: ($memberTestMode
? 'https://testws.baroservice.com'
: 'https://ws.baroservice.com');
$this->soapUrl = $baseUrl . '/TI.asmx?WSDL';
$this->soapUrl = $baseUrl.'/TI.asmx?WSDL';
// SOAP 클라이언트 재초기화
$this->initSoapClient();
Log::info('[Etax] 서버 모드 적용', [
'targetEnv' => $targetEnv,
'certKey' => substr($this->certKey ?? '', 0, 10) . '...',
'certKey' => substr($this->certKey ?? '', 0, 10).'...',
'corpNum' => $this->corpNum,
'soapUrl' => $this->soapUrl,
]);
@@ -173,7 +177,7 @@ public function getInvoices(): JsonResponse
$allInvoices = $data['invoices'] ?? [];
// 본사(테넌트 1)가 아니면 해당 테넌트의 세금계산서만 필터링
if (!$isHeadquarters && $tenantId) {
if (! $isHeadquarters && $tenantId) {
$invoices = array_values(array_filter($allInvoices, function ($invoice) use ($tenantId) {
return ($invoice['tenant_id'] ?? null) == $tenantId;
}));
@@ -204,12 +208,12 @@ public function issue(Request $request): JsonResponse
$input = $request->all();
$useRealAPI = $this->soapClient !== null && ($this->isTestMode || !empty($this->certKey));
$useRealAPI = $this->soapClient !== null && ($this->isTestMode || ! empty($this->certKey));
$debugInfo = [
'hasSoapClient' => $this->soapClient !== null,
'hasCertKey' => !empty($this->certKey),
'hasCorpNum' => !empty($this->corpNum),
'hasCertKey' => ! empty($this->certKey),
'hasCorpNum' => ! empty($this->corpNum),
'isTestMode' => $this->isTestMode,
'willUseRealAPI' => $useRealAPI,
];
@@ -218,7 +222,7 @@ public function issue(Request $request): JsonResponse
$apiResult = $this->issueTaxInvoice($input);
if ($apiResult['success']) {
$mgtKey = $input['issueKey'] ?? 'MGT' . date('YmdHis') . rand(1000, 9999);
$mgtKey = $input['issueKey'] ?? 'MGT'.date('YmdHis').rand(1000, 9999);
$newInvoice = $this->createInvoiceRecord($input, $mgtKey, $apiResult['data'] ?? null);
$this->saveInvoice($newInvoice);
@@ -245,7 +249,7 @@ public function issue(Request $request): JsonResponse
}
} else {
// 시뮬레이션 모드
$issueKey = 'BARO-' . date('Y') . '-' . str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
$issueKey = 'BARO-'.date('Y').'-'.str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
$newInvoice = $this->createInvoiceRecord($input, $issueKey, null);
$this->saveInvoice($newInvoice);
@@ -293,16 +297,16 @@ public function sendToNts(Request $request): JsonResponse
}
}
if (!$invoice) {
if (! $invoice) {
return response()->json([
'success' => false,
'error' => '세금계산서를 찾을 수 없습니다.',
], 404);
}
$useRealAPI = $this->soapClient !== null && !empty($this->certKey);
$useRealAPI = $this->soapClient !== null && ! empty($this->certKey);
if ($useRealAPI && !empty($invoice['mgtKey'])) {
if ($useRealAPI && ! empty($invoice['mgtKey'])) {
$result = $this->callBarobillSOAP('SendToNTS', [
'CorpNum' => $this->corpNum,
'MgtKey' => $invoice['mgtKey'],
@@ -310,7 +314,7 @@ public function sendToNts(Request $request): JsonResponse
if ($result['success']) {
$data['invoices'][$invoiceIndex]['status'] = 'sent';
$data['invoices'][$invoiceIndex]['ntsReceiptNo'] = 'NTS-' . date('YmdHis');
$data['invoices'][$invoiceIndex]['ntsReceiptNo'] = 'NTS-'.date('YmdHis');
$data['invoices'][$invoiceIndex]['sentAt'] = date('Y-m-d');
file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
@@ -327,7 +331,7 @@ public function sendToNts(Request $request): JsonResponse
} else {
// 시뮬레이션
$data['invoices'][$invoiceIndex]['status'] = 'sent';
$data['invoices'][$invoiceIndex]['ntsReceiptNo'] = 'NTS-SIM-' . date('YmdHis');
$data['invoices'][$invoiceIndex]['ntsReceiptNo'] = 'NTS-SIM-'.date('YmdHis');
$data['invoices'][$invoiceIndex]['sentAt'] = date('Y-m-d');
file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
@@ -345,12 +349,12 @@ public function sendToNts(Request $request): JsonResponse
public function getSupplier(): JsonResponse
{
$tenantId = session('selected_tenant_id');
if (!$tenantId) {
if (! $tenantId) {
return response()->json(['success' => false, 'error' => '테넌트가 선택되지 않았습니다.'], 400);
}
$member = BarobillMember::where('tenant_id', $tenantId)->first();
if (!$member) {
if (! $member) {
return response()->json(['success' => false, 'error' => '바로빌 회원사 정보가 없습니다.'], 404);
}
@@ -376,12 +380,12 @@ public function getSupplier(): JsonResponse
public function updateSupplier(Request $request): JsonResponse
{
$tenantId = session('selected_tenant_id');
if (!$tenantId) {
if (! $tenantId) {
return response()->json(['success' => false, 'error' => '테넌트가 선택되지 않았습니다.'], 400);
}
$member = BarobillMember::where('tenant_id', $tenantId)->first();
if (!$member) {
if (! $member) {
return response()->json(['success' => false, 'error' => '바로빌 회원사 정보가 없습니다.'], 404);
}
@@ -424,7 +428,7 @@ public function delete(Request $request): JsonResponse
$dataFile = storage_path('app/barobill/invoices_data.json');
if (!file_exists($dataFile)) {
if (! file_exists($dataFile)) {
return response()->json([
'success' => false,
'error' => '데이터 파일이 없습니다.',
@@ -434,7 +438,7 @@ public function delete(Request $request): JsonResponse
$data = json_decode(file_get_contents($dataFile), true) ?? ['invoices' => []];
$originalCount = count($data['invoices']);
$data['invoices'] = array_values(array_filter($data['invoices'], fn($inv) => $inv['id'] !== $invoiceId));
$data['invoices'] = array_values(array_filter($data['invoices'], fn ($inv) => $inv['id'] !== $invoiceId));
if (count($data['invoices']) === $originalCount) {
return response()->json([
@@ -456,20 +460,20 @@ public function delete(Request $request): JsonResponse
*/
private function callBarobillSOAP(string $method, array $params = []): array
{
if (!$this->soapClient) {
if (! $this->soapClient) {
return [
'success' => false,
'error' => '바로빌 SOAP 클라이언트가 초기화되지 않았습니다.',
];
}
if (!isset($params['CERTKEY'])) {
if (! isset($params['CERTKEY'])) {
$params['CERTKEY'] = $this->certKey;
}
try {
$result = $this->soapClient->$method($params);
$resultProperty = $method . 'Result';
$resultProperty = $method.'Result';
if (isset($result->$resultProperty)) {
$resultData = $result->$resultProperty;
@@ -477,7 +481,7 @@ private function callBarobillSOAP(string $method, array $params = []): array
if (is_numeric($resultData) && $resultData < 0) {
return [
'success' => false,
'error' => '바로빌 API 오류 코드: ' . $resultData,
'error' => '바로빌 API 오류 코드: '.$resultData,
'error_code' => $resultData,
];
}
@@ -495,12 +499,12 @@ private function callBarobillSOAP(string $method, array $params = []): array
} catch (\SoapFault $e) {
return [
'success' => false,
'error' => 'SOAP 오류: ' . $e->getMessage(),
'error' => 'SOAP 오류: '.$e->getMessage(),
];
} catch (\Throwable $e) {
return [
'success' => false,
'error' => 'API 호출 오류: ' . $e->getMessage(),
'error' => 'API 호출 오류: '.$e->getMessage(),
];
}
}
@@ -510,7 +514,7 @@ private function callBarobillSOAP(string $method, array $params = []): array
*/
private function issueTaxInvoice(array $invoiceData): array
{
$mgtKey = $invoiceData['issueKey'] ?? 'MGT' . date('YmdHis') . rand(1000, 9999);
$mgtKey = $invoiceData['issueKey'] ?? 'MGT'.date('YmdHis').rand(1000, 9999);
$supplyAmt = 0;
$vat = 0;
@@ -583,7 +587,7 @@ private function issueTaxInvoice(array $invoiceData): array
$month = str_pad($item['month'] ?? '', 2, '0', STR_PAD_LEFT);
$day = str_pad($item['day'] ?? '', 2, '0', STR_PAD_LEFT);
$purchaseExpiry = ($month && $day && $month !== '00' && $day !== '00')
? $year . $month . $day
? $year.$month.$day
: '';
$taxInvoice['TaxInvoiceTradeLineItems']['TaxInvoiceTradeLineItem'][] = [
@@ -613,7 +617,7 @@ private function issueTaxInvoice(array $invoiceData): array
private function createInvoiceRecord(array $input, string $issueKey, $apiData): array
{
return [
'id' => 'inv_' . time() . '_' . rand(1000, 9999),
'id' => 'inv_'.time().'_'.rand(1000, 9999),
'tenant_id' => session('selected_tenant_id'), // 테넌트별 필터링용
'issueKey' => $issueKey,
'mgtKey' => $issueKey,
@@ -638,7 +642,7 @@ private function createInvoiceRecord(array $input, string $issueKey, $apiData):
'memo' => $input['memo'] ?? '',
'createdAt' => date('Y-m-d\TH:i:s'),
'sentAt' => date('Y-m-d'),
'barobillInvoiceId' => is_numeric($apiData) ? (string)$apiData : '',
'barobillInvoiceId' => is_numeric($apiData) ? (string) $apiData : '',
];
}
@@ -648,11 +652,11 @@ private function createInvoiceRecord(array $input, string $issueKey, $apiData):
private function saveInvoice(array $invoice): bool
{
$dataDir = storage_path('app/barobill');
if (!is_dir($dataDir)) {
if (! is_dir($dataDir)) {
mkdir($dataDir, 0755, true);
}
$dataFile = $dataDir . '/invoices_data.json';
$dataFile = $dataDir.'/invoices_data.json';
$existingData = ['invoices' => []];
if (file_exists($dataFile)) {

File diff suppressed because it is too large Load Diff

View File

@@ -208,7 +208,7 @@ public function index(Request $request): View|Response
private function flattenTree($categories): \Illuminate\Support\Collection
{
$result = collect();
$byParent = $categories->groupBy(fn($c) => $c->parent_id ?? 0);
$byParent = $categories->groupBy(fn ($c) => $c->parent_id ?? 0);
$this->addChildrenRecursive($result, $byParent, 0, 0);

View File

@@ -22,6 +22,7 @@ class CategorySyncController extends Controller
protected function getTenantId(): int
{
$tenantId = session('selected_tenant_id');
return ($tenantId && $tenantId !== 'all') ? (int) $tenantId : 1;
}
@@ -155,6 +156,7 @@ public function import(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -188,6 +190,7 @@ public function import(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -218,7 +221,7 @@ public function import(Request $request): JsonResponse
return response()->json([
'success' => true,
'message' => "{$imported}개 카테고리가 동기화되었습니다." . ($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'message' => "{$imported}개 카테고리가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'imported' => $imported,
'skipped' => $skipped,
]);
@@ -247,6 +250,7 @@ public function push(Request $request): JsonResponse
$localCategories = $this->getCategoryList($validated['type']);
$selectedCategories = array_filter($localCategories, function ($cat) use ($validated) {
$key = $this->makeCategoryKey($cat);
return in_array($key, $validated['category_keys']);
});
@@ -259,7 +263,7 @@ public function push(Request $request): JsonResponse
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->post(rtrim($env['url'], '/') . '/category-sync/import', [
])->post(rtrim($env['url'], '/').'/category-sync/import', [
'categories' => array_values($selectedCategories),
]);
@@ -276,7 +280,7 @@ public function push(Request $request): JsonResponse
'error' => $response->json('error', '원격 서버 오류'),
], $response->status());
} catch (\Exception $e) {
return response()->json(['error' => '연결 실패: ' . $e->getMessage()], 500);
return response()->json(['error' => '연결 실패: '.$e->getMessage()], 500);
}
}
@@ -309,6 +313,7 @@ public function pull(Request $request): JsonResponse
// 선택된 카테고리만 필터링
$selectedCategories = array_filter($remoteCategories, function ($cat) use ($validated) {
$key = $this->makeCategoryKey($cat);
return in_array($key, $validated['category_keys']);
});
@@ -328,6 +333,7 @@ public function pull(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -359,6 +365,7 @@ public function pull(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -388,7 +395,7 @@ public function pull(Request $request): JsonResponse
return response()->json([
'success' => true,
'message' => "{$imported}개 카테고리가 동기화되었습니다." . ($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'message' => "{$imported}개 카테고리가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'imported' => $imported,
'skipped' => $skipped,
]);
@@ -396,7 +403,8 @@ public function pull(Request $request): JsonResponse
/**
* 카테고리 목록 조회
* @param string $type 'global', 'tenant', or 'all'
*
* @param string $type 'global', 'tenant', or 'all'
*/
private function getCategoryList(string $type = 'all'): array
{
@@ -472,12 +480,12 @@ private function fetchRemoteCategories(array $env, string $type = 'all'): array
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->timeout(10)->get(rtrim($env['url'], '/') . '/category-sync/export', [
])->timeout(10)->get(rtrim($env['url'], '/').'/category-sync/export', [
'type' => $type,
]);
if (! $response->successful()) {
throw new \Exception('API 오류: HTTP ' . $response->status());
throw new \Exception('API 오류: HTTP '.$response->status());
}
$data = $response->json();
@@ -496,6 +504,7 @@ private function fetchRemoteCategories(array $env, string $type = 'all'): array
private function makeCategoryKey(array $cat): string
{
$typePart = $cat['is_global'] ? 'global' : "tenant:{$cat['tenant_id']}";
return "{$typePart}:{$cat['code_group']}:{$cat['code']}";
}
@@ -504,8 +513,8 @@ private function makeCategoryKey(array $cat): string
*/
private function calculateDiff(array $localCategories, array $remoteCategories): array
{
$localKeys = array_map(fn($c) => $this->makeCategoryKey($c), $localCategories);
$remoteKeys = array_map(fn($c) => $this->makeCategoryKey($c), $remoteCategories);
$localKeys = array_map(fn ($c) => $this->makeCategoryKey($c), $localCategories);
$remoteKeys = array_map(fn ($c) => $this->makeCategoryKey($c), $remoteCategories);
return [
'local_only' => array_values(array_diff($localKeys, $remoteKeys)),

View File

@@ -10,7 +10,6 @@
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class CommonCodeController extends Controller
@@ -272,6 +271,7 @@ public function update(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '테넌트를 먼저 선택해주세요.'], 400);
}
return redirect()->back()->with('error', '테넌트를 먼저 선택해주세요.');
}
@@ -282,6 +282,7 @@ public function update(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '코드를 찾을 수 없습니다.'], 404);
}
return redirect()->back()->with('error', '코드를 찾을 수 없습니다.');
}
@@ -294,6 +295,7 @@ public function update(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '글로벌 코드는 본사만 수정할 수 있습니다.'], 403);
}
return redirect()->back()->with('error', '글로벌 코드는 본사만 수정할 수 있습니다.');
}
@@ -302,6 +304,7 @@ public function update(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '다른 테넌트의 코드는 수정할 수 없습니다.'], 403);
}
return redirect()->back()->with('error', '다른 테넌트의 코드는 수정할 수 없습니다.');
}
}
@@ -393,6 +396,7 @@ public function bulkPromoteToGlobal(Request $request): RedirectResponse|JsonResp
if ($request->ajax()) {
return response()->json(['error' => '본사 또는 슈퍼관리자만 글로벌로 복사할 수 있습니다.'], 403);
}
return redirect()->back()->with('error', '본사 또는 슈퍼관리자만 글로벌로 복사할 수 있습니다.');
}
@@ -429,6 +433,7 @@ public function bulkPromoteToGlobal(Request $request): RedirectResponse|JsonResp
if ($exists) {
$skippedCount++;
continue;
}
@@ -447,6 +452,7 @@ public function bulkPromoteToGlobal(Request $request): RedirectResponse|JsonResp
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
return redirect()->back()->with('error', '복사 중 오류가 발생했습니다.');
}
@@ -471,6 +477,7 @@ public function copy(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '테넌트를 먼저 선택해주세요.'], 400);
}
return redirect()->back()->with('error', '테넌트를 먼저 선택해주세요.');
}
@@ -479,6 +486,7 @@ public function copy(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '글로벌 코드를 찾을 수 없습니다.'], 404);
}
return redirect()->back()->with('error', '글로벌 코드를 찾을 수 없습니다.');
}
@@ -493,6 +501,7 @@ public function copy(Request $request, int $id): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '이미 복사된 코드가 있습니다.'], 400);
}
return redirect()->back()->with('error', '이미 복사된 코드가 있습니다.');
}
@@ -527,6 +536,7 @@ public function bulkCopy(Request $request): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '테넌트를 먼저 선택해주세요.'], 400);
}
return redirect()->back()->with('error', '테넌트를 먼저 선택해주세요.');
}
@@ -538,6 +548,7 @@ public function bulkCopy(Request $request): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '복사할 코드를 선택해주세요.'], 400);
}
return redirect()->back()->with('error', '복사할 코드를 선택해주세요.');
}
} else {
@@ -570,6 +581,7 @@ public function bulkCopy(Request $request): RedirectResponse|JsonResponse
if ($exists) {
$skippedCount++;
continue;
}
@@ -593,6 +605,7 @@ public function bulkCopy(Request $request): RedirectResponse|JsonResponse
if ($request->ajax()) {
return response()->json(['error' => '복사 중 오류가 발생했습니다.'], 500);
}
return redirect()->back()->with('error', '복사 중 오류가 발생했습니다.');
}
@@ -624,6 +637,7 @@ public function promoteToGlobal(Request $request, int $id): RedirectResponse|Jso
if ($request->ajax()) {
return response()->json(['error' => '본사 또는 슈퍼관리자만 글로벌로 복사할 수 있습니다.'], 403);
}
return redirect()->back()->with('error', '본사 또는 슈퍼관리자만 글로벌로 복사할 수 있습니다.');
}
@@ -632,6 +646,7 @@ public function promoteToGlobal(Request $request, int $id): RedirectResponse|Jso
if ($request->ajax()) {
return response()->json(['error' => '테넌트 코드를 찾을 수 없습니다.'], 404);
}
return redirect()->back()->with('error', '테넌트 코드를 찾을 수 없습니다.');
}
@@ -646,6 +661,7 @@ public function promoteToGlobal(Request $request, int $id): RedirectResponse|Jso
if ($request->ajax()) {
return response()->json(['error' => '이미 동일한 글로벌 코드가 존재합니다.'], 400);
}
return redirect()->back()->with('error', '이미 동일한 글로벌 코드가 존재합니다.');
}
@@ -680,6 +696,7 @@ public function destroy(Request $request, int $id): RedirectResponse|JsonRespons
if ($request->ajax()) {
return response()->json(['error' => '테넌트를 먼저 선택해주세요.'], 400);
}
return redirect()->back()->with('error', '테넌트를 먼저 선택해주세요.');
}
@@ -690,6 +707,7 @@ public function destroy(Request $request, int $id): RedirectResponse|JsonRespons
if ($request->ajax()) {
return response()->json(['error' => '코드를 찾을 수 없습니다.'], 404);
}
return redirect()->back()->with('error', '코드를 찾을 수 없습니다.');
}
@@ -702,6 +720,7 @@ public function destroy(Request $request, int $id): RedirectResponse|JsonRespons
if ($request->ajax()) {
return response()->json(['error' => '글로벌 코드는 본사만 삭제할 수 있습니다.'], 403);
}
return redirect()->back()->with('error', '글로벌 코드는 본사만 삭제할 수 있습니다.');
}
@@ -710,6 +729,7 @@ public function destroy(Request $request, int $id): RedirectResponse|JsonRespons
if ($request->ajax()) {
return response()->json(['error' => '다른 테넌트의 코드는 삭제할 수 없습니다.'], 403);
}
return redirect()->back()->with('error', '다른 테넌트의 코드는 삭제할 수 없습니다.');
}
}

View File

@@ -21,6 +21,7 @@ class CommonCodeSyncController extends Controller
protected function getTenantId(): int
{
$tenantId = session('selected_tenant_id');
return ($tenantId && $tenantId !== 'all') ? (int) $tenantId : 1;
}
@@ -153,6 +154,7 @@ public function import(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -170,7 +172,7 @@ public function import(Request $request): JsonResponse
return response()->json([
'success' => true,
'message' => "{$imported}개 코드가 동기화되었습니다." . ($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'message' => "{$imported}개 코드가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'imported' => $imported,
'skipped' => $skipped,
]);
@@ -199,6 +201,7 @@ public function push(Request $request): JsonResponse
$localCodes = $this->getCodeList($validated['type']);
$selectedCodes = array_filter($localCodes, function ($code) use ($validated) {
$key = $this->makeCodeKey($code);
return in_array($key, $validated['code_keys']);
});
@@ -211,7 +214,7 @@ public function push(Request $request): JsonResponse
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->post(rtrim($env['url'], '/') . '/common-code-sync/import', [
])->post(rtrim($env['url'], '/').'/common-code-sync/import', [
'codes' => array_values($selectedCodes),
]);
@@ -228,7 +231,7 @@ public function push(Request $request): JsonResponse
'error' => $response->json('error', '원격 서버 오류'),
], $response->status());
} catch (\Exception $e) {
return response()->json(['error' => '연결 실패: ' . $e->getMessage()], 500);
return response()->json(['error' => '연결 실패: '.$e->getMessage()], 500);
}
}
@@ -261,6 +264,7 @@ public function pull(Request $request): JsonResponse
// 선택된 코드만 필터링
$selectedCodes = array_filter($remoteCodes, function ($code) use ($validated) {
$key = $this->makeCodeKey($code);
return in_array($key, $validated['code_keys']);
});
@@ -282,6 +286,7 @@ public function pull(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}
@@ -299,7 +304,7 @@ public function pull(Request $request): JsonResponse
return response()->json([
'success' => true,
'message' => "{$imported}개 코드가 동기화되었습니다." . ($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'message' => "{$imported}개 코드가 동기화되었습니다.".($skipped > 0 ? " ({$skipped}개 스킵)" : ''),
'imported' => $imported,
'skipped' => $skipped,
]);
@@ -307,7 +312,8 @@ public function pull(Request $request): JsonResponse
/**
* 코드 목록 조회
* @param string $type 'global', 'tenant', or 'all'
*
* @param string $type 'global', 'tenant', or 'all'
*/
private function getCodeList(string $type = 'all'): array
{
@@ -369,12 +375,12 @@ private function fetchRemoteCodes(array $env, string $type = 'all'): array
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->timeout(10)->get(rtrim($env['url'], '/') . '/common-code-sync/export', [
])->timeout(10)->get(rtrim($env['url'], '/').'/common-code-sync/export', [
'type' => $type,
]);
if (! $response->successful()) {
throw new \Exception('API 오류: HTTP ' . $response->status());
throw new \Exception('API 오류: HTTP '.$response->status());
}
$data = $response->json();
@@ -393,6 +399,7 @@ private function fetchRemoteCodes(array $env, string $type = 'all'): array
private function makeCodeKey(array $code): string
{
$tenantPart = $code['tenant_id'] ?? 'global';
return "{$tenantPart}:{$code['code_group']}:{$code['code']}";
}
@@ -401,8 +408,8 @@ private function makeCodeKey(array $code): string
*/
private function calculateDiff(array $localCodes, array $remoteCodes): array
{
$localKeys = array_map(fn($c) => $this->makeCodeKey($c), $localCodes);
$remoteKeys = array_map(fn($c) => $this->makeCodeKey($c), $remoteCodes);
$localKeys = array_map(fn ($c) => $this->makeCodeKey($c), $localCodes);
$remoteKeys = array_map(fn ($c) => $this->makeCodeKey($c), $remoteCodes);
return [
'local_only' => array_values(array_diff($localKeys, $remoteKeys)),

View File

@@ -26,7 +26,7 @@ public function inquiry(Request $request): View|Response
return response('', 200)->header('HX-Redirect', route('credit.inquiry.index'));
}
$service = new CooconService();
$service = new CooconService;
$hasConfig = $service->hasConfig();
// 검색 조건
@@ -42,10 +42,10 @@ public function inquiry(Request $request): View|Response
// 기간 검색
if ($request->filled('start_date')) {
$query->where('inquired_at', '>=', $request->input('start_date') . ' 00:00:00');
$query->where('inquired_at', '>=', $request->input('start_date').' 00:00:00');
}
if ($request->filled('end_date')) {
$query->where('inquired_at', '<=', $request->input('end_date') . ' 23:59:59');
$query->where('inquired_at', '<=', $request->input('end_date').' 23:59:59');
}
// 이슈 있는 것만
@@ -79,9 +79,9 @@ public function search(Request $request): JsonResponse
$companyKey = preg_replace('/[^0-9]/', '', $request->input('company_key'));
$cooconService = new CooconService();
$cooconService = new CooconService;
if (!$cooconService->hasConfig()) {
if (! $cooconService->hasConfig()) {
return response()->json([
'success' => false,
'error' => '쿠콘 API 설정이 없습니다. 설정을 먼저 등록해주세요.',
@@ -92,7 +92,7 @@ public function search(Request $request): JsonResponse
$apiResult = $cooconService->getAllCreditInfo($companyKey);
// 국세청 사업자등록 상태 조회
$ntsService = new NtsBusinessService();
$ntsService = new NtsBusinessService;
$ntsResult = $ntsService->getBusinessStatus($companyKey);
// DB에 저장 (tenant_id는 세션에서 가져옴)
@@ -354,14 +354,14 @@ public function toggleConfig(int $id): JsonResponse
{
$config = CooconConfig::findOrFail($id);
if (!$config->is_active) {
if (! $config->is_active) {
// 같은 환경에서 활성화된 설정이 이미 있으면 비활성화
CooconConfig::where('environment', $config->environment)
->where('is_active', true)
->update(['is_active' => false]);
}
$config->update(['is_active' => !$config->is_active]);
$config->update(['is_active' => ! $config->is_active]);
return response()->json([
'success' => true,
@@ -380,9 +380,9 @@ public function testConnection(Request $request): JsonResponse
]);
$companyKey = $request->input('company_key');
$service = new CooconService();
$service = new CooconService;
if (!$service->hasConfig()) {
if (! $service->hasConfig()) {
return response()->json([
'success' => false,
'error' => '쿠콘 API 설정이 없습니다.',

View File

@@ -44,8 +44,8 @@ public function index(Request $request): View|Response
$startDate = "{$year}-01-01 00:00:00";
$endDate = "{$year}-12-31 23:59:59";
} elseif ($viewType === 'custom') {
$startDate = $request->input('start_date', date('Y-m-01')) . ' 00:00:00';
$endDate = $request->input('end_date', date('Y-m-t')) . ' 23:59:59';
$startDate = $request->input('start_date', date('Y-m-01')).' 00:00:00';
$endDate = $request->input('end_date', date('Y-m-t')).' 23:59:59';
} else {
$startDate = "{$year}-{$month}-01 00:00:00";
$endDate = date('Y-m-t 23:59:59', strtotime($startDate));
@@ -116,7 +116,7 @@ private function getAllTenantsUsage(string $startDate, string $endDate, string $
$tenantId = $row->tenant_id;
$month = $row->month;
if (!isset($monthlyData[$tenantId])) {
if (! isset($monthlyData[$tenantId])) {
$monthlyData[$tenantId] = [];
}
$monthlyData[$tenantId][$month] = $row->total_count;
@@ -173,7 +173,7 @@ private function getAllTenantsUsage(string $startDate, string $endDate, string $
}
// 정렬: 조회 건수 내림차순
usort($details, fn($a, $b) => $b['count'] - $a['count']);
usort($details, fn ($a, $b) => $b['count'] - $a['count']);
return [
'total_count' => $totalCount,
@@ -228,7 +228,7 @@ private function getSingleTenantUsage(int $tenantId, string $startDate, string $
$existingMonths = collect($details)->pluck('month')->toArray();
for ($m = 1; $m <= 12; $m++) {
$monthKey = sprintf('%s-%02d', $year, $m);
if (!in_array($monthKey, $existingMonths)) {
if (! in_array($monthKey, $existingMonths)) {
$details[] = [
'tenant_id' => $tenantId,
'tenant_name' => $tenant?->company_name ?? '(삭제됨)',
@@ -241,7 +241,7 @@ private function getSingleTenantUsage(int $tenantId, string $startDate, string $
}
}
// 월 순서로 정렬
usort($details, fn($a, $b) => strcmp($a['month'], $b['month']));
usort($details, fn ($a, $b) => strcmp($a['month'], $b['month']));
}
return [
@@ -257,6 +257,7 @@ private function getSingleTenantUsage(int $tenantId, string $startDate, string $
private function calculateFee(int $count): int
{
$paidCount = max(0, $count - self::FREE_MONTHLY_QUOTA);
return $paidCount * self::ADDITIONAL_FEE_PER_INQUIRY;
}
}

View File

@@ -7,10 +7,9 @@
use App\Models\System\Schedule;
use App\Services\GoogleCloudStorageService;
use Carbon\Carbon;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
@@ -174,7 +173,7 @@ public function uploadFiles(Request $request, int $scheduleId, GoogleCloudStorag
foreach ($request->file('files') as $file) {
$originalName = $file->getClientOriginalName();
$storedName = Str::random(40) . '.' . $file->getClientOriginalExtension();
$storedName = Str::random(40).'.'.$file->getClientOriginalExtension();
$storagePath = "schedules/{$tenantId}/{$schedule->id}/{$storedName}";
// 로컬(tenant 디스크) 저장
@@ -215,7 +214,7 @@ public function uploadFiles(Request $request, int $scheduleId, GoogleCloudStorag
return response()->json([
'success' => true,
'message' => count($uploaded) . '개 파일이 업로드되었습니다.',
'message' => count($uploaded).'개 파일이 업로드되었습니다.',
'files' => $uploaded,
]);
}
@@ -274,9 +273,16 @@ public function downloadFile(int $scheduleId, int $fileId)
*/
private function determineFileType(string $mimeType): string
{
if (str_starts_with($mimeType, 'image/')) return 'image';
if (str_contains($mimeType, 'spreadsheet') || str_contains($mimeType, 'excel')) return 'excel';
if (str_contains($mimeType, 'zip') || str_contains($mimeType, 'rar') || str_contains($mimeType, 'archive')) return 'archive';
if (str_starts_with($mimeType, 'image/')) {
return 'image';
}
if (str_contains($mimeType, 'spreadsheet') || str_contains($mimeType, 'excel')) {
return 'excel';
}
if (str_contains($mimeType, 'zip') || str_contains($mimeType, 'rar') || str_contains($mimeType, 'archive')) {
return 'archive';
}
return 'document';
}

View File

@@ -461,13 +461,13 @@ public function users(): JsonResponse
// 세션에서 직접 테넌트 ID 조회 (관리자가 선택한 테넌트)
$selectedTenantId = session('selected_tenant_id');
if (!$selectedTenantId) {
if (! $selectedTenantId) {
// 테넌트가 선택되지 않은 경우 로그인 사용자의 기본 테넌트 사용
$currentTenant = auth()->user()->tenants()
->where('is_default', true)
->first() ?? auth()->user()->tenants()->first();
if (!$currentTenant) {
if (! $currentTenant) {
return response()->json([]);
}
@@ -477,7 +477,7 @@ public function users(): JsonResponse
// Tenant 모델에서 직접 조회 (사용자의 테넌트 관계와 무관하게)
$tenant = \App\Models\Tenants\Tenant::find($selectedTenantId);
if (!$tenant) {
if (! $tenant) {
return response()->json([]);
}
@@ -510,7 +510,7 @@ public function issueToken(Request $request): JsonResponse
$user = \App\Models\User::find($validated['user_id']);
if (!$user) {
if (! $user) {
return response()->json(['error' => '사용자를 찾을 수 없습니다.'], 404);
}

View File

@@ -248,6 +248,7 @@ public function show(int $id): View
->filter(fn ($lot) => $lot->total_qty < 0)
->map(function ($lot) {
$lot->total_qty = abs($lot->total_qty);
return $lot;
})
->values();

View File

@@ -332,7 +332,7 @@ private function resolveDisplayText(?string $sourceTable, int $linkableId, ?arra
$title = is_object($record) ? ($record->$titleField ?? '') : ($record->$titleField ?? '');
$subtitle = $subtitleField ? (is_object($record) ? ($record->$subtitleField ?? '') : ($record->$subtitleField ?? '')) : '';
return $title . ($subtitle ? " ({$subtitle})" : '');
return $title.($subtitle ? " ({$subtitle})" : '');
} catch (\Exception $e) {
return "ID: {$linkableId}";
}

View File

@@ -1059,7 +1059,7 @@ private function sendAlimtalk(
// 등록된 버튼 URL을 그대로 사용 (동적 URL 사용 시 템플릿 불일치 오류)
$buttons = ! empty($templateButtons) ? $templateButtons : [
['Name' => '계약서 확인하기', 'ButtonType' => 'WL',
'Url1' => 'https://mng.codebridge-x.com', 'Url2' => 'https://mng.codebridge-x.com'],
'Url1' => 'https://mng.codebridge-x.com', 'Url2' => 'https://mng.codebridge-x.com'],
];
$receiverNum = preg_replace('/[^0-9]/', '', $signer->phone);

View File

@@ -19,8 +19,8 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('merchant', 'like', "%{$search}%")
->orWhere('memo', 'like', "%{$search}%")
->orWhere('approval_no', 'like', "%{$search}%");
->orWhere('memo', 'like', "%{$search}%")
->orWhere('approval_no', 'like', "%{$search}%");
});
}
@@ -72,7 +72,7 @@ public function index(Request $request): JsonResponse
'total' => $transactions->count(),
'totalAmount' => $transactions->sum('amount'),
'approvedAmount' => $transactions->where('status', 'approved')->sum('amount'),
'cancelledAmount' => $transactions->where('status', 'cancelled')->sum(fn($t) => abs($t['amount'])),
'cancelledAmount' => $transactions->where('status', 'cancelled')->sum(fn ($t) => abs($t['amount'])),
];
// 카드 목록

View File

@@ -17,14 +17,16 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('consultant', 'like', "%{$search}%")
->orWhere('customer', 'like', "%{$search}%");
->orWhere('customer', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
$fees = $query->orderBy('date', 'desc')->get()->map(fn($item) => [
$fees = $query->orderBy('date', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'date' => $item->date?->format('Y-m-d'),
'consultant' => $item->consultant, 'customer' => $item->customer,
'service' => $item->service, 'hours' => $item->hours,
@@ -82,6 +84,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
ConsultingFee::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '컨설팅비가 삭제되었습니다.']);
}
}

View File

@@ -227,7 +227,7 @@ public function summary(): JsonResponse
$adjustedDate = $this->getAdjustedPaymentDate($tenantId, $nextMonth->year, $nextMonth->month, $paymentDay);
}
$isAdjusted = !$originalDate->isSameDay($adjustedDate);
$isAdjusted = ! $originalDate->isSameDay($adjustedDate);
// 청구기간: 결제일 기준 전월 1일 ~ 결제일
$billingStart = $adjustedDate->copy()->subMonth()->startOfMonth();
@@ -283,7 +283,7 @@ public function updatePrepayment(Request $request): JsonResponse
$tenantId = session('selected_tenant_id', 1);
$yearMonth = $this->getBillingYearMonth($tenantId);
$items = collect($request->input('items', []))->filter(fn($item) => ($item['amount'] ?? 0) > 0)->values()->toArray();
$items = collect($request->input('items', []))->filter(fn ($item) => ($item['amount'] ?? 0) > 0)->values()->toArray();
$amount = collect($items)->sum('amount');
$prepayment = CorporateCardPrepayment::updateOrCreate(
@@ -328,6 +328,7 @@ private function getBillingYearMonth(int $tenantId): string
private function createPaymentDate(int $year, int $month, int $day): Carbon
{
$maxDay = Carbon::create($year, $month)->daysInMonth;
return Carbon::create($year, $month, min($day, $maxDay));
}
@@ -367,7 +368,7 @@ private function getAdjustedPaymentDate(int $tenantId, int $year, int $month, in
private function calculateBillingUsage(int $tenantId, string $startDate, string $endDate, array $cardNumbers): array
{
// 카드번호 정규화 (하이픈 제거) + 원본↔정규화 매핑
$normalizedNums = array_map(fn($num) => str_replace('-', '', $num), $cardNumbers);
$normalizedNums = array_map(fn ($num) => str_replace('-', '', $num), $cardNumbers);
if (empty($normalizedNums)) {
return ['total' => 0, 'perCard' => []];

View File

@@ -45,8 +45,8 @@ public function list(Request $request): JsonResponse
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('plate_number', 'like', "%{$search}%")
->orWhere('model', 'like', "%{$search}%")
->orWhere('driver', 'like', "%{$search}%");
->orWhere('model', 'like', "%{$search}%")
->orWhere('driver', 'like', "%{$search}%");
});
}

View File

@@ -19,18 +19,22 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('ceo', 'like', "%{$search}%")
->orWhere('manager', 'like', "%{$search}%");
->orWhere('ceo', 'like', "%{$search}%")
->orWhere('manager', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
if ($grade = $request->input('grade')) {
if ($grade !== 'all') $query->where('grade', $grade);
if ($grade !== 'all') {
$query->where('grade', $grade);
}
}
$customers = $query->orderBy('created_at', 'desc')->get()->map(fn($item) => [
$customers = $query->orderBy('created_at', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'name' => $item->name, 'bizNo' => $item->biz_no,
'ceo' => $item->ceo, 'industry' => $item->industry, 'grade' => $item->grade,
'contact' => $item->contact, 'email' => $item->email, 'address' => $item->address,
@@ -90,6 +94,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
Customer::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '고객사가 삭제되었습니다.']);
}
@@ -130,13 +135,14 @@ function ($attribute, $value, $fail) {
return response()->json(['ok' => false, 'message' => $e->getMessage()], 500);
} catch (\Throwable $e) {
Log::error('고객사 OCR 예상치 못한 오류', ['error' => $e->getMessage()]);
return response()->json(['ok' => false, 'message' => 'OCR 처리 중 오류가 발생했습니다.'], 500);
}
}
private function matchIndustry(string $bizType, string $bizItem): string
{
$text = $bizType . ' ' . $bizItem;
$text = $bizType.' '.$bizItem;
$keywords = [
'IT/소프트웨어' => ['소프트웨어', 'IT', '정보통신', '전산', '컴퓨터', '인터넷', '데이터', '프로그램'],
@@ -162,8 +168,13 @@ private function buildCustomerMemo(array $raw): string
$parts = [];
$bizType = trim($raw['biz_type'] ?? '');
$bizItem = trim($raw['biz_item'] ?? '');
if ($bizType) $parts[] = "[업태] {$bizType}";
if ($bizItem) $parts[] = "[종목] {$bizItem}";
if ($bizType) {
$parts[] = "[업태] {$bizType}";
}
if ($bizItem) {
$parts[] = "[종목] {$bizItem}";
}
return implode(' / ', $parts);
}
}

View File

@@ -20,10 +20,12 @@ public function index(Request $request): JsonResponse
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
$settlements = $query->orderBy('created_at', 'desc')->get()->map(fn($item) => [
$settlements = $query->orderBy('created_at', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'period' => $item->period,
'customer' => $item->customer, 'totalSales' => $item->total_sales,
'commission' => $item->commission, 'expense' => $item->expense,
@@ -85,6 +87,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
CustomerSettlement::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '정산이 삭제되었습니다.']);
}
}

View File

@@ -3,13 +3,12 @@
namespace App\Http\Controllers\Finance;
use App\Http\Controllers\Controller;
use App\Models\Finance\DailyFundTransaction;
use App\Models\Finance\DailyFundMemo;
use App\Models\Barobill\BankTransaction as BarobillBankTransaction;
use App\Models\Barobill\BankTransactionOverride;
use App\Models\Finance\DailyFundMemo;
use App\Models\Finance\DailyFundTransaction;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class DailyFundController extends Controller
{
@@ -179,14 +178,14 @@ public function periodReport(Request $request): JsonResponse
->whereBetween('trans_date', [$startDateYmd, $endDateYmd])
->orderBy('id', 'desc') // 최신 ID 우선 (올바른 잔액)
->get()
->unique(fn($tx) => $tx->unique_key)
->unique(fn ($tx) => $tx->unique_key)
->sortByDesc('trans_date')
->sortByDesc(fn($tx) => $tx->trans_date . $tx->trans_time)
->sortByDesc(fn ($tx) => $tx->trans_date.$tx->trans_time)
->values();
// 오버라이드 데이터 병합 (수정된 적요/내용)
if ($transactions->isNotEmpty()) {
$uniqueKeys = $transactions->map(fn($t) => $t->unique_key)->toArray();
$uniqueKeys = $transactions->map(fn ($t) => $t->unique_key)->toArray();
$overrides = BankTransactionOverride::getByUniqueKeys($tenantId, $uniqueKeys);
$transactions = $transactions->map(function ($tx) use ($overrides) {
@@ -199,6 +198,7 @@ public function periodReport(Request $request): JsonResponse
$tx->cast = $override->modified_cast;
}
}
return $tx;
});
}
@@ -211,7 +211,7 @@ public function periodReport(Request $request): JsonResponse
$date = $tx->trans_date;
$accountNum = $tx->bank_account_num;
if (!isset($dailyData[$date])) {
if (! isset($dailyData[$date])) {
$dailyData[$date] = [
'date' => $date,
'dateFormatted' => $this->formatDateKorean($date),
@@ -224,7 +224,7 @@ public function periodReport(Request $request): JsonResponse
}
// 계좌별 데이터 집계
if (!isset($dailyData[$date]['accounts'][$accountNum])) {
if (! isset($dailyData[$date]['accounts'][$accountNum])) {
$dailyData[$date]['accounts'][$accountNum] = [
'bankName' => $tx->bank_name,
'accountNum' => $accountNum,

View File

@@ -17,17 +17,21 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('vendor', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
->orWhere('description', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
if ($category = $request->input('category')) {
if ($category !== 'all') $query->where('category', $category);
if ($category !== 'all') {
$query->where('category', $category);
}
}
$expenses = $query->orderBy('date', 'desc')->get()->map(fn($item) => [
$expenses = $query->orderBy('date', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'date' => $item->date?->format('Y-m-d'),
'vendor' => $item->vendor, 'description' => $item->description,
'category' => $item->category, 'amount' => $item->amount,
@@ -87,6 +91,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
Expense::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '지출이 삭제되었습니다.']);
}
}

View File

@@ -7,7 +7,6 @@
use App\Models\Barobill\BankTransactionOverride;
use App\Models\Barobill\CardTransaction as BarobillCardTransaction;
use App\Models\Finance\BankAccount;
use App\Models\Finance\FundSchedule;
use App\Services\BankAccountService;
use App\Services\FundScheduleService;
use Illuminate\Contracts\View\View;
@@ -53,7 +52,7 @@ public function index(): View
// 오버라이드 데이터 병합 (수정된 적요/내용)
if ($recentTransactions->isNotEmpty()) {
$uniqueKeys = $recentTransactions->map(fn($t) => $t->unique_key)->toArray();
$uniqueKeys = $recentTransactions->map(fn ($t) => $t->unique_key)->toArray();
$overrides = BankTransactionOverride::getByUniqueKeys($tenantId, $uniqueKeys);
$recentTransactions = $recentTransactions->map(function ($transaction) use ($overrides) {
@@ -71,6 +70,7 @@ public function index(): View
} else {
$transaction->is_overridden = false;
}
return $transaction;
});
}

View File

@@ -17,13 +17,21 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('customer', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
->orWhere('description', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) { if ($status !== 'all') $query->where('status', $status); }
if ($category = $request->input('category')) { if ($category !== 'all') $query->where('category', $category); }
if ($status = $request->input('status')) {
if ($status !== 'all') {
$query->where('status', $status);
}
}
if ($category = $request->input('category')) {
if ($category !== 'all') {
$query->where('category', $category);
}
}
$incomes = $query->orderBy('date', 'desc')->get()->map(fn($item) => [
$incomes = $query->orderBy('date', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'date' => $item->date?->format('Y-m-d'),
'customer' => $item->customer, 'description' => $item->description,
'category' => $item->category, 'amount' => $item->amount,
@@ -80,6 +88,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
Income::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '수입이 삭제되었습니다.']);
}
}

View File

@@ -17,17 +17,21 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('vendor', 'like', "%{$search}%")
->orWhere('item', 'like', "%{$search}%");
->orWhere('item', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
if ($category = $request->input('category')) {
if ($category !== 'all') $query->where('category', $category);
if ($category !== 'all') {
$query->where('category', $category);
}
}
$purchases = $query->orderBy('date', 'desc')->get()->map(fn($item) => [
$purchases = $query->orderBy('date', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'date' => $item->date?->format('Y-m-d'),
'vendor' => $item->vendor, 'item' => $item->item,
'category' => $item->category, 'amount' => $item->amount,
@@ -85,6 +89,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
Purchase::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '매입이 삭제되었습니다.']);
}
}

View File

@@ -18,7 +18,7 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('customer_name', 'like', "%{$search}%")
->orWhere('product_name', 'like', "%{$search}%");
->orWhere('product_name', 'like', "%{$search}%");
});
}

View File

@@ -27,7 +27,7 @@ public function __construct(
public function index(Request $request): View|Response
{
// HTMX 요청 시 전체 페이지로 리다이렉트 (JavaScript 필요)
if ($request->header('HX-Request') && !$request->header('HX-Boosted')) {
if ($request->header('HX-Request') && ! $request->header('HX-Boosted')) {
return response('', 200)->header('HX-Redirect', route('finance.sales-commissions.index'));
}
@@ -77,7 +77,7 @@ public function show(int $id): JsonResponse
{
$commission = $this->service->getCommissionById($id);
if (!$commission) {
if (! $commission) {
return response()->json([
'success' => false,
'message' => '정산 정보를 찾을 수 없습니다.',
@@ -377,9 +377,9 @@ public function export(Request $request)
// 전체 데이터 조회 (페이지네이션 없이)
$commissions = SalesCommission::query()
->with(['tenant', 'partner.user', 'manager'])
->when(!empty($filters['status']), fn($q) => $q->where('status', $filters['status']))
->when(!empty($filters['payment_type']), fn($q) => $q->where('payment_type', $filters['payment_type']))
->when(!empty($filters['partner_id']), fn($q) => $q->where('partner_id', $filters['partner_id']))
->when(! empty($filters['status']), fn ($q) => $q->where('status', $filters['status']))
->when(! empty($filters['payment_type']), fn ($q) => $q->where('payment_type', $filters['payment_type']))
->when(! empty($filters['partner_id']), fn ($q) => $q->where('partner_id', $filters['partner_id']))
->forScheduledMonth($year, $month)
->orderBy('scheduled_payment_date')
->get();
@@ -402,7 +402,7 @@ public function export(Request $request)
fputcsv($file, [
'번호', '테넌트', '입금구분', '입금액', '입금일',
'기준액', '영업파트너', '파트너수당', '매니저', '매니저수당',
'지급예정일', '상태', '실제지급일'
'지급예정일', '상태', '실제지급일',
]);
// 데이터

View File

@@ -17,17 +17,21 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('customer', 'like', "%{$search}%")
->orWhere('project', 'like', "%{$search}%");
->orWhere('project', 'like', "%{$search}%");
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
if ($type = $request->input('type')) {
if ($type !== 'all') $query->where('type', $type);
if ($type !== 'all') {
$query->where('type', $type);
}
}
$records = $query->orderBy('date', 'desc')->get()->map(fn($item) => [
$records = $query->orderBy('date', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'date' => $item->date?->format('Y-m-d'),
'customer' => $item->customer, 'project' => $item->project,
'type' => $item->type, 'taxType' => $item->tax_type ?? 'taxable',
@@ -93,6 +97,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
SalesRecord::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '매출이 삭제되었습니다.']);
}
}

View File

@@ -20,10 +20,12 @@ public function index(Request $request): JsonResponse
});
}
if ($status = $request->input('status')) {
if ($status !== 'all') $query->where('status', $status);
if ($status !== 'all') {
$query->where('status', $status);
}
}
$subscriptions = $query->orderBy('created_at', 'desc')->get()->map(fn($item) => [
$subscriptions = $query->orderBy('created_at', 'desc')->get()->map(fn ($item) => [
'id' => $item->id, 'customer' => $item->customer,
'plan' => $item->plan, 'monthlyFee' => $item->monthly_fee,
'billingCycle' => $item->billing_cycle,
@@ -87,6 +89,7 @@ public function destroy(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
Subscription::forTenant($tenantId)->findOrFail($id)->delete();
return response()->json(['success' => true, 'message' => '구독이 삭제되었습니다.']);
}
}

View File

@@ -19,8 +19,8 @@ public function index(Request $request): JsonResponse
if ($search = $request->input('search')) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('ceo', 'like', "%{$search}%")
->orWhere('manager', 'like', "%{$search}%");
->orWhere('ceo', 'like', "%{$search}%")
->orWhere('manager', 'like', "%{$search}%");
});
}

View File

@@ -3,11 +3,11 @@
namespace App\Http\Controllers\Finance;
use App\Http\Controllers\Controller;
use App\Models\Finance\VatRecord;
use App\Models\Barobill\CardTransaction as BarobillCardTransaction;
use App\Models\Barobill\CardTransactionSplit;
use App\Models\Barobill\CardTransactionHide;
use App\Models\Barobill\CardTransactionSplit;
use App\Models\Barobill\HometaxInvoice;
use App\Models\Finance\VatRecord;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -43,7 +43,7 @@ public function index(Request $request): JsonResponse
$hometaxSalesRecords = $hometaxSales->map(function ($inv) use ($period, $taxTypeMap) {
return [
'id' => 'hometax_' . $inv->id,
'id' => 'hometax_'.$inv->id,
'period' => $period,
'type' => 'sales',
'taxType' => $taxTypeMap[$inv->tax_type] ?? 'taxable',
@@ -69,7 +69,7 @@ public function index(Request $request): JsonResponse
$hometaxPurchaseRecords = $hometaxPurchases->map(function ($inv) use ($period, $taxTypeMap) {
return [
'id' => 'hometax_' . $inv->id,
'id' => 'hometax_'.$inv->id,
'period' => $period,
'type' => 'purchase',
'taxType' => $taxTypeMap[$inv->tax_type] ?? 'taxable',
@@ -104,7 +104,7 @@ public function index(Request $request): JsonResponse
foreach ($splitsByKey as $fullKey => $splits) {
$parts = explode('|', $fullKey);
if (count($parts) >= 3) {
$partialKey = $parts[0] . '|' . $parts[1] . '|' . $parts[2];
$partialKey = $parts[0].'|'.$parts[1].'|'.$parts[2];
$splitsByPartialKey[$partialKey] = $splits;
}
}
@@ -117,8 +117,8 @@ public function index(Request $request): JsonResponse
// 분개 매칭: 정확한 키 → 부분키(금액 제외) 순으로 시도
$splits = $splitsByKey[$card->unique_key] ?? null;
if (!$splits) {
$cardPartialKey = $card->card_num . '|' . $card->use_dt . '|' . $card->approval_num;
if (! $splits) {
$cardPartialKey = $card->card_num.'|'.$card->use_dt.'|'.$card->approval_num;
$splits = $splitsByPartialKey[$cardPartialKey] ?? null;
}
@@ -127,7 +127,7 @@ public function index(Request $request): JsonResponse
foreach ($splits as $split) {
if ($split->deduction_type === 'deductible') {
$cardRecords->push([
'id' => 'card_split_' . $split->id,
'id' => 'card_split_'.$split->id,
'period' => $period,
'type' => 'purchase',
'taxType' => 'taxable',
@@ -153,7 +153,7 @@ public function index(Request $request): JsonResponse
$effectiveTax = $card->modified_tax ?? $card->tax;
$cardRecords->push([
'id' => 'card_' . $card->id,
'id' => 'card_'.$card->id,
'period' => $period,
'type' => 'purchase',
'taxType' => 'taxable',
@@ -269,13 +269,13 @@ public function index(Request $request): JsonResponse
// 확정(C) 기간이면 대응하는 예정(P)의 netVat를 계산
if ($period && str_ends_with($period, 'C')) {
try {
$prelimPeriod = substr($period, 0, -1) . 'P';
$prelimPeriod = substr($period, 0, -1).'P';
$stats['preliminaryVat'] = $this->calculatePeriodNetVat($tenantId, $prelimPeriod);
} catch (\Throwable $e) {
\Log::error('예정 세액 계산 실패', [
'message' => $e->getMessage(),
'file' => $e->getFile() . ':' . $e->getLine(),
'trace' => array_slice(array_map(fn($t) => ($t['file'] ?? '') . ':' . ($t['line'] ?? '') . ' ' . ($t['function'] ?? ''), $e->getTrace()), 0, 5),
'file' => $e->getFile().':'.$e->getLine(),
'trace' => array_slice(array_map(fn ($t) => ($t['file'] ?? '').':'.($t['line'] ?? '').' '.($t['function'] ?? ''), $e->getTrace()), 0, 5),
'tenant_id' => $tenantId,
'period' => $prelimPeriod ?? null,
]);
@@ -385,7 +385,7 @@ public function destroy(int $id): JsonResponse
private function calculatePeriodNetVat(int $tenantId, string $period): int
{
[$startDate, $endDate] = $this->periodToDateRange($period);
if (!$startDate || !$endDate) {
if (! $startDate || ! $endDate) {
return 0;
}
@@ -422,7 +422,7 @@ private function calculatePeriodNetVat(int $tenantId, string $period): int
foreach ($splitsByKey as $fullKey => $splits) {
$parts = explode('|', $fullKey);
if (count($parts) >= 3) {
$partialKey = $parts[0] . '|' . $parts[1] . '|' . $parts[2];
$partialKey = $parts[0].'|'.$parts[1].'|'.$parts[2];
$splitsByPartialKey[$partialKey] = $splits;
}
}
@@ -433,8 +433,8 @@ private function calculatePeriodNetVat(int $tenantId, string $period): int
}
$splits = $splitsByKey[$card->unique_key] ?? null;
if (!$splits) {
$cardPartialKey = $card->card_num . '|' . $card->use_dt . '|' . $card->approval_num;
if (! $splits) {
$cardPartialKey = $card->card_num.'|'.$card->use_dt.'|'.$card->approval_num;
$splits = $splitsByPartialKey[$cardPartialKey] ?? null;
}

View File

@@ -71,10 +71,10 @@ public function list(Request $request): JsonResponse
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('driver_name', 'like', "%{$search}%")
->orWhere('department', 'like', "%{$search}%")
->orWhere('departure_name', 'like', "%{$search}%")
->orWhere('arrival_name', 'like', "%{$search}%")
->orWhere('note', 'like', "%{$search}%");
->orWhere('department', 'like', "%{$search}%")
->orWhere('departure_name', 'like', "%{$search}%")
->orWhere('arrival_name', 'like', "%{$search}%")
->orWhere('note', 'like', "%{$search}%");
});
}
@@ -233,9 +233,9 @@ public function summary(Request $request): JsonResponse
COUNT(*) as count,
SUM(distance_km) as total_distance
')
->groupBy('trip_type')
->get()
->keyBy('trip_type');
->groupBy('trip_type')
->get()
->keyBy('trip_type');
$tripTypes = VehicleLog::getTripTypes();
$result = [];

View File

@@ -71,8 +71,8 @@ public function list(Request $request): JsonResponse
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('description', 'like', "%{$search}%")
->orWhere('vendor', 'like', "%{$search}%")
->orWhere('memo', 'like', "%{$search}%");
->orWhere('vendor', 'like', "%{$search}%")
->orWhere('memo', 'like', "%{$search}%");
});
}

View File

@@ -43,7 +43,7 @@ public function show(int $id): JsonResponse
{
$photo = ConstructionSitePhoto::with(['user', 'rows'])->find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -77,7 +77,7 @@ public function uploadPhoto(Request $request, int $id, int $rowId): JsonResponse
{
$photo = ConstructionSitePhoto::find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -88,7 +88,7 @@ public function uploadPhoto(Request $request, int $id, int $rowId): JsonResponse
->where('construction_site_photo_id', $id)
->first();
if (!$row) {
if (! $row) {
return response()->json([
'success' => false,
'message' => '사진 행을 찾을 수 없습니다.',
@@ -102,7 +102,7 @@ public function uploadPhoto(Request $request, int $id, int $rowId): JsonResponse
$result = $this->service->uploadPhoto($row, $request->file('photo'), $validated['type']);
if (!$result) {
if (! $result) {
return response()->json([
'success' => false,
'message' => '사진 업로드에 실패했습니다.',
@@ -120,7 +120,7 @@ public function update(Request $request, int $id): JsonResponse
{
$photo = ConstructionSitePhoto::find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -146,7 +146,7 @@ public function destroy(int $id): JsonResponse
{
$photo = ConstructionSitePhoto::with('rows')->find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -165,7 +165,7 @@ public function deletePhoto(int $id, int $rowId, string $type): JsonResponse
{
$photo = ConstructionSitePhoto::find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -176,14 +176,14 @@ public function deletePhoto(int $id, int $rowId, string $type): JsonResponse
->where('construction_site_photo_id', $id)
->first();
if (!$row) {
if (! $row) {
return response()->json([
'success' => false,
'message' => '사진 행을 찾을 수 없습니다.',
], 404);
}
if (!in_array($type, ['before', 'during', 'after'])) {
if (! in_array($type, ['before', 'during', 'after'])) {
return response()->json([
'success' => false,
'message' => '올바르지 않은 사진 유형입니다.',
@@ -203,7 +203,7 @@ public function downloadPhoto(Request $request, int $id, int $rowId, string $typ
{
$photo = ConstructionSitePhoto::find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -214,23 +214,23 @@ public function downloadPhoto(Request $request, int $id, int $rowId, string $typ
->where('construction_site_photo_id', $id)
->first();
if (!$row) {
if (! $row) {
return response()->json([
'success' => false,
'message' => '사진 행을 찾을 수 없습니다.',
], 404);
}
if (!in_array($type, ['before', 'during', 'after'])) {
if (! in_array($type, ['before', 'during', 'after'])) {
return response()->json([
'success' => false,
'message' => '올바르지 않은 사진 유형입니다.',
], 422);
}
$path = $row->{$type . '_photo_path'};
$path = $row->{$type.'_photo_path'};
if (!$path) {
if (! $path) {
return response()->json([
'success' => false,
'message' => '파일을 찾을 수 없습니다.',
@@ -240,7 +240,7 @@ public function downloadPhoto(Request $request, int $id, int $rowId, string $typ
$googleCloudService = app(GoogleCloudService::class);
$content = $googleCloudService->downloadFromStorage($path);
if (!$content) {
if (! $content) {
return response()->json([
'success' => false,
'message' => '파일 다운로드에 실패했습니다.',
@@ -248,7 +248,7 @@ public function downloadPhoto(Request $request, int $id, int $rowId, string $typ
}
$extension = pathinfo($path, PATHINFO_EXTENSION) ?: 'jpg';
$mimeType = 'image/' . ($extension === 'jpg' ? 'jpeg' : $extension);
$mimeType = 'image/'.($extension === 'jpg' ? 'jpeg' : $extension);
$typeLabel = match ($type) {
'before' => '작업전',
@@ -273,7 +273,7 @@ public function addRow(int $id): JsonResponse
{
$photo = ConstructionSitePhoto::find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -293,7 +293,7 @@ public function deleteRow(int $id, int $rowId): JsonResponse
{
$photo = ConstructionSitePhoto::with('rows')->find($id);
if (!$photo) {
if (! $photo) {
return response()->json([
'success' => false,
'message' => '사진대지를 찾을 수 없습니다.',
@@ -309,7 +309,7 @@ public function deleteRow(int $id, int $rowId): JsonResponse
$row = $photo->rows->firstWhere('id', $rowId);
if (!$row) {
if (! $row) {
return response()->json([
'success' => false,
'message' => '사진 행을 찾을 수 없습니다.',

View File

@@ -2,7 +2,6 @@
namespace App\Http\Controllers\Juil;
use App\Helpers\AiTokenHelper;
use App\Http\Controllers\Controller;
use App\Models\Juil\MeetingMinute;
use App\Services\GoogleCloudService;
@@ -172,7 +171,7 @@ public function saveSegments(Request $request, int $id): JsonResponse
return response()->json([
'success' => false,
'message' => '세그먼트 저장 중 오류가 발생했습니다: ' . $e->getMessage(),
'message' => '세그먼트 저장 중 오류가 발생했습니다: '.$e->getMessage(),
], 500);
}
}
@@ -310,7 +309,7 @@ public function downloadAudio(Request $request, int $id): Response|JsonResponse
}
$extension = pathinfo($meeting->audio_file_path, PATHINFO_EXTENSION) ?: 'webm';
$mimeType = 'audio/' . $extension;
$mimeType = 'audio/'.$extension;
$safeTitle = preg_replace('/[\/\\\\:*?"<>|]/', '_', $meeting->title);
$filename = "{$safeTitle}.{$extension}";

View File

@@ -22,6 +22,7 @@ private function handlePresentationPage(Request $request, string $routeName): ?R
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route($routeName));
}
return null;
}
@@ -33,6 +34,7 @@ public function labor(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.labor'));
}
return view('lab.strategy.labor');
}
@@ -44,6 +46,7 @@ public function chatbot(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.chatbot'));
}
return view('lab.strategy.chatbot');
}
@@ -55,6 +58,7 @@ public function knowledgeSearch(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.knowledge-search'));
}
return view('lab.strategy.knowledge-search');
}
@@ -66,6 +70,7 @@ public function chatbotCompare(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.chatbot-compare'));
}
return view('lab.strategy.chatbot-compare');
}
@@ -77,6 +82,7 @@ public function ragStartups(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.rag-startups'));
}
return view('lab.strategy.rag-startups');
}
@@ -88,6 +94,7 @@ public function douzone(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.douzone'));
}
return view('lab.strategy.douzone');
}
@@ -99,6 +106,7 @@ public function confluenceVsNotion(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.confluence-vs-notion'));
}
return view('lab.strategy.confluence-vs-notion');
}
@@ -110,6 +118,7 @@ public function salesStrategy(Request $request): View|Response
if ($request->header('HX-Request')) {
return response('', 200)->header('HX-Redirect', route('lab.strategy.sales-strategy'));
}
return view('lab.strategy.sales-strategy');
}
}

View File

@@ -21,6 +21,7 @@ class MenuSyncController extends Controller
protected function getTenantId(): int
{
$tenantId = session('selected_tenant_id');
return ($tenantId && $tenantId !== 'all') ? (int) $tenantId : 1;
}
@@ -229,7 +230,7 @@ public function push(Request $request): JsonResponse
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->post(rtrim($env['url'], '/') . '/menu-sync/import', [
])->post(rtrim($env['url'], '/').'/menu-sync/import', [
'menus' => $menuData,
]);
@@ -244,7 +245,7 @@ public function push(Request $request): JsonResponse
'error' => $response->json('error', '원격 서버 오류'),
], $response->status());
} catch (\Exception $e) {
return response()->json(['error' => '연결 실패: ' . $e->getMessage()], 500);
return response()->json(['error' => '연결 실패: '.$e->getMessage()], 500);
}
}
@@ -307,10 +308,11 @@ public function testConnection(Request $request): JsonResponse
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $validated['api_key'],
'Accept' => 'application/json',
])->timeout(10)->get(rtrim($validated['url'], '/') . '/menu-sync/export');
])->timeout(10)->get(rtrim($validated['url'], '/').'/menu-sync/export');
if ($response->successful()) {
$data = $response->json();
return response()->json([
'success' => true,
'message' => '연결 성공',
@@ -321,12 +323,12 @@ public function testConnection(Request $request): JsonResponse
return response()->json([
'success' => false,
'message' => 'API 오류: ' . $response->status(),
'message' => 'API 오류: '.$response->status(),
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => '연결 실패: ' . $e->getMessage(),
'message' => '연결 실패: '.$e->getMessage(),
]);
}
}
@@ -394,12 +396,12 @@ private function fetchRemoteMenus(array $env): array
$response = Http::withHeaders([
'X-Menu-Sync-Key' => $env['api_key'],
'Accept' => 'application/json',
])->timeout(10)->get(rtrim($env['url'], '/') . '/menu-sync/export', [
])->timeout(10)->get(rtrim($env['url'], '/').'/menu-sync/export', [
'tenant_id' => $this->getTenantId(), // 현재 선택된 테넌트 전달
]);
if (! $response->successful()) {
throw new \Exception('API 오류: HTTP ' . $response->status());
throw new \Exception('API 오류: HTTP '.$response->status());
}
$data = $response->json();
@@ -440,6 +442,7 @@ private function flattenMenuNames(array $menus, string $prefix = ''): array
$names = array_merge($names, $this->flattenMenuNames($menu['children'], $fullName));
}
}
return $names;
}

View File

@@ -25,7 +25,7 @@ class AdminProspectController extends Controller
*/
private function checkAdminAccess(): void
{
if (!auth()->user()->isAdmin() && !auth()->user()->isSuperAdmin()) {
if (! auth()->user()->isAdmin() && ! auth()->user()->isSuperAdmin()) {
abort(403, '관리자만 접근할 수 있습니다.');
}
}
@@ -45,7 +45,7 @@ private function getPaymentTypeForField(string $field): string
*/
private function loadMergedCommission(?SalesTenantManagement $management): ?object
{
if (!$management) {
if (! $management) {
return null;
}
@@ -58,12 +58,12 @@ private function loadMergedCommission(?SalesTenantManagement $management): ?obje
$balance = $commissions->firstWhere('payment_type', SalesCommission::PAYMENT_BALANCE);
// balance 레코드가 없으면 기존 단일 레코드 그대로 반환 (하위호환)
if (!$balance) {
if (! $balance) {
return $deposit ?? $commissions->first();
}
// 1차 필드는 deposit, 2차 필드는 balance에서 가져옴
$merged = new \stdClass();
$merged = new \stdClass;
$merged->first_payment_at = $deposit?->first_payment_at;
$merged->first_partner_paid_at = $deposit?->first_partner_paid_at;
$merged->second_payment_at = $balance->second_payment_at;
@@ -118,7 +118,7 @@ public function modalShow(int $id): View
// 파트너 타입
$partnerType = $management->salesPartner?->partner_type;
if (!$partnerType && $prospect->registered_by) {
if (! $partnerType && $prospect->registered_by) {
$partnerType = SalesPartner::where('user_id', $prospect->registered_by)->value('partner_type');
}
$partnerType = $partnerType ?? 'individual';
@@ -161,7 +161,7 @@ private function getIndexData(Request $request): array
$query = TenantProspect::with(['registeredBy', 'tenant']);
// 검색
if (!empty($filters['search'])) {
if (! empty($filters['search'])) {
$search = $filters['search'];
$query->where(function ($q) use ($search) {
$q->where('company_name', 'like', "%{$search}%")
@@ -174,7 +174,7 @@ private function getIndexData(Request $request): array
// 상태 필터
$isProgressCompleteFilter = ($filters['status'] === 'progress_complete');
$isHandoverFilter = ($filters['status'] === 'handover');
if (!empty($filters['status']) && !$isProgressCompleteFilter && !$isHandoverFilter) {
if (! empty($filters['status']) && ! $isProgressCompleteFilter && ! $isHandoverFilter) {
$query->where('status', $filters['status']);
}
@@ -185,7 +185,7 @@ private function getIndexData(Request $request): array
}
// 영업파트너 필터
if (!empty($filters['registered_by'])) {
if (! empty($filters['registered_by'])) {
$query->where('registered_by', $filters['registered_by']);
}
@@ -215,7 +215,7 @@ private function getIndexData(Request $request): array
// 파트너 타입: management → registered_by 순으로 조회
$partnerType = $management?->salesPartner?->partner_type;
if (!$partnerType && $prospect->registered_by) {
if (! $partnerType && $prospect->registered_by) {
$partnerType = SalesPartner::where('user_id', $prospect->registered_by)->value('partner_type');
}
$prospect->partner_type = $partnerType ?? 'individual';
@@ -264,7 +264,7 @@ private function getIndexData(Request $request): array
// 파트너 타입: management → registered_by 순으로 조회
$partnerType = $management?->salesPartner?->partner_type;
if (!$partnerType && $prospect->registered_by) {
if (! $partnerType && $prospect->registered_by) {
$partnerType = SalesPartner::where('user_id', $prospect->registered_by)->value('partner_type');
}
$prospect->partner_type = $partnerType ?? 'individual';
@@ -314,7 +314,7 @@ public function updateHqStatus(int $id, Request $request)
$this->checkAdminAccess();
$request->validate([
'hq_status' => 'required|in:' . implode(',', array_keys(SalesTenantManagement::$hqStatusLabels)),
'hq_status' => 'required|in:'.implode(',', array_keys(SalesTenantManagement::$hqStatusLabels)),
]);
$prospect = TenantProspect::findOrFail($id);
@@ -410,7 +410,7 @@ public function updateCommissionDate(int $id, Request $request)
// 파트너 resolve → 요율 결정
$partner = $management->salesPartner;
if (!$partner && $prospect->registered_by) {
if (! $partner && $prospect->registered_by) {
$partner = SalesPartner::where('user_id', $prospect->registered_by)->first();
}
$isGroup = $partner?->isGroup() ?? false;
@@ -557,7 +557,7 @@ public function updateReferrerCommission(int $id, Request $request)
// 단체 파트너는 수동 수정 불가
$partner = $management->salesPartner;
if (!$partner && $prospect->registered_by) {
if (! $partner && $prospect->registered_by) {
$partner = SalesPartner::where('user_id', $prospect->registered_by)->first();
}
if ($partner && $partner->isGroup()) {
@@ -619,7 +619,7 @@ public function clearCommissionDate(int $id, Request $request)
$prospect = TenantProspect::findOrFail($id);
$management = SalesTenantManagement::where('tenant_prospect_id', $prospect->id)->first();
if (!$management) {
if (! $management) {
return response()->json(['success' => false, 'message' => '관리 정보가 없습니다.']);
}
@@ -632,7 +632,7 @@ public function clearCommissionDate(int $id, Request $request)
->where('payment_type', $paymentType)
->first();
if (!$commission) {
if (! $commission) {
return response()->json(['success' => false, 'message' => '수당 정보가 없습니다.']);
}
$updateData = [$field => null];

View File

@@ -114,7 +114,7 @@ public function uploadAudio(Request $request, GoogleCloudStorageService $gcs): J
// 파일 저장
$file = $request->file('audio');
$fileName = 'audio_' . now()->format('Ymd_His') . '_' . uniqid() . '.' . $file->getClientOriginalExtension();
$fileName = 'audio_'.now()->format('Ymd_His').'_'.uniqid().'.'.$file->getClientOriginalExtension();
$localPath = $file->storeAs("tenant/consultations/{$tenantId}", $fileName, 'local');
$fileSize = $file->getSize();
@@ -154,7 +154,7 @@ public function uploadAudio(Request $request, GoogleCloudStorageService $gcs): J
'formatted_duration' => $consultation->formatted_duration,
'created_by_name' => $consultation->creator->name,
'created_at' => $consultation->created_at->format('Y-m-d H:i'),
'has_gcs' => !empty($gcsUri),
'has_gcs' => ! empty($gcsUri),
],
]);
}
@@ -178,7 +178,7 @@ public function uploadFile(Request $request): JsonResponse
// 파일 저장
$file = $request->file('file');
$originalName = $file->getClientOriginalName();
$fileName = now()->format('Ymd_His') . '_' . uniqid() . '_' . $originalName;
$fileName = now()->format('Ymd_His').'_'.uniqid().'_'.$originalName;
$path = $file->storeAs("tenant/attachments/{$tenantId}", $fileName, 'local');
// DB에 저장
@@ -229,7 +229,7 @@ public function downloadAudio(int $consultationId, GoogleCloudStorageService $gc
// GCS에 저장된 경우 서명된 URL로 리다이렉트
if ($consultation->gcs_uri) {
$objectName = str_replace('gs://' . $gcs->getBucketName() . '/', '', $consultation->gcs_uri);
$objectName = str_replace('gs://'.$gcs->getBucketName().'/', '', $consultation->gcs_uri);
$signedUrl = $gcs->getSignedUrl($objectName, 60);
if ($signedUrl) {
@@ -240,7 +240,7 @@ public function downloadAudio(int $consultationId, GoogleCloudStorageService $gc
// 로컬 파일 다운로드
$localPath = Storage::disk('local')->path($consultation->file_path);
if (!file_exists($localPath)) {
if (! file_exists($localPath)) {
abort(404, '파일을 찾을 수 없습니다.');
}
@@ -250,11 +250,11 @@ public function downloadAudio(int $consultationId, GoogleCloudStorageService $gc
'wav' => 'audio/wav',
'mp3' => 'audio/mpeg',
'ogg' => 'audio/ogg',
'm4a' => 'audio/mp4'
'm4a' => 'audio/mp4',
];
$contentType = $mimeTypes[$extension] ?? 'audio/webm';
$downloadFileName = '상담녹음_' . $consultation->created_at->format('Ymd_His') . '.' . $extension;
$downloadFileName = '상담녹음_'.$consultation->created_at->format('Ymd_His').'.'.$extension;
return response()->download($localPath, $downloadFileName, [
'Content-Type' => $contentType,
@@ -274,7 +274,7 @@ public function downloadFile(int $consultationId): BinaryFileResponse
$localPath = Storage::disk('local')->path($consultation->file_path);
if (!file_exists($localPath)) {
if (! file_exists($localPath)) {
abort(404, '파일을 찾을 수 없습니다.');
}
@@ -359,7 +359,7 @@ public function prospectUploadAudio(Request $request, GoogleCloudStorageService
$duration = $request->input('duration');
$file = $request->file('audio');
$fileName = 'audio_' . now()->format('Ymd_His') . '_' . uniqid() . '.' . $file->getClientOriginalExtension();
$fileName = 'audio_'.now()->format('Ymd_His').'_'.uniqid().'.'.$file->getClientOriginalExtension();
$localPath = $file->storeAs("prospect/consultations/{$prospectId}", $fileName, 'local');
$fileSize = $file->getSize();
@@ -397,7 +397,7 @@ public function prospectUploadAudio(Request $request, GoogleCloudStorageService
'formatted_duration' => $consultation->formatted_duration,
'created_by_name' => $consultation->creator->name,
'created_at' => $consultation->created_at->format('Y-m-d H:i'),
'has_gcs' => !empty($gcsUri),
'has_gcs' => ! empty($gcsUri),
],
]);
}
@@ -420,7 +420,7 @@ public function prospectUploadFile(Request $request): JsonResponse
$file = $request->file('file');
$originalName = $file->getClientOriginalName();
$fileName = now()->format('Ymd_His') . '_' . uniqid() . '_' . $originalName;
$fileName = now()->format('Ymd_His').'_'.uniqid().'_'.$originalName;
$path = $file->storeAs("prospect/attachments/{$prospectId}", $fileName, 'local');
$consultation = SalesConsultation::createFileByProspect(

View File

@@ -89,7 +89,7 @@ public function saveProducts(Request $request): JsonResponse
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => '저장 중 오류가 발생했습니다: ' . $e->getMessage(),
'message' => '저장 중 오류가 발생했습니다: '.$e->getMessage(),
], 500);
}
}

View File

@@ -141,7 +141,7 @@ private function getDashboardData(Request $request): array
],
];
if (!$isGroupPartner) {
if (! $isGroupPartner) {
$commissionByRole[] = [
'name' => '관리자',
'rate' => null, // 1개월 구독료 (퍼센트가 아닌 고정 금액)
@@ -181,7 +181,7 @@ private function getDashboardData(Request $request): array
// 수당 계산: 개발비 × 요율% (개인 20%, 단체 30%) - 1차/2차 분할은 calculateExpectedCommissionSummary에서 처리
$handoverPartnerRate = $isGroupPartner ? 0.30 : 0.20;
$handoverPartnerCommission = (int)($handoverTotalRegFee * $handoverPartnerRate);
$handoverPartnerCommission = (int) ($handoverTotalRegFee * $handoverPartnerRate);
// 내가 매니저로 지정된 인계 완료 건의 수당 계산
$managedHandoverManagements = SalesTenantManagement::where('manager_user_id', $currentUserId)
@@ -190,7 +190,7 @@ private function getDashboardData(Request $request): array
$managedHandoverManagementIds = $managedHandoverManagements->pluck('id')->toArray();
// 매니저 수당: 1개월 구독료 (퍼센트가 아닌 고정 금액)
$handoverManagerCommission = (int)SalesContractProduct::whereIn('management_id', $managedHandoverManagementIds)
$handoverManagerCommission = (int) SalesContractProduct::whereIn('management_id', $managedHandoverManagementIds)
->sum('subscription_fee');
// 기존 수당에 인계 완료 수당 추가
@@ -202,7 +202,7 @@ private function getDashboardData(Request $request): array
// 역할별 수당 업데이트 (실제 지급된 수당 기준)
// 참고: 예상 수당은 나중에 $totalExpectedCommission으로 별도 계산됨
$commissionByRole[0]['amount'] = $partnerCommissionTotal;
if (!$isGroupPartner) {
if (! $isGroupPartner) {
$commissionByRole[1]['amount'] = $managerCommissionTotal;
}
@@ -278,7 +278,7 @@ private function getDashboardData(Request $request): array
->toArray();
$devInProgressRegFee = SalesContractProduct::whereIn('management_id', $devInProgressManagementIds)
->sum('registration_fee');
$expectedFromDevInProgress = (int)($devInProgressRegFee * $handoverPartnerRate); // 개발비 × 요율 (개인 20%, 단체 30%)
$expectedFromDevInProgress = (int) ($devInProgressRegFee * $handoverPartnerRate); // 개발비 × 요율 (개인 20%, 단체 30%)
// 2) 인계 완료 중 지급 미완료 건
$handoverUnpaidRegFee = SalesContractProduct::whereIn('management_id', $handoverManagementIds)
@@ -288,7 +288,7 @@ private function getDashboardData(Request $request): array
->whereIn('management_id', $handoverManagementIds)
->where('status', SalesCommission::STATUS_PAID)
->sum('partner_commission');
$expectedFromHandover = (int)($handoverUnpaidRegFee * $handoverPartnerRate) - $paidCommissionFromHandover;
$expectedFromHandover = (int) ($handoverUnpaidRegFee * $handoverPartnerRate) - $paidCommissionFromHandover;
$expectedFromHandover = max(0, $expectedFromHandover);
// 총 예상 수당 (지급 완료 제외)
@@ -383,7 +383,7 @@ public function assignManager(int $tenantId, Request $request): JsonResponse
} else {
// 특정 매니저 지정
$manager = User::find($managerId);
if (!$manager) {
if (! $manager) {
return response()->json([
'success' => false,
'message' => '매니저를 찾을 수 없습니다.',
@@ -428,7 +428,7 @@ public function assignProspectManager(int $prospectId, Request $request): JsonRe
} else {
// 특정 매니저 지정
$manager = User::find($managerId);
if (!$manager) {
if (! $manager) {
return response()->json([
'success' => false,
'message' => '매니저를 찾을 수 없습니다.',
@@ -581,7 +581,7 @@ private function getManagerOnlyProspects(int $currentUserId): array
$prospect = $management->tenantProspect;
// 내가 등록한 건은 제외 (순수하게 매니저로만 참여한 건만)
if (!$prospect || $prospect->registered_by === $currentUserId) {
if (! $prospect || $prospect->registered_by === $currentUserId) {
continue;
}
@@ -615,7 +615,7 @@ private function getManagerOnlyProspects(int $currentUserId): array
foreach ($tenantManagements as $management) {
$tenant = $management->tenant;
if (!$tenant) {
if (! $tenant) {
continue;
}
@@ -676,12 +676,12 @@ private function calculatePartnerSummaryStats(array $partnerIds, int $currentUse
// 개인 파트너 예상 수당: 1개월 구독료
$individualProspectIds = TenantProspect::whereIn('registered_by', $individualPartnerIds)->pluck('id')->toArray();
$individualMgmtIds = SalesTenantManagement::whereIn('tenant_prospect_id', $individualProspectIds)->pluck('id')->toArray();
$individualExpected = (int)SalesContractProduct::whereIn('management_id', $individualMgmtIds)->sum('subscription_fee');
$individualExpected = (int) SalesContractProduct::whereIn('management_id', $individualMgmtIds)->sum('subscription_fee');
// 단체 파트너 예상 수당: 개발비 × 3%
$groupProspectIds = TenantProspect::whereIn('registered_by', $groupPartnerUserIds)->pluck('id')->toArray();
$groupMgmtIds = SalesTenantManagement::whereIn('tenant_prospect_id', $groupProspectIds)->pluck('id')->toArray();
$groupExpected = (int)(SalesContractProduct::whereIn('management_id', $groupMgmtIds)->sum('registration_fee') * 0.03);
$groupExpected = (int) (SalesContractProduct::whereIn('management_id', $groupMgmtIds)->sum('registration_fee') * 0.03);
$expectedFromFee = $individualExpected + $groupExpected;
@@ -727,16 +727,16 @@ private function calculatePartnerSummaryStats(array $partnerIds, int $currentUse
'expected_commission' => $expectedCommission,
'paid_commission' => $paidManagerCommission,
'first_commission' => [
'total' => (int)$halfExpected,
'pending' => (int)$halfPending,
'scheduled' => (int)$halfScheduled,
'paid' => (int)$halfPaid,
'total' => (int) $halfExpected,
'pending' => (int) $halfPending,
'scheduled' => (int) $halfScheduled,
'paid' => (int) $halfPaid,
],
'second_commission' => [
'total' => (int)$halfExpected,
'pending' => (int)$halfPending,
'scheduled' => (int)$halfScheduled,
'paid' => (int)$halfPaid,
'total' => (int) $halfExpected,
'pending' => (int) $halfPending,
'scheduled' => (int) $halfScheduled,
'paid' => (int) $halfPaid,
],
];
}
@@ -782,8 +782,8 @@ private function getPartnerActivitiesDetail($recruitedPartners, int $currentUser
// 단체 파트너: 협업지원금(개발비 × 3%), 개인 파트너: 관리자 수당(1개월 구독료)
$isRecruitedGroupPartner = $salesPartner && $salesPartner->isGroup();
$expectedCommission = $isRecruitedGroupPartner
? (int)($totalRegistrationFee * 0.03)
: (int)$totalSubscriptionFee;
? (int) ($totalRegistrationFee * 0.03)
: (int) $totalSubscriptionFee;
// 최종 수당 (확정 + 예상 중 큰 값)
$managerCommission = max($confirmedCommission, $expectedCommission);
@@ -864,7 +864,7 @@ private function getPartnerActivitiesDetail($recruitedPartners, int $currentUser
// 역할 정보
$roles = $partner->userRoles->pluck('role.name')->filter()->toArray();
$roleLabel = !empty($roles) ? implode(', ', $roles) : '영업';
$roleLabel = ! empty($roles) ? implode(', ', $roles) : '영업';
$activities[] = [
'partner' => $partner,
@@ -912,7 +912,7 @@ private function getCommissionData(): array
*/
private function getAllManagerUsers()
{
return User::whereHas('userRoles.role', fn($q) => $q->where('name', 'manager'))
return User::whereHas('userRoles.role', fn ($q) => $q->where('name', 'manager'))
->where('is_active', true)
->where('id', '!=', auth()->id()) // 본인 제외
->get(['id', 'name', 'email']);
@@ -930,7 +930,7 @@ public function searchManagers(Request $request): JsonResponse
// 디버깅: SQL 쿼리 로깅
\DB::enableQueryLog();
$managers = User::whereHas('userRoles.role', fn($q) => $q->where('name', 'manager'))
$managers = User::whereHas('userRoles.role', fn ($q) => $q->where('name', 'manager'))
->where('is_active', true)
->where('id', '!=', $authId)
->when($query, function ($q) use ($query) {
@@ -1012,24 +1012,24 @@ private function calculateExpectedCommissionSummary($commissions, int $totalExpe
return [
'scheduled_this_month' => $commissions
->where('status', SalesCommission::STATUS_APPROVED)
->filter(fn($c) => $c->scheduled_payment_date?->format('Y-m') === $thisMonth)
->filter(fn ($c) => $c->scheduled_payment_date?->format('Y-m') === $thisMonth)
->sum('partner_commission'),
'total_received' => $paidCommission,
'pending_amount' => $pendingAmount,
'contracts_this_month' => $commissions
->filter(fn($c) => $c->payment_date >= $thisMonthStart && $c->payment_date <= $thisMonthEnd)
->filter(fn ($c) => $c->payment_date >= $thisMonthStart && $c->payment_date <= $thisMonthEnd)
->count(),
'first_commission' => [
'total' => (int)$halfExpected,
'pending' => (int)$halfPending,
'scheduled' => (int)$halfScheduled,
'paid' => (int)$halfPaid,
'total' => (int) $halfExpected,
'pending' => (int) $halfPending,
'scheduled' => (int) $halfScheduled,
'paid' => (int) $halfPaid,
],
'second_commission' => [
'total' => (int)$halfExpected,
'pending' => (int)$halfPending,
'scheduled' => (int)$halfScheduled,
'paid' => (int)$halfPaid,
'total' => (int) $halfExpected,
'pending' => (int) $halfPending,
'scheduled' => (int) $halfScheduled,
'paid' => (int) $halfPaid,
],
'total_commission' => $totalExpectedCommission,
];
@@ -1053,7 +1053,7 @@ private function calculateCommissionSummaryFromCollection($commissions): array
return [
'scheduled_this_month' => $commissions
->where('status', SalesCommission::STATUS_APPROVED)
->filter(fn($c) => $c->scheduled_payment_date?->format('Y-m') === $thisMonth)
->filter(fn ($c) => $c->scheduled_payment_date?->format('Y-m') === $thisMonth)
->sum('partner_commission'),
'total_received' => $commissions
->where('status', SalesCommission::STATUS_PAID)
@@ -1062,7 +1062,7 @@ private function calculateCommissionSummaryFromCollection($commissions): array
->where('status', SalesCommission::STATUS_PENDING)
->sum('partner_commission'),
'contracts_this_month' => $commissions
->filter(fn($c) => $c->payment_date >= $thisMonthStart && $c->payment_date <= $thisMonthEnd)
->filter(fn ($c) => $c->payment_date >= $thisMonthStart && $c->payment_date <= $thisMonthEnd)
->count(),
'first_commission' => $firstCommission,
'second_commission' => $secondCommission,

View File

@@ -24,7 +24,7 @@ public function __construct(
public function index(Request $request): View|Response
{
// 권한 체크: admin 역할만 접근 가능
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -62,7 +62,7 @@ public function index(Request $request): View|Response
public function approve(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -97,7 +97,7 @@ public function approve(Request $request, int $id)
public function reject(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -136,7 +136,7 @@ public function reject(Request $request, int $id)
public function updateStatus(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -176,7 +176,7 @@ public function updateStatus(Request $request, int $id)
public function revertToPending(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -211,7 +211,7 @@ public function revertToPending(Request $request, int $id)
public function detail(int $id): View
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}

View File

@@ -199,7 +199,7 @@ public function update(Request $request, int $id)
$validated = $request->validate([
'name' => 'required|string|max:100',
'email' => 'required|email|max:255|unique:users,email,' . $id,
'email' => 'required|email|max:255|unique:users,email,'.$id,
'phone' => 'nullable|string|max:20',
'password' => 'nullable|string|min:4|confirmed',
'role_ids' => 'required|array|min:1',
@@ -242,7 +242,7 @@ public function update(Request $request, int $id)
public function destroy(int $id)
{
// 권한 체크: admin 역할만 삭제 가능
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '삭제 권한이 없습니다.');
}
@@ -298,6 +298,7 @@ public function delegateRole(Request $request, int $id)
$this->service->delegateRole($fromUser, $toUser, $validated['role_name']);
$roleLabel = '상담매니저';
return redirect()->back()
->with('success', "{$roleLabel} 역할이 {$toUser->name}님에게 위임되었습니다.");
} catch (\InvalidArgumentException $e) {
@@ -319,6 +320,7 @@ public function assignRole(Request $request, int $id)
$this->service->assignRole($partner, $validated['role_name']);
$roleLabels = ['sales' => '영업파트너', 'manager' => '상담매니저'];
return redirect()->back()
->with('success', "{$roleLabels[$validated['role_name']]} 역할이 부여되었습니다.");
}
@@ -336,6 +338,7 @@ public function removeRole(Request $request, int $id)
$this->service->removeRole($partner, $validated['role_name']);
$roleLabels = ['sales' => '영업파트너', 'manager' => '상담매니저'];
return redirect()->back()
->with('success', "{$roleLabels[$validated['role_name']]} 역할이 제거되었습니다.");
}
@@ -371,7 +374,7 @@ public function deleteDocument(int $id, int $documentId)
public function approvals(Request $request): View|Response
{
// 권한 체크: admin 역할만 접근 가능
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -404,7 +407,7 @@ public function approvals(Request $request): View|Response
public function approveFromList(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}
@@ -428,7 +431,7 @@ public function approveFromList(Request $request, int $id)
public function rejectFromList(Request $request, int $id)
{
// 권한 체크
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
abort(403, '접근 권한이 없습니다.');
}

View File

@@ -27,7 +27,7 @@ public function index(Request $request): View|Response
$categories = SalesProductCategory::active()
->ordered()
->with(['products' => fn($q) => $q->ordered()])
->with(['products' => fn ($q) => $q->ordered()])
->get();
$currentCategoryCode = $request->input('category', $categories->first()?->code);
@@ -43,7 +43,7 @@ public function productList(Request $request): View
{
$categoryCode = $request->input('category');
$category = SalesProductCategory::where('code', $categoryCode)
->with(['products' => fn($q) => $q->ordered()])
->with(['products' => fn ($q) => $q->ordered()])
->first();
return view('sales.products.partials.product-list', compact('category'));
@@ -144,7 +144,7 @@ public function destroy(int $id): JsonResponse
public function toggleActive(int $id): JsonResponse
{
$product = SalesProduct::findOrFail($id);
$product->update(['is_active' => !$product->is_active]);
$product->update(['is_active' => ! $product->is_active]);
return response()->json([
'success' => true,
@@ -268,7 +268,7 @@ public function getProductsApi(): JsonResponse
{
$categories = SalesProductCategory::active()
->ordered()
->with(['products' => fn($q) => $q->active()->ordered()])
->with(['products' => fn ($q) => $q->active()->ordered()])
->get();
return response()->json([

View File

@@ -99,19 +99,19 @@ public function store(Request $request)
]);
// 명함 이미지 저장 (Base64)
if (!empty($validated['business_card_image_data'])) {
if (! empty($validated['business_card_image_data'])) {
$validated['business_card_image'] = $this->saveBase64Image($validated['business_card_image_data'], 'business-cards');
}
unset($validated['business_card_image_data']);
// 신분증 이미지 저장 (Base64)
if (!empty($validated['id_card_image_data'])) {
if (! empty($validated['id_card_image_data'])) {
$validated['id_card_image'] = $this->saveBase64Image($validated['id_card_image_data'], 'id-cards');
}
unset($validated['id_card_image_data']);
// 통장사본 이미지 저장 (Base64)
if (!empty($validated['bankbook_image_data'])) {
if (! empty($validated['bankbook_image_data'])) {
$validated['bankbook_image'] = $this->saveBase64Image($validated['bankbook_image_data'], 'bankbooks');
}
unset($validated['bankbook_image_data']);
@@ -132,7 +132,7 @@ public function show(int $id): View
'salesManager',
'products',
'scenarios',
'consultations.manager'
'consultations.manager',
])->findOrFail($id);
$managers = SalesManager::active()
@@ -250,7 +250,7 @@ private function saveBase64Image(string $base64Data, string $folder): ?string
return null;
}
$filename = $folder . '/' . date('Ymd') . '_' . uniqid() . '.' . $extension;
$filename = $folder.'/'.date('Ymd').'_'.uniqid().'.'.$extension;
Storage::disk('public')->put($filename, $imageData);
return $filename;

View File

@@ -7,9 +7,9 @@
use App\Models\Sales\SalesTenantManagement;
use App\Models\Sales\TenantProspect;
use App\Models\Tenants\Tenant;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
use Illuminate\View\View;
/**

View File

@@ -71,7 +71,7 @@ public function store(Request $request)
// 등록 가능 여부 확인
$checkResult = $this->service->canRegister($validated['business_number']);
if (!$checkResult['can_register']) {
if (! $checkResult['can_register']) {
return redirect()->back()
->withInput()
->with('error', $checkResult['reason']);
@@ -172,7 +172,7 @@ public function destroy(int $id)
}
// 관리자만 삭제 가능
if (!auth()->user()->isAdmin()) {
if (! auth()->user()->isAdmin()) {
return redirect()->route('sales.prospects.index')
->with('error', '삭제 권한이 없습니다. 본사 운영팀에 문의하세요.');
}
@@ -257,7 +257,7 @@ public function deleteAttachment(Request $request, int $id)
$type = $request->get('type');
$allowedTypes = ['business_card', 'id_card', 'bankbook'];
if (!in_array($type, $allowedTypes)) {
if (! in_array($type, $allowedTypes)) {
return response()->json(['success' => false, 'message' => '잘못된 요청입니다.'], 400);
}

View File

@@ -9,7 +9,6 @@
use App\Services\GoogleCloudService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\Response;

View File

@@ -158,6 +158,7 @@ public function bulkStore(Request $request): JsonResponse
if ($exists) {
$skipped++;
continue;
}

View File

@@ -38,10 +38,10 @@ public function index(Request $request): View
// 날짜 범위 필터
if ($request->filled('date_from')) {
$query->where('created_at', '>=', $request->date_from . ' 00:00:00');
$query->where('created_at', '>=', $request->date_from.' 00:00:00');
}
if ($request->filled('date_to')) {
$query->where('created_at', '<=', $request->date_to . ' 23:59:59');
$query->where('created_at', '<=', $request->date_to.' 23:59:59');
}
$alerts = $query->paginate(50)->withQueryString();
@@ -95,4 +95,4 @@ public function markAllAsRead(): Response
return response('', 200, ['HX-Refresh' => 'true']);
}
}
}

View File

@@ -124,4 +124,4 @@ public function store(Request $request): RedirectResponse
return redirect()->route('tenant-settings.index')
->with('success', '설정이 저장되었습니다.');
}
}
}

View File

@@ -43,7 +43,7 @@ public function upload(Request $request): JsonResponse
'screenshots.*' => 'required|image|max:10240', // 최대 10MB
]);
$uploadDir = storage_path('app/tutorial_uploads/' . auth()->id() . '/' . time());
$uploadDir = storage_path('app/tutorial_uploads/'.auth()->id().'/'.time());
if (! is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
@@ -52,7 +52,7 @@ public function upload(Request $request): JsonResponse
foreach ($request->file('screenshots') as $i => $file) {
$filename = sprintf('screenshot_%02d.%s', $i + 1, $file->getClientOriginalExtension());
$file->move($uploadDir, $filename);
$paths[] = $uploadDir . '/' . $filename;
$paths[] = $uploadDir.'/'.$filename;
}
return response()->json([
@@ -79,7 +79,7 @@ public function analyze(Request $request): JsonResponse
if (! file_exists($path)) {
return response()->json([
'success' => false,
'message' => '업로드된 파일을 찾을 수 없습니다: ' . basename($path),
'message' => '업로드된 파일을 찾을 수 없습니다: '.basename($path),
], 400);
}
}
@@ -93,7 +93,7 @@ public function analyze(Request $request): JsonResponse
return response()->json([
'success' => false,
'message' => 'AI 분석 중 오류가 발생했습니다: ' . $e->getMessage(),
'message' => 'AI 분석 중 오류가 발생했습니다: '.$e->getMessage(),
], 500);
}
@@ -188,7 +188,7 @@ public function download(int $id): BinaryFileResponse|RedirectResponse|JsonRespo
return response()->json(['message' => '영상 파일을 찾을 수 없습니다.'], 404);
}
$filename = 'tutorial_' . ($tutorial->title ? preg_replace('/[^a-zA-Z0-9가-힣_\-.]/', '_', $tutorial->title) : $tutorial->id) . '.mp4';
$filename = 'tutorial_'.($tutorial->title ? preg_replace('/[^a-zA-Z0-9가-힣_\-.]/', '_', $tutorial->title) : $tutorial->id).'.mp4';
return response()->download($tutorial->output_path, $filename, [
'Content-Type' => 'video/mp4',

View File

@@ -355,12 +355,12 @@ private function buildYoutubeText(VideoGeneration $video, array $scenario, array
// 해시태그 생성
$hashtags = ['#shorts', '#쇼츠'];
if ($keyword) {
$hashtags[] = '#' . str_replace(' ', '', $keyword);
$hashtags[] = '#'.str_replace(' ', '', $keyword);
}
// 시나리오에서 추가 태그 추출
$bgmMood = $scenario['bgm_mood'] ?? '';
if ($bgmMood) {
$hashtags[] = '#' . $bgmMood;
$hashtags[] = '#'.$bgmMood;
}
$hashtags = array_merge($hashtags, ['#건강', '#건강정보', '#헬스']);
@@ -373,7 +373,7 @@ private function buildYoutubeText(VideoGeneration $video, array $scenario, array
foreach ($scenes as $scene) {
$narration = $scene['narration'] ?? '';
if ($narration && ($scene['scene_type'] ?? '') !== 'HOOK') {
$descLines[] = '- ' . mb_substr($narration, 0, 60);
$descLines[] = '- '.mb_substr($narration, 0, 60);
}
}

View File

@@ -30,16 +30,18 @@ public function handle(Request $request, Closure $next): Response
$user = Auth::user();
// HQ 테넌트 소속 확인
if (!$user->belongsToHQ()) {
if (! $user->belongsToHQ()) {
Auth::logout();
Log::info('[AutoLoginViaRemember] Non-HQ user rejected', ['user_id' => $user->id]);
return $next($request);
}
// 활성 상태 확인
if (!$user->is_active) {
if (! $user->is_active) {
Auth::logout();
Log::info('[AutoLoginViaRemember] Inactive user rejected', ['user_id' => $user->id]);
return $next($request);
}
@@ -79,4 +81,4 @@ private function refreshApiToken(int $userId, int $tenantId): void
]);
}
}
}
}

View File

@@ -3,12 +3,12 @@
namespace App\Jobs;
use App\Models\VideoGeneration;
use App\Services\GoogleCloudStorageService;
use App\Services\Video\BgmService;
use App\Services\Video\GeminiScriptService;
use App\Services\Video\TtsService;
use App\Services\Video\VeoVideoService;
use App\Services\Video\VideoAssemblyService;
use App\Services\GoogleCloudStorageService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
@@ -114,7 +114,7 @@ public function handle(
$video->updateProgress(
VideoGeneration::STATUS_GENERATING_CLIPS,
20 + (int) (($sceneNum / count($scenes)) * 10),
"영상 클립 생성 요청 중 ({$sceneNum}/" . count($scenes) . ')'
"영상 클립 생성 요청 중 ({$sceneNum}/".count($scenes).')'
);
$result = $veo->generateClip($prompt, $duration);
@@ -137,7 +137,7 @@ public function handle(
$video->updateProgress(
VideoGeneration::STATUS_GENERATING_CLIPS,
30 + (int) (($sceneNum / count($scenes)) * 40),
"영상 클립 생성 대기 중 ({$sceneNum}/" . count($scenes) . ')'
"영상 클립 생성 대기 중 ({$sceneNum}/".count($scenes).')'
);
$result = $veo->waitAndSave(
@@ -189,7 +189,7 @@ public function handle(
// 성공한 클립이 절반 미만이면 전체 실패
if (count($clipPaths) < ceil(count($scenes) / 2)) {
$video->markFailed('영상 클립 생성 실패 (성공: ' . count($clipPaths) . '/' . count($scenes) . ')');
$video->markFailed('영상 클립 생성 실패 (성공: '.count($clipPaths).'/'.count($scenes).')');
return;
}
@@ -310,7 +310,7 @@ public function handle(
// === 완료 ===
$stepMsg = empty($skippedScenes)
? '완료'
: '완료 (장면 ' . implode(',', $skippedScenes) . ' 건너뜀)';
: '완료 (장면 '.implode(',', $skippedScenes).' 건너뜀)';
$video->update([
'status' => VideoGeneration::STATUS_COMPLETED,
@@ -344,7 +344,7 @@ public function handle(
public function failed(\Throwable $exception): void
{
$video = VideoGeneration::withoutGlobalScopes()->find($this->videoGenerationId);
$video?->markFailed('Job 실패: ' . $exception->getMessage());
$video?->markFailed('Job 실패: '.$exception->getMessage());
}
/**
@@ -356,6 +356,6 @@ private function makeSafePrompt(string $prompt): string
$prompt = preg_replace('/\b(woman|man|girl|boy|person|people|her|his|she|he)\b/i', 'subject', $prompt);
// 안전 키워드 추가
return 'Safe for all audiences. Professional stock footage style. ' . $prompt;
return 'Safe for all audiences. Professional stock footage style. '.$prompt;
}
}

View File

@@ -6,8 +6,8 @@
use App\Models\ESign\EsignSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
@@ -32,7 +32,7 @@ public function envelope(): Envelope
public function content(): Content
{
$downloadUrl = config('app.url') . '/esign/sign/' . $this->signer->access_token . '/api/document';
$downloadUrl = config('app.url').'/esign/sign/'.$this->signer->access_token.'/api/document';
return new Content(
html: 'emails.esign.completed',

View File

@@ -4,8 +4,8 @@
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

View File

@@ -6,8 +6,8 @@
use App\Models\ESign\EsignSigner;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
@@ -33,7 +33,7 @@ public function envelope(): Envelope
public function content(): Content
{
$signUrl = config('app.url') . '/esign/sign/' . $this->signer->access_token;
$signUrl = config('app.url').'/esign/sign/'.$this->signer->access_token;
return new Content(
html: 'emails.esign.request',

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 계정과목 모델

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 바로빌 계좌 거래 동기화 상태 모델

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 계좌 입출금 거래 분개 모델
@@ -62,7 +62,7 @@ public static function getByDateRange(int $tenantId, string $startDate, string $
$grouped = [];
foreach ($splits as $split) {
$key = $split->original_unique_key;
if (!isset($grouped[$key])) {
if (! isset($grouped[$key])) {
$grouped[$key] = [];
}
$grouped[$key][] = $split;

View File

@@ -102,6 +102,6 @@ public function getMaskedCertKeyAttribute(): string
return $this->cert_key;
}
return substr($this->cert_key, 0, 8) . str_repeat('*', 8) . '...';
return substr($this->cert_key, 0, 8).str_repeat('*', 8).'...';
}
}

View File

@@ -60,8 +60,9 @@ public function getFormattedBizNoAttribute(): string
{
$bizNo = preg_replace('/[^0-9]/', '', $this->biz_no);
if (strlen($bizNo) === 10) {
return substr($bizNo, 0, 3) . '-' . substr($bizNo, 3, 2) . '-' . substr($bizNo, 5);
return substr($bizNo, 0, 3).'-'.substr($bizNo, 3, 2).'-'.substr($bizNo, 5);
}
return $this->biz_no;
}

View File

@@ -50,7 +50,9 @@ class BarobillPricingPolicy extends Model
* 서비스 유형 상수
*/
public const TYPE_CARD = 'card';
public const TYPE_TAX_INVOICE = 'tax_invoice';
public const TYPE_BANK_ACCOUNT = 'bank_account';
/**
@@ -104,7 +106,7 @@ public static function getAllActive(): \Illuminate\Database\Eloquent\Collection
/**
* 추가 과금액 계산
*
* @param int $usageCount 사용량
* @param int $usageCount 사용량
* @return array ['free_count' => int, 'billable_count' => int, 'billable_amount' => int]
*/
public function calculateBilling(int $usageCount): array

View File

@@ -60,10 +60,19 @@ public function tenant(): BelongsTo
public function getActiveServicesAttribute(): array
{
$services = [];
if ($this->use_tax_invoice) $services[] = 'tax_invoice';
if ($this->use_bank_account) $services[] = 'bank_account';
if ($this->use_card_usage) $services[] = 'card_usage';
if ($this->use_hometax) $services[] = 'hometax';
if ($this->use_tax_invoice) {
$services[] = 'tax_invoice';
}
if ($this->use_bank_account) {
$services[] = 'bank_account';
}
if ($this->use_card_usage) {
$services[] = 'card_usage';
}
if ($this->use_hometax) {
$services[] = 'hometax';
}
return $services;
}
}

View File

@@ -74,12 +74,13 @@ public function getServiceTypeLabelAttribute(): string
*/
public function getStatusLabelAttribute(): string
{
if (!$this->is_active) {
if (! $this->is_active) {
return '비활성';
}
if ($this->ended_at && $this->ended_at->isPast()) {
return '종료';
}
return '구독중';
}
@@ -88,12 +89,13 @@ public function getStatusLabelAttribute(): string
*/
public function getStatusColorAttribute(): string
{
if (!$this->is_active) {
if (! $this->is_active) {
return 'bg-gray-100 text-gray-800';
}
if ($this->ended_at && $this->ended_at->isPast()) {
return 'bg-red-100 text-red-800';
}
return 'bg-green-100 text-green-800';
}
@@ -103,10 +105,10 @@ public function getStatusColorAttribute(): string
public function scopeActive($query)
{
return $query->where('is_active', true)
->where(function ($q) {
$q->whereNull('ended_at')
->orWhere('ended_at', '>=', now()->toDateString());
});
->where(function ($q) {
$q->whereNull('ended_at')
->orWhere('ended_at', '>=', now()->toDateString());
});
}
/**

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 바로빌 카드 사용내역 모델
@@ -103,6 +103,6 @@ public static function getByDateRange(int $tenantId, string $startDate, string $
$query->where('card_num', $cardNum);
}
return $query->get()->keyBy(fn($item) => $item->unique_key);
return $query->get()->keyBy(fn ($item) => $item->unique_key);
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 카드 거래 분개 모델
@@ -67,7 +67,7 @@ public static function getByDateRange(int $tenantId, string $startDate, string $
$grouped = [];
foreach ($splits as $split) {
$key = $split->original_unique_key;
if (!isset($grouped[$key])) {
if (! isset($grouped[$key])) {
$grouped[$key] = [];
}
$grouped[$key][] = $split;

View File

@@ -99,15 +99,19 @@ class HometaxInvoice extends Model
// 과세유형 상수
public const TAX_TYPE_TAXABLE = 1; // 과세
public const TAX_TYPE_ZERO_RATE = 2; // 영세
public const TAX_TYPE_EXEMPT = 3; // 면세
// 영수/청구 상수
public const PURPOSE_TYPE_RECEIPT = 1; // 영수
public const PURPOSE_TYPE_CLAIM = 2; // 청구
// 발급유형 상수
public const ISSUE_TYPE_NORMAL = 1; // 정발행
public const ISSUE_TYPE_REVERSE = 2; // 역발행
/**
@@ -147,7 +151,7 @@ public function scopePurchase($query)
*/
public function scopePeriod($query, string $startDate, string $endDate, string $dateType = 'write')
{
$column = match($dateType) {
$column = match ($dateType) {
'issue' => 'issue_date',
'send' => 'send_date',
default => 'write_date',
@@ -169,12 +173,12 @@ public function scopeSearchCorp($query, string $keyword, string $invoiceType = '
if ($invoiceType === 'sales') {
return $query->where(function ($q) use ($keyword) {
$q->where('invoicee_corp_name', 'like', "%{$keyword}%")
->orWhere('invoicee_corp_num', 'like', "%{$keyword}%");
->orWhere('invoicee_corp_num', 'like', "%{$keyword}%");
});
} else {
return $query->where(function ($q) use ($keyword) {
$q->where('invoicer_corp_name', 'like', "%{$keyword}%")
->orWhere('invoicer_corp_num', 'like', "%{$keyword}%");
->orWhere('invoicer_corp_num', 'like', "%{$keyword}%");
});
}
}
@@ -184,7 +188,7 @@ public function scopeSearchCorp($query, string $keyword, string $invoiceType = '
*/
public function getTaxTypeNameAttribute(): string
{
return match($this->tax_type) {
return match ($this->tax_type) {
self::TAX_TYPE_TAXABLE => '과세',
self::TAX_TYPE_ZERO_RATE => '영세',
self::TAX_TYPE_EXEMPT => '면세',
@@ -197,7 +201,7 @@ public function getTaxTypeNameAttribute(): string
*/
public function getPurposeTypeNameAttribute(): string
{
return match($this->purpose_type) {
return match ($this->purpose_type) {
self::PURPOSE_TYPE_RECEIPT => '영수',
self::PURPOSE_TYPE_CLAIM => '청구',
default => '-',
@@ -209,7 +213,7 @@ public function getPurposeTypeNameAttribute(): string
*/
public function getIssueTypeNameAttribute(): string
{
return match($this->issue_type) {
return match ($this->issue_type) {
self::ISSUE_TYPE_NORMAL => '정발급',
self::ISSUE_TYPE_REVERSE => '역발급',
default => '-',
@@ -247,17 +251,17 @@ public static function fromApiData(array $apiData, int $tenantId, string $invoic
{
// 작성일자 파싱
$writeDate = null;
if (!empty($apiData['writeDate']) && strlen($apiData['writeDate']) >= 8) {
$writeDate = substr($apiData['writeDate'], 0, 4) . '-' .
substr($apiData['writeDate'], 4, 2) . '-' .
if (! empty($apiData['writeDate']) && strlen($apiData['writeDate']) >= 8) {
$writeDate = substr($apiData['writeDate'], 0, 4).'-'.
substr($apiData['writeDate'], 4, 2).'-'.
substr($apiData['writeDate'], 6, 2);
}
// 발급일자 파싱
$issueDate = null;
if (!empty($apiData['issueDT']) && strlen($apiData['issueDT']) >= 8) {
$issueDate = substr($apiData['issueDT'], 0, 4) . '-' .
substr($apiData['issueDT'], 4, 2) . '-' .
if (! empty($apiData['issueDT']) && strlen($apiData['issueDT']) >= 8) {
$issueDate = substr($apiData['issueDT'], 0, 4).'-'.
substr($apiData['issueDT'], 4, 2).'-'.
substr($apiData['issueDT'], 6, 2);
}
@@ -273,11 +277,11 @@ public static function fromApiData(array $apiData, int $tenantId, string $invoic
'invoicee_corp_num' => $apiData['invoiceeCorpNum'] ?? '',
'invoicee_corp_name' => $apiData['invoiceeCorpName'] ?? '',
'invoicee_ceo_name' => $apiData['invoiceeCEOName'] ?? null,
'supply_amount' => (int)($apiData['supplyAmount'] ?? 0),
'tax_amount' => (int)($apiData['taxAmount'] ?? 0),
'total_amount' => (int)($apiData['totalAmount'] ?? 0),
'tax_type' => (int)($apiData['taxType'] ?? 1),
'purpose_type' => (int)($apiData['purposeType'] ?? 1),
'supply_amount' => (int) ($apiData['supplyAmount'] ?? 0),
'tax_amount' => (int) ($apiData['taxAmount'] ?? 0),
'total_amount' => (int) ($apiData['totalAmount'] ?? 0),
'tax_type' => (int) ($apiData['taxType'] ?? 1),
'purpose_type' => (int) ($apiData['purposeType'] ?? 1),
'issue_type' => 1, // 기본값: 정발행
'item_name' => $apiData['itemName'] ?? null,
'remark' => $apiData['remark'] ?? null,

View File

@@ -2,9 +2,9 @@
namespace App\Models\Barobill;
use App\Models\Tenants\Tenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Models\Tenants\Tenant;
/**
* 홈택스 세금계산서 분개 모델
@@ -72,15 +72,15 @@ public static function saveJournals(int $tenantId, int $invoiceId, array $invoic
'dc_type' => $line['dc_type'],
'account_code' => $line['account_code'],
'account_name' => $line['account_name'],
'debit_amount' => (int)($line['debit_amount'] ?? 0),
'credit_amount' => (int)($line['credit_amount'] ?? 0),
'debit_amount' => (int) ($line['debit_amount'] ?? 0),
'credit_amount' => (int) ($line['credit_amount'] ?? 0),
'description' => $line['description'] ?? '',
'sort_order' => $index,
'invoice_type' => $invoiceData['invoice_type'] ?? '',
'write_date' => $invoiceData['write_date'] ?? null,
'supply_amount' => (int)($invoiceData['supply_amount'] ?? 0),
'tax_amount' => (int)($invoiceData['tax_amount'] ?? 0),
'total_amount' => (int)($invoiceData['total_amount'] ?? 0),
'supply_amount' => (int) ($invoiceData['supply_amount'] ?? 0),
'tax_amount' => (int) ($invoiceData['tax_amount'] ?? 0),
'total_amount' => (int) ($invoiceData['total_amount'] ?? 0),
'trading_partner_name' => $invoiceData['trading_partner_name'] ?? '',
]);
}

View File

@@ -68,4 +68,4 @@ public function replies(): HasMany
{
return $this->children();
}
}
}

View File

@@ -79,4 +79,4 @@ public function scopeActive($query)
{
return $query->where('is_active', true);
}
}
}

View File

@@ -102,6 +102,6 @@ public function getMaskedApiKeyAttribute(): string
return $this->api_key;
}
return substr($this->api_key, 0, 8) . str_repeat('*', 8) . '...';
return substr($this->api_key, 0, 8).str_repeat('*', 8).'...';
}
}

View File

@@ -87,7 +87,7 @@ protected static function boot()
*/
public static function generateInquiryKey(): string
{
return date('Ymd') . Str::upper(Str::random(24));
return date('Ymd').Str::upper(Str::random(24));
}
/**
@@ -126,8 +126,9 @@ public function getFormattedCompanyKeyAttribute(): string
{
$key = $this->company_key;
if (strlen($key) === 10) {
return substr($key, 0, 3) . '-' . substr($key, 3, 2) . '-' . substr($key, 5);
return substr($key, 0, 3).'-'.substr($key, 3, 2).'-'.substr($key, 5);
}
return $key;
}
@@ -172,11 +173,11 @@ public function getNtsStatusLabelAttribute(): string
/**
* API 응답으로부터 모델 생성
*
* @param string $companyKey 사업자번호
* @param array $apiResult 쿠콘 API 결과
* @param array|null $ntsResult 국세청 API 결과
* @param int|null $userId 조회자 ID
* @param int|null $tenantId 테넌트 ID
* @param string $companyKey 사업자번호
* @param array $apiResult 쿠콘 API 결과
* @param array|null $ntsResult 국세청 API 결과
* @param int|null $userId 조회자 ID
* @param int|null $tenantId 테넌트 ID
*/
public static function createFromApiResponse(
string $companyKey,
@@ -199,10 +200,10 @@ public static function createFromApiResponse(
$businessType = $companyInfoData['bizcnd'] ?? $companyInfoData['indutyNm'] ?? null;
$businessItem = $companyInfoData['bizitm'] ?? $companyInfoData['indutyDetailNm'] ?? null;
$establishmentDate = null;
if (!empty($companyInfoData['estbDt']) || !empty($companyInfoData['estbDate'])) {
if (! empty($companyInfoData['estbDt']) || ! empty($companyInfoData['estbDate'])) {
$estbDt = $companyInfoData['estbDt'] ?? $companyInfoData['estbDate'];
if (strlen($estbDt) === 8) {
$establishmentDate = substr($estbDt, 0, 4) . '-' . substr($estbDt, 4, 2) . '-' . substr($estbDt, 6, 2);
$establishmentDate = substr($estbDt, 0, 4).'-'.substr($estbDt, 4, 2).'-'.substr($estbDt, 6, 2);
}
}
@@ -216,8 +217,8 @@ public static function createFromApiResponse(
$ntsStatus = $ntsData['b_stt'] ?? null;
$ntsStatusCode = $ntsData['b_stt_cd'] ?? null;
$ntsTaxType = $ntsData['tax_type'] ?? null;
if (!empty($ntsData['end_dt']) && strlen($ntsData['end_dt']) === 8) {
$ntsClosureDate = substr($ntsData['end_dt'], 0, 4) . '-' . substr($ntsData['end_dt'], 4, 2) . '-' . substr($ntsData['end_dt'], 6, 2);
if (! empty($ntsData['end_dt']) && strlen($ntsData['end_dt']) === 8) {
$ntsClosureDate = substr($ntsData['end_dt'], 0, 4).'-'.substr($ntsData['end_dt'], 4, 2).'-'.substr($ntsData['end_dt'], 6, 2);
}
}
@@ -230,7 +231,7 @@ public static function createFromApiResponse(
if (isset($apiResult[$key]['success']) && $apiResult[$key]['success']) {
$successCount++;
} else {
$errors[] = $key . ': ' . ($apiResult[$key]['error'] ?? 'Unknown error');
$errors[] = $key.': '.($apiResult[$key]['error'] ?? 'Unknown error');
}
}

View File

@@ -10,7 +10,7 @@
class DocumentTemplate extends Model
{
use HasFactory, BelongsToTenant, SoftDeletes;
use BelongsToTenant, HasFactory, SoftDeletes;
protected $fillable = [
'tenant_id',

View File

@@ -27,4 +27,4 @@ public function template(): BelongsTo
{
return $this->belongsTo(DocumentTemplate::class, 'template_id');
}
}
}

View File

@@ -27,4 +27,4 @@ public function template(): BelongsTo
{
return $this->belongsTo(DocumentTemplate::class, 'template_id');
}
}
}

View File

@@ -29,4 +29,4 @@ public function template(): BelongsTo
{
return $this->belongsTo(DocumentTemplate::class, 'template_id');
}
}
}

View File

@@ -32,4 +32,4 @@ public function items(): HasMany
return $this->hasMany(DocumentTemplateSectionItem::class, 'section_id')
->orderBy('sort_order');
}
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Models\ESign;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

View File

@@ -3,8 +3,8 @@
namespace App\Models\ESign;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class EsignFieldTemplate extends Model
{

View File

@@ -86,14 +86,14 @@ public function getFormattedBalanceAttribute(): string
$amount = abs($this->balance);
if ($amount >= 100000000) {
return number_format($amount / 100000000, 1) . '억원';
return number_format($amount / 100000000, 1).'억원';
} elseif ($amount >= 10000000) {
return number_format($amount / 10000000, 0) . '천만원';
return number_format($amount / 10000000, 0).'천만원';
} elseif ($amount >= 10000) {
return number_format($amount / 10000, 0) . '만원';
return number_format($amount / 10000, 0).'만원';
}
return number_format($amount) . '원';
return number_format($amount).'원';
}
/**
@@ -106,7 +106,7 @@ public function getMaskedAccountNumberAttribute(): string
return $number;
}
return substr($number, 0, 3) . '-***-' . substr($number, -4);
return substr($number, 0, 3).'-***-'.substr($number, -4);
}
// ============================================================

View File

@@ -18,7 +18,9 @@ class BankTransaction extends Model
// 거래 유형 상수
public const TYPE_DEPOSIT = 'deposit'; // 입금
public const TYPE_WITHDRAWAL = 'withdrawal'; // 출금
public const TYPE_TRANSFER = 'transfer'; // 이체
protected $fillable = [
@@ -106,7 +108,8 @@ public function getIsWithdrawalAttribute(): bool
public function getFormattedAmountAttribute(): string
{
$prefix = $this->is_deposit ? '+' : '-';
return $prefix . number_format(abs($this->amount)) . '원';
return $prefix.number_format(abs($this->amount)).'원';
}
/**
@@ -114,7 +117,7 @@ public function getFormattedAmountAttribute(): string
*/
public function getFormattedBalanceAfterAttribute(): string
{
return number_format($this->balance_after) . '원';
return number_format($this->balance_after).'원';
}
/**

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Models\Finance;
use Illuminate\Database\Eloquent\Model;

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Models\Finance;
use Illuminate\Database\Eloquent\Model;

View File

@@ -1,4 +1,5 @@
<?php
namespace App\Models\Finance;
use Illuminate\Database\Eloquent\Model;

Some files were not shown because too many files have changed in this diff Show More