<?php
namespace Plugin\PiaHistory\EventSubscriber;
use Eccube\Entity\Product;
use Eccube\Repository\ProductRepository;
use Eccube\Repository\MemberRepository;
use Doctrine\ORM\EntityManagerInterface;
use Plugin\PiaHistory\Entity\PiaHistory;
use Plugin\PiaHistory\Entity\PiaHisProduct;
use Plugin\PiaHistory\Entity\PiaHisProductClass;
use Plugin\PiaHistory\Entity\PiaHisProductCategory;
use Plugin\PiaHistory\Entity\PiaHisProductImage;
use Plugin\PiaHistory\Entity\PiaHisProductStock;
use Plugin\PiaHistory\Entity\PiaHisProductTag;
use Plugin\PiaHistory\Entity\PiaHisProductAdd;
use Plugin\PiaHistory\Entity\PiaHisRankPrice;
use Plugin\PiaHistory\Entity\PiaHisCustomerClass;
use Plugin\PiaHistory\Entity\PiaHisPoint;
use Plugin\PiaHistory\Entity\PiaHisMeyasu;
use Plugin\PiaHistory\Repository\PiaHistoryRepository;
use Plugin\PiaHistory\Repository\PiaHisProductRepository;
use Plugin\PiaHistory\Repository\PiaHisProductClassRepository;
use Plugin\PiaHistory\Repository\PiaHisProductCategoryRepository;
use Plugin\PiaHistory\Repository\PiaHisProductImageRepository;
use Plugin\PiaHistory\Repository\PiaHisProductStockRepository;
use Plugin\PiaHistory\Repository\PiaHisProductTagRepository;
use Plugin\PiaHistory\Repository\PiaHisProductAddRepository;
use Plugin\PiaHistory\Repository\PiaHisRankPriceRepository;
use Plugin\PiaHistory\Repository\PiaHisCustomerClassRepository;
use Plugin\PiaHistory\Repository\PiaHisPointRepository;
use Plugin\PiaHistory\Repository\PiaHisMeyasuRepository;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
class ProductEditEventSubscriber implements EventSubscriberInterface
{
private $piaHistoryRepository;
private $piaHisProductRepository;
private $piaHisProductClassRepository;
private $piaHisProductCategoryRepository;
private $piaHisProductImageRepository;
private $piaHisProductStockRepository;
private $piaHisProductTagRepository;
private $piaHisProductAddRepository;
private $piaHisRankPriceRepository;
private $piaHisCustomerClassRepository;
private $piaHisPointRepository;
private $piaHisMeyasuRepository;
private $productRepository;
private $memberRepository;
private $tokenStorage;
private $entityManager;
private $requestStack;
// 商品基本情報のフィールドラベル(updateNote生成用)
private static $basicFieldLabels = [
'name' => '商品名',
'note' => 'ショップ用メモ欄',
'description_list' => '商品一覧コメント',
'description_detail' => '商品説明',
'search_word' => '検索ワード',
'free_area' => 'フリーエリア',
'status' => '商品ステータス',
'datetime_start' => '表示設定日時(開始)',
'datetime_end' => '表示設定日時(終了)',
];
// 商品規格フィールドのラベル(updateNote生成用)
private static $classFieldLabels = [
'price02' => '販売価格',
'price01' => '通常価格',
'stock' => '在庫',
];
public function __construct(
PiaHistoryRepository $piaHistoryRepository,
PiaHisProductRepository $piaHisProductRepository,
PiaHisProductClassRepository $piaHisProductClassRepository,
PiaHisProductCategoryRepository $piaHisProductCategoryRepository,
PiaHisProductImageRepository $piaHisProductImageRepository,
PiaHisProductStockRepository $piaHisProductStockRepository,
PiaHisProductTagRepository $piaHisProductTagRepository,
PiaHisProductAddRepository $piaHisProductAddRepository,
PiaHisRankPriceRepository $piaHisRankPriceRepository,
PiaHisCustomerClassRepository $piaHisCustomerClassRepository,
PiaHisPointRepository $piaHisPointRepository,
PiaHisMeyasuRepository $piaHisMeyasuRepository,
ProductRepository $productRepository,
MemberRepository $memberRepository,
TokenStorageInterface $tokenStorage,
EntityManagerInterface $entityManager,
RequestStack $requestStack
) {
$this->piaHistoryRepository = $piaHistoryRepository;
$this->piaHisProductRepository = $piaHisProductRepository;
$this->piaHisProductClassRepository = $piaHisProductClassRepository;
$this->piaHisProductCategoryRepository = $piaHisProductCategoryRepository;
$this->piaHisProductImageRepository = $piaHisProductImageRepository;
$this->piaHisProductStockRepository = $piaHisProductStockRepository;
$this->piaHisProductTagRepository = $piaHisProductTagRepository;
$this->piaHisProductAddRepository = $piaHisProductAddRepository;
$this->piaHisRankPriceRepository = $piaHisRankPriceRepository;
$this->piaHisCustomerClassRepository = $piaHisCustomerClassRepository;
$this->piaHisPointRepository = $piaHisPointRepository;
$this->piaHisMeyasuRepository = $piaHisMeyasuRepository;
$this->productRepository = $productRepository;
$this->memberRepository = $memberRepository;
$this->tokenStorage = $tokenStorage;
$this->entityManager = $entityManager;
$this->requestStack = $requestStack;
}
public static function getSubscribedEvents()
{
return [
'kernel.request' => ['onKernelRequest', 0],
EccubeEvents::ADMIN_PRODUCT_EDIT_COMPLETE => ['onProductEditComplete', -1000],
];
}
/**
* 商品編集画面のPOSTリクエストを検知して変更前の値を保存
*/
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
if ($request->isMethod('POST') &&
$request->attributes->get('_route') === 'admin_product_product_edit') {
$productId = $request->get('id');
error_log('PiaHistory: onKernelRequest - Product ID: ' . $productId);
if ($productId) {
$this->saveProductBeforeData($productId);
}
}
}
public function onProductEditComplete(EventArgs $event)
{
error_log('PiaHistory: onProductEditComplete called');
$Product = $event->getArgument('Product');
if ($Product && $Product->getId()) {
$this->saveProductHistory($Product->getId());
}
}
// -------------------------------------------------------------------------
// 変更前データをセッションに保存
// -------------------------------------------------------------------------
private function saveProductBeforeData($productId)
{
try {
$product = $this->productRepository->find($productId);
if (!$product) {
return;
}
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
return;
}
$session = $request->getSession();
$beforeData = [
'product' => $this->buildProductSnapshot($product),
'product_classes' => $this->buildProductClassesSnapshot($product),
'product_categories' => $this->buildProductCategoriesSnapshot($product),
'product_images' => $this->buildProductImagesSnapshot($product),
'product_tags' => $this->buildProductTagsSnapshot($product),
'rank_prices' => $this->buildRankPricesSnapshot($product),
'product_add' => $this->buildProductAddSnapshot($product),
];
$session->set('pia_history_before_data_' . $productId, $beforeData);
} catch (\Exception $e) {
error_log('PiaHistory: 変更前データ保存エラー - ' . $e->getMessage());
}
}
/** 商品基本情報スナップショット */
private function buildProductSnapshot(Product $product): array
{
return [
'id' => $product->getId(),
'name' => $product->getName(),
'note' => $product->getNote(),
'description_list' => $product->getDescriptionList(),
'description_detail' => $product->getDescriptionDetail(),
'search_word' => $product->getSearchWord(),
'free_area' => $product->getFreeArea(),
'status' => $product->getStatus() ? $product->getStatus()->getId() : null,
'datetime_start' => $this->getDisplayStartDate($product),
'datetime_end' => $this->getDisplayEndDate($product),
];
}
/** 商品規格スナップショット(変更検知で比較するフィールドのみ) */
private function buildProductClassesSnapshot(Product $product): array
{
$data = [];
foreach ($product->getProductClasses() as $pc) {
$data[] = [
'id' => $pc->getId(),
'code' => $pc->getCode(),
'price01' => (string)$pc->getPrice01(),
'price02' => (string)$pc->getPrice02(),
'stock' => $pc->isStockUnlimited() ? null : (string)$pc->getStock(),
];
}
return $data;
}
/** 商品カテゴリースナップショット */
private function buildProductCategoriesSnapshot(Product $product): array
{
$data = [];
foreach ($product->getProductCategories() as $i => $pc) {
$data[] = [
'category_id' => $pc->getCategory()->getId(),
'rank' => $i + 1,
];
}
return $data;
}
/** 商品画像スナップショット */
private function buildProductImagesSnapshot(Product $product): array
{
$data = [];
foreach ($product->getProductImage() as $i => $img) {
$data[] = [
'file_name' => $img->getFileName(),
'rank' => $img->getSortNo() ?: ($i + 1),
];
}
return $data;
}
/** 商品タグスナップショット */
private function buildProductTagsSnapshot(Product $product): array
{
$data = [];
foreach ($product->getProductTag() as $pt) {
$data[] = ['tag_id' => $pt->getTag()->getId()];
}
return $data;
}
/** 会員別価格スナップショット(CustomerRank42) */
private function buildRankPricesSnapshot(Product $product): array
{
$data = [];
if (!class_exists('Plugin\CustomerRank42\Entity\CustomerPrice')) {
return $data;
}
try {
$repo = $this->entityManager->getRepository('Plugin\CustomerRank42\Entity\CustomerPrice');
foreach ($product->getProductClasses() as $pc) {
$prices = $repo->findBy(['ProductClass' => $pc]);
foreach ($prices as $cp) {
$data[] = [
'product_class_id' => $pc->getId(),
'product_code' => $pc->getCode(),
'rank_id' => $cp->getCustomerRank()->getId(),
'rank_name' => $cp->getCustomerRank()->getName(),
'price' => (string)$cp->getPrice(),
];
}
}
} catch (\Exception $e) {
error_log('PiaHistory: 会員別価格スナップショットエラー - ' . $e->getMessage());
}
return $data;
}
/** 商品追加項目スナップショット(ProductPlus42) */
private function buildProductAddSnapshot(Product $product): array
{
$data = [];
if (!class_exists('Plugin\ProductPlus42\Entity\ProductData')) {
return $data;
}
try {
$repo = $this->entityManager->getRepository('Plugin\ProductPlus42\Entity\ProductData');
$productDatas = $repo->findBy(['Product' => $product]);
foreach ($productDatas as $pd) {
$item = $pd->getProductItem();
if (!$item) {
continue;
}
$data[] = [
'item_id' => $item->getId(),
'item_name' => $item->getName(),
'value' => $pd->getDataValue(),
];
}
} catch (\Exception $e) {
error_log('PiaHistory: 商品追加項目スナップショットエラー - ' . $e->getMessage());
}
return $data;
}
// -------------------------------------------------------------------------
// 履歴保存メイン
// -------------------------------------------------------------------------
private function saveProductHistory($productId)
{
try {
error_log('PiaHistory: saveProductHistory called for Product ID: ' . $productId);
if (!$this->entityManager->isOpen()) {
error_log('PiaHistory: EntityManager is closed, skipping history save');
return;
}
$product = $this->productRepository->find($productId);
if (!$product) {
return;
}
$request = $this->requestStack->getCurrentRequest();
if (!$request) {
return;
}
$session = $request->getSession();
$beforeData = $session->get('pia_history_before_data_' . $productId);
if (!$beforeData) {
return;
}
// 変更検知
$changes = $this->detectDetailedChanges($product, $beforeData);
error_log('PiaHistory: Changes detected: ' . (empty($changes) ? 'NO' : 'YES'));
if (empty($changes)) {
$session->remove('pia_history_before_data_' . $productId);
return;
}
// updateNote / updateNum を生成
['num' => $num, 'note' => $note] = $this->generateUpdateNote($changes);
// 管理者情報を取得
[$adminId, $adminName, $adminDepartment] = $this->getAdminInfo();
$this->entityManager->beginTransaction();
// 履歴メイン登録
$history = new PiaHistory();
$history->setProductId($productId);
$history->setUpdateId($adminId);
$history->setUpdateName($adminName);
$history->setUpdateDepartment($adminDepartment);
$history->setUpdateNum($num);
$history->setUpdateNote($note);
$history->setCreateDate(new \DateTime());
$history->setUpdateDate(new \DateTime());
$history->setDelFlg(0);
$this->entityManager->persist($history);
$this->entityManager->flush();
$historyId = $history->getId();
// 各詳細テーブルへの保存
if (isset($changes['product'])) {
$this->saveProductBasicHistory($historyId, $product, $changes['product']);
}
if (isset($changes['product_classes'])) {
$this->saveProductClassHistory($historyId, $product);
}
if (isset($changes['product_categories'])) {
$this->saveProductCategoryHistory($historyId, $product);
}
if (isset($changes['product_images'])) {
$this->saveProductImageHistory($historyId, $product);
}
if (isset($changes['product_tags'])) {
$this->saveProductTagHistory($historyId, $product);
}
// 在庫は常に現状を保存
$this->saveProductStockHistory($historyId, $product);
// 会員別価格(変更があった場合のみ)
if (isset($changes['rank_prices'])) {
$this->saveRankPriceHistory($historyId, $product);
}
// 商品追加項目(変更があった場合のみ)
if (isset($changes['product_add'])) {
$this->saveProductAddHistory($historyId, $product);
}
// 目安価格
$this->saveMeyasuHistory($historyId, $product);
$this->entityManager->flush();
$this->entityManager->commit();
$session->remove('pia_history_before_data_' . $productId);
} catch (\Exception $e) {
if ($this->entityManager->getConnection()->isTransactionActive()) {
$this->entityManager->rollback();
}
error_log('PiaHistory: 商品履歴保存エラー - ' . $e->getMessage());
}
}
// -------------------------------------------------------------------------
// 変更検知
// -------------------------------------------------------------------------
private function detectDetailedChanges(Product $product, array $beforeData): array
{
$changes = [];
// 基本情報
$currentProduct = $this->buildProductSnapshot($product);
$diffFields = [];
foreach (array_keys(self::$basicFieldLabels) as $field) {
if (($currentProduct[$field] ?? null) !== ($beforeData['product'][$field] ?? null)) {
$diffFields[$field] = [
'before' => $beforeData['product'][$field] ?? null,
'after' => $currentProduct[$field] ?? null,
];
}
}
if (!empty($diffFields)) {
$changes['product'] = $diffFields;
}
// 商品規格(同一フィールド構造で比較)
$currentClasses = $this->buildProductClassesSnapshot($product);
if ($currentClasses !== ($beforeData['product_classes'] ?? [])) {
$changes['product_classes'] = [
'before' => $beforeData['product_classes'] ?? [],
'after' => $currentClasses,
];
}
// カテゴリー
$currentCategories = $this->buildProductCategoriesSnapshot($product);
if ($currentCategories !== ($beforeData['product_categories'] ?? [])) {
$changes['product_categories'] = [
'before' => $beforeData['product_categories'] ?? [],
'after' => $currentCategories,
];
}
// 画像
$currentImages = $this->buildProductImagesSnapshot($product);
if ($currentImages !== ($beforeData['product_images'] ?? [])) {
$changes['product_images'] = [
'before' => $beforeData['product_images'] ?? [],
'after' => $currentImages,
];
}
// タグ
$currentTags = $this->buildProductTagsSnapshot($product);
if ($currentTags !== ($beforeData['product_tags'] ?? [])) {
$changes['product_tags'] = [
'before' => $beforeData['product_tags'] ?? [],
'after' => $currentTags,
];
}
// 会員別価格(CustomerRank42)
$changedRankPrices = $this->detectRankPriceChanges($product, $beforeData['rank_prices'] ?? []);
if (!empty($changedRankPrices)) {
$changes['rank_prices'] = [
'before' => $beforeData['rank_prices'] ?? [],
'after' => $this->buildRankPricesSnapshot($product),
'changed' => $changedRankPrices,
];
}
// 商品追加項目(ProductPlus42)
$changedProductAdd = $this->detectProductAddChanges($product, $beforeData['product_add'] ?? []);
if (!empty($changedProductAdd)) {
$changes['product_add'] = [
'before' => $beforeData['product_add'] ?? [],
'after' => $this->buildProductAddSnapshot($product),
'changed' => $changedProductAdd,
];
}
return $changes;
}
/** 会員別価格の変更検知 */
private function detectRankPriceChanges(Product $product, array $beforeRankPrices): array
{
if (!class_exists('Plugin\CustomerRank42\Entity\CustomerPrice')) {
return [];
}
$currentRankPrices = $this->buildRankPricesSnapshot($product);
// [rank_id_productClassId] => price のマップで比較
$beforeMap = [];
foreach ($beforeRankPrices as $rp) {
$key = $rp['rank_id'] . '_' . $rp['product_class_id'];
$beforeMap[$key] = $rp;
}
$afterMap = [];
foreach ($currentRankPrices as $rp) {
$key = $rp['rank_id'] . '_' . $rp['product_class_id'];
$afterMap[$key] = $rp;
}
$changed = [];
foreach ($afterMap as $key => $after) {
$before = $beforeMap[$key] ?? null;
if (!$before || $before['price'] !== $after['price']) {
$changed[] = [
'rank_name' => $after['rank_name'],
'product_code' => $after['product_code'],
'before_price' => $before ? $before['price'] : null,
'after_price' => $after['price'],
];
}
}
foreach ($beforeMap as $key => $before) {
if (!isset($afterMap[$key])) {
$changed[] = [
'rank_name' => $before['rank_name'],
'product_code' => $before['product_code'],
'before_price' => $before['price'],
'after_price' => null,
];
}
}
return $changed;
}
/** 商品追加項目の変更検知 */
private function detectProductAddChanges(Product $product, array $beforeProductAdd): array
{
if (!class_exists('Plugin\ProductPlus42\Entity\ProductData')) {
return [];
}
$currentProductAdd = $this->buildProductAddSnapshot($product);
$beforeMap = [];
foreach ($beforeProductAdd as $pa) {
$beforeMap[$pa['item_id']] = $pa;
}
$afterMap = [];
foreach ($currentProductAdd as $pa) {
$afterMap[$pa['item_id']] = $pa;
}
$changed = [];
foreach ($afterMap as $itemId => $after) {
$before = $beforeMap[$itemId] ?? null;
if (!$before || $before['value'] !== $after['value']) {
$changed[] = [
'item_name' => $after['item_name'],
'before_value' => $before ? $before['value'] : null,
'after_value' => $after['value'],
];
}
}
return $changed;
}
// -------------------------------------------------------------------------
// updateNote / updateNum の生成(EC-CUBE3準拠形式)
// -------------------------------------------------------------------------
private function generateUpdateNote(array $changes): array
{
$logs = [];
$num = 0;
// 商品基本情報
if (isset($changes['product'])) {
foreach (array_keys($changes['product']) as $field) {
$label = self::$basicFieldLabels[$field] ?? $field;
$logs[] = "「{$label}」";
$num++;
}
}
// 商品規格(価格・在庫)フィールド単位でログ
if (isset($changes['product_classes'])) {
$beforeMap = [];
foreach ($changes['product_classes']['before'] as $bc) {
if (isset($bc['code'])) {
$beforeMap[$bc['code']] = $bc;
}
}
foreach ($changes['product_classes']['after'] as $ac) {
$code = $ac['code'] ?? '';
$bc = $beforeMap[$code] ?? null;
if (!$bc) {
continue;
}
foreach (self::$classFieldLabels as $field => $label) {
if (array_key_exists($field, $ac) && array_key_exists($field, $bc) &&
$ac[$field] !== $bc[$field]) {
$logs[] = "「{$code}の{$label}」";
$num++;
}
}
}
}
// 会員別価格
if (isset($changes['rank_prices']['changed'])) {
foreach ($changes['rank_prices']['changed'] as $rp) {
$code = $rp['product_code'] ?? '';
$label = $code ? "{$code}の会員価格:{$rp['rank_name']}" : "会員価格:{$rp['rank_name']}";
$logs[] = "「{$label}」";
$num++;
}
}
// 商品追加項目
if (isset($changes['product_add']['changed'])) {
foreach ($changes['product_add']['changed'] as $pa) {
$logs[] = "「拡張項目:{$pa['item_name']}」";
$num++;
}
}
// カテゴリー
if (isset($changes['product_categories'])) {
$logs[] = '「カテゴリー」';
$num++;
}
// 画像
if (isset($changes['product_images'])) {
$logs[] = '「商品画像」';
$num++;
}
// タグ
if (isset($changes['product_tags'])) {
$logs[] = '「商品タグ」';
$num++;
}
$note = !empty($logs)
? implode('、', $logs) . 'を更新しました。'
: '変更箇所無し';
return ['num' => $num, 'note' => $note];
}
// -------------------------------------------------------------------------
// 各詳細テーブルへの保存
// -------------------------------------------------------------------------
private function saveProductBasicHistory(int $historyId, Product $product, array $changedFields)
{
$productHistory = new PiaHisProduct();
$productHistory->setHisId($historyId);
$productHistory->setProductId($product->getId());
$productHistory->setStatus($product->getStatus() ? $product->getStatus()->getId() : 0);
$productHistory->setName($product->getName());
$productHistory->setNote($product->getNote());
$productHistory->setDescriptionList($product->getDescriptionList());
$productHistory->setDescriptionDetail($product->getDescriptionDetail());
$productHistory->setSearchWord($product->getSearchWord());
$productHistory->setFreeArea($product->getFreeArea());
$productHistory->setDatetimeStart($this->getDisplayStartDate($product));
$productHistory->setDatetimeEnd($this->getDisplayEndDate($product));
$productHistory->setDelFlg(0);
$productHistory->setChangeData(json_encode($changedFields, JSON_UNESCAPED_UNICODE));
$this->entityManager->persist($productHistory);
}
private function saveProductClassHistory(int $historyId, Product $product)
{
foreach ($product->getProductClasses() as $pc) {
$classHistory = new PiaHisProductClass();
$classHistory->setHisId($historyId);
$classHistory->setProductId($product->getId());
$classHistory->setProductTypeId(null);
$classHistory->setClassCategoryId1($pc->getClassCategory1() ? $pc->getClassCategory1()->getId() : null);
$classHistory->setClassCategoryId2($pc->getClassCategory2() ? $pc->getClassCategory2()->getId() : null);
$classHistory->setDeliveryDateId($pc->getDeliveryDuration() ? $pc->getDeliveryDuration()->getId() : null);
$classHistory->setProductCode($pc->getCode());
$classHistory->setStock($pc->getStock());
$classHistory->setStockUnlimited($pc->isStockUnlimited());
$classHistory->setSaleLimit($pc->getSaleLimit());
$classHistory->setPrice01($pc->getPrice01());
$classHistory->setPrice02($pc->getPrice02());
$classHistory->setDeliveryFee($pc->getDeliveryFee());
$this->entityManager->persist($classHistory);
}
}
private function saveProductCategoryHistory(int $historyId, Product $product)
{
foreach ($product->getProductCategories() as $i => $productCategory) {
$categoryHistory = new PiaHisProductCategory();
$categoryHistory->setHisId($historyId);
$categoryHistory->setProductId($product->getId());
$categoryHistory->setCategoryId($productCategory->getCategory()->getId());
$categoryHistory->setRank($i + 1);
$this->entityManager->persist($categoryHistory);
}
}
private function saveProductImageHistory(int $historyId, Product $product)
{
foreach ($product->getProductImage() as $i => $productImage) {
$imageHistory = new PiaHisProductImage();
$imageHistory->setHisId($historyId);
$imageHistory->setProductId($product->getId());
$imageHistory->setFileName($productImage->getFileName());
$imageHistory->setRank($productImage->getSortNo() ?: ($i + 1));
$this->entityManager->persist($imageHistory);
}
}
private function saveProductStockHistory(int $historyId, Product $product)
{
foreach ($product->getProductClasses() as $pc) {
$stockHistory = new PiaHisProductStock();
$stockHistory->setHisId($historyId);
$stockHistory->setProductClassId($pc->getId());
$stockHistory->setStock($pc->isStockUnlimited() ? null : $pc->getStock());
$this->entityManager->persist($stockHistory);
}
}
private function saveProductTagHistory(int $historyId, Product $product)
{
foreach ($product->getProductTag() as $productTag) {
$tagHistory = new PiaHisProductTag();
$tagHistory->setHisId($historyId);
$tagHistory->setProductId($product->getId());
$tagHistory->setTag($productTag->getTag()->getId());
$this->entityManager->persist($tagHistory);
}
}
/** 会員別価格履歴を保存(CustomerRank42) */
private function saveRankPriceHistory(int $historyId, Product $product)
{
if (!class_exists('Plugin\CustomerRank42\Entity\CustomerPrice')) {
return;
}
try {
$repo = $this->entityManager->getRepository('Plugin\CustomerRank42\Entity\CustomerPrice');
foreach ($product->getProductClasses() as $pc) {
$prices = $repo->findBy(['ProductClass' => $pc]);
foreach ($prices as $cp) {
$rankHistory = new PiaHisRankPrice();
$rankHistory->setHisId($historyId);
$rankHistory->setCustomerRankId($cp->getCustomerRank()->getId());
$rankHistory->setProductClassId($pc->getId());
$rankHistory->setPrice($cp->getPrice());
$this->entityManager->persist($rankHistory);
}
}
} catch (\Exception $e) {
error_log('PiaHistory: 会員別価格履歴保存エラー - ' . $e->getMessage());
}
}
/** 商品追加項目履歴を保存(ProductPlus42) */
private function saveProductAddHistory(int $historyId, Product $product)
{
if (!class_exists('Plugin\ProductPlus42\Entity\ProductData')) {
return;
}
try {
$repo = $this->entityManager->getRepository('Plugin\ProductPlus42\Entity\ProductData');
$productDatas = $repo->findBy(['Product' => $product]);
foreach ($productDatas as $pd) {
$item = $pd->getProductItem();
if (!$item) {
continue;
}
$addHistory = new PiaHisProductAdd();
$addHistory->setHisId($historyId);
$addHistory->setProductId($product->getId());
$addHistory->setColumnId($item->getId());
$addHistory->setValue($pd->getDataValue());
$this->entityManager->persist($addHistory);
}
} catch (\Exception $e) {
error_log('PiaHistory: 商品追加項目履歴保存エラー - ' . $e->getMessage());
}
}
/** 目安価格履歴を保存(PiaMeyasu) */
private function saveMeyasuHistory(int $historyId, Product $product)
{
try {
if (!class_exists('Plugin\PiaMeyasu\Entity\PiaMeyasu')) {
return;
}
$meyasuRepo = $this->entityManager->getRepository('Plugin\PiaMeyasu\Entity\PiaMeyasu');
$meyasuData = $meyasuRepo->findOneBy(['product_id' => $product->getId()]);
if ($meyasuData) {
$meyasuHistory = new PiaHisMeyasu();
$meyasuHistory->setHisId($historyId);
$meyasuHistory->setProductId($product->getId());
$meyasuHistory->setCoinCost($meyasuData->getCoinCost());
$meyasuHistory->setExTypeId($meyasuData->getExTypeId());
$meyasuHistory->setCommission($meyasuData->getCommission());
$meyasuHistory->setEsDispPrice($meyasuData->getEsDispPrice());
$this->entityManager->persist($meyasuHistory);
}
} catch (\Exception $e) {
error_log('PiaHistory: 目安価格履歴保存エラー - ' . $e->getMessage());
}
}
// -------------------------------------------------------------------------
// ユーティリティ
// -------------------------------------------------------------------------
/** ログイン管理者情報を取得 */
private function getAdminInfo(): array
{
$adminId = 1;
$adminName = '管理者';
$adminDepartment = '';
if ($this->tokenStorage->getToken() && $this->tokenStorage->getToken()->getUser()) {
$admin = $this->tokenStorage->getToken()->getUser();
$adminId = $admin->getId();
$member = $this->memberRepository->find($adminId);
if ($member) {
$adminName = $member->getName();
if (method_exists($member, 'getDepartment')) {
$adminDepartment = $member->getDepartment() ?: '';
}
}
}
return [$adminId, $adminName, $adminDepartment];
}
/** PiaProductDispプラグインから表示開始日を取得 */
private function getDisplayStartDate(Product $product): ?string
{
try {
if (class_exists('Plugin\PiaProductDisp\Entity\ProductDisplayPeriod')) {
$repo = $this->entityManager->getRepository('Plugin\PiaProductDisp\Entity\ProductDisplayPeriod');
$dp = $repo->findOneBy(['Product' => $product]);
if ($dp && $dp->getDisplayStartDate()) {
return $dp->getDisplayStartDate()->format('Y-m-d H:i:s');
}
}
} catch (\Exception $e) {
error_log('PiaHistory: 表示開始日取得エラー - ' . $e->getMessage());
}
return null;
}
/** PiaProductDispプラグインから表示終了日を取得 */
private function getDisplayEndDate(Product $product): ?string
{
try {
if (class_exists('Plugin\PiaProductDisp\Entity\ProductDisplayPeriod')) {
$repo = $this->entityManager->getRepository('Plugin\PiaProductDisp\Entity\ProductDisplayPeriod');
$dp = $repo->findOneBy(['Product' => $product]);
if ($dp && $dp->getDisplayEndDate()) {
return $dp->getDisplayEndDate()->format('Y-m-d H:i:s');
}
}
} catch (\Exception $e) {
error_log('PiaHistory: 表示終了日取得エラー - ' . $e->getMessage());
}
return null;
}
}