shopService = Zc::singleton(ShopService::class); $this->moveService = Zc::singleton(MoveService::class); $this->productService = Zc::singleton(ProductService::class); $this->rsyncProductService = Zc::singleton(RsyncProductService::class); $this->watermarkService = Zc::singleton('WatermarkService'); $this->moveImportService = Zc::singleton('MoveImportService'); $this->feedbackService = Zc::singleton(FeedbackService::class); $this->productUtil = Zc::singleton(ProductUtil::class); $this->moveUtil = Zc::singleton(MoveUtil::class); $this->materialUtil = Zc::singleton('MaterialUtil'); $this->spider = new PageSpider(array (), null, $_SERVER['REMOTE_ADDR']); $this->dsClient = Zc::singleton('DsClient'); $this->webShop = Zc::getWebUser(); $this->moveBatchSettingLog = Zc::getLog('move/batch/setting'); $this->moveBatchUrlLog = Zc::getLog('move/batch/url'); $this->timeStatLog = Zc::getLog('move/batch/time_stat'); $this->moveBatchSaveTaskLog = Zc::getLog('move/batch/saveTask'); $this->moveBatchDebugLog = Zc::getLog('move/batch/debug'); $this->failRetryMoveTaskLog = Zc::getLog('move/batch/fail_retry'); $this->moveAgainDetailLog = Zc::getLog('move/batch/again_detail'); $this->moveBatchShopLog = Zc::getLog('move/batch/shop'); $this->tailorImgTool = new TailorImgTool(); $this->ltaoTool = new LtaoTool(); $this->materialService = Zc::singleton(MaterialService::class); Zc::import('@.vendor.CSVParse', '', '.php', 'class.'); $this->csvParse = new CSVParse(); $this->redis = RedisExt::factory('bizCache'); } public function target() { if (!isset($_SESSION[SessionConst::geoIpArea])) { $geoInfo = $this->shopService->getGeoIpInfo(CommonTool::clientIp(), false); if (!empty($geoInfo)) { $_SESSION[SessionConst::geoIpArea] = $geoInfo; } } if ($_GET['copyType'] == MoveConst::collectFetchBank) { $this->redirect(Zc::url(RouteConst::moveBatchTarget, array('copyType' => $_GET['copyType']), 'https', Zc::C('fetchBank.domain'))); } $copyType = in_array($_GET['copyType'], array ( MoveConst::collectLinksCopy, MoveConst::collectShopCopy, MoveConst::collectWebsiteCopy, MoveConst::collectDsCopy, MoveConst::collectLtaoCopy, MoveConst::collectSameProduct, MoveConst::collectClueCopy, )) ? $_GET['copyType'] : MoveConst::collectLinksCopy; $shopId = $_SESSION[SessionConst::shopId]; $shopName = $_SESSION[SessionConst::shopName]; $moveAdvancedConfig = $this->moveService->getMoveAdvancedConfig($shopId); $appOrder = $this->shopService->getShopFirstAppOrder($shopId); $isFetchBank = $this->webShop->getFlash('isFetchBank') ?: $_POST['isFetchBank']; $categoryOptionArray = $this->productUtil->getCategoryOptionArray($shopId); $dsHelpArticleList = []; $dsBuyUrl = $this->moveService->getDsBuyUrl($shopId); $dsMemberInfo = $this->moveService->getDsMemberInfo($shopId); $dsMemberName = $dsMemberInfo['cnali_member_name']; $ruleList = $this->getChoicenessSourceItemTag(); $collectTaskWareIds = $_POST['collectTaskWareIds'] ? json_decode($_POST['collectTaskWareIds'], true) : $this->webShop->getFlash('collectTaskWareIds'); $fetchBankDetailIds = $_POST['fetchBankDetailIds'] ? json_decode($_POST['fetchBankDetailIds'], true) : $this->webShop->getFlash('fetchBankDetailIds'); $this->render(array ( 'copyType' => $copyType, 'shopId' => $shopId, 'shopName' => $shopName, 'appOrder' => $appOrder, 'isFetchBank' => $isFetchBank, 'collectTaskWareIds' => $collectTaskWareIds, 'fetchBankDetailIds' => $fetchBankDetailIds, 'moveAdvancedConfig' => $moveAdvancedConfig, 'categoryOptionArray' => $categoryOptionArray, 'alibabaHelpArticleList' => $dsHelpArticleList, 'ltaoAuthInfo' => $ltaoAuthInfo, 'dsBuyUrl' => $dsBuyUrl, 'alibabaMemberName' => $dsMemberName, 'alibabaMemberExpire' => $dsMemberInfo['gmt_expire'], 'folderMenuTree' => $this->materialService->getMaterialFolderMenuTree($shopId), 'ruleList' => $ruleList, ), 'move/batch/target_all'); } private function getChoicenessSourceItemTag() { $tagCache = DsClientTool::tryGetChoicenessSourceItemTagByLocal(); if ($tagCache) { return $tagCache; } $getRet = $this->dsClient->getChoicenessSourceItemTag(DsConst::platformDd); if (CommonTool::isSuccessRet($getRet)) { DsClientTool::stashChoicenessSourceItemTagToLocal($getRet['data']); } return $getRet['data']; } public function resetMoveSetting() { $moveSettingId = !empty($_POST['moveSettingId']) ? (int)$_POST['moveSettingId'] : 0; $shopId = $_SESSION[SessionConst::shopId]; if (!$moveSettingId || !$shopId) { return $this->renderJSON(CommonTool::failResult('参数错误')); } $newMoveSettingId = $this->moveUtil->resetMoveSetting($moveSettingId, $shopId); if ($newMoveSettingId) { $moveSettingList = $this->moveUtil->getInitMoveSettingList($shopId); $renderData = array( 'moveSettingList' => $moveSettingList, 'moveSettingId' => $newMoveSettingId, ); return $this->renderJSON(CommonTool::successResult($renderData)); } return $this->renderJSON(CommonTool::failResult('恢复默认设置失败')); } public function getInitDataList() { header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); $ret = $this->moveUtil->getInitDataList(); return $this->renderJSON($ret); } public function getFreightTemplateList() { $shopId = $_POST['authShopId'] ? $_POST['authShopId'] : $_SESSION[SessionConst::shopId]; $accessToken = $this->shopService->getShopAccessToken($shopId); $freightTemplateRet = $this->moveService->getFreightTemplateListFromDd($accessToken); $ret = [ 'freightTemplateList' => $freightTemplateRet['freightTemplateList'] ? $freightTemplateRet['freightTemplateList'] : [], ]; $this->renderJSON(CommonTool::successResult($ret)); } public function getCurrentShopMoveSetting() { header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); $shopId = $_POST['curShopId'] ? $_POST['curShopId'] : $_SESSION[SessionConst::shopId]; $accessToken = $_SESSION[SessionConst::accessToken]; if (empty($shopId) || empty($accessToken)) { $this->renderJSON(CommonTool::failResult("获取用户id失败,请联系客服")); return ; } $moveSettingList = $this->moveUtil->getInitMoveSettingList($shopId); foreach ($moveSettingList as $moveSetting) { if ($moveSetting['is_config_default'] == 1) { return $this->renderJSON(CommonTool::successResult('moveSetting', $moveSetting)); } } $moveSetting = array_shift($moveSettingList); return $this->renderJSON(CommonTool::successResult('moveSetting', $moveSetting)); } public function saveMoveBatchConfigFirst() { header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); $shopId = $_SESSION[SessionConst::shopId]; $moveSetting = $_POST['moveSetting']; $ret = $this->moveUtil->saveMoveBatchConfigFirst($shopId, $moveSetting, $this->moveBatchSettingLog); return $this->renderJSON($ret); } public function fetchAlibabaDetailUrlInfo() { $shopId = $_SESSION[SessionConst::shopId]; $alibabaMemberId = $this->moveService->getAlibabaMemberId($shopId); if (empty($alibabaMemberId)) { $isExistDs = $this->moveService->isExistDs($shopId); if ($isExistDs) { return $this->renderJSON(CommonTool::failCodeResult(ErrorCodeConst::expireDsAuth, '抖店和1688授权过期,请重新授权')); } return $this->renderJSON(CommonTool::failCodeResult(ErrorCodeConst::noDsAuth, '抖店没有1688主客授权,请授权')); } $checkRet = $this->moveUtil->checkAbnormalRequest($shopId); if (CommonTool::isFailRet($checkRet)) { return $this->renderJSON($checkRet); } $startTime = ZcNumberHelper::microtimeFloat(); $this->moveBatchUrlLog->info('fetchDetailUrlInfo, shopId[' . $_SESSION[SessionConst::shopId] . '], post: ' . print_r($_POST, true)); $detailUrls = $_POST['detailUrls']; $getProductInfoListRet = $this->getAlibabaProductsInfoListByDetailUrls($detailUrls, $shopId, true); if (CommonTool::isFailRet($getProductInfoListRet)) { return $this->renderJSON($getProductInfoListRet); } $endTime = ZcNumberHelper::microtimeFloat(); $costTime = bcsub($endTime, $startTime, 3); $timeStatLogStr = sprintf('searchProductStat | %s | %s | %s', $shopId, count($detailUrls), $costTime); $this->timeStatLog->info($timeStatLogStr); $productsInfoList = $getProductInfoListRet['productsInfoList']; $productList = $this->moveUtil->processProductList($productsInfoList, $shopId, null, $_POST['productClueCatePathMap'] ?: [], $_POST['productClueIdMap'] ?: []); $productList = $this->moveUtil->attachIsMoved($productList, $shopId); return $this->renderJSON(CommonTool::successResult(array( 'productList' => $productList, 'sourceItemIds' => array_keys($productList), 'hostname' => gethostname() ))); } private function getAlibabaProductsInfoListByDetailUrls($detailUrls, $shopId, $needCheckFree = false) { $detailUrls = array_map('trim', preg_split("/\\r\\n|\\r|\\n|,|,|;|;/u", $detailUrls)); $ret = $this->buildAlibabaFetchUrlList($shopId, $detailUrls, $needCheckFree); if (CommonTool::isFailRet($ret)) { return $ret; } $fetchList = $ret['fetchList']; $productsInfoListRet = $this->moveUtil->fetchProductsList($fetchList, true); $productsInfoList = $productsInfoListRet['productsInfoList']; return CommonTool::successResult(array( 'productsInfoList' => $productsInfoList, )); } private function buildAlibabaFetchUrlList($shopId, $detailUrls, $needCheckFree = false) { $uniqueSourceProductArray = array(); $sourceProducts = array(); $fetchList = array(); $fetchSourceList = []; $aliCount = 0; $shortUrlToNormalUrlMap = $this->moveUtil->getRealItemUrlFromShortUrl($detailUrls); foreach ($detailUrls as $url){ //ctype_digit纯数字检测 if(empty($url) || ctype_digit($url)){ continue; } $url = $shortUrlToNormalUrlMap[$url] ? : $url; $sourceProduct = $this->moveUtil->parseDetailUrl($url); if (!empty($sourceProduct)) { $productId = $sourceProduct['itemId']; $source = $sourceProduct['source']; $site = $sourceProduct['site']; $isFromMobileLink = $sourceProduct['isFromMobileLink']; if ($uniqueSourceProductArray[$source.$productId.$site]) { continue; } $uniqueSourceProductArray[$source.$productId.$site] = true; if ($source == FetchClientConst::collectTaskSource1688) { $aliCount++; } $sourceProducts[] = $sourceProduct; $fetchSourceList[] = $source; } if ($source == FetchClientConst::collectTaskSource1688) { $fetchUrl = Zc::url(RouteConst::TimerMoveTaskFetchDsItem, array('itemId' => $productId, 'source' => $source, 'site' => $site, 'shopId' => $shopId, 'isFromMobileLink' => $isFromMobileLink, 'moveNeedCollectDetail' => FetchClientTool::moveNeedCollectDetail($source), 'trace' => MoveConst::traceDdmsFetchUrl()), 'http', Zc::C('multi.crawler.domain')); } else { $fetchUrl = Zc::url(RouteConst::TimerMoveTaskFetchItem, array('itemId' => $productId, 'source' => $source, 'site' => $site, 'shopId' => $shopId, 'isFromMobileLink' => $isFromMobileLink, 'moveNeedCollectDetail' => FetchClientTool::moveNeedCollectDetail($source), 'trace' => MoveConst::traceDdmsFetchUrl()), 'http', Zc::C('multi.crawler.domain')); } $fetchList[$fetchUrl] = array(); } $ret = $this->moveService->checkPlatformAuthorize($fetchSourceList, [FetchClientConst::collectTaskSource1688]); if (CommonTool::isFailRet($ret)) { return $ret; } if ($needCheckFree && $aliCount > 50) { $getVersionRet = $this->shopService->getShopAppVersion($shopId); $shopVersion = $getVersionRet['appVersion']; if (AppConst::checkIsFreeVersion($shopVersion)) { $authCode = $this->shopService->getAuthCodeByShopId($shopId); $searchRet = $this->dsClient->getDsMemberVersion(DsConst::platformDd, $authCode); if (CommonTool::isFailRet($searchRet)) { return $searchRet; } $isFree = $searchRet['isFree']; if ($isFree) { return CommonTool::failCodeResult(ErrorCodeConst::isDsFreeUserLimit, '每次输入链接最多50条,请减少商品数量后重试或升级高级版'); } } } $ret = $this->checkProductErrorInfo($sourceProducts, $aliCount); if (CommonTool::isFailRet($ret)) { return $ret; } return CommonTool::successResult([ 'fetchList' => $fetchList, ]); } private function checkProductErrorInfo($sourceProducts, $aliCount) { if(empty($sourceProducts)){ return CommonTool::failResult("商品详情页面链接或者ID错误, 请重新输入"); } if ($aliCount > 200) { return CommonTool::failCodeResult('overLimit', "1688商品一次最多只支持200个链接,您当前提交了{$aliCount}个商品"); } if(count($sourceProducts) > 500){ return CommonTool::failCodeResult('overLimit', "最多支持500个商品链接"); } } private function checkRequireAttrAndQuality($products, $setting) { if (!empty($setting['isValidateRequire'])) { return CommonTool::successResult(); } $requirePresetAttrNames = MoveConst::getRequirePresetAttrNames(); $requirePresetQualityNames = MoveConst::getRequirePresetQualityNames(); $checkAttrNames = []; foreach ($requirePresetAttrNames as $attrName) { $isset = false; foreach ((array)$setting['preset_attrs'] as $presetAttr) { if (($attrName == $presetAttr['presetAttrName']) && $presetAttr['presetAttrValue'] && ($presetAttr['presetAttrEnable'] == 1)) { $isset = true; break; } } if (!$isset) { $checkAttrNames[] = $attrName; } } $checkQualityNames = []; $ret = $this->doGetQualityListByCid($setting['move_shop_setting_id'], 0); foreach ($requirePresetQualityNames as $qualityName) { $isset = false; foreach ($ret['qualityList'] as $quality) { if (($qualityName == $quality['quality_name']) && !empty($quality['img_list'])) { $isset = true; break; } } if (!$isset) { $checkQualityNames[] = $qualityName; } } if (!$checkAttrNames && !$checkQualityNames) { return CommonTool::successResult(); } $needGetCateAttrCids = $needGetCateQualityCids = []; foreach ($products as $product) { if ($checkAttrNames) { $needGetCateAttrCids[] = $product['cid']; } if ($checkQualityNames) { $needGetCateQualityCids[] = $product['cid']; } } list($cateAttrs, $cateQualitys) = $this->moveService->getCateAttrsAndQualitys($needGetCateAttrCids, $needGetCateQualityCids, $_SESSION[SessionConst::accessToken]); if ($needGetCateQualityCids) { $needGetCateQualityCids[] = 0; $shopProductQualitySettingList = $this->moveService->getShopProductQualitySettingList($_SESSION[SessionConst::shopId], $setting['move_shop_setting_id'], $needGetCateQualityCids); $qualitySettings = []; foreach ($shopProductQualitySettingList as $qualitySetting) { $qualitySettings[$qualitySetting['cid']][] = $qualitySetting; } $productQualityMap = $qualitySettings ? $this->moveService->getProductQualityMap() : null; } $requireAttrNames = $requireQualityList = []; foreach ($products as $product) { $cid = $product['cid']; if (!empty($cateAttrs[$cid])) { foreach ($cateAttrs[$cid] as $prop) { $propId = $prop['property_id']; if (in_array($prop['property_name'], $checkAttrNames) && empty($product['props'][$propId]) && $prop['required']) { $requireAttrNames[] = $prop['property_name']; } } } if (!empty($cateQualitys[$cid])) { $productQualityList = $cateQualitys[$cid]; if ($qualitySettings[0]) { $productQualityList = $this->moveUtil->appendQualityImgs($productQualityList, $qualitySettings[0], $productQualityMap); } if ($qualitySettings[$cid]) { $productQualityList = $this->moveUtil->appendQualityImgs($productQualityList, $qualitySettings[$cid], $productQualityMap); } foreach ($productQualityList as $quality) { if(!$quality['is_required']) { continue; } if (isset($product['productQualityMap'][$cid][$quality['quality_key']]) && array_filter($product['productQualityMap'][$cid][$quality['quality_key']])) { continue; } if (!empty($quality['img_list'])) { continue; } $requireQualityList[$quality['quality_key']] = $quality; } } } $res = []; $requireAttrNames && $res['requireAttrNames'] = $requireAttrNames; $requireQualityList && $res['requireQualityList'] = $requireQualityList; if ($res) { return CommonTool::failResult($res); } else { return CommonTool::successResult(); } } public function saveTask() { $shopId = $_SESSION[SessionConst::shopId]; $this->moveBatchSaveTaskLog->info("shopId $shopId start saveTask"); ini_set('memory_limit', '1024M'); $_POST = $_POST['valueMap'] ? json_decode($_POST['valueMap'], true) : json_decode(file_get_contents('php://input'), true); // 20220112起没有valueMap,兼容作用 $needMoveShopIds = isset($_POST['needMoveShopIds']) ? $_POST['needMoveShopIds'] : (array($shopId)); // 前端没有传这个参数的时候使用这个用户自己 $productSimpleDetails = json_decode($_POST['productSimpleDetails'], true); $copyType = $_POST['copyType']; $shopMoveSettingOperateLogMap = json_decode($_POST['shopMoveSettingOperateLogMap'], true); $shopMoveConditionMap = $_POST['shopMoveConditionMap']; $shopPreviewCateAttr = json_decode($_POST['previewCateAttr'], true); $source = $_POST['source']; $isFetchBank = $_POST['isFetchBank'] ? $_POST['isFetchBank'] : false; $copyType = $isFetchBank ? MoveConst::collectFetchBank : $_POST['copyType']; $hostname = gethostname(); $shopGroupMoveType = isset($_POST['shopGroupMoveType']) ? $_POST['shopGroupMoveType'] : null; $shopGroupAllocType = isset($_POST['shopGroupAllocType']) ? $_POST['shopGroupAllocType'] : null; $this->moveBatchSaveTaskLog->info("shopId $shopId start checkAndFormatData"); $checkAndFormatRet = $this->checkAndFormatData($shopId, $needMoveShopIds, $_POST, $shopMoveConditionMap, $shopPreviewCateAttr, $productSimpleDetails, $hostname, $copyType); $this->moveBatchSaveTaskLog->info("shopId $shopId end checkAndFormatData"); if (CommonTool::isFailRet($checkAndFormatRet)) { return $this->renderJSON($checkAndFormatRet); } $curProductDetails = $checkAndFormatRet['curProductDetails']; $shopConditions = $checkAndFormatRet['shopConditions']; $shopMoveConditionMap = $checkAndFormatRet['shopMoveConditionMap']; $this->moveBatchSaveTaskLog->info("shopId $shopId start allocShopProductsByAuthShop"); $shopProducts = $this->allocShopProductsByAuthShop($needMoveShopIds, $curProductDetails); $checkDsValidRet = $this->checkDsValid($needMoveShopIds, $shopProducts); if (CommonTool::isFailRet($checkDsValidRet)) { return $this->renderJSON($checkDsValidRet); } $this->moveBatchSaveTaskLog->info("shopId $shopId start saveTaskByAuthShop"); $operateSource = $_POST['copyStep2Preview'] ? 'pc' : 'platform'; // 埋点,主客统计搬家来源 $isFromLtaoRank = isset($_POST['isFromLtaoRank']) ? $_POST['isFromLtaoRank'] : 0; $saveRet = $this->saveTaskByAuthShop($shopId, $copyType, $shopMoveConditionMap, $shopMoveSettingOperateLogMap, $shopConditions, $shopProducts, $shopPreviewCateAttr, $hostname, $operateSource, $isFromLtaoRank); if (CommonTool::isFailRet($saveRet)) { return $this->renderJSON($saveRet); } $shopTaskId = $saveRet['taskId']; $redirectURL = Zc::url(RouteConst::moveBatchFinish, array('taskId' => $shopTaskId, 'source' => $source)); $this->moveBatchSaveTaskLog->info("shopId $shopId session shopId " . $_SESSION[SessionConst::shopId] . " saveTask success " . print_r(Zc::G(), true)); $submitCnt = (int)count($shopProducts[$_SESSION[SessionConst::shopId]]); if ($submitCnt == 0) { return $this->renderJSON(array( 'result' => 'fail', 'reason' => sprintf('%s:提交商品数为0,请检查是否正常提交商品', $hostname), 'taskId' => $shopTaskId, 'submitCnt' => $submitCnt, )); } if ($_POST['sameType']) { $this->moveService->saveSameProductCopyLog($_POST['sameType'], $_POST['searchSameProductMap'], $shopId, $copyType == MoveConst::collectDsCopy); } $this->renderJSON(CommonTool::successResult(array( 'hostname' => $hostname, 'taskId' => $shopTaskId, 'submitCnt' => $submitCnt, 'redirectURL' => $redirectURL ))); } private function checkNeedChangeBrand($shopMoveConditionMap) { return CommonTool::successResult(); // 先不判断 foreach ($shopMoveConditionMap as $authShopId => $moveCondition) { $brandId = $moveCondition['brand_id']; if(!is_numeric($brandId) || empty($brandId)) { return CommonTool::successResult(); } $name = $this->moveService->getBrandName($brandId, $authShopId); if(empty($name)) { return CommonTool::failResult('请在搬家配置重新设置品牌信息在提交任务!'); } } return CommonTool::successResult(); } private function getProductSimpleDetails($productSimpleDetails, $shopId) { foreach ($productSimpleDetails as $authShopId => &$curProductDetails) { foreach ($curProductDetails as $skipProductId => &$product) { if ($product['needSkip'] == 1) { unset($curProductDetails[$skipProductId]); } if ($shopId != $authShopId) { unset($product['freight_template_id']); } } } return $productSimpleDetails; } public function saveTaskFailLog() { $this->moveService->saveTaskFailLog($_SESSION[SessionConst::shopId], $_REQUEST, $_SERVER, CommonTool::clientIp(), 'save_task_fail_log'); $this->renderJSON(CommonTool::successResult()); } private function checkAndFormatData($shopId, $needMoveShopIds, $post, $shopMoveConditionMap, $shopPreviewCateAttr, $productSimpleDetails, $hostname, $copyType) { $hasError = false; $errorArray = array(); $shopConditions = array(); $productSimpleDetails = $this->getProductSimpleDetails($productSimpleDetails, $shopId); $curProductDetails = $productSimpleDetails[$shopId]; if(empty($curProductDetails)){ $this->moveService->saveTaskFailLog($_SESSION[SessionConst::shopId], $_REQUEST, $_SERVER, CommonTool::clientIp(), 'save_task'); $this->moveBatchDebugLog->info("shopId[$shopId] empty curProductDetails"); $this->moveBatchDebugLog->info($post); $ret = CommonTool::failResult(sprintf('%s shopId:%s,未选择要搬家的商品', $hostname, $shopId)); $ret['hostname'] = $hostname; return $ret; } foreach ($curProductDetails as $productId => $productDetail) { if (!$productDetail['cid']) { $this->moveBatchDebugLog->info("shopId[$shopId] productId[$productId] invalid cid"); $ret = CommonTool::failResult(sprintf('商品ID:%s 类目必填,请先设置', $productId)); $ret['hostname'] = $hostname; return $ret; } } foreach ($needMoveShopIds as $authShopId) { $this->moveBatchSaveTaskLog->info("shopId $shopId $authShopId start rebuild move data"); if (empty($shopMoveConditionMap[$authShopId]) || empty($shopMoveConditionMap[$authShopId]['desc_copy_type'])) { $hasError = true; $errorArray[] = sprintf('shopId:%s,搬家配置数据不完整,提交失败。请联系客服!', $authShopId); $this->moveBatchDebugLog->info("shopId[$authShopId] 搬家配置数据不完整~~"); $this->moveBatchDebugLog->info($post); break; } if (!empty($shopPreviewCateAttr[$authShopId])) { $shopMoveConditionMap[$authShopId]['usePreviewCommonCateAttr'] = true; } $conditionRet = $this->moveService->getTaskCondition($shopMoveConditionMap[$authShopId]); if(CommonTool::isFailRet($conditionRet)){ $hasError = true; $errorArray[] = $conditionRet['reason']; break; } $shopConditions[$authShopId] = $conditionRet['condition']; $shopIsExpire = $this->moveService->checkShopIsExpire($authShopId); if ($shopIsExpire) { $shopInfo = $this->shopService->getShop($authShopId); $hasError = true; $tip = ($shopId == $authShopId) ? '请联系客服续费!' : '请取消搬家至该店铺'; $errorArray[] = sprintf('店铺【%s】,已过期,%s', $shopInfo['shop_name'], $tip); break; } if ($copyType == MoveConst::collectDsCopy) { $this->moveService->attachDsMoveCopyTotal($authShopId); } $moveConfig = $this->moveService->getAvailableCopyCount($authShopId); $productTotal = count($curProductDetails); $dsProducts = $this->moveService->getDsDetails($curProductDetails); $dsProductTotal = $dsProducts ? count($dsProducts) : 0; $productTotal = $productTotal - $dsProductTotal; if ($productTotal > 0 && $productTotal > $moveConfig['available_total']){ $appVersionRet = $this->shopService->getShopAppVersion($shopId); $this->moveService->recordTriggerAppVersionLimitLog($shopId, $appVersionRet['appVersion'], $moveConfig['total'], $moveConfig['used_total'], $productTotal, 'move'); $shopInfo = $this->shopService->getShop($authShopId); $hasError = true; $tip = $this->moveUtil->getChargeTipByShopInfo($shopInfo, $productTotal, $moveConfig['available_total']); $errorArray[] = $tip; break; } } if ($hasError) { $this->moveBatchSaveTaskLog->info("shopId $shopId saveTask hasError" . print_r(Zc::G(), true)); $ret = CommonTool::failResult(implode(';', $errorArray)); $ret['hostname'] = $hostname; return $ret; } return CommonTool::successResult(array( 'curProductDetails' => $curProductDetails, 'shopConditions' => $shopConditions, 'shopMoveConditionMap' => $shopMoveConditionMap, )); } private function allocShopProductsByAuthShop($needMoveShopIds, $curProductDetails) { $shopProducts = array(); foreach ($needMoveShopIds as $authShopId) { foreach ($curProductDetails as $productInfo){ $newProduct = $this->moveUtil->formatSaveMoveTaskProduct($productInfo, $authShopId); if (empty($newProduct)) { continue; } $productId = $productInfo['productId']; $shopProducts[$authShopId][$productId] = $newProduct; } } return $shopProducts; } private function saveTaskByAuthShop($shopId, $copyType, $shopMoveConditionMap, $shopMoveSettingOperateLogMap, $shopConditions, $shopProducts, $shopPreviewCateAttr, $hostname, $operateSource, $isFromLtaoRank) { Zc::G("shopId $shopId start saveMoveSetting"); list($updateErrorShopIds, $moveShopSettingIds) = $this->saveMoveSetting($shopMoveConditionMap, $shopMoveSettingOperateLogMap); Zc::G("shopId $shopId end saveMoveSetting"); if (!empty($updateErrorShopIds)) { $ret = CommonTool::failResult(sprintf('店铺Id:%s,保存搬家配置失败,请稍后再尝试', implode(' ', $updateErrorShopIds))); $ret['hostname'] = $hostname; return $ret; } if ($copyType == MoveConst::collectLinksCopy) { $name = sprintf('%s 批量抓取', ZcDateHelper::now()); } else { $name = sprintf('%s', ZcDateHelper::now()); } Zc::G("shopId $shopId start replaceShopConditionsBigField"); $shopConditions = $this->moveService->replaceShopConditionsBigField($shopConditions, $moveShopSettingIds); Zc::G("shopId $shopId end replaceShopConditionsBigField"); $shopConditions = $this->attachMoveSettingIdToMoveTaskCondition($moveShopSettingIds, $shopConditions); $this->moveBatchSaveTaskLog->info("shopId $shopId start addShopCollectTask"); $addRet = $this->moveService->addShopCollectTask($shopId, $shopProducts, $name, $copyType, $shopConditions, $shopPreviewCateAttr, $operateSource,$isFromLtaoRank); if (CommonTool::isFailRet($addRet)) { $this->moveBatchSaveTaskLog->info("shopId $shopId saveTask addRet fail" . print_r(Zc::G(), true)); $addRet['hostname'] = $hostname; } return $addRet; } public function saveMoveSetting($shopMoveConditionMap, $shopMoveSettingOperateLogMap = array()) { $shopId = $_SESSION[SessionConst::shopId]; $updateErrorShopIds = array(); $moveShopSettingIds = array(); foreach ($shopMoveConditionMap as $authShopId => $moveCondition) { if (empty($moveCondition)) { $this->moveBatchSettingLog->info("authShopId[$authShopId] get empty moveCondition"); continue; } $moveCondition = $this->moveUtil->processMoveSetting($moveCondition); $moveCondition['shop_id'] = $authShopId; $moveShopSettingId = $moveCondition['move_shop_setting_id']; if ($moveShopSettingId) { $ret = $this->moveService->updateMoveSetting($authShopId, $moveShopSettingId, $moveCondition); $this->moveService->addMoveShopSettingOperateLog($shopId, $authShopId, $shopMoveSettingOperateLogMap[$authShopId]); $moveShopSettingIds[$authShopId] = $moveShopSettingId; } else { $ret = $this->moveService->insertMoveSetting($moveCondition); if ($ret) { $moveShopSettingIds[$authShopId] = $ret; } } if (!$ret) { $updateErrorShopIds[] = $authShopId; } $this->moveBatchSettingLog->info("shopId[$shopId] authShopId[$authShopId] post data:" . print_r($moveCondition, true) . "update ret:[$ret]" ); } return [$updateErrorShopIds, $moveShopSettingIds]; } public function history() { $moveShopStopInfo = $this->moveService->getMoveShopStopInfo($_SESSION[SessionConst::shopId]); $folderMenuTree = $this->materialService->getMaterialFolderMenuTree($_SESSION[SessionConst::shopId]); $shopId = $_SESSION[SessionConst::shopId]; $productCatList = $this->rsyncProductService->getAllLeafProductCatList($_SESSION[SessionConst::shopId]); $cates = []; $cates[] = '请选择分类'; foreach ($productCatList as $productCat) { $cates[$productCat['category_id']] = $productCat['path']; } $this->render([ 'moveShopStopInfo' => $moveShopStopInfo, 'folderMenuTree' => $folderMenuTree, 'shopId' => $shopId, 'productCatList' => $cates ]); } public function historyProductList() { $pageNo = $_GET['page'] > 0 ? (int)$_GET['page'] : 1; $pageSize = $_GET['pageSize'] > 0 ? (int)$_GET['pageSize'] : 20; $source = $_GET['source']; $status = $_GET['status']; $shopId = $_SESSION[SessionConst::shopId]; $filter = $this->moveUtil->buildHistoryProductListFilter($_GET); $filter['isMoveHugeSeller'] = $_SESSION[SessionConst::isMoveHugeSeller]; if (!in_array($pageSize, [20, 40, 100, 500, 1000, 2000])) { $pageSize = 20; } list($processingTaskCount, $taskDetailList, $total, $moveShopStopInfo) = $this->productUtil->getHistoryProductList($shopId, $filter, $pageNo, $pageSize); $taskDetailList = $this->productUtil->buildLtaoProductToDsItemTag($taskDetailList); $pagin = new ZcPagination($total, $pageSize, $pageNo); $html = $this->renderWithoutLayout(array( 'taskDetailList' => $taskDetailList, 'pagin' => $pagin, 'pageSize' => $pageSize, 'status' => $status, 'source' => $source, 'taskTotal' => $total, 'processingTaskCount' => $processingTaskCount, 'filter' => $filter, 'moveShopStopInfo' => $moveShopStopInfo, 'showLimitPublishReason' => $this->productUtil->showLimitPublishReason($taskDetailList, $moveShopStopInfo), ), 'move/batch/history_product_list', true); $data['html'] = $html; return $this->renderJSON($data); } public function failRetryMoveTasks() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } $shopId = $_SESSION[SessionConst::shopId]; $taskDetailIds = is_array($_POST['taskDetailIds']) ? $_POST['taskDetailIds'] : [$_POST['taskDetailIds']]; $retryRet = $this->moveUtil->failRetryMoveTasks($shopId, $taskDetailIds, $this->failRetryMoveTaskLog); $this->renderJSON($retryRet); } public function moveAgainDetail() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } $shopId = $_SESSION[SessionConst::shopId]; $taskDetailIds = is_array($_POST['taskDetailIds']) ? $_POST['taskDetailIds'] : [$_POST['taskDetailIds']]; if (count($taskDetailIds) == 1) { $newDetailId = $this->moveService->moveAgainDetailsByDetailId($shopId, array_pop($taskDetailIds), false, $this->moveAgainDetailLog); if ($newDetailId) { return $this->renderJSON(CommonTool::successResult('processCount', 1)); } else { return $this->renderJSON(CommonTool::failResult('当前商品数据已失效,暂不支持操作,如有疑问请联系客服')); } } else { $ret = $this->moveUtil->moveAgainDetail($shopId, $taskDetailIds, $this->moveAgainDetailLog); return $this->renderJSON($ret); } } public function deleteDeleteTask(){ if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult(ErrorCodeConst::csrfTokenErrorTip)); } $shopId = $_SESSION[SessionConst::shopId]; $delCnt = 0; ZC::G('start deleteDeleteTask'); $detailIds = $this->moveService->getAllDeleteMoveCollectTaskDetailIds($shopId); $allChunkedDetailIds = array_chunk($detailIds, 100); foreach ($allChunkedDetailIds as $sliceDetailIds) { foreach ($sliceDetailIds as $detailId) { $delRet = $this->moveService->delMoveTaskDetailHistory($shopId, $detailId); if ($delRet) { $delCnt++; } } } ZC::G('end deleteFailTask'); return $this->renderJSON(CommonTool::successResult('total', $delCnt)); } public function batchDeleteTaskDetail() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } $shopId = $_SESSION[SessionConst::shopId]; $accessToken = $_SESSION[SessionConst::accessToken]; $ret = $this->moveUtil->batchDeleteTaskDetail($shopId, $accessToken); return $this->renderJSON($ret); } public function cancelCollectTask() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } list($successCancelDetailIds, $skipCancelDetailIds) = $this->moveUtil->cancelCollectTask(); $html = ''; if ($skipCancelDetailIds) { list($processingTaskCount, $taskDetailList,) = $this->productUtil->getHistoryProductList($_SESSION[SessionConst::shopId], ['taskDetailIds' => $skipCancelDetailIds], 1, count($skipCancelDetailIds)); $html = $this->renderWithoutLayout(array( 'taskDetailList' => $taskDetailList, ), 'move/batch/skip_cancel', true); } return $this->renderJSON(CommonTool::successResult([ 'processCount' => count($successCancelDetailIds), 'skipCount' => count($skipCancelDetailIds), 'html' => $html ])); } public function deleteFailTaskDetail() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } $shopId = $_SESSION[SessionConst::shopId]; $delCount = $this->moveService->delMoveHistoryByStatus($shopId, StatusConst::fail); return $this->renderJSON(CommonTool::successResult('total', $delCount)); } public function deleteSkipTaskDetail() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult('CSRF校验不通过')); } $shopId = $_SESSION[SessionConst::shopId]; $delCount = $this->moveService->delMoveHistoryByStatus($shopId, StatusConst::skip); return $this->renderJSON(CommonTool::successResult('total', $delCount)); } public function getDsAuthUrl() { $shopId = $_SESSION[SessionConst::shopId]; $getUrlRet = $this->dsClient->getDsAuthUrl($shopId, AppConst::getDsPlatform(), Zc::C('acn.ds.domain')); return $this->renderJSON($getUrlRet); } public function checkDsAuthExpire() { $log = Zc::getLog('tool/fetch/checkAuth'); $shopId = $_SESSION[SessionConst::shopId]; $authCode = $this->shopService->getAuthCodeByShopId($shopId); if (empty($authCode)) { return $this->renderJSON(CommonTool::successResult()); } $dsMemberInfo = $this->moveService->getDsMemberInfo($shopId); $checkRet = $this->dsClient->checkDsAppAuthExpire(AppConst::getDsPlatform(), [], $dsMemberInfo['cnali_member_id'], $authCode); $log->info('-----checkRet-----' . print_r($checkRet, true)); if (CommonTool::isFailRet($checkRet)) { return $this->renderJSON(CommonTool::successResult()); } $checkRet = $checkRet['userIdAndCheckRetMap'][$shopId]; if (CommonTool::isSuccessRet($checkRet) || empty($checkRet['code'])) { return $this->renderJSON(CommonTool::successResult()); } if ($checkRet['code'] == DsConst::authExpireTypeAuthExpire) { $getUrlRet = $this->dsClient->getDsAuthUrl($shopId, AppConst::getDsPlatform(), Zc::C('acn.ds.domain')); if (CommonTool::isSuccessRet($getUrlRet)) { $checkRet['reason'] = sprintf('1688' . DsConst::getDsAppChineseName() . '授权已失效,重新授权', $getUrlRet['redirectUrl']); } } else { $dsBuyUrl = $this->moveService->getDsBuyUrl($shopId); $checkRet['reason'] = sprintf('1688' . DsConst::getDsAppChineseName() . '已过期,重新订购', $dsBuyUrl); } return $this->renderJSON($checkRet); } private function buildSearchSameProductFilter($sameType, $detailUrls, $shopId, $cluePicUrlNameMap = []) { if ($sameType == MoveConst::collectSameProductTypeImg) { if (empty($_FILES['searchSameProductImg'])) { return CommonTool::failResult('请上传图片'); } $moveDir = 'shop/upload/' . $shopId; $uploadRet = $this->materialUtil->uploadLocalMultipleImageToOss('searchSameProductImg', $moveDir, false); if (CommonTool::isFailRet($uploadRet)) { return $uploadRet; } $srcs = ZcArrayHelper::getSub($uploadRet['images'], 'src'); $detailUrls = implode(',', $srcs); if (empty($detailUrls)) { return CommonTool::failResult('上传图片失败,请重试'); } } $detailUrls = array_map('trim', preg_split("/\\r\\n|\\r|\\n|,|,|;|;/u", $detailUrls)); $detailUrls = array_filter(array_unique($detailUrls)); if (empty($detailUrls)) { return CommonTool::failResult('请输入链接'); } $detailUrls = array_slice($detailUrls, 0, 10); $productsInfoList = []; if ($sameType == MoveConst::collectSameProductTypeMixContent) { $linkDetails = []; $k = mt_rand(1000, 100000); foreach ($detailUrls as $detailUrl) { if (CommonTool::checkIsImageLink($detailUrl)) { $k++; $productsInfoList[$k] = [ 'itemId' => $k, 'imgUrl' => $detailUrl, 'title' => $cluePicUrlNameMap[$detailUrl] ?: '', ]; } else { $linkDetails[] = $detailUrl; } } if ($linkDetails) { $getProductsInfoListRet = $this->moveUtil->getProductsInfoListByDetailUrls(implode(',', $linkDetails), $shopId, null, null, null, null, true); if (CommonTool::isSuccessRet($getProductsInfoListRet)) { $fetchProductsInfoList = $getProductsInfoListRet['productsInfoList']; $fetchProductsInfoList = $this->buildSearchSameProductProductInfoList($fetchProductsInfoList); $productsInfoList = $productsInfoList + $fetchProductsInfoList; } } } else if ($sameType == MoveConst::collectSameProductTypeLink) { $getProductsInfoListRet = $this->moveUtil->getProductsInfoListByDetailUrls(implode(',', $detailUrls), $shopId); if (CommonTool::isFailRet($getProductsInfoListRet)) { return $getProductsInfoListRet; } $productsInfoList = $getProductsInfoListRet['productsInfoList']; $productsInfoList = $this->buildSearchSameProductProductInfoList($productsInfoList); } else if ($sameType == MoveConst::collectSameProductTypeImgUrl || $sameType == MoveConst::collectSameProductTypeImg) { $k = mt_rand(1000, 100000); foreach ($detailUrls as $imgUrl) { $k++; $productsInfoList[$k] = [ 'itemId' => $k, 'imgUrl' => $imgUrl, 'title' => $cluePicUrlNameMap[$imgUrl] ?: '', ]; } } return CommonTool::successResult('productsInfoList', $productsInfoList); } public function searchSameProduct() { if (!$this->webShop->validateCsrfToken()) { return $this->renderJSON(CommonTool::failResult(ErrorCodeConst::csrfTokenErrorTip)); } $this->moveBatchUrlLog->info('fetchDetailUrlInfo, shopId[' . $_SESSION[SessionConst::shopId] . '], post: ' . print_r($_POST, true)); $shopId = $_SESSION[SessionConst::shopId]; $detailUrls = $_POST['detailUrls']; $sameType = $_POST['sameType']; $copyType = $_POST['copyType']; $cluePicUrlNameMap = $_POST['cluePicUrlNameMap']; $checkRet = $this->moveUtil->checkAbnormalRequest($shopId); if (CommonTool::isFailRet($checkRet)) { return $this->renderJSON($checkRet); } $ret = $this->buildSearchSameProductFilter($sameType, $detailUrls, $shopId, $cluePicUrlNameMap ?: []); if (CommonTool::isFailRet($ret)) { return $this->renderJSON($ret); } $productsInfoList = $ret['productsInfoList']; if ($copyType == MoveConst::collectLtaoCopy) { list($productsInfoList) = $this->moveUtil->searchLtaoSameProducts($productsInfoList, $shopId, $cluePicUrlNameMap ?: []); } else { $productsInfoList = $this->moveUtil->searchSameProducts($productsInfoList, FetchClientConst::collectTaskSource1688, $shopId, $copyType == MoveConst::collectDsCopy); } $productsInfoList = $this->mergeSameProductIsSelect($productsInfoList); $html = $this->renderWithoutLayout([ 'productsInfoList' => $productsInfoList, 'copyType' => $copyType, ], 'move/batch/search_1688_same_product', true); return $this->renderJSON(CommonTool::successResult([ 'html' => $html, 'productsInfoList' => $productsInfoList ])); } private function filterNotDsProducts($productsInfoList, $shopId) { $i = 0; foreach ($productsInfoList as &$productsInfo) { $sameWareList = array_slice($productsInfo['sameWareList'], 0, 20); $sameWareList = ZcArrayHelper::changeKeyRow($sameWareList, 'itemId'); $productsInfo['sameWareList'] = $sameWareList; $productsInfo['sameWareNum'] = count($productsInfo['sameWareList']); if ($i > 0) { continue; } $detailUrls = ZcArrayHelper::getSub($productsInfo['sameWareList'], 'itemUrl'); $detailUrls = implode(',', $detailUrls); $getProductInfoListRet = $this->getAlibabaProductsInfoListByDetailUrls($detailUrls, $shopId); if (CommonTool::isFailRet($getProductInfoListRet)) { $productsInfo['sameWareList'] = []; $productsInfo['sameWareNum'] = 0; $i++; continue; } $itemsInfoList = $getProductInfoListRet['productsInfoList']; foreach ($productsInfo['sameWareList'] as $itemId => $itemInfo) { if (!isset($itemsInfoList[$itemId]) || !$itemsInfoList[$itemId]['isFromDs']) { unset($productsInfo['sameWareList'][$itemId]); } } $productsInfo['sameWareNum'] = count($productsInfo['sameWareList']); $productsInfo['hasFilterDs'] = true; $i++; } return $productsInfoList; } private function buildSearchSameProductProductInfoList($productsInfoList) { $newProductsInfoList = []; foreach ($productsInfoList as $productsInfo) { $imgUrl = $productsInfo['item_image'] ?: reset($productsInfo['image_paths']); if (empty($imgUrl)) { continue; } $newProductsInfoList[$productsInfo['itemId']] = [ 'itemId' => $productsInfo['itemId'], 'source' => $productsInfo['source'], 'site' => $productsInfo['site'], 'imgUrl' => $imgUrl, 'title' => $productsInfo['title'], 'price' => $productsInfo['sale_price'] ?: $productsInfo['jd_price'] ]; } return $newProductsInfoList; } private function mergeSameProductIsSelect($productsInfoList) { foreach ($productsInfoList as &$productsInfo) { foreach ($productsInfo['sameWareList'] as &$sameProduct) { $sameProduct['isSelect'] = 0; unset($sameProduct); } unset($productsInfo); } return $productsInfoList; } public function singleRetrySearchSameProduct() { $shopId = $_SESSION[SessionConst::shopId]; $imgUrl = $_POST['imgUrl']; $copyType = $_POST['copyType']; $cluePicUrlNameMap = $_POST['cluePicUrlNameMap']; $productsInfoList = ['100000' => ['itemId' => 100000, 'imgUrl' => $imgUrl]]; if ($copyType == MoveConst::collectLtaoCopy) { list($productsInfoList) = $this->moveUtil->searchLtaoSameProducts($productsInfoList, $shopId, $cluePicUrlNameMap ?: []); } else { $productsInfoList = $this->moveUtil->searchSameProducts($productsInfoList, FetchClientConst::collectTaskSource1688, $shopId, $copyType == MoveConst::collectDsCopy); } $productsInfoList = $this->mergeSameProductIsSelect($productsInfoList); if ($copyType == MoveConst::collectDsCopy) { $productsInfoList = $this->filterNotDsProducts($productsInfoList, $shopId); } $sameProductInfos = $productsInfoList[100000]; return CommonTool::successResult([ 'sameProductInfos' => $sameProductInfos ]); } }