Files
sam-api/app/Swagger/v1/PricingApi.php
hskwon b6f36cc967 feat: ClientGroup 및 Pricing API 완성 및 Swagger 문서 작성
- ClientGroupService 구현: 고객 그룹 관리 비즈니스 로직 (CRUD + toggle)
- ClientGroupController 구현: 6개 REST API 엔드포인트
- PricingController 구현: 5개 가격 관리 API 엔드포인트
- routes/api.php에 client-groups, pricing 라우트 등록
- ClientGroupApi.php Swagger 문서 작성 (OpenAPI 3.0)
- PricingApi.php Swagger 문서 작성 (OpenAPI 3.0)
- l5-swagger 재생성 완료

추가된 파일:
- app/Services/ClientGroupService.php
- app/Http/Controllers/Api/V1/ClientGroupController.php
- app/Http/Controllers/Api/V1/PricingController.php
- app/Swagger/v1/ClientGroupApi.php
- app/Swagger/v1/PricingApi.php

수정된 파일:
- routes/api.php (라우트 11개 추가)
- CURRENT_WORKS.md (작업 내용 문서화)

API 엔드포인트:
- GET/POST/PUT/DELETE /api/v1/client-groups
- GET/POST /api/v1/pricing (show, bulk, upsert 포함)
2025-10-13 22:06:42 +09:00

204 lines
9.6 KiB
PHP

<?php
namespace App\Swagger\v1;
/**
* @OA\Tag(name="Pricing", description="가격 이력 관리")
*
* @OA\Schema(
* schema="PriceHistory",
* type="object",
* required={"id","item_type_code","item_id","price_type_code","price","started_at"},
* @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="tenant_id", type="integer", example=1),
* @OA\Property(property="item_type_code", type="string", enum={"PRODUCT","MATERIAL"}, example="PRODUCT", description="항목 유형"),
* @OA\Property(property="item_id", type="integer", example=10, description="제품/자재 ID"),
* @OA\Property(property="price_type_code", type="string", enum={"SALE","PURCHASE"}, example="SALE", description="가격 유형"),
* @OA\Property(property="client_group_id", type="integer", nullable=true, example=1, description="고객 그룹 ID (NULL=기본 가격)"),
* @OA\Property(property="price", type="number", format="decimal", example=50000.00),
* @OA\Property(property="started_at", type="string", format="date", example="2025-01-01"),
* @OA\Property(property="ended_at", type="string", format="date", nullable=true, example="2025-12-31"),
* @OA\Property(property="created_at", type="string", example="2025-10-01 12:00:00"),
* @OA\Property(property="updated_at", type="string", example="2025-10-01 12:00:00")
* )
*
* @OA\Schema(
* schema="PriceHistoryPagination",
* type="object",
* @OA\Property(property="current_page", type="integer", example=1),
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/PriceHistory")
* ),
* @OA\Property(property="first_page_url", type="string", example="/api/v1/pricing?page=1"),
* @OA\Property(property="from", type="integer", example=1),
* @OA\Property(property="last_page", type="integer", example=3),
* @OA\Property(property="last_page_url", type="string", example="/api/v1/pricing?page=3"),
* @OA\Property(
* property="links",
* type="array",
* @OA\Items(type="object",
* @OA\Property(property="url", type="string", nullable=true, example=null),
* @OA\Property(property="label", type="string", example="&laquo; Previous"),
* @OA\Property(property="active", type="boolean", example=false)
* )
* ),
* @OA\Property(property="next_page_url", type="string", nullable=true, example="/api/v1/pricing?page=2"),
* @OA\Property(property="path", type="string", example="/api/v1/pricing"),
* @OA\Property(property="per_page", type="integer", example=15),
* @OA\Property(property="prev_page_url", type="string", nullable=true, example=null),
* @OA\Property(property="to", type="integer", example=15),
* @OA\Property(property="total", type="integer", example=50)
* )
*
* @OA\Schema(
* schema="PriceUpsertRequest",
* type="object",
* required={"item_type_code","item_id","price_type_code","price","started_at"},
* @OA\Property(property="item_type_code", type="string", enum={"PRODUCT","MATERIAL"}, example="PRODUCT"),
* @OA\Property(property="item_id", type="integer", example=10),
* @OA\Property(property="price_type_code", type="string", enum={"SALE","PURCHASE"}, example="SALE"),
* @OA\Property(property="client_group_id", type="integer", nullable=true, example=1, description="NULL=기본 가격"),
* @OA\Property(property="price", type="number", format="decimal", example=50000.00),
* @OA\Property(property="started_at", type="string", format="date", example="2025-01-01"),
* @OA\Property(property="ended_at", type="string", format="date", nullable=true, example="2025-12-31")
* )
*
* @OA\Schema(
* schema="PriceQueryResult",
* type="object",
* @OA\Property(property="price", type="number", format="decimal", nullable=true, example=50000.00),
* @OA\Property(property="price_history_id", type="integer", nullable=true, example=1),
* @OA\Property(property="client_group_id", type="integer", nullable=true, example=1),
* @OA\Property(property="warning", type="string", nullable=true, example="가격을 찾을 수 없습니다")
* )
*
* @OA\Schema(
* schema="BulkPriceQueryRequest",
* type="object",
* required={"items"},
* @OA\Property(
* property="items",
* type="array",
* @OA\Items(type="object",
* @OA\Property(property="item_type", type="string", enum={"PRODUCT","MATERIAL"}, example="PRODUCT"),
* @OA\Property(property="item_id", type="integer", example=10)
* )
* ),
* @OA\Property(property="client_id", type="integer", nullable=true, example=5),
* @OA\Property(property="date", type="string", format="date", nullable=true, example="2025-10-13")
* )
*
* @OA\Schema(
* schema="BulkPriceQueryResult",
* type="object",
* @OA\Property(
* property="prices",
* type="array",
* @OA\Items(type="object",
* @OA\Property(property="item_type", type="string", example="PRODUCT"),
* @OA\Property(property="item_id", type="integer", example=10),
* @OA\Property(property="price", type="number", nullable=true, example=50000.00),
* @OA\Property(property="price_history_id", type="integer", nullable=true, example=1),
* @OA\Property(property="client_group_id", type="integer", nullable=true, example=1)
* )
* ),
* @OA\Property(property="warnings", type="array", @OA\Items(type="string"))
* )
*/
class PricingApi
{
/**
* @OA\Get(
* path="/api/v1/pricing",
* tags={"Pricing"},
* summary="가격 이력 목록",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
* @OA\Parameter(name="item_type_code", in="query", @OA\Schema(type="string", enum={"PRODUCT","MATERIAL"})),
* @OA\Parameter(name="item_id", in="query", @OA\Schema(type="integer")),
* @OA\Parameter(name="price_type_code", in="query", @OA\Schema(type="string", enum={"SALE","PURCHASE"})),
* @OA\Parameter(name="client_group_id", in="query", @OA\Schema(type="integer")),
* @OA\Parameter(name="date", in="query", description="특정 날짜 기준 유효한 가격", @OA\Schema(type="string", format="date")),
* @OA\Parameter(name="size", in="query", @OA\Schema(type="integer", example=15)),
* @OA\Response(response=200, description="조회 성공",
* @OA\JsonContent(allOf={
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/PriceHistoryPagination"))
* })
* ),
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function index() {}
/**
* @OA\Get(
* path="/api/v1/pricing/show",
* tags={"Pricing"},
* summary="단일 항목 가격 조회",
* description="특정 제품/자재의 현재 유효한 가격 조회",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
* @OA\Parameter(name="item_type", in="query", required=true, @OA\Schema(type="string", enum={"PRODUCT","MATERIAL"})),
* @OA\Parameter(name="item_id", in="query", required=true, @OA\Schema(type="integer")),
* @OA\Parameter(name="client_id", in="query", @OA\Schema(type="integer"), description="고객 ID (고객 그룹별 가격 적용)"),
* @OA\Parameter(name="date", in="query", @OA\Schema(type="string", format="date"), description="기준일 (미지정시 오늘)"),
* @OA\Response(response=200, description="조회 성공",
* @OA\JsonContent(allOf={
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/PriceQueryResult"))
* })
* )
* )
*/
public function show() {}
/**
* @OA\Post(
* path="/api/v1/pricing/bulk",
* tags={"Pricing"},
* summary="여러 항목 일괄 가격 조회",
* description="여러 제품/자재의 가격을 한 번에 조회",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/BulkPriceQueryRequest")),
* @OA\Response(response=200, description="조회 성공",
* @OA\JsonContent(allOf={
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/BulkPriceQueryResult"))
* })
* )
* )
*/
public function bulk() {}
/**
* @OA\Post(
* path="/api/v1/pricing/upsert",
* tags={"Pricing"},
* summary="가격 등록/수정",
* description="가격 이력 등록 (동일 조건 존재 시 업데이트)",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/PriceUpsertRequest")),
* @OA\Response(response=200, description="저장 성공",
* @OA\JsonContent(allOf={
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/PriceHistory"))
* })
* ),
* @OA\Response(response=400, description="검증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
* )
*/
public function upsert() {}
/**
* @OA\Delete(
* path="/api/v1/pricing/{id}",
* tags={"Pricing"},
* summary="가격 이력 삭제(soft)",
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
* @OA\Parameter(name="id", in="path", required=true, @OA\Schema(type="integer")),
* @OA\Response(response=200, description="삭제 성공", @OA\JsonContent(ref="#/components/schemas/ApiResponse"))
* )
*/
public function destroy() {}
}