<?php
/**
* @version EC-CUBE4系
* @copyright 株式会社 翔 kakeru.co.jp
*
* 2022年01月15日カスタマイズ
*
* app\Customize\Controller\AjaxController.php
*
*
* LM側のセキュリティテーブルを読み込み
* TYPE で作業を行う
*
*
* ≡≡≡┏(^o^)┛
*****************************************************/
namespace Customize\Controller;
use Customize\Event\LmEvents;
use Customize\Service\AmountCalculationService;
use Customize\Service\EstimateCharacterizer;
use Customize\Service\GoodsService;
use Eccube\Controller\AbstractController;
use Lm\Engine\EC\Entity\CategoryWithRelated;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#use Symfony\Component\DependencyInjection\ContainerInterface;
#use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Customize\Service\AutoLoadService;
use Customize\Service\OrderHelper;
use Customize\Service\CartService;
use Customize\Converter\OrderConverter;
use Customize\Service\CommonService;
use Lm\Service\Db\SqlService;
use Customize\Validator as Varid;
use Customize\Converter\EstimateConverter;
use Eccube\Repository\ProductClassRepository;
use Lm\Service\Store\FileStoreService;
use Customize\Service\LmHelper;
use Customize\Service\CustomerService;
use Customize\Service\MobileDetector as LmMobileDetector;
#use Error;
use Eccube\Repository\CartItemRepository;
class AjaxController extends AbstractController
{
const Token_Name = 'AjaxToken';
const Coupon_Table = 'coupon_campaign_table';
const History_Table = 'coupon_history_table';
const Estimate_name = 'estimate';
const TMP_DIR = 'front-public/images/tmp_img/';
protected $OrderConverter;
protected $OrderHelper;
protected $AutoLoadService;
protected $CommonService;
protected $CartService;
protected $Validator;
protected $EstimateConverter;
protected $Errors = [];
protected $ProductClassRepository;
protected $ProductClass;
protected $ImageFiles =[];
protected $CartItemRepository;
/**
* @var EstimateCharacterizer
*/
private $EstimateCharacterizer;
private $customerService;
/**
* @var LmMobileDetector
*/
private $mobileDetector;
public function __construct(
// ContainerInterface $Container
// ,RequestStack $RequestStack
OrderConverter $OrderConverter,
AutoLoadService $AutoLoadService,
CommonService $CommonService,
OrderHelper $OrderHelper,
CartService $CartService,
ValidatorInterface $Validator,
EstimateConverter $EstimateConverter,
ProductClassRepository $ProductClassRepository,
CartItemRepository $CartItemRepository,
GoodsService $GoodsService,
EstimateCharacterizer $EstimateCharacterizer,
CustomerService $customerService,
LmMobileDetector $mobileDetector
)
{
$this->AutoLoadService = $AutoLoadService;
$this->OrderConverter = $OrderConverter;
$this->CommonService = $CommonService;
$this->OrderHelper = $OrderHelper;
$this->CartService = $CartService;
$this->Validator = $Validator;
$this->EstimateConverter = $EstimateConverter;
$this->ProductClassRepository = $ProductClassRepository;
$this->CartItemRepository = $CartItemRepository;
$this->GoodsService = $GoodsService;
$this->EstimateCharacterizer = $EstimateCharacterizer;
$this->customerService = $customerService;
$this->mobileDetector = $mobileDetector;
}
/**
* 成り代わり 識別入力設定Data を セットする
* mode =clos 閉じる
* @Route("/Ajax/NarikawariDataSet/{Token}", name="Ajax_NarikawariDataSet", methods={"POST"}, requirements={"Token" = "\w+"})
*/
public function NarikawariDataSet(Request $request, $Token = null)
{
$Sessions = $this->AutoLoadService->GetNariKawariSession();
if ($Token != $Sessions['token']) {
throw new NotFoundHttpException();
}
if (!'close' == $request->request->get('mode')) {
if (!$Datas = $request->request->get('NariKawari')) {
throw new NotFoundHttpException();
}
$Sessions = $this->session->get(AutoLoadService::NARIKAWARI_SESSON);
foreach ($Datas as $Column => $Data) {
switch ($Column) {
case 'fax_no':
if (!is_numeric(str_replace('-', '', $Data))) {
$Data = '';
}
break;
case ('fusen'):
if (is_array($Data)){
$Id = array_key_first($Data) ;
# $this->OrderConverter->SetFusen($Id,$Data[$Id]);
}
break;
default:
break;
}
$Sessions[$Column] = $Data;
}
}
$Sessions['show_flg']=false;
$this->session->set(AutoLoadService::NARIKAWARI_SESSON, $Sessions);
return $this->json(['done' => true]);
}
/**
* 成り代わり 識別入力設定Data を セットする
* mode =clos 閉じる
* @Route("/Ajax/CouponJdge/{Token}", name="Ajax_CouponJdge", methods={"POST"}, requirements={"Token" = "\w+"})
*/
public function CouponJdge(Request $request, $Token = null){
if($Token != $this->CommonService->GetToken('CouponJdge')){
return $this->json(['status' => 'NG'], 400);
//throw new NotFoundHttpException();
}
$CouponCd = $request->request->get('CouponCd');
if(!preg_match('/'. $this->CommonService->GetConfig('CouponCode_Regex').'/',$CouponCd)){
return $this->json(['status' => 'NG','message'=>trans('Common.coupon_messege03')]);
}
$Sql= new SqlService();
$Coupon = $Sql->Table(self::Coupon_Table)
->set('coupon_campaign_code' ,$CouponCd)
->Set('coupon_campaign_ddate','NULL')
->Find();
#クーポンがない
if(!$Coupon){
return $this->json(['status' => 'NG','message'=>trans('Common.coupon_messege03')]);
}
#LNOrderOptin の初期化
$this->CommonService->InitializeLmOrderOption(CommonService::Lm_Option_Coupon);
#期間がおかしい
if($Coupon['coupon_campaign_start_date'] > date('Y-m-d') || $Coupon['coupon_campaign_end_date'] < date('Y-m-d')){
return $this->json(['status' => 'NG','message'=>trans('Common.coupon_messege04') .' '.$Coupon['coupon_campaign_start_date'].'〜'.$Coupon['coupon_campaign_end_date']]);
}
#未使用
$Customer = $this->getUser();
$History = $Sql->Table(self::History_Table)
->Set('coupon_history_campaign_id',$Coupon['coupon_campaign_id'])
->Set('coupon_history_customer_id',$Customer->getLmCustomerId())
->Find();
if ($History){
return $this->json(['status' => 'NG','message'=>trans('Common.coupon_messege05') .' '.$History['coupon_history_cdate']]);
}
#金額
$preOrderId = $this->CartService->getPreOrderId();
$Order = $this->OrderHelper->getPurchaseProcessingOrder($preOrderId);
if($Coupon['coupon_campaign_price'] > $Order->getProductTotal()){
$Messege=str_replace('@@@',$Coupon['coupon_campaign_price'], trans('Common.coupon_messege06'));
return $this->json(['status' => 'NG','message'=>$Messege ]);
}
#LnOrderOprionに登録する
$this->CommonService->AddLmOrderOption(CommonService::Lm_Option_Coupon,$Coupon);
#全て正常終了
return $this->json(['status' => 'OK' ]);
}
//@Route("/ajax/amount-calculation", name="Ajax_CouponJdge", methods={"POST", "GET"})
/**
* TODO: 金額計算API
* TODO: トークン?
* TODO: methods={"GET"}はリリース時には削除のこと
*
* @param Request $request
* @param AmountCalculationService $amountCalculationService
*
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function amountCalculation(Request $request, AmountCalculationService $amountCalculationService)
{
//
$data = $request->get('data', []);
//
$result = $amountCalculationService->calculate($data);
//
return $this->json([
'status' => 'OK',
'result' => $result,
]);
}
/**
* @Route("/ajax/show-goods-size-list-pull-down-by-color", name="ajax_show-goods-size-list-pull-down-by-color", methods={"POST"} )
* @Template("Ajax/size-list.twig")
*/
public function showCartItemSizePullDownByColor(Request $request)
{
$context = [
'ItemId' => $request->get('ItemId'),
'ProductId' => $request->get('ProductId'),
'ClassCategory2Id' => $request->get('ClassCategory2Id'),
'ClassCategory1Id' => $request->get('ClassCategory1Id'),
'EstimateId' => $request->get('EstimateId'),
];
return $context;
}
/**
* @Route("/ajax/show-goods-color-list-pull-down-by-size", name="ajax_show-goods-color-list-pull-down-by-size", methods={"POST"} )
* @Template("Ajax/color-list.twig")
*/
public function showCartItemColorPullDownBySize(Request $request)
{
$context = [
'ItemId' => $request->get('ItemId'),
'ProductId' => $request->get('ProductId'),
'ClassCategory2Id' => $request->get('ClassCategory2Id'),
'ClassCategory1Id' => $request->get('ClassCategory1Id'),
'EstimateId' => $request->get('EstimateId')
];
return $context;
}
/**
* @Route("/ajax/show-stock-label", name="ajax_show-stock-label", methods={"GET", "POST"} )
* @Template("Ajax/stock-label.twig")
*/
public function showStockLabel(Request $request)
{
$context = [
'ProductId' => $request->get('ProductId'),
'ClassCategory1Id' => $request->get('ClassCategory1Id'),
'ClassCategory2Id' => $request->get('ClassCategory2Id'),
];
return $context;
}
/**
* 見積もりシミュレーションで バリデーションする
*
* @Route("/Ajax/estimate", name="Ajax_estimate", methods={"GET","POST"} )
*/
public function EstimatetValids(Request $request){
if ($this->CommonService->GetToken(CommonService::Matrix_Token) != $request->get('OlToken') ){
throw new NotFoundHttpException();
}
$Estimate = $request->get(self::Estimate_name);
//$_SESSION['data'][]=$Estimate;
// $File = $request->files->get('estimate');
$this->EstimatetValidPrint($Estimate);
$this->EstimatetValidSusoage($Estimate);
$this->EstimatetValidImage($Estimate,$request->files->get(self::Estimate_name));
if (count($this->Errors)>0){
$Token =$this->CommonService->ResetToken(CommonService::Matrix_Token);
return $this->json(['status' => 'Error','OlToken'=> $Token,'Errors'=> $this->Errors ]);
}else{
return $this->json(['status' => 'OK','FileName'=>$this->ImageFiles]);
}
}
protected function EstimatetValidPrint($Estimate){
if (2 != ($Estimate['type'] ?? 0 )) {return ;}
$GetMessage = function ($i){
return trans('front.estimatet.Error' . str_pad($i,2,0,STR_PAD_LEFT));
};
$tateMax = 9999;
$yokoMax = 9999;
if($ProductClassId = $Estimate['product_class_id'] ?? null ){
$goods = $this->GoodsService->getGoodsByJanId($ProductClassId);
$tenshaDetailList = $this->EstimateConverter->getTenshaDetailListById($goods['goods_tensha']);
if($tenshaDetailList && isset($tenshaDetailList[0]['tensha_tate']) && isset($tenshaDetailList[0]['tensha_yoko'])) {
$Yohaku = $this->CommonService->GetConfig('ESTIMATE_YOHAKU');
$tateMax = $tenshaDetailList[0]['tensha_tate'] - $Yohaku ?? 9999;
$yokoMax = $tenshaDetailList[0]['tensha_yoko'] - $Yohaku ?? 9999;
}
}
$Error = $this->Validator->validate(
($Estimate['type'] ?? 0 ),
[
new Varid\Estimate(['Estimate'=>$Estimate,
'TateMax' => $tateMax,
'YokoMax' => $yokoMax,
]),
]
);
if ($Error->count()<1){return [];}
$Re=[];
foreach (json_decode($Error[0]->getMessage(),true) as $key => $Errors){
if (!is_array($Error)<1){
$Re[] = $GetMessage($Errors);
continue;
}
foreach ($Errors as $i){
$line = $key .'行目 ';
$Message = $GetMessage($i);
switch($i){
case 13:
$Message = str_replace('@TATE',$tateMax,$Message);
$Message = str_replace('@YOKO',$yokoMax,$Message);
break;
}
$Re[] = $line . $Message;
}
}
$this->Errors = $Re;
return ;
}
protected function EstimatetValidSusoage($Estimate){
if (1 != ($Estimate['type'] ?? 0 )) {return ;}
$Config = $this->CommonService->GetConfig('EstimatetValid');
$Max = $Config['SUSOAGE_NAME_MAX'];
$Message = str_replace('@MAX',$Max,trans('front.estimatet.Error14') );
$Susoages =$Estimate['susoage'] ?? [];
foreach ($Susoages as $ProductClassId => $Susoage){
foreach ($Susoage as $i => $Value){
if (!$Value['do']){continue;}
if (!$Name = $Value['name']?? null){continue;}
$Error = $this->Validator->validate(
$Name,
[
new Assert\Length(
['max' => $Max,
'maxMessage' => $Message
]),
]);
if(count($Error)){
$ProductClass = $this->CartService->GetProductClass($ProductClassId);
$ClassCategoryName=[1=>'', 2=>''];
if ($ClassCategory1 = $ProductClass->getClassCategory1()){
$ClassCategoryName[1] = $ClassCategory1->getName() . ' : ';
}
if ($ClassCategory2 = $ProductClass->getClassCategory2()){
$ClassCategoryName[2] = $ClassCategory2->getName() .' : ';
}
$Line = ($i + 1 ) .'行目 ';
$this->Errors[] = $ClassCategoryName[1] . $ClassCategoryName[2]. $Line. $Error[0]->getMessage();
}
}
}
return ;
}
protected function EstimatetValidImage($Estimate,$Files){
if (2 != ($Estimate['type'] ?? 0 )) {return ;}
$Valid = $this->CommonService->GetConfig('EstimatetValid');
$CompanyName = $this->CommonService->BaseInfo('CompanyName');
foreach ($Files as $i => $File) {
if (filesize($File) > ((env('ESTIMATE_IMAGE_SIZE') ?? 10) * 1024 * 1024)) {
return $this->Errors[] = "ファイル容量が大き過ぎます。";
}
}
$s3 = new FileStoreService(env('S3_LM_DOC'), self::TMP_DIR);
$date = date('YmdHis');
foreach ($Files as $i => $File){
if ($File){
$kaku = $File->getClientOriginalExtension();
$code = substr(str_pad(mt_rand(0,99999999),8,0,STR_PAD_LEFT),-4);
$newFilename = $date.$code.'.'.$kaku;
$this->ImageFiles[$i]['name'] = $File->getClientOriginalName();
$this->ImageFiles[$i]['tmp_name'] = $newFilename;
// S3へファイルアップロード
$s3->uploadFile($newFilename, $File->getPathname());
}
$Error = $this->Validator->validate(
$File,
[
new Varid\EstimateImage([
'allowExtensions' => $Valid['IMAGE_EXT'],
])
]);
if(count($Error)){
if ($Message = $Error[0]->getMessage()){
$Message = str_replace('@LINE',$i , $Message );
$Message = str_replace('@CompanyName',$CompanyName,$Message);
$this->Errors[] = $Message;
}
}
}
return ;
}
/**
* 見積もりシミュレーションで DATAを文字化する
*
* @Route("/Ajax/estimate_character", name="Ajax_Estimate_Character", methods={"GET","POST"} )
* @Template("Estimate/Parts/Chara.twig")
*/
public function EstimateCharacter(Request $request){
$isMobile = $this->mobileDetector->isMobile();
$Estimate = $request->get(self::Estimate_name);
// Get cart items for campaign discount calculation (fallback to session estimate products)
try {
$didSet = false;
$carts = $this->CartService->getCarts();
if (!empty($carts)) {
$CartItems = $this->CartItemRepository->findBy(['Cart' => $carts]);
if (!empty($CartItems)) {
// Calculate campaign discount from real cart items
$this->EstimateCharacterizer->SetEstimateOption($CartItems, [], 'cart');
$didSet = true;
}
}
if (!$didSet) {
// Fallback: build lightweight items from session 'estimate_products'
$products = $this->get('session')->get('estimate_products', []);
if (is_array($products) && !empty($products)) {
$fakeItems = [];
$pcs = $this->ProductClassRepository->findBy(['id' => array_keys($products)]);
foreach ($pcs as $pc) {
$qty = (int)($products[$pc->getId()] ?? 0);
if ($qty <= 0) { continue; }
// Minimal adapter exposing getProductClass/getQuantity/getPriceIncTax
$fakeItems[] = new class($pc, $qty) {
private $pc; private $qty;
public function __construct($pc, $qty){ $this->pc=$pc; $this->qty=$qty; }
public function getProductClass(){ return $this->pc; }
public function getQuantity(){ return $this->qty; }
public function getPriceIncTax(){ return method_exists($this->pc,'getPrice02IncTax') ? (int)$this->pc->getPrice02IncTax() : 0; }
};
}
if (!empty($fakeItems)) {
$this->EstimateCharacterizer->SetEstimateOption($fakeItems, [], 'estimate');
}
}
}
} catch (\Throwable $e) {
error_log("DEBUG: Error in SetEstimateOption: " . $e->getMessage());
}
try {
$this->EstimateCharacterizer->EstimateCharacterIzation($Estimate);
} catch (\Throwable $e) {
error_log("DEBUG: EstimateCharacterIzation error: " . $e->getMessage());
return;
}
$characters = $this->EstimateCharacterizer->GetCharacters();
$campaignDiscount = $this->EstimateCharacterizer->GetCampaignDiscount();
$campaignDetails = $this->EstimateCharacterizer->GetCampaignDetails();
return [
'EstimateOptions' => $characters,
'CampaignDiscount' => $campaignDiscount,
'CampaignDetails' => $campaignDetails,
'isMobile' => $isMobile
];
}
/**
* Handle Karte when user click phone on any screen
*
* @Route("/Ajax/karte_phone", name="ajax_karte_tel_inquiry", methods={"POST"})
*/
public function ajaxKartePhoneRequest(Request $request)
{
$lmCustomer = null;
$customer = $this->getUser();
if (!empty($customer)) {
$lmCustomer = $this->customerService->GetLandMarkCustomerId($customer->getLmCustomerId());
}
$fromUrl = $request->get('fromUrl', '');
$karte['telephone_inquiry'] = [
'from_url' => $fromUrl,
'email' => empty($lmCustomer) ? "" : $lmCustomer['customer_mail']
];
$templateContent = $this->renderView('Karte/telephone_inquiry.twig', [
'Karte' => $karte,
]);
$response = [
'status' => 200,
'message' => 'Process completed successfully.',
'data' => [
'script' => json_encode($templateContent)
],
];
return new JsonResponse($response);
}
/**
* Handle Karte when user click phone on any screen
*
* @Route("/Ajax/karte_download_fax_form", name="karte_download_fax_form", methods={"POST"})
*/
public function ajaxKarteDownloadFaxFormRequest(Request $request)
{
$fromUrl = $request->get('fromUrl', '');
$lmCustomer = null;
$customer = $this->getUser();
if (!empty($customer)) {
$lmCustomer = $this->customerService->GetLandMarkCustomerId($customer->getLmCustomerId());
}
$karte['download_fax_form'] = [
'from_url' => $fromUrl,
'email' => empty($lmCustomer) ? "" : $lmCustomer['customer_mail'],
'ip_address' => $request->getClientIp(),
];
$templateContent = $this->renderView('Karte/download_fax_form.twig', [
'Karte' => $karte,
]);
$response = [
'status' => 200,
'message' => 'Process completed successfully.',
'data' => [
'script' => json_encode($templateContent)
],
];
return new JsonResponse($response);
}
/**
* Handle Karte when user access to route name page/sub-category
*
* @Route("/Ajax/karte_page_sub_category", name="karte_page_sub_category", methods={"POST"})
*/
public function ajaxKartePageSubCategoryRequest(Request $request)
{
$listUrl = $request->get('listUrl', '');
$mcName = $request->get('mcName', null);
$ct = $request->get('ct', null);
$mcMcName = $request->get('mcMcName', null);
$isMobile = $request->get('isMobile', false) ? true : false;
try {
// 親・子・祖父
$category = new CategoryWithRelated($mcName, $ct, $mcMcName, $isMobile);
} catch (\Exception $e) {
// カテゴリデータの取得に失敗した場合「404 Not Found」とする
throw new NotFoundHttpException("指定されたカテゴリのデータが取得出来ませんでした({$e->getMessage()})", $e);
}
$karte['view_list'] = [
'list_url' => $listUrl,
'list_num' => $category->getItemListCount(),
'l_category_name' => $category->getMainCategoryName(),
's_category_name' => $category->getCategoryName(),
'l_category_cd' => $category->getMainCategoryWebname(),
's_category_cd' => $category->getCategoryWebname(),
];
$templateContent = $this->renderView('Karte/view_list.twig', [
'Karte' => $karte,
]);
$response = [
'status' => 200,
'message' => 'Process completed successfully.',
'data' => [
'script' => json_encode($templateContent)
],
];
return new JsonResponse($response);
}
#本番では不要
protected function Data(){
// $Data = $this->CartItemRepository->find(875);
//$Data = $this->CartItemRepository->find(556);
$Data = $this->CartItemRepository->find(873);
return $Data->getOptions();
}
}