Files
Gnuboard7/modules/_bundled/sirsoft-ecommerce/src/Repositories/ExtraFeeTemplateRepository.php
T
HeuJung b3d0da9355 fix(release): 7.0.7 릴리즈 검증 발견 결함 전수 처리 및 출시일 8/18 정렬
7.0.7 페이로드 전수 검증에서 발견된 error 4건·warn 14건을 릴리즈 전에
처리했다. 미출시 분량의 자체 결함(회원 통합검색 500, 관리자 스코프 403 의
500 위장 등)이므로 페이로드에 합류시키고, 출시 대상 26개 CHANGELOG 의
버전 섹션 날짜를 2026-08-18 로 정렬했다.

- 통합검색 import 복원 + 이커머스 관리자 typed 403 catch 대칭(테스트 동반)
- admin 판정 스니핑 사설 사본 전수 수렴(BoardResource) + 조건 스캔 테스트
- 스케줄 인터프리터 변형 표기(확장자·버전 접미사) 정규화 차단
- ckeditor5 참조 판정 배치화·fail-safe, 결제 플러그인 진단 페이로드 대칭
- 템플릿 다크 대비·상태 Select value-제어 + --production 재빌드
- Upgrade_7_0_7 잔존 중복 색인 정리 스텝, API 문서·i18n(ko/en/ja) 동기
2026-08-18 08:12:55 +09:00

271 lines
7.7 KiB
PHP

<?php
namespace Modules\Sirsoft\Ecommerce\Repositories;
use App\Repositories\Concerns\PaginatesWithDeferredJoin;
use App\Repositories\Concerns\ResolvesSortSpec;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
use Modules\Sirsoft\Ecommerce\Models\ExtraFeeTemplate;
use Modules\Sirsoft\Ecommerce\Repositories\Contracts\ExtraFeeTemplateRepositoryInterface;
/**
* 추가배송비 템플릿 Repository 구현체
*/
class ExtraFeeTemplateRepository implements ExtraFeeTemplateRepositoryInterface
{
use PaginatesWithDeferredJoin;
use ResolvesSortSpec;
/** 허용 정렬 컬럼 (ExtraFeeTemplate::scopeOrderByField 와 동일 집합) */
private const SORTABLE_COLUMNS = ['id', 'zipcode', 'fee', 'region', 'is_active', 'created_at', 'updated_at'];
public function __construct(
protected ExtraFeeTemplate $model
) {}
/**
* {@inheritDoc}
*/
public function find(int $id): ?ExtraFeeTemplate
{
return $this->model->find($id);
}
/**
* {@inheritDoc}
*/
public function findByZipcode(string $zipcode): ?ExtraFeeTemplate
{
return $this->model->where('zipcode', $zipcode)->first();
}
/**
* 여러 우편번호로 템플릿을 한 번에 조회
*
* @param array $zipcodes 우편번호 목록
* @return Collection
*/
public function findByZipcodes(array $zipcodes): Collection
{
if (empty($zipcodes)) {
return $this->model->newCollection();
}
return $this->model->whereIn('zipcode', $zipcodes)->get();
}
/**
* {@inheritDoc}
*/
public function getListWithFilters(array $filters, int $perPage = 20): LengthAwarePaginator
{
$query = $this->model->newQuery();
// 검색어 (우편번호 또는 지역명)
if (! empty($filters['search'])) {
$query->search($filters['search']);
}
// 지역 필터
if (! empty($filters['region'])) {
$query->inRegion($filters['region']);
}
// 사용여부 필터
if (isset($filters['is_active']) && $filters['is_active'] !== '') {
$isActive = filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN);
$query->where('is_active', $isActive);
}
// 정렬 (모델 scopeOrderByField 와 동일한 허용 집합)
$sort = $this->resolveSortSpec($filters, self::SORTABLE_COLUMNS, 'zipcode', 'asc');
// 지연 조인: 우편번호 단위 행이라 건수가 커질 수 있고 description(text)이 있어
// OFFSET 이 훑는 구간에서 넓은 컬럼까지 읽힌다. inner 는 id 만 훑는다.
return $this->paginateWithDeferredJoin(
query: $query,
columns: ['*'],
sort: $sort,
perPage: $perPage,
);
}
/**
* {@inheritDoc}
*/
public function create(array $data): ExtraFeeTemplate
{
$data['created_by'] = auth()->id();
return $this->model->create($data);
}
/**
* {@inheritDoc}
*/
public function update(ExtraFeeTemplate $template, array $data): ExtraFeeTemplate
{
$data['updated_by'] = auth()->id();
$template->update($data);
return $template->fresh();
}
/**
* {@inheritDoc}
*/
public function delete(ExtraFeeTemplate $template): bool
{
return $template->delete();
}
/**
* {@inheritDoc}
*/
public function toggleActive(ExtraFeeTemplate $template): ExtraFeeTemplate
{
$template->update([
'is_active' => ! $template->is_active,
'updated_by' => auth()->id(),
]);
return $template->fresh();
}
/**
* {@inheritDoc}
*/
public function bulkDelete(array $ids): int
{
return $this->model->whereIn('id', $ids)->delete();
}
/**
* {@inheritDoc}
*/
public function bulkToggleActive(array $ids, bool $isActive): int
{
return $this->model
->whereIn('id', $ids)
->update([
'is_active' => $isActive,
'updated_by' => auth()->id(),
'updated_at' => now(),
]);
}
/**
* {@inheritDoc}
*/
public function getActiveList(): Collection
{
// audit:allow query-unbounded-get reason: 추가배송비 템플릿은 운영자 등록 설정성 테이블 — 행 수가 운영자 행위(도서산간 우편번호 등록)에 묶여 데이터 증가에 비례하지 않는다
return $this->model
->active()
->orderBy('zipcode')
->get();
}
/**
* {@inheritDoc}
*/
public function getAllAsExtraFeeSettings(): array
{
// audit:allow query-unbounded-get reason: 추가배송비 템플릿은 운영자 등록 설정성 테이블 — 행 수가 운영자 행위(도서산간 우편번호 등록)에 묶여 데이터 증가에 비례하지 않는다
return $this->model
->active()
->orderBy('zipcode')
->get()
->map(fn ($template) => $template->toExtraFeeSetting())
->toArray();
}
/**
* {@inheritDoc}
*/
public function bulkCreate(array $items): int
{
$userId = auth()->id();
$now = now();
$count = 0;
// Batch insert for performance
$chunks = array_chunk($items, 100);
foreach ($chunks as $chunk) {
$records = array_map(function ($item) use ($userId, $now) {
return [
'zipcode' => $item['zipcode'],
'fee' => $item['fee'] ?? 0,
'region' => $item['region'] ?? null,
'description' => $item['description'] ?? null,
'is_active' => $item['is_active'] ?? true,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
];
}, $chunk);
// upsert: 우편번호 중복 시 업데이트
$this->model->upsert(
$records,
['zipcode'],
['fee', 'region', 'description', 'is_active', 'updated_by', 'updated_at']
);
$count += count($chunk);
}
return $count;
}
/**
* {@inheritDoc}
*/
public function getStatisticsByRegion(): array
{
$total = $this->model->count();
$active = $this->model->where('is_active', true)->count();
$inactive = $this->model->where('is_active', false)->count();
// 지역별 통계
$regionStats = $this->model
->selectRaw('region, COUNT(*) as count, AVG(fee) as avg_fee, MIN(fee) as min_fee, MAX(fee) as max_fee')
->whereNotNull('region')
->groupBy('region')
->orderBy('region')
->get()
->map(fn ($row) => [
'region' => $row->region,
'count' => $row->count,
'avg_fee' => round($row->avg_fee, 2),
'min_fee' => $row->min_fee,
'max_fee' => $row->max_fee,
])
->toArray();
return [
'total' => $total,
'active' => $active,
'inactive' => $inactive,
'by_region' => $regionStats,
];
}
/**
* ID 목록으로 조회하고 ID 키 맵으로 반환합니다 (bulk activity log lookup).
*
* @param array<int, int> $ids ID 목록
* @return Collection
*/
public function findByIdsKeyed(array $ids): Collection
{
if (empty($ids)) {
return new Collection;
}
return ExtraFeeTemplate::whereIn('id', $ids)->get()->keyBy('id');
}
}