1051 lines
52 KiB
PHP
1051 lines
52 KiB
PHP
<?php
|
|
|
|
namespace Modules\Sirsoft\Ecommerce\Database\Seeders;
|
|
|
|
use App\Enums\ActivityLogType;
|
|
use App\Models\ActivityLog;
|
|
use App\Models\User;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Carbon;
|
|
use Modules\Sirsoft\Ecommerce\Enums\CouponIssueStatus;
|
|
use Modules\Sirsoft\Ecommerce\Enums\OrderStatusEnum;
|
|
use Modules\Sirsoft\Ecommerce\Enums\ProductSalesStatus;
|
|
use Modules\Sirsoft\Ecommerce\Models\Brand;
|
|
use Modules\Sirsoft\Ecommerce\Models\Category;
|
|
use Modules\Sirsoft\Ecommerce\Models\Coupon;
|
|
use Modules\Sirsoft\Ecommerce\Models\ExtraFeeTemplate;
|
|
use Modules\Sirsoft\Ecommerce\Models\Order;
|
|
use Modules\Sirsoft\Ecommerce\Models\OrderOption;
|
|
use Modules\Sirsoft\Ecommerce\Models\Product;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductCommonInfo;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductImage;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductLabel;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductNoticeTemplate;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductOption;
|
|
use Modules\Sirsoft\Ecommerce\Models\ProductReview;
|
|
use Modules\Sirsoft\Ecommerce\Models\ShippingCarrier;
|
|
use Modules\Sirsoft\Ecommerce\Models\ShippingPolicy;
|
|
|
|
/**
|
|
* 이커머스 활동 로그 샘플 시더
|
|
*
|
|
* 데모용 ActivityLog를 생성합니다.
|
|
* 각 리소스마다 rand(1, 50)건의 로그를 무작위 생성합니다.
|
|
*/
|
|
class ActivityLogSampleSeeder extends Seeder
|
|
{
|
|
/** @var string 다국어 키 접두사 */
|
|
private const PREFIX = 'sirsoft-ecommerce::activity_log.description.';
|
|
|
|
/** @var array<string> 샘플 IP 목록 */
|
|
private const IPS = ['192.168.1.10', '10.0.0.5', '172.16.0.1', '192.168.0.100', '10.10.10.1'];
|
|
|
|
/** @var array<string> 샘플 User-Agent 목록 */
|
|
private const USER_AGENTS = [
|
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/125.0',
|
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15',
|
|
'Mozilla/5.0 (X11; Linux x86_64) Firefox/126.0',
|
|
];
|
|
|
|
/**
|
|
* 시더를 실행합니다.
|
|
*/
|
|
public function run(): void
|
|
{
|
|
$admins = User::whereHas('roles', fn ($q) => $q->where('identifier', 'admin'))->get();
|
|
if ($admins->isEmpty()) {
|
|
$this->command->warn('관리자 사용자가 없어 이커머스 활동 로그 시더를 건너뜁니다.');
|
|
|
|
return;
|
|
}
|
|
|
|
$users = User::whereDoesntHave('roles', fn ($q) => $q->where('identifier', 'admin'))->get();
|
|
if ($users->isEmpty()) {
|
|
$users = $admins;
|
|
}
|
|
|
|
// 기존 이커머스 활동 로그 삭제
|
|
$deleted = ActivityLog::where('description_key', 'like', 'sirsoft-ecommerce::%')->delete();
|
|
if ($deleted > 0) {
|
|
$this->command->info("기존 이커머스 활동 로그 {$deleted}건 삭제.");
|
|
}
|
|
|
|
$count = 0;
|
|
|
|
$count += $this->seedProductLogs($admins);
|
|
$count += $this->seedProductImageLogs($admins);
|
|
$count += $this->seedProductOptionLogs($admins);
|
|
$count += $this->seedOrderLogs($admins);
|
|
$count += $this->seedCouponLogs($admins);
|
|
$count += $this->seedShippingPolicyLogs($admins);
|
|
$count += $this->seedCategoryLogs($admins);
|
|
$count += $this->seedBrandLogs($admins);
|
|
$count += $this->seedReviewLogs($admins);
|
|
$count += $this->seedLabelLogs($admins);
|
|
$count += $this->seedCommonInfoLogs($admins);
|
|
$count += $this->seedNoticeTemplateLogs($admins);
|
|
$count += $this->seedExtraFeeLogs($admins);
|
|
$count += $this->seedCarrierLogs($admins);
|
|
$count += $this->seedSettingsLogs($admins);
|
|
$count += $this->seedCartLogs($users);
|
|
$count += $this->seedWishlistLogs($users);
|
|
$count += $this->seedCouponUseLogs($users);
|
|
$count += $this->seedMileageLogs($users);
|
|
$count += $this->seedUserOrderLogs($users);
|
|
|
|
$this->command->info("이커머스 활동 로그 {$count}건 생성 완료.");
|
|
}
|
|
|
|
// ──────────────────────────────────────────────
|
|
// Admin 리소스 로그
|
|
// ──────────────────────────────────────────────
|
|
|
|
/**
|
|
* 상품 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedProductLogs($admins): int
|
|
{
|
|
$products = Product::get();
|
|
if ($products->isEmpty()) {
|
|
$this->command->warn('상품 데이터가 없어 상품 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'product.create', 'key' => 'product_create', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'product.update', 'key' => 'product_update', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'selling_price', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.selling_price', 'old' => (int) ($p->selling_price * $this->randomFloat(0.8, 1.2)), 'new' => $p->selling_price, 'type' => 'currency'],
|
|
['field' => 'sales_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.sales_status', 'old' => $this->pickDifferentEnum(ProductSalesStatus::class, $p->sales_status), 'new' => $p->sales_status?->value ?? ProductSalesStatus::ON_SALE->value, 'type' => 'enum'],
|
|
]],
|
|
['action' => 'product.show', 'key' => 'product_show', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_id' => $p->id]],
|
|
['action' => 'product.delete', 'key' => 'product_delete', 'loggable' => false,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)],
|
|
'properties' => fn ($p) => ['deleted_id' => $p->id, 'product_name' => $this->getLocalizedName($p->name), 'product_code' => $p->product_code]],
|
|
['action' => 'product.bulk_update', 'key' => 'product_bulk_update', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name), 'count' => 1],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'sales_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.sales_status', 'old' => $p->sales_status?->value ?? ProductSalesStatus::ON_SALE->value, 'new' => $this->pickDifferentEnum(ProductSalesStatus::class, $p->sales_status), 'type' => 'enum'],
|
|
]],
|
|
['action' => 'product.bulk_price_update', 'key' => 'product_bulk_price_update', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name), 'count' => 1],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'selling_price', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.selling_price', 'old' => (int) ($p->selling_price * $this->randomFloat(0.8, 1.2)), 'new' => $p->selling_price, 'type' => 'currency'],
|
|
]],
|
|
['action' => 'product.bulk_stock_update', 'key' => 'product_bulk_stock_update', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name), 'count' => 1],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'stock_quantity', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.stock_quantity', 'old' => rand(0, 50), 'new' => $p->stock_quantity ?? rand(10, 100), 'type' => 'number'],
|
|
]],
|
|
['action' => 'product.stock_sync', 'key' => 'product_stock_sync', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($products, $admins, ActivityLogType::Admin, (new Product)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'product.index', 'key' => 'product_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 상품 이미지 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedProductImageLogs($admins): int
|
|
{
|
|
$images = ProductImage::with('product')->get();
|
|
if ($images->isEmpty()) {
|
|
$this->command->warn('상품 이미지 데이터가 없어 이미지 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$getName = fn ($img) => $img->product ? $this->getLocalizedName($img->product->name) : '삭제된 상품';
|
|
|
|
$actions = [
|
|
['action' => 'product_image.upload', 'key' => 'product_image_upload', 'loggable' => true,
|
|
'params' => fn ($img) => ['product_name' => $getName($img)]],
|
|
['action' => 'product_image.delete', 'key' => 'product_image_delete', 'loggable' => false,
|
|
'params' => fn ($img) => ['product_name' => $getName($img)],
|
|
'properties' => fn ($img) => ['deleted_id' => $img->id]],
|
|
['action' => 'product_image.reorder', 'key' => 'product_image_reorder', 'loggable' => true,
|
|
'params' => fn ($img) => ['product_name' => $getName($img)]],
|
|
];
|
|
|
|
return $this->generateResourceLogs($images, $admins, ActivityLogType::Admin, (new ProductImage)->getMorphClass(), $actions);
|
|
}
|
|
|
|
/**
|
|
* 상품 옵션 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedProductOptionLogs($admins): int
|
|
{
|
|
$options = ProductOption::with('product')->get();
|
|
if ($options->isEmpty()) {
|
|
$this->command->warn('상품 옵션 데이터가 없어 옵션 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'product_option.bulk_price_update', 'key' => 'product_option_bulk_price_update', 'loggable' => true,
|
|
'params' => fn ($opt) => ['count' => rand(2, 20)],
|
|
'changes' => fn ($opt) => [
|
|
['field' => 'price_adjustment', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.price_adjustment', 'old' => rand(0, 5000), 'new' => $opt->price_adjustment ?? 0, 'type' => 'currency'],
|
|
]],
|
|
['action' => 'product_option.bulk_stock_update', 'key' => 'product_option_bulk_stock_update', 'loggable' => true,
|
|
'params' => fn ($opt) => ['count' => rand(2, 20)],
|
|
'changes' => fn ($opt) => [
|
|
['field' => 'stock_quantity', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.stock_quantity', 'old' => rand(0, 30), 'new' => $opt->stock_quantity ?? rand(10, 100), 'type' => 'number'],
|
|
]],
|
|
['action' => 'product_option.bulk_update', 'key' => 'product_option_bulk_update', 'loggable' => true,
|
|
'params' => fn ($opt) => ['count' => rand(2, 20)],
|
|
'changes' => fn ($opt) => [
|
|
['field' => 'sku', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.sku', 'old' => 'OLD-SKU-'.rand(100, 999), 'new' => $opt->sku ?? 'SKU-'.rand(100, 999), 'type' => 'text'],
|
|
]],
|
|
];
|
|
|
|
return $this->generateResourceLogs($options, $admins, ActivityLogType::Admin, (new ProductOption)->getMorphClass(), $actions);
|
|
}
|
|
|
|
/**
|
|
* 주문 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedOrderLogs($admins): int
|
|
{
|
|
$orders = Order::with('options')->get();
|
|
if ($orders->isEmpty()) {
|
|
$this->command->warn('주문 데이터가 없어 주문 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$orderActions = [
|
|
['action' => 'order.create', 'key' => 'order_create', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'order.show', 'key' => 'order_show', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'order.update', 'key' => 'order_update', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number],
|
|
'changes' => fn ($o) => [
|
|
['field' => 'order_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.order_status', 'old' => $this->pickDifferentEnum(OrderStatusEnum::class, $o->order_status), 'new' => $o->order_status?->value ?? OrderStatusEnum::PAYMENT_COMPLETE->value, 'type' => 'enum'],
|
|
['field' => 'admin_memo', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.admin_memo', 'old' => ($o->admin_memo ?? '').' (수정 전)', 'new' => $o->admin_memo ?? '', 'type' => 'text'],
|
|
]],
|
|
['action' => 'order.delete', 'key' => 'order_delete', 'loggable' => false,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number],
|
|
'properties' => fn ($o) => ['deleted_id' => $o->id, 'order_number' => $o->order_number, 'total_amount' => $o->total_amount]],
|
|
['action' => 'order.cancel', 'key' => 'order_cancel', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number],
|
|
'properties' => fn ($o) => ['cancelled_amount' => $o->total_amount, 'reason' => '고객 요청에 의한 취소']],
|
|
['action' => 'order.partial_cancel', 'key' => 'order_partial_cancel', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'order.bulk_update', 'key' => 'order_bulk_update', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number, 'count' => 1],
|
|
'changes' => fn ($o) => [
|
|
['field' => 'admin_memo', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.admin_memo', 'old' => '이전 메모', 'new' => $o->admin_memo ?? '', 'type' => 'text'],
|
|
]],
|
|
['action' => 'order.bulk_status_update', 'key' => 'order_bulk_status_update', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number, 'count' => 1],
|
|
'changes' => fn ($o) => [
|
|
['field' => 'order_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.order_status', 'old' => $o->order_status?->value ?? OrderStatusEnum::PAYMENT_COMPLETE->value, 'new' => $this->pickDifferentEnum(OrderStatusEnum::class, $o->order_status), 'type' => 'enum'],
|
|
]],
|
|
['action' => 'order.bulk_shipping_update', 'key' => 'order_bulk_shipping_update', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number, 'count' => 1],
|
|
'changes' => fn ($o) => [
|
|
['field' => 'order_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.order_status', 'old' => OrderStatusEnum::PREPARING->value, 'new' => OrderStatusEnum::SHIPPING->value, 'type' => 'enum',
|
|
'old_label_key' => OrderStatusEnum::PREPARING->labelKey(), 'new_label_key' => OrderStatusEnum::SHIPPING->labelKey()],
|
|
]],
|
|
['action' => 'order.payment_complete', 'key' => 'order_payment_complete', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'order.payment_failed', 'key' => 'order_payment_failed', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'order.update_shipping_address', 'key' => 'order_update_shipping_address', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number],
|
|
'changes' => fn ($o) => [
|
|
['field' => 'recipient_name', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.recipient_name', 'old' => '홍길동', 'new' => '김철수', 'type' => 'text'],
|
|
['field' => 'address', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.address', 'old' => '서울시 강남구', 'new' => '서울시 서초구', 'type' => 'text'],
|
|
]],
|
|
['action' => 'order.send_email', 'key' => 'order_send_email', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'coupon.restore', 'key' => 'order_coupon_restore', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
['action' => 'mileage.restore', 'key' => 'order_mileage_restore', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number, 'amount' => number_format(rand(500, 3000))]],
|
|
['action' => 'coupon.use', 'key' => 'coupon_use', 'loggable' => true,
|
|
'params' => fn ($o) => ['coupon_name' => '샘플 쿠폰']],
|
|
['action' => 'mileage.use', 'key' => 'mileage_use', 'loggable' => true,
|
|
'params' => fn ($o) => ['amount' => number_format(rand(500, 3000))]],
|
|
['action' => 'mileage.earn', 'key' => 'mileage_earn', 'loggable' => true,
|
|
'params' => fn ($o) => ['amount' => number_format(rand(100, 5000))]],
|
|
['action' => 'payment.refund', 'key' => 'payment_refund', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($orders, $admins, ActivityLogType::Admin, (new Order)->getMorphClass(), $orderActions);
|
|
|
|
// OrderOption 레벨 로그
|
|
$allOptions = OrderOption::with('order')->whereIn('order_id', $orders->pluck('id'))->get();
|
|
if ($allOptions->isNotEmpty()) {
|
|
$optionActions = [
|
|
['action' => 'order_option.status_change', 'key' => 'order_option_status_change', 'loggable' => true,
|
|
'params' => fn ($opt) => ['order_number' => $opt->order?->order_number ?? 'N/A']],
|
|
['action' => 'order_option.bulk_status_change', 'key' => 'order_option_bulk_status_change', 'loggable' => true,
|
|
'params' => fn ($opt) => ['count' => 1]],
|
|
['action' => 'order_option.confirm', 'key' => 'order_option_confirm', 'loggable' => true,
|
|
'params' => fn ($opt) => ['order_number' => $opt->order?->order_number ?? 'N/A'],
|
|
'properties' => fn ($opt) => ['order_id' => $opt->order_id]],
|
|
['action' => 'order_option.partial_cancel', 'key' => 'order_option_partial_cancel', 'loggable' => true,
|
|
'params' => fn ($opt) => ['order_number' => $opt->order?->order_number ?? 'N/A'],
|
|
'properties' => fn ($opt) => ['order_id' => $opt->order_id, 'product_name' => $opt->product_name, 'quantity' => $opt->quantity]],
|
|
];
|
|
|
|
$count += $this->generateResourceLogs($allOptions, $admins, ActivityLogType::Admin, (new OrderOption)->getMorphClass(), $optionActions);
|
|
}
|
|
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'order.index', 'key' => 'order_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 쿠폰 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCouponLogs($admins): int
|
|
{
|
|
$coupons = Coupon::get();
|
|
if ($coupons->isEmpty()) {
|
|
$this->command->warn('쿠폰 데이터가 없어 쿠폰 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'coupon.create', 'key' => 'coupon_create', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name]],
|
|
['action' => 'coupon.update', 'key' => 'coupon_update', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name],
|
|
'changes' => fn ($c) => [
|
|
['field' => 'discount_value', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.discount_value', 'old' => (int) (($c->discount_value ?? 1000) * $this->randomFloat(0.8, 1.2)), 'new' => $c->discount_value, 'type' => 'currency'],
|
|
['field' => 'issue_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.issue_status', 'old' => $this->pickDifferentEnum(CouponIssueStatus::class, $c->issue_status), 'new' => $c->issue_status?->value ?? CouponIssueStatus::ISSUING->value, 'type' => 'enum'],
|
|
]],
|
|
['action' => 'coupon.show', 'key' => 'coupon_show', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name]],
|
|
['action' => 'coupon.delete', 'key' => 'coupon_delete', 'loggable' => false,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name],
|
|
'properties' => fn ($c) => ['deleted_id' => $c->id, 'coupon_name' => $c->name]],
|
|
['action' => 'coupon.bulk_status', 'key' => 'coupon_bulk_status', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name, 'count' => 1],
|
|
'changes' => fn ($c) => [
|
|
['field' => 'issue_status', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.issue_status', 'old' => $c->issue_status?->value ?? CouponIssueStatus::ISSUING->value, 'new' => $this->pickDifferentEnum(CouponIssueStatus::class, $c->issue_status), 'type' => 'enum'],
|
|
]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($coupons, $admins, ActivityLogType::Admin, (new Coupon)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'coupon.index', 'key' => 'coupon_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 배송정책 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedShippingPolicyLogs($admins): int
|
|
{
|
|
$policies = ShippingPolicy::get();
|
|
if ($policies->isEmpty()) {
|
|
$this->command->warn('배송정책 데이터가 없어 배송정책 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'shipping_policy.create', 'key' => 'shipping_policy_create', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'shipping_policy.update', 'key' => 'shipping_policy_update', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name)],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'is_active', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.is_active', 'old' => ! $p->is_active, 'new' => $p->is_active, 'type' => 'boolean'],
|
|
]],
|
|
['action' => 'shipping_policy.toggle_active', 'key' => 'shipping_policy_toggle_active', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'shipping_policy.set_default', 'key' => 'shipping_policy_set_default', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'shipping_policy.delete', 'key' => 'shipping_policy_delete', 'loggable' => false,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name)],
|
|
'properties' => fn ($p) => ['deleted_id' => $p->id, 'policy_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'shipping_policy.bulk_delete', 'key' => 'shipping_policy_bulk_delete', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name), 'count' => 1]],
|
|
['action' => 'shipping_policy.bulk_toggle_active', 'key' => 'shipping_policy_bulk_toggle_active', 'loggable' => true,
|
|
'params' => fn ($p) => ['policy_name' => $this->getLocalizedName($p->name), 'count' => 1]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($policies, $admins, ActivityLogType::Admin, (new ShippingPolicy)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'shipping_policy.index', 'key' => 'shipping_policy_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 카테고리 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCategoryLogs($admins): int
|
|
{
|
|
$categories = Category::get();
|
|
if ($categories->isEmpty()) {
|
|
$this->command->warn('카테고리 데이터가 없어 카테고리 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'category.create', 'key' => 'category_create', 'loggable' => true,
|
|
'params' => fn ($c) => ['category_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'category.update', 'key' => 'category_update', 'loggable' => true,
|
|
'params' => fn ($c) => ['category_name' => $this->getLocalizedName($c->name)],
|
|
'changes' => fn ($c) => [
|
|
['field' => 'sort_order', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.sort_order', 'old' => $c->sort_order + rand(1, 5), 'new' => $c->sort_order, 'type' => 'number'],
|
|
]],
|
|
['action' => 'category.toggle_status', 'key' => 'category_toggle_status', 'loggable' => true,
|
|
'params' => fn ($c) => ['category_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'category.show', 'key' => 'category_show', 'loggable' => true,
|
|
'params' => fn ($c) => ['category_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'category.delete', 'key' => 'category_delete', 'loggable' => false,
|
|
'params' => fn ($c) => ['category_name' => $this->getLocalizedName($c->name)],
|
|
'properties' => fn ($c) => ['deleted_id' => $c->id, 'category_name' => $this->getLocalizedName($c->name)]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($categories, $admins, ActivityLogType::Admin, (new Category)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'category.index', 'key' => 'category_index', 'params' => []],
|
|
['action' => 'category.reorder', 'key' => 'category_reorder', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 브랜드 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedBrandLogs($admins): int
|
|
{
|
|
$brands = Brand::get();
|
|
if ($brands->isEmpty()) {
|
|
$this->command->warn('브랜드 데이터가 없어 브랜드 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'brand.create', 'key' => 'brand_create', 'loggable' => true,
|
|
'params' => fn ($b) => ['brand_name' => $this->getLocalizedName($b->name)]],
|
|
['action' => 'brand.update', 'key' => 'brand_update', 'loggable' => true,
|
|
'params' => fn ($b) => ['brand_name' => $this->getLocalizedName($b->name)],
|
|
'changes' => fn ($b) => [
|
|
['field' => 'website', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.website', 'old' => 'https://old-brand.example.com', 'new' => $b->website ?? 'https://brand.example.com', 'type' => 'text'],
|
|
]],
|
|
['action' => 'brand.show', 'key' => 'brand_show', 'loggable' => true,
|
|
'params' => fn ($b) => ['brand_name' => $this->getLocalizedName($b->name)]],
|
|
['action' => 'brand.toggle_status', 'key' => 'brand_toggle_status', 'loggable' => true,
|
|
'params' => fn ($b) => ['brand_name' => $this->getLocalizedName($b->name)]],
|
|
['action' => 'brand.delete', 'key' => 'brand_delete', 'loggable' => false,
|
|
'params' => fn ($b) => ['brand_name' => $this->getLocalizedName($b->name)],
|
|
'properties' => fn ($b) => ['deleted_id' => $b->id, 'brand_name' => $this->getLocalizedName($b->name)]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($brands, $admins, ActivityLogType::Admin, (new Brand)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'brand.index', 'key' => 'brand_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 리뷰 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedReviewLogs($admins): int
|
|
{
|
|
$reviews = ProductReview::with('product')->get();
|
|
if ($reviews->isEmpty()) {
|
|
$this->command->warn('리뷰 데이터가 없어 리뷰 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'review.show', 'key' => 'review_show', 'loggable' => true,
|
|
'params' => fn ($r) => ['review_id' => $r->id]],
|
|
['action' => 'review.create', 'key' => 'review_create', 'loggable' => true,
|
|
'params' => fn ($r) => ['product_name' => $r->product ? $this->getLocalizedName($r->product->name) : '삭제된 상품']],
|
|
['action' => 'review.delete', 'key' => 'review_delete', 'loggable' => false,
|
|
'params' => fn ($r) => ['review_id' => $r->id],
|
|
'properties' => fn ($r) => ['deleted_id' => $r->id, 'product_id' => $r->product_id, 'user_id' => $r->user_id]],
|
|
['action' => 'review.reply', 'key' => 'review_reply', 'loggable' => true,
|
|
'params' => fn ($r) => ['review_id' => $r->id]],
|
|
['action' => 'product_review.bulk_delete', 'key' => 'review_bulk_delete', 'loggable' => true,
|
|
'params' => fn ($r) => ['review_id' => $r->id, 'count' => 1]],
|
|
['action' => 'product_review.create', 'key' => 'product_review_create', 'loggable' => true,
|
|
'params' => fn ($r) => ['product_name' => $r->product ? $this->getLocalizedName($r->product->name) : '삭제된 상품']],
|
|
['action' => 'product_review.delete', 'key' => 'product_review_delete', 'loggable' => false,
|
|
'params' => fn ($r) => ['product_name' => $r->product ? $this->getLocalizedName($r->product->name) : '삭제된 상품'],
|
|
'properties' => fn ($r) => ['deleted_id' => $r->id]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($reviews, $admins, ActivityLogType::Admin, (new ProductReview)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'review.index', 'key' => 'review_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 라벨 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedLabelLogs($admins): int
|
|
{
|
|
$labels = ProductLabel::get();
|
|
if ($labels->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'label.create', 'key' => 'label_create', 'loggable' => true,
|
|
'params' => fn ($l) => ['label_name' => $this->getLocalizedName($l->name)]],
|
|
['action' => 'label.update', 'key' => 'label_update', 'loggable' => true,
|
|
'params' => fn ($l) => ['label_name' => $this->getLocalizedName($l->name)]],
|
|
['action' => 'label.toggle_status', 'key' => 'label_toggle_status', 'loggable' => true,
|
|
'params' => fn ($l) => ['label_name' => $this->getLocalizedName($l->name)]],
|
|
['action' => 'label.delete', 'key' => 'label_delete', 'loggable' => false,
|
|
'params' => fn ($l) => ['label_name' => $this->getLocalizedName($l->name)],
|
|
'properties' => fn ($l) => ['deleted_id' => $l->id]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($labels, $admins, ActivityLogType::Admin, (new ProductLabel)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'label.index', 'key' => 'label_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 공통정보 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCommonInfoLogs($admins): int
|
|
{
|
|
$infos = ProductCommonInfo::get();
|
|
if ($infos->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'product_common_info.create', 'key' => 'product_common_info_create', 'loggable' => true,
|
|
'params' => fn ($i) => ['info_name' => $this->getLocalizedName($i->name)]],
|
|
['action' => 'product_common_info.update', 'key' => 'product_common_info_update', 'loggable' => true,
|
|
'params' => fn ($i) => ['info_name' => $this->getLocalizedName($i->name)]],
|
|
['action' => 'product_common_info.delete', 'key' => 'product_common_info_delete', 'loggable' => false,
|
|
'params' => fn ($i) => ['info_name' => $this->getLocalizedName($i->name)],
|
|
'properties' => fn ($i) => ['deleted_id' => $i->id]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($infos, $admins, ActivityLogType::Admin, (new ProductCommonInfo)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'product_common_info.index', 'key' => 'product_common_info_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 고시정보 템플릿 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedNoticeTemplateLogs($admins): int
|
|
{
|
|
$templates = ProductNoticeTemplate::get();
|
|
if ($templates->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'product_notice_template.create', 'key' => 'product_notice_template_create', 'loggable' => true,
|
|
'params' => fn ($t) => ['template_name' => $this->getLocalizedName($t->name)]],
|
|
['action' => 'product_notice_template.update', 'key' => 'product_notice_template_update', 'loggable' => true,
|
|
'params' => fn ($t) => ['template_name' => $this->getLocalizedName($t->name)]],
|
|
['action' => 'product_notice_template.copy', 'key' => 'product_notice_template_copy', 'loggable' => true,
|
|
'params' => fn ($t) => ['template_name' => $this->getLocalizedName($t->name)]],
|
|
['action' => 'product_notice_template.delete', 'key' => 'product_notice_template_delete', 'loggable' => false,
|
|
'params' => fn ($t) => ['template_name' => $this->getLocalizedName($t->name)],
|
|
'properties' => fn ($t) => ['deleted_id' => $t->id]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($templates, $admins, ActivityLogType::Admin, (new ProductNoticeTemplate)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'product_notice_template.index', 'key' => 'product_notice_template_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 추가배송비 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedExtraFeeLogs($admins): int
|
|
{
|
|
$fees = ExtraFeeTemplate::get();
|
|
if ($fees->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$getName = fn ($f) => $f->region ?? $f->zipcode;
|
|
|
|
$actions = [
|
|
['action' => 'extra_fee_template.create', 'key' => 'extra_fee_template_create', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f)]],
|
|
['action' => 'extra_fee_template.update', 'key' => 'extra_fee_template_update', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f)]],
|
|
['action' => 'extra_fee_template.toggle_active', 'key' => 'extra_fee_template_toggle_active', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f)]],
|
|
['action' => 'extra_fee_template.delete', 'key' => 'extra_fee_template_delete', 'loggable' => false,
|
|
'params' => fn ($f) => ['template_name' => $getName($f)],
|
|
'properties' => fn ($f) => ['deleted_id' => $f->id]],
|
|
['action' => 'extra_fee_template.bulk_delete', 'key' => 'extra_fee_template_bulk_delete', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f), 'count' => 1]],
|
|
['action' => 'extra_fee_template.bulk_toggle_active', 'key' => 'extra_fee_template_bulk_toggle_active', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f), 'count' => 1]],
|
|
['action' => 'extra_fee_template.bulk_create', 'key' => 'extra_fee_template_bulk_create', 'loggable' => true,
|
|
'params' => fn ($f) => ['template_name' => $getName($f), 'count' => 1]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($fees, $admins, ActivityLogType::Admin, (new ExtraFeeTemplate)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'extra_fee_template.index', 'key' => 'extra_fee_template_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 배송사 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCarrierLogs($admins): int
|
|
{
|
|
$carriers = ShippingCarrier::get();
|
|
if ($carriers->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'shipping_carrier.create', 'key' => 'shipping_carrier_create', 'loggable' => true,
|
|
'params' => fn ($c) => ['carrier_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'shipping_carrier.update', 'key' => 'shipping_carrier_update', 'loggable' => true,
|
|
'params' => fn ($c) => ['carrier_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'shipping_carrier.show', 'key' => 'shipping_carrier_show', 'loggable' => true,
|
|
'params' => fn ($c) => ['carrier_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'shipping_carrier.toggle_status', 'key' => 'shipping_carrier_toggle_status', 'loggable' => true,
|
|
'params' => fn ($c) => ['carrier_name' => $this->getLocalizedName($c->name)]],
|
|
['action' => 'shipping_carrier.delete', 'key' => 'shipping_carrier_delete', 'loggable' => false,
|
|
'params' => fn ($c) => ['carrier_name' => $this->getLocalizedName($c->name)],
|
|
'properties' => fn ($c) => ['deleted_id' => $c->id]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($carriers, $admins, ActivityLogType::Admin, (new ShippingCarrier)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'shipping_carrier.index', 'key' => 'shipping_carrier_index', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 이커머스 설정 활동 로그
|
|
*
|
|
* @param Collection $admins 관리자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedSettingsLogs($admins): int
|
|
{
|
|
return $this->generateNonResourceLogs($admins, ActivityLogType::Admin, [
|
|
['action' => 'ecommerce_settings.index', 'key' => 'ecommerce_settings_index', 'params' => []],
|
|
]);
|
|
}
|
|
|
|
// ──────────────────────────────────────────────
|
|
// User 리소스 로그
|
|
// ──────────────────────────────────────────────
|
|
|
|
/**
|
|
* 장바구니 활동 로그
|
|
*
|
|
* @param Collection $users 사용자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCartLogs($users): int
|
|
{
|
|
$products = Product::where('sales_status', ProductSalesStatus::ON_SALE)->get();
|
|
if ($products->isEmpty()) {
|
|
$this->command->warn('판매중 상품이 없어 장바구니 활동 로그를 건너뜁니다.');
|
|
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'cart.add', 'key' => 'cart_add', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'cart.update_quantity', 'key' => 'cart_update_quantity', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)],
|
|
'changes' => fn ($p) => [
|
|
['field' => 'quantity', 'label_key' => 'sirsoft-ecommerce::activity_log.fields.quantity', 'old' => rand(1, 3), 'new' => rand(1, 10), 'type' => 'number'],
|
|
]],
|
|
['action' => 'cart.change_option', 'key' => 'cart_change_option', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'cart.delete', 'key' => 'cart_delete', 'loggable' => false,
|
|
'params' => fn ($p) => [],
|
|
'properties' => fn ($p) => ['product_id' => $p->id, 'product_name' => $this->getLocalizedName($p->name)]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($products, $users, ActivityLogType::User, (new Product)->getMorphClass(), $actions);
|
|
$count += $this->generateNonResourceLogs($users, ActivityLogType::User, [
|
|
['action' => 'cart.delete_all', 'key' => 'cart_delete_all', 'params' => []],
|
|
]);
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 찜 활동 로그
|
|
*
|
|
* @param Collection $users 사용자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedWishlistLogs($users): int
|
|
{
|
|
$products = Product::where('sales_status', ProductSalesStatus::ON_SALE)->get();
|
|
if ($products->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'wishlist.add', 'key' => 'wishlist_add', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
['action' => 'wishlist.remove', 'key' => 'wishlist_remove', 'loggable' => true,
|
|
'params' => fn ($p) => ['product_name' => $this->getLocalizedName($p->name)]],
|
|
];
|
|
|
|
return $this->generateResourceLogs($products, $users, ActivityLogType::User, (new Product)->getMorphClass(), $actions);
|
|
}
|
|
|
|
/**
|
|
* 쿠폰 사용/다운로드/복원 활동 로그
|
|
*
|
|
* @param Collection $users 사용자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedCouponUseLogs($users): int
|
|
{
|
|
$coupons = Coupon::get();
|
|
if ($coupons->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'coupon.use', 'key' => 'coupon_use', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name]],
|
|
['action' => 'coupon.restore', 'key' => 'coupon_restore', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name]],
|
|
['action' => 'user_coupon.download', 'key' => 'user_coupon_download', 'loggable' => true,
|
|
'params' => fn ($c) => ['coupon_name' => $c->name]],
|
|
];
|
|
|
|
return $this->generateResourceLogs($coupons, $users, ActivityLogType::User, (new Coupon)->getMorphClass(), $actions);
|
|
}
|
|
|
|
/**
|
|
* 마일리지 활동 로그
|
|
*
|
|
* @param Collection $users 사용자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedMileageLogs($users): int
|
|
{
|
|
$orders = Order::get();
|
|
if ($orders->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
$actions = [
|
|
['action' => 'mileage.earn', 'key' => 'mileage_earn', 'loggable' => true,
|
|
'params' => fn ($o) => ['amount' => number_format($o->total_earned_points_amount > 0 ? $o->total_earned_points_amount : rand(100, 5000))]],
|
|
['action' => 'mileage.use', 'key' => 'mileage_use', 'loggable' => true,
|
|
'params' => fn ($o) => ['amount' => number_format($o->total_points_used_amount > 0 ? $o->total_points_used_amount : rand(500, 3000))]],
|
|
['action' => 'mileage.restore', 'key' => 'mileage_restore', 'loggable' => true,
|
|
'params' => fn ($o) => ['amount' => number_format(rand(100, 2000))]],
|
|
];
|
|
|
|
return $this->generateResourceLogs($orders, $users, ActivityLogType::User, (new Order)->getMorphClass(), $actions);
|
|
}
|
|
|
|
/**
|
|
* 사용자 주문/구매확인 활동 로그 (User 타입)
|
|
*
|
|
* @param Collection $users 사용자 컬렉션
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function seedUserOrderLogs($users): int
|
|
{
|
|
$orders = Order::with('options')->get();
|
|
if ($orders->isEmpty()) {
|
|
return 0;
|
|
}
|
|
|
|
// 주문 레벨
|
|
$orderActions = [
|
|
['action' => 'order.create', 'key' => 'user_order_create', 'loggable' => true,
|
|
'params' => fn ($o) => ['order_number' => $o->order_number]],
|
|
];
|
|
|
|
$count = $this->generateResourceLogs($orders, $users, ActivityLogType::User, (new Order)->getMorphClass(), $orderActions);
|
|
|
|
// OrderOption 레벨
|
|
$allOptions = OrderOption::with('order')->whereIn('order_id', $orders->pluck('id'))->get();
|
|
if ($allOptions->isNotEmpty()) {
|
|
$optionActions = [
|
|
['action' => 'order_option.confirm', 'key' => 'user_order_option_confirm', 'loggable' => true,
|
|
'params' => fn ($opt) => ['order_number' => $opt->order?->order_number ?? 'N/A'],
|
|
'properties' => fn ($opt) => ['order_id' => $opt->order_id]],
|
|
];
|
|
|
|
$count += $this->generateResourceLogs($allOptions, $users, ActivityLogType::User, (new OrderOption)->getMorphClass(), $optionActions);
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
// ──────────────────────────────────────────────
|
|
// 헬퍼 메서드
|
|
// ──────────────────────────────────────────────
|
|
|
|
/**
|
|
* 리소스별 rand(1, 50)건의 랜덤 활동 로그를 생성합니다.
|
|
*
|
|
* @param iterable $resources 리소스 컬렉션
|
|
* @param Collection $actors 사용자 컬렉션
|
|
* @param ActivityLogType $logType 로그 유형
|
|
* @param string $morphType 모델 morph 타입
|
|
* @param array $actions 액션 템플릿 배열
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function generateResourceLogs(
|
|
$resources,
|
|
Collection $actors,
|
|
ActivityLogType $logType,
|
|
string $morphType,
|
|
array $actions,
|
|
): int {
|
|
$count = 0;
|
|
|
|
foreach ($resources as $resource) {
|
|
$logCount = rand(1, 50);
|
|
|
|
for ($i = 0; $i < $logCount; $i++) {
|
|
$action = $actions[array_rand($actions)];
|
|
|
|
$this->createLog(
|
|
$logType,
|
|
$action['loggable'] ? $morphType : null,
|
|
$action['loggable'] ? $resource->id : null,
|
|
$actors->random()->id,
|
|
$action['action'],
|
|
self::PREFIX.$action['key'],
|
|
($action['params'])($resource),
|
|
isset($action['changes']) ? ($action['changes'])($resource) : null,
|
|
isset($action['properties']) ? ($action['properties'])($resource) : null,
|
|
);
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* 리소스에 속하지 않는 글로벌 액션 로그를 생성합니다. (index 등)
|
|
*
|
|
* @param Collection $actors 사용자 컬렉션
|
|
* @param ActivityLogType $logType 로그 유형
|
|
* @param array $actions 액션 정의 배열
|
|
* @return int 생성된 로그 수
|
|
*/
|
|
private function generateNonResourceLogs(
|
|
Collection $actors,
|
|
ActivityLogType $logType,
|
|
array $actions,
|
|
): int {
|
|
$count = 0;
|
|
|
|
foreach ($actions as $action) {
|
|
$logCount = rand(1, 5);
|
|
|
|
for ($i = 0; $i < $logCount; $i++) {
|
|
$this->createLog(
|
|
$logType,
|
|
null,
|
|
null,
|
|
$actors->random()->id,
|
|
$action['action'],
|
|
self::PREFIX.$action['key'],
|
|
$action['params'],
|
|
);
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* ActivityLog 레코드를 생성합니다.
|
|
*
|
|
* @param ActivityLogType $logType 로그 유형
|
|
* @param string|null $loggableType 모델 morph 타입
|
|
* @param int|null $loggableId 모델 ID
|
|
* @param int $userId 사용자 ID
|
|
* @param string $action 액션명
|
|
* @param string $descriptionKey 다국어 키
|
|
* @param array $descriptionParams 다국어 파라미터
|
|
* @param array|null $changes 변경 이력
|
|
* @param array|null $properties 추가 속성
|
|
*/
|
|
private function createLog(
|
|
ActivityLogType $logType,
|
|
?string $loggableType,
|
|
?int $loggableId,
|
|
int $userId,
|
|
string $action,
|
|
string $descriptionKey,
|
|
array $descriptionParams,
|
|
?array $changes = null,
|
|
?array $properties = null,
|
|
): ActivityLog {
|
|
return ActivityLog::create([
|
|
'log_type' => $logType,
|
|
'loggable_type' => $loggableType,
|
|
'loggable_id' => $loggableId,
|
|
'user_id' => $userId,
|
|
'action' => $action,
|
|
'description_key' => $descriptionKey,
|
|
'description_params' => $descriptionParams,
|
|
'changes' => $changes,
|
|
'properties' => $properties,
|
|
'ip_address' => self::IPS[array_rand(self::IPS)],
|
|
'user_agent' => self::USER_AGENTS[array_rand(self::USER_AGENTS)],
|
|
'created_at' => Carbon::now()->subDays(rand(1, 30))->subHours(rand(0, 23))->subMinutes(rand(0, 59)),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 다국어 name 배열에서 현재 로케일 값을 가져옵니다.
|
|
*
|
|
* @param mixed $name name 속성 (배열 또는 문자열)
|
|
*/
|
|
private function getLocalizedName(mixed $name): string
|
|
{
|
|
if (is_string($name)) {
|
|
return $name;
|
|
}
|
|
|
|
if (is_array($name)) {
|
|
$locale = app()->getLocale();
|
|
|
|
return $name[$locale] ?? $name['ko'] ?? $name[array_key_first($name)] ?? '';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Enum에서 현재 값과 다른 값을 반환합니다.
|
|
*
|
|
* @param class-string $enumClass Enum 클래스
|
|
* @param mixed $currentValue 현재 값
|
|
*/
|
|
private function pickDifferentEnum(string $enumClass, mixed $currentValue): string
|
|
{
|
|
$cases = $enumClass::cases();
|
|
$currentStr = $currentValue instanceof \BackedEnum ? $currentValue->value : (string) $currentValue;
|
|
|
|
$others = array_filter($cases, fn ($c) => $c->value !== $currentStr);
|
|
|
|
if (empty($others)) {
|
|
return $cases[0]->value;
|
|
}
|
|
|
|
return $others[array_rand($others)]->value;
|
|
}
|
|
|
|
/**
|
|
* 지정 범위 내 랜덤 float를 반환합니다.
|
|
*
|
|
* @param float $min 최소값
|
|
* @param float $max 최대값
|
|
*/
|
|
private function randomFloat(float $min, float $max): float
|
|
{
|
|
return $min + mt_rand() / mt_getrandmax() * ($max - $min);
|
|
}
|
|
}
|