| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657 |
- <?php
- // +----------------------------------------------------------------------
- // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
- // +----------------------------------------------------------------------
- // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
- // +----------------------------------------------------------------------
- // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
- // +----------------------------------------------------------------------
- // | Author: CRMEB Team <admin@crmeb.com>
- // +----------------------------------------------------------------------
- namespace app\services\product\product;
- use app\dao\product\product\StoreProductDao;
- use app\jobs\product\ProductStockTips;
- use app\model\product\product\StoreProduct;
- use app\Request;
- use app\services\activity\discounts\StoreDiscountsProductsServices;
- use app\services\activity\bargain\StoreBargainServices;
- use app\services\activity\combination\StoreCombinationServices;
- use app\services\activity\promotions\StorePromotionsServices;
- use app\services\activity\seckill\StoreSeckillServices;
- use app\services\activity\seckill\StoreSeckillTimeServices;
- use app\services\BaseServices;
- use app\services\activity\coupon\StoreCouponIssueServices;
- use app\services\diy\DiyServices;
- use app\services\order\StoreCartServices;
- use app\services\product\category\StoreProductCategoryServices;
- use app\services\product\branch\StoreBranchProductServices;
- use app\services\product\brand\StoreBrandServices;
- use app\services\other\queue\QueueServices;
- use app\services\product\ensure\StoreProductEnsureServices;
- use app\services\product\label\StoreProductLabelServices;
- use app\services\product\sku\StoreProductAttrResultServices;
- use app\services\product\sku\StoreProductAttrServices;
- use app\services\product\sku\StoreProductAttrValueServices;
- use app\services\product\sku\StoreProductRuleServices;
- use app\services\product\shipping\ShippingTemplatesServices;
- use app\services\product\sku\StoreProductVirtualServices;
- use app\services\product\specs\StoreProductSpecsServices;
- use app\services\store\SystemStoreServices;
- use app\services\supplier\SystemSupplierServices;
- use app\services\system\form\SystemFormServices;
- use app\services\user\label\UserLabelServices;
- use app\services\user\level\SystemUserLevelServices;
- use app\services\user\member\MemberCardServices;
- use app\services\activity\collage\UserCollagePartakeServices;
- use app\services\user\UserRelationServices;
- use app\services\user\UserSearchServices;
- use app\services\user\UserServices;
- use app\jobs\product\ProductLogJob;
- use crmeb\exceptions\AdminException;
- use crmeb\services\FormBuilder as Form;
- use crmeb\services\SystemConfigService;
- use crmeb\traits\ServicesTrait;
- use crmeb\traits\OptionTrait;
- use think\exception\ValidateException;
- use think\facade\Config;
- use think\facade\Route as Url;
- /**
- * Class StoreProductService
- * @package app\services\product\product
- * @mixin StoreProductDao
- */
- class StoreProductServices extends BaseServices
- {
- use OptionTrait, ServicesTrait;
- /**
- * StoreProductServices constructor.
- * @param StoreProductDao $dao
- */
- public function __construct(StoreProductDao $dao)
- {
- $this->dao = $dao;
- }
- /**
- * 获取顶部标签
- * @param int $store_id
- * @param array $where
- * @return array[]
- */
- public function getHeader(int $store_id = 0, array $where = [])
- {
- if ($store_id || (isset($where['store_id']) && $where['store_id'])) {
- $where['type'] = 1;
- $where['relation_id'] = $store_id ?: $where['store_id'];
- unset($where['store_id']);
- } elseif (isset($where['supplier_id']) && $where['supplier_id']) {
- $where['type'] = 2;
- $where['relation_id'] = $where['supplier_id'];
- unset($where['supplier_id']);
- } else {
- $where['pid'] = 0;
- }
- //出售中的商品
- $onsale = $this->dao->getCount(['status' => 1] + $where);
- //已经售馨商品
- $outofstock = $this->dao->getCount(['status' => 4] + $where);
- //警戒库存商品
- $store_stock = sys_config('store_stock', 0);
- $policeforce = $this->dao->getCount(['status' => 5, 'store_stock' => $store_stock > 0 ? $store_stock : 2] + $where);
- //仓库中的商品
- $forsale = $this->dao->getCount(['status' => 2] + $where);
- //回收站商品
- $delete = $this->dao->getCount(['status' => 6] + $where);
- //待审核商品
- $unVerify = $this->dao->getCount(['status' => 0] + $where);
- //审核未通过商品
- $refuseVerify = $this->dao->getCount(['status' => -1] + $where);
- //强制下架商品
- $removeVerify = $this->dao->getCount(['status' => -2] + $where);
- return [
- ['type' => 1, 'name' => '销售中', 'count' => $onsale],
- ['type' => 2, 'name' => '仓库中', 'count' => $forsale],
- ['type' => 4, 'name' => '已售罄', 'count' => $outofstock],
- ['type' => 5, 'name' => '库存预警', 'count' => $policeforce],
- ['type' => 6, 'name' => '回收站', 'count' => $delete],
- ['type' => 0, 'name' => '待审核', 'count' => $unVerify],
- ['type' => -1, 'name' => '审核未通过', 'count' => $refuseVerify],
- ['type' => -2, 'name' => '强制下架', 'count' => $removeVerify]
- ];
- }
- /**
- * 获取列表
- * @param $where
- * @return array
- */
- public function getList(array $where)
- {
- $store_stock = sys_config('store_stock', 0);
- $where['store_stock'] = $store_stock > 0 ? $store_stock : 2;
- [$page, $limit] = $this->getPageValue();
- $order_string = '';
- $order_arr = ['asc', 'desc'];
- if (isset($where['sales']) && in_array($where['sales'], $order_arr)) {
- $order_string = 'sales ' . $where['sales'];
- }
- //门店不展示卡密商品
- $count = $this->dao->getCount($where);
- //页面搜索,第二页之后没有结果,强制返回第一页数据
- if ($count <= $limit && $page !== 1) {
- $page = 1;
- }
- $list = $this->dao->getList($where, $page, $limit, $order_string);
- if ($list) {
- $cateIds = implode(',', array_column($list, 'cate_id'));
- /** @var StoreProductCategoryServices $categoryService */
- $categoryService = app()->make(StoreProductCategoryServices::class);
- $cateList = $categoryService->getCateParentAndChildName($cateIds);
- $supplierIds = $storeIds = [];
- foreach ($list as $value) {
- switch ($value['type']) {
- case 0:
- break;
- case 1://门店
- $storeIds[] = $value['relation_id'];
- break;
- case 2://供应商
- $supplierIds[] = $value['relation_id'];
- break;
- }
- }
- $supplierIds = array_unique($supplierIds);
- $storeIds = array_unique($storeIds);
- $supplierList = $storeList = [];
- if ($supplierIds) {
- /** @var SystemSupplierServices $supplierServices */
- $supplierServices = app()->make(SystemSupplierServices::class);
- $supplierList = $supplierServices->getColumn([['id', 'in', $supplierIds], ['is_del', '=', 0]], 'id,supplier_name', 'id');
- }
- if ($storeIds) {
- /** @var SystemStoreServices $storeServices */
- $storeServices = app()->make(SystemStoreServices::class);
- $storeList = $storeServices->getColumn([['id', 'in', $storeIds], ['is_del', '=', 0]], 'id,name', 'id');
- }
- foreach ($list as &$item) {
- $item['branch_sales'] = $item['sales'] ?? 0;
- $item['branch_stock'] = $item['stock'] ?? 0;
- $item['is_show'] = $item['branch_is_show'] ?? $item['is_show'];
- $item['cate_name'] = '';
- if (isset($item['cate_id']) && $item['cate_id']) {
- $cate_name = $categoryService->getCateName(explode(',', $item['cate_id']), $cateList);
- if ($cate_name) {
- $item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
- }
- }
- $item['stock_attr'] = $item['stock'] > 0;//库存
- $item['plate_name'] = '平台';
- switch ($item['type']) {
- case 0:
- $item['plate_name'] = '平台';
- break;
- case 1://门店
- $item['plate_name'] = '门店:' . ($storeList[$item['relation_id']]['name'] ?? '');
- break;
- case 2://供应商
- $item['plate_name'] = '供应商:' . ($supplierList[$item['relation_id']]['supplier_name'] ?? '');
- break;
- }
- }
- }
- return compact('list', 'count');
- }
- /**
- * 设置商品上下架
- * @param $ids
- * @param $is_show
- */
- public function setShow(array $ids, int $is_show)
- {
- if ($is_show == 0) {
- //下架检测是否有参与活动商品
- $this->checkActivity($ids);
- } else {
- $count = $this->dao->getCount(['ids' => $ids, 'is_del' => 1]);
- if ($count) throw new AdminException('回收站商品无法直接上架,请先恢复商品');
- }
- /** @var StoreCartServices $cartService */
- $cartService = app()->make(StoreCartServices::class);
- $cartService->batchUpdate($ids, ['status' => $is_show], 'product_id');
- $update = ['is_show' => $is_show];
- if ($is_show) {//手动上架 清空定时下架状态
- $update['auto_off_time'] = 0;
- }
- $this->dao->batchUpdate($ids, $update);
- /** @var StoreProductRelationServices $storeProductRelationServices */
- $storeProductRelationServices = app()->make(StoreProductRelationServices::class);
- $storeProductRelationServices->setShow($ids, (int)$is_show);
- //门店商品处理
- /** @var StoreBranchProductServices $storeBranchProductServices */
- $storeBranchProductServices = app()->make(StoreBranchProductServices::class);
- $storeBranchProductServices->update(['pid' => $ids, 'type' => 1], ['is_show' => $is_show ? 1 : 0]);
- event('product.status', [$ids, $is_show]);
- $this->dao->cacheTag()->clear();
- return true;
- }
- /**
- * 队列批量上下架
- * @param array $ids
- * @param int $is_show
- * @param $redisKey
- * @param $queueId
- */
- public function setBatchShow(array $ids, int $is_show, $redisKey, $queueId)
- {
- $res = $this->dao->batchUpdate($ids, ['is_show' => $is_show]);
- /** @var StoreProductRelationServices $storeProductRelationServices */
- $storeProductRelationServices = app()->make(StoreProductRelationServices::class);
- /** @var QueueServices $queueService */
- $queueService = app()->make(QueueServices::class);
- $re = true;
- if ($is_show == 0) {
- try {
- //下架检测是否有参与活动商品
- $re = $this->checkActivity($ids);
- //改变购物车中状态
- $storeProductRelationServices->setShow($ids, (int)$is_show);
- /** @var StoreCartServices $cartService */
- $cartService = app()->make(StoreCartServices::class);
- $cartService->changeStatus($ids, 1);
- } catch (\Throwable $e) {
- $re = false;
- }
- }
- if ($re) $storeProductRelationServices->setShow($ids, (int)$is_show);
- $queueService->doSuccessSremRedis($ids, $redisKey, $queueId['type']);
- if (!$res) {
- $queueService->addQueueFail($queueId['id'], $redisKey);
- }
- return true;
- }
- /**
- * 商品审核表单
- * @param int $id
- * @param int $is_verify
- * @return mixed
- */
- public function verifyForm(int $id, int $is_verify = 1)
- {
- $f = [];
- if ($is_verify == 1) {
- $f[] = Form::radio('is_verify', '审核状态', 1)->options([['value' => 1, 'label' => '通过'], ['value' => -1, 'label' => '拒绝']])->appendControl(-1, [
- Form::textarea('refusal', '拒绝原因')->required('请输入拒绝原因')]);
- } else {
- $f[] = Form::hidden('is_verify', '-2');
- $f[] = Form::textarea('refusal', '下架原因')->required('请输入下架原因');
- }
- return create_form($is_verify == 1 ? '商品审核' : '强制下架', $f, Url::buildUrl('/product/product/set_verify/' . $id), 'post');
- }
- /**
- * 商品审核
- * @param int $id
- * @param int $is_verify
- * @return bool
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function verify(int $id, array $data)
- {
- $info = $this->dao->get($id);
- if (!$info) {
- throw new ValidateException('商品不存在');
- }
- $is_verify = $data['is_verify'] ?? 1;
- /** @var StoreCartServices $cartService */
- $cartService = app()->make(StoreCartServices::class);
- if (in_array($is_verify, [-1, -2])) {
- if ($is_verify == -1) {
- $data['is_show'] = 0;
- }
- $cartService->update(['product_id' => $id, 'status' => 1], ['status' => 0]);
- } elseif ($is_verify == 1) {
- if ($info['is_show']) $cartService->update(['product_id' => $id, 'status' => 0], ['status' => 1]);
- }
- $this->dao->update($id, $data);
- return true;
- }
- /**
- * 获取规格模板
- * @param int $type
- * @param int $relation_id
- * @return mixed
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getRule(int $type = 0, int $relation_id = 0)
- {
- /** @var StoreProductRuleServices $storeProductRuleServices */
- $storeProductRuleServices = app()->make(StoreProductRuleServices::class);
- $list = $storeProductRuleServices->getList(['type' => $type, 'relation_id' => $relation_id])['list'] ?? [];
- foreach ($list as &$item) {
- $item['rule_value'] = json_decode($item['rule_value'], true);
- }
- return $list;
- }
- /**
- * 获取商品详情
- * @param int $id
- * @return array|\think\Model|null
- */
- public function getInfo(int $id)
- {
- /** @var StoreProductCategoryServices $storeCatecoryService */
- $storeCatecoryService = app()->make(StoreProductCategoryServices::class);
- /** @var StoreDescriptionServices $storeDescriptionServices */
- $storeDescriptionServices = app()->make(StoreDescriptionServices::class);
- /** @var StoreProductAttrResultServices $storeProductAttrResultServices */
- $storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
- /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
- $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
- /** @var StoreCouponIssueServices $storeCouponIssueServices */
- $storeCouponIssueServices = app()->make(StoreCouponIssueServices::class);
- /** @var UserLabelServices $userLabelServices */
- $userLabelServices = app()->make(UserLabelServices::class);
- $productInfo = $this->dao->getInfo($id);
- if ($productInfo) $productInfo = $productInfo->toArray();
- else throw new ValidateException('商品不存在');
- $data['tempList'] = $this->getTemp((int)$productInfo['type'], (int)$productInfo['relation_id']);
- $data['cateList'] = $storeCatecoryService->cascaderList();
- $couponIds = $productInfo['coupons'] ? array_column($productInfo['coupons'], 'issue_coupon_id') : [];
- $is_sub = $recommend = [];
- if ($productInfo['is_sub'] == 1) array_push($is_sub, 1);
- if ($productInfo['is_vip'] == 1) array_push($is_sub, 0);
- $productInfo['is_sub'] = $is_sub;
- $productInfo['recommend'] = $recommend;
- $productInfo['price'] = floatval($productInfo['price']);
- $productInfo['postage'] = floatval($productInfo['postage']);
- $productInfo['ot_price'] = floatval($productInfo['ot_price']);
- $productInfo['vip_price'] = floatval($productInfo['vip_price']);
- $productInfo['is_limit'] = boolval($productInfo['is_limit'] ?? 0);
- $productInfo['cost'] = floatval($productInfo['cost']);
- $productInfo['brand_id'] = $productInfo['brand_com'] ? array_map('intval', explode(',', $productInfo['brand_com'])) : [];
- $productInfo['video_open'] = (bool)$productInfo['video_open'];
- if ($productInfo['video_link'] && strpos($productInfo['video_link'], 'http') === false) {
- $productInfo['video_link'] = sys_config('site_url') . $productInfo['video_link'];
- }
- $productInfo['coupons'] = $storeCouponIssueServices->productCouponList([['id', 'in', $couponIds]], 'title,id');
- $productInfo['cate_id'] = is_array($productInfo['cate_id']) ? $productInfo['cate_id'] : explode(',', $productInfo['cate_id']);
- if ($productInfo['label_id']) {
- $label_id = is_array($productInfo['label_id']) ? $productInfo['label_id'] : explode(',', $productInfo['label_id']);
- $productInfo['label_id'] = $userLabelServices->getLabelList(['ids' => $label_id], ['id', 'label_name']);
- } else {
- $productInfo['label_id'] = [];
- }
- if ($productInfo['store_label_id']) {
- /** @var StoreProductLabelServices $storeProductLabelServices */
- $storeProductLabelServices = app()->make(StoreProductLabelServices::class);
- $productInfo['store_label_id'] = $storeProductLabelServices->getColumn([['id', 'in', $productInfo['store_label_id']]], 'id,label_name');
- } else {
- $productInfo['store_label_id'] = [];
- }
- $productInfo['give_integral'] = floatval($productInfo['give_integral']);
- $productInfo['presale_time'] = $productInfo['presale_start_time'] == 0 ? [] : [date('Y-m-d H:i:s', $productInfo['presale_start_time']), date('Y-m-d H:i:s', $productInfo['presale_end_time'])];
- $productInfo['auto_on_time'] = $productInfo['is_show'] ? '' : ($productInfo['auto_on_time'] ? date('Y-m-d H:i:s', $productInfo['auto_on_time']) : '');
- $productInfo['auto_off_time'] = !$productInfo['is_show'] ? '' : ($productInfo['auto_off_time'] ? date('Y-m-d H:i:s', $productInfo['auto_off_time']) : '');
- $productInfo['description'] = $storeDescriptionServices->getDescription(['product_id' => $id, 'type' => 0]);
- //系统表单
- $productInfo['custom_form'] = $productInfo['custom_form_info'] = [];
- if ($productInfo['system_form_id']) {
- /** @var SystemFormServices $systemFormServices */
- $systemFormServices = app()->make(SystemFormServices::class);
- $systemForm = $systemFormServices->value(['id' => $productInfo['system_form_id']], 'value');
- if ($systemForm) {
- $productInfo['custom_form'] = is_string($systemForm) ? json_decode($systemForm, true) : $systemForm;
- }
- $productInfo['custom_form_info'] = $systemFormServices->handleForm($productInfo['custom_form']);
- }
- //无属性添加默认属性
- if (!$storeProductAttrResultServices->getResult(['product_id' => $id, 'type' => 0])) {
- $attr = [
- [
- 'value' => '规格',
- 'detailValue' => '',
- 'attrHidden' => '',
- 'detail' => ['默认']
- ]
- ];
- $detail[0] = [
- 'value1' => '默认',
- 'detail' => ['规格' => '默认'],
- 'pic' => $productInfo['image'],
- 'price' => $productInfo['price'],
- 'settle_price' => $productInfo['settle_price'] ?? 0,
- 'award_price' => $productInfo['award_price'] ?? 0,
- 'cost' => $productInfo['cost'],
- 'ot_price' => $productInfo['ot_price'],
- 'stock' => $productInfo['stock'],
- 'bar_code' => '',
- 'weight' => 0,
- 'volume' => 0,
- 'brokerage' => 0,
- 'brokerage_two' => 0,
- 'code' => 0,
- ];
- /** @var StoreProductAttrServices $storeProductAttrServices */
- $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
- $skuList = $storeProductAttrServices->validateProductAttr($attr, $detail, $id);
- $storeProductAttrServices->saveProductAttr($skuList, $id, 0);
- $this->dao->update($id, ['spec_type' => 0]);
- }
- if ($productInfo['spec_type'] == 1) {
- $result = $storeProductAttrResultServices->getResult(['product_id' => $id, 'type' => 0]);
- foreach ($result['value'] as $k => $v) {
- $num = 1;
- foreach ($v['detail'] as $dv) {
- $result['value'][$k]['value' . $num] = $dv;
- $num++;
- }
- }
- $productInfo['items'] = $result['attr'];
- $productInfo['attrs'] = $result['value'];
- $productInfo['attr'] = ['pic' => '', 'vip_price' => 0, 'price' => 0, 'settle_price' => 0, 'award_price' => 0, 'cost' => 0, 'ot_price' => 0, 'stock' => 0, 'bar_code' => '', 'weight' => 0, 'volume' => 0, 'brokerage' => 0, 'brokerage_two' => 0, 'code' => ''];
- } else {
- /** @var StoreProductVirtualServices $virtualService */
- $virtualService = app()->make(StoreProductVirtualServices::class);
- $result = $storeProductAttrValueServices->getOne(['product_id' => $id, 'type' => 0]);
- $productInfo['items'] = [];
- $productInfo['attrs'] = [];
- $productInfo['attr'] = [
- 'pic' => $result['image'] ?? '',
- 'vip_price' => isset($result['vip_price']) ? floatval($result['vip_price']) : 0,
- 'price' => isset($result['price']) ? floatval($result['price']) : 0,
- 'settle_price' => isset($result['settle_price']) ? floatval($result['settle_price']) : 0,
- 'award_price' => isset($result['award_price']) ? floatval($result['award_price']) : 0,
- 'cost' => isset($result['cost']) ? floatval($result['cost']) : 0,
- 'ot_price' => isset($result['ot_price']) ? floatval($result['ot_price']) : 0,
- 'stock' => isset($result['stock']) ? floatval($result['stock']) : 0,
- 'bar_code' => isset($result['bar_code']) ? $result['bar_code'] : '',
- 'code' => isset($result['code']) ? $result['code'] : '',
- 'virtual_list' => $virtualService->getArr(isset($result['unique']), $id),
- 'weight' => isset($result['weight']) ? floatval($result['weight']) : 0,
- 'volume' => isset($result['volume']) ? floatval($result['volume']) : 0,
- 'brokerage' => isset($result['brokerage']) ? floatval($result['brokerage']) : 0,
- 'brokerage_two' => isset($result['brokerage_two']) ? floatval($result['brokerage_two']) : 0,
- 'disk_info' => $result['disk_info'] ?? [],
- 'write_times' => intval($result['write_times'] ?? 1),//核销次数
- 'write_valid' => intval($result['write_valid'] ?? 1),//核销时效类型
- 'days' => intval($result['write_days'] ?? $result['days'] ?? 0),//购买后:N天有效
- 'section_time' => [($result['write_start'] ?? '') ? date('Y-m-d', $result['write_start'] ?? '') : '', ($result['write_end'] ?? '') ? date('Y-m-d', $result['write_end'] ?? '') : ''],//[核销开始时间,核销结束时间]
- ];
- }
- if ($productInfo['activity']) {
- $activity = explode(',', $productInfo['activity']);
- foreach ($activity as $k => $v) {
- if ($v == 1) {
- $activity[$k] = '秒杀';
- } elseif ($v == 2) {
- $activity[$k] = '砍价';
- } elseif ($v == 3) {
- $activity[$k] = '拼团';
- } elseif ($v == 0) {
- $activity[$k] = '默认';
- }
- }
- $productInfo['activity'] = $activity;
- } else {
- $productInfo['activity'] = ['默认', '秒杀', '砍价', '拼团'];
- }
- //推荐产品
- $recommend_list = [];
- if ($productInfo['recommend_list'] != '') {
- $productInfo['recommend_list'] = explode(',', $productInfo['recommend_list']);
- if (count($productInfo['recommend_list'])) {
- $images = $this->getColumn([['id', 'in', $productInfo['recommend_list']]], 'image', 'id');
- foreach ($productInfo['recommend_list'] as $item) {
- $recommend_list[] = [
- 'product_id' => $item,
- 'image' => $images[$item]
- ];
- }
- }
- }
- $productInfo['recommend_list'] = $recommend_list;
- //适用门店
- $productInfo['stores'] = [];
- if (isset($productInfo['applicable_type']) && ($productInfo['applicable_type'] == 1 || ($productInfo['applicable_type'] == 2 && isset($productInfo['applicable_store_id']) && $productInfo['applicable_store_id']))) {//查询门店信息
- $where = ['is_del' => 0];
- if ($productInfo['applicable_type'] == 2) {
- $store_ids = is_array($productInfo['applicable_store_id']) ? $productInfo['applicable_store_id'] : explode(',', $productInfo['applicable_store_id']);
- $where['id'] = $store_ids;
- }
- $field = ['id', 'cate_id', 'name', 'phone', 'address', 'detailed_address', 'image', 'is_show', 'day_time', 'day_start', 'day_end'];
- /** @var SystemStoreServices $storeServices */
- $storeServices = app()->make(SystemStoreServices::class);
- $storeData = $storeServices->getStoreList($where, $field, '', '', 0, ['categoryName']);
- $productInfo['stores'] = $storeData['list'] ?? [];
- }
- $data['productInfo'] = $productInfo;
- return $data;
- }
- /**
- * 获取运费模板列表
- * @param int $type
- * @param int $relation_id
- * @return array
- */
- public function getTemp(int $type = 0, int $relation_id = 0)
- {
- /** @var ShippingTemplatesServices $shippingTemplatesServices */
- $shippingTemplatesServices = app()->make(ShippingTemplatesServices::class);
- return $shippingTemplatesServices->getSelectList(['type' => $type, 'relation_id' => $relation_id]);
- }
- /**
- * 获取商品规格
- * @param array $data
- * @param int $id
- * @param int $type
- * @param int $plat_type
- * @param int $relation_id
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getAttr(array $data, int $id, int $type, int $plat_type = 0, int $relation_id = 0)
- {
- /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
- $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
- $productInfo = [];
- if ($id) {
- $productInfo = $this->dao->get($id);
- if (!$productInfo) {
- throw new ValidateException('商品不存在');
- }
- }
- /** @var StoreProductVirtualServices $virtualService */
- $virtualService = app()->make(StoreProductVirtualServices::class);
- $attr = $data['attrs'];
- $product_type = $productInfo['product_type'] ?? $data['product_type'] ?? 0; //商品类型
- $value = attr_format($attr)[1];
- $valueNew = [];
- $count = 0;
- foreach ($value as $key => $item) {
- $detail = $item['detail'];
- foreach ($detail as $v => $d) {
- $detail[$v] = trim($d);
- }
- // sort($item['detail'], SORT_STRING);
- $suk = implode(',', $detail);
- $types = 1;
- if ($id) {
- $sukValue = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => 0, 'suk' => $suk], 'unique,bar_code,code,cost,award_price,price,settle_price,ot_price,stock,image as pic,weight,volume,brokerage,brokerage_two,vip_price,disk_info', 'suk');
- if (!$sukValue) {
- if ($type == 0) $types = 0; //编辑商品时,将没有规格的数据不生成默认值
- $sukValue[$suk]['pic'] = '';
- $sukValue[$suk]['price'] = 0;
- $sukValue[$suk]['award_price'] = 0;
- $sukValue[$suk]['settle_price'] = 0;
- $sukValue[$suk]['cost'] = 0;
- $sukValue[$suk]['ot_price'] = 0;
- $sukValue[$suk]['stock'] = 0;
- $sukValue[$suk]['bar_code'] = '';
- $sukValue[$suk]['code'] = '';
- $sukValue[$suk]['weight'] = 0;
- $sukValue[$suk]['volume'] = 0;
- $sukValue[$suk]['brokerage'] = 0;
- $sukValue[$suk]['brokerage_two'] = 0;
- switch ($product_type) {
- case 1://卡密
- $sukValue[$suk]['virtual_list'] = [];
- break;
- case 2://优惠券
- $sukValue[$suk]['coupon_id'] = 0;
- break;
- case 3://虚拟商品
- break;
- case 4://次卡商品
- $sukValue[$suk]['write_times'] = 1;//核销次数
- $sukValue[$suk]['write_valid'] = 1;//核销时效类型
- $sukValue[$suk]['days'] = 0;//购买后:N天有效
- $sukValue[$suk]['section_time'] = [];//[核销开始时间,核销结束时间]
- break;
- }
- }
- } else {
- $sukValue[$suk]['pic'] = '';
- $sukValue[$suk]['price'] = 0;
- $sukValue[$suk]['award_price'] = 0;
- $sukValue[$suk]['settle_price'] = 0;
- $sukValue[$suk]['cost'] = 0;
- $sukValue[$suk]['ot_price'] = 0;
- $sukValue[$suk]['stock'] = 0;
- $sukValue[$suk]['bar_code'] = '';
- $sukValue[$suk]['code'] = '';
- $sukValue[$suk]['weight'] = 0;
- $sukValue[$suk]['volume'] = 0;
- $sukValue[$suk]['brokerage'] = 0;
- $sukValue[$suk]['brokerage_two'] = 0;
- switch ($product_type) {
- case 1://卡密
- $sukValue[$suk]['virtual_list'] = [];
- break;
- case 2://优惠券
- $sukValue[$suk]['coupon_id'] = 0;
- break;
- case 3://虚拟商品
- break;
- case 4://次卡商品
- $sukValue[$suk]['write_times'] = 1;//核销次数
- $sukValue[$suk]['write_valid'] = 1;//核销时效类型
- $sukValue[$suk]['days'] = 0;//购买后:N天有效
- $sukValue[$suk]['section_time'] = [];//[核销开始时间,核销结束时间]
- break;
- }
- }
- if ($types) { //编辑商品时,将没有规格的数据不生成默认值
- foreach (array_keys($detail) as $k => $title) {
- $header[$k]['title'] = $title;
- $header[$k]['align'] = 'center';
- $header[$k]['minWidth'] = 130;
- }
- $values = '';
- foreach (array_values($detail) as $k => $v) {
- $valueNew[$count]['value' . ($k + 1)] = $v;
- $header[$k]['slot'] = 'value' . ($k + 1);
- $values .= $v . ',';
- }
- $valueNew[$count]['values'] = substr($values, 0, strlen($values) - 1);
- $valueNew[$count]['detail'] = $detail;
- $valueNew[$count]['pic'] = $sukValue[$suk]['pic'] ?? '';
- $valueNew[$count]['price'] = $sukValue[$suk]['price'] ? floatval($sukValue[$suk]['price']) : 0;
- $valueNew[$count]['settle_price'] = $sukValue[$suk]['settle_price'] ? floatval($sukValue[$suk]['settle_price']) : 0;
- $valueNew[$count]['award_price'] = $sukValue[$suk]['award_price'] ? floatval($sukValue[$suk]['award_price']) : 0;
- $valueNew[$count]['cost'] = $sukValue[$suk]['cost'] ? floatval($sukValue[$suk]['cost']) : 0;
- $valueNew[$count]['ot_price'] = isset($sukValue[$suk]['ot_price']) ? floatval($sukValue[$suk]['ot_price']) : 0;
- $valueNew[$count]['vip_price'] = isset($sukValue[$suk]['vip_price']) ? floatval($sukValue[$suk]['vip_price']) : 0;
- $valueNew[$count]['stock'] = $sukValue[$suk]['stock'] ? intval($sukValue[$suk]['stock']) : 0;
- $valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? '';
- $valueNew[$count]['code'] = $sukValue[$suk]['code'] ?? '';
- $valueNew[$count]['weight'] = floatval($sukValue[$suk]['weight']) ?? 0;
- $valueNew[$count]['volume'] = floatval($sukValue[$suk]['volume']) ?? 0;
- $valueNew[$count]['brokerage'] = floatval($sukValue[$suk]['brokerage']) ?? 0;
- $valueNew[$count]['brokerage_two'] = floatval($sukValue[$suk]['brokerage_two']) ?? 0;
- switch ($product_type) {
- case 1://卡密
- if (!$type) {
- $valueNew[$count]['virtual_list'] = isset($sukValue[$suk]['unique']) && $sukValue[$suk]['unique'] ? $virtualService->getArr($sukValue[$suk]['unique'], $id) : [];
- $valueNew[$count]['disk_info'] = $sukValue[$suk]['disk_info'] ?? '';
- }
- break;
- case 2://优惠券
- break;
- case 3://虚拟商品
- break;
- case 4://次卡商品
- $valueNew[$count]['write_times'] = intval($sukValue[$suk]['write_times'] ?? 1);//核销次数
- $valueNew[$count]['write_valid'] = intval($sukValue[$suk]['write_valid'] ?? 1);//核销时效类型
- $valueNew[$count]['days'] = intval($sukValue[$suk]['write_days'] ?? $sukValue[$suk]['days'] ?? 0);//购买后:N天有效
- $start = $sukValue[$suk]['write_start'] ?? '';
- $end = $sukValue[$suk]['write_end'] ?? '';
- $valueNew[$count]['section_time'] = [$start ? date('Y-m-d', $start) : '', $end ? date('Y-m-d', $end) : ''];//[核销开始时间,核销结束时间]
- break;
- }
- $count++;
- }
- }
- $header[] = ['title' => '图片', 'slot' => 'pic', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '售价', 'slot' => 'price', 'align' => 'center', 'minWidth' => 120];
- if ($plat_type == 2) {//供应商
- $header[] = ['title' => '结算价', 'slot' => 'settle_price', 'align' => 'center', 'minWidth' => 120];
- } else {//供应商不展示成本价
- $header[] = ['title' => '成本价', 'slot' => 'cost', 'align' => 'center', 'minWidth' => 140];
- }
- $header[] = ['title' => '奖金结算', 'slot' => 'award_price', 'align' => 'center', 'minWidth' => 140];
- $header[] = ['title' => '原价', 'slot' => 'ot_price', 'align' => 'center', 'minWidth' => 140];
- // $header[] = ['title' => '会员价', 'slot' => 'vip_price', 'align' => 'center', 'minWidth' => 140];
- $header[] = ['title' => '库存', 'slot' => 'stock', 'align' => 'center', 'minWidth' => 140];
- $header[] = ['title' => '商品条形码', 'slot' => 'bar_code', 'align' => 'center', 'minWidth' => 140];
- $header[] = ['title' => '商品编码', 'slot' => 'code', 'align' => 'center', 'minWidth' => 140];
- switch ($product_type) {
- case 0:
- $header[] = ['title' => '重量(KG)', 'slot' => 'weight', 'align' => 'center', 'minWidth' => 140];
- $header[] = ['title' => '体积(m³)', 'slot' => 'volume', 'align' => 'center', 'minWidth' => 140];
- break;
- case 1://卡密
- $header[] = ['title' => '卡密商品', 'slot' => 'fictitious', 'align' => 'center', 'minWidth' => 140];
- break;
- case 2://优惠券
- break;
- case 3://虚拟商品
- break;
- case 4://次卡商品
- break;
- default:
- break;
- }
- $header[] = ['title' => '操作', 'slot' => 'action', 'align' => 'center', 'minWidth' => 70];
- return ['attr' => $attr, 'value' => $valueNew, 'header' => $header, 'product_type' => $product_type];
- }
- /**
- * SPU
- * @return string
- */
- public function createSpu()
- {
- mt_srand();
- return substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . str_pad((string)mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
- }
- /**
- * 新增编辑商品
- * @param int $id
- * @param array $data
- * @param int $type
- * @param int $relation_id
- * @return void
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function save(int $id, array $data, int $type = 0, int $relation_id = 0)
- {
- if (count($data['cate_id']) < 1) throw new AdminException('请选择商品分类');
- if (!$data['store_name']) throw new AdminException('请输入商品名称');
- if (count($data['slider_image']) < 1) throw new AdminException('请上传商品轮播图');
- if ($data['product_type'] == 0 && isset($data['delivery_type']) && count($data['delivery_type']) < 1) throw new AdminException('请选择商品配送方式');
- if (in_array($data['product_type'], [1, 2, 3, 4])) {
- $data['freight'] = 2;
- $data['temp_id'] = 0;
- $data['postage'] = 0;
- } else {
- if ($data['freight'] == 1) {
- $data['temp_id'] = 0;
- $data['postage'] = 0;
- } elseif ($data['freight'] == 2) {
- $data['temp_id'] = 0;
- } elseif ($data['freight'] == 3) {
- $data['postage'] = 0;
- }
- if ($data['freight'] == 2 && !$data['postage']) {
- throw new AdminException('请设置运费金额');
- }
- if ($data['freight'] == 3 && !$data['temp_id']) {
- throw new AdminException('请选择运费模版');
- }
- }
- // 开启ERP后商品编码验证
- $isOpen = sys_config('erp_open');
- if ($isOpen && $data['product_type'] == 0 && empty($data['code'])) {
- throw new AdminException('请输入商品编码');
- }
- $detail = $data['attrs'];
- $attr = $data['items'];
- $coupon_ids = $data['coupon_ids'];
- //关联补充信息
- $relationData = [];
- $relationData['cate_id'] = $data['cate_id'] ?? [];
- $relationData['brand_id'] = $data['brand_id'] ?? [];
- $relationData['store_label_id'] = $data['store_label_id'] ?? [];
- $relationData['label_id'] = $data['label_id'] ?? [];
- $relationData['ensure_id'] = $data['ensure_id'] ?? [];
- $relationData['specs_id'] = $data['specs_id'] ?? [];
- $relationData['coupon_ids'] = $data['coupon_ids'] ?? [];
- $description = $data['description'];
- $data['type'] = $type;
- $data['relation_id'] = $relation_id;
- $supplier_id = $data['supplier_id'] ?? 0;
- if ($supplier_id) {
- $data['type'] = 2;
- $data['relation_id'] = $supplier_id;
- }
- if ($data['type'] == 0) {//平台商品不需要审核
- $data['is_verify'] = 1;
- }
- $is_copy = $data['is_copy'];
- unset($data['supplier_id'], $data['is_copy']);
- //视频
- if ($data['video_link'] && strpos($data['video_link'], 'http') === false) {
- $data['video_link'] = sys_config('site_url') . $data['video_link'];
- }
- //品牌
- $data['brand_com'] = $data['brand_id'] ? implode(',', $data['brand_id']) : '';
- $data['brand_id'] = $data['brand_id'] ? end($data['brand_id']) : 0;
- $data['is_vip'] = in_array(0, $data['is_sub']) ? 1 : 0;
- $data['is_sub'] = in_array(1, $data['is_sub']) ? 1 : 0;
- $data['product_type'] = intval($data['product_type']);
- $data['is_vip_product'] = intval($data['is_vip_product']);
- $data['is_presale_product'] = intval($data['is_presale_product']);
- $data['presale_start_time'] = $data['is_presale_product'] ? strtotime($data['presale_time'][0]) : 0;
- $data['presale_end_time'] = $data['is_presale_product'] ? strtotime($data['presale_time'][1]) : 0;
- if ($data['presale_start_time'] && $data['presale_start_time'] < time()) {
- throw new AdminException('预售开始时间不能小于当前时间');
- }
- if ($data['presale_end_time'] && $data['presale_end_time'] < time()) {
- throw new AdminException('预售结束时间不能小于当前时间');
- }
- $data['auto_on_time'] = $data['auto_on_time'] ? strtotime($data['auto_on_time']) : 0;
- $data['auto_off_time'] = $data['auto_off_time'] ? strtotime($data['auto_off_time']) : 0;
- if ($data['auto_on_time']) {
- $data['is_show'] = 0;
- }
- $data['is_limit'] = intval($data['is_limit']);
- if (!$data['is_limit']) {
- $data['limit_type'] = 0;
- $data['limit_num'] = 0;
- } else {
- if (!in_array($data['limit_type'], [1, 2])) throw new AdminException('请选择限购类型');
- if ($data['limit_num'] <= 0) throw new AdminException('限购数量不能小于1');
- }
- $data['custom_form'] = json_encode($data['custom_form']);
- $storeLabelId = $data['store_label_id'];
- if ($data['store_label_id']) {
- $data['store_label_id'] = is_array($data['store_label_id']) ? implode(',', $data['store_label_id']) : $data['store_label_id'];
- } else {
- $data['store_label_id'] = '';
- }
- if ($data['ensure_id']) {
- $data['ensure_id'] = is_array($data['ensure_id']) ? implode(',', $data['ensure_id']) : $data['ensure_id'];
- } else {
- $data['ensure_id'] = '';
- }
- if (!$data['specs_id']) {
- $data['specs'] = '';
- }
- if ($data['specs']) {
- $specs = [];
- if (is_array($data['specs'])) {
- /** @var StoreProductSpecsServices $storeProductSpecsServices */
- $storeProductSpecsServices = app()->make(StoreProductSpecsServices::class);
- foreach ($data['specs'] as $item) {
- $specs[] = $storeProductSpecsServices->checkSpecsData($item);
- }
- $data['specs'] = json_encode($specs);
- }
- } else {
- $data['specs'] = '';
- }
- if ($data['spec_type'] == 0) {
- $attr = [
- [
- 'value' => '规格',
- 'detailValue' => '',
- 'attrHidden' => '',
- 'detail' => ['默认']
- ]
- ];
- $detail[0]['value1'] = '默认';
- $detail[0]['detail'] = ['规格' => '默认'];
- }
- foreach ($detail as &$item) {
- if ($isOpen && $data['product_type'] == 0 && (!isset($item['code']) || !$item['code'])) {
- throw new AdminException('请输入【' . ($item['values'] ?? '默认') . '】商品编码');
- }
- if ($type == 2 && !$item['settle_price']) {
- throw new AdminException('请输入结算价');
- }
- $item['product_type'] = $data['product_type'];
- if ($data['is_sub'] == 0) {
- $item['brokerage'] = 0;
- $item['brokerage_two'] = 0;
- }
- if (($item['brokerage'] + $item['brokerage_two']) > $item['price']) {
- throw new AdminException('一二级返佣相加不能大于商品售价');
- }
- //验证次卡商品数据
- if ($data['product_type'] == 4) {
- if (!isset($item['write_times']) || !$item['write_times']) {
- throw new AdminException('请输入核销次数');
- }
- if (!isset($item['write_valid'])) {
- throw new AdminException('请选择核销时效类型');
- }
- switch ($item['write_valid']) {
- case 1://永久
- $item['days'] = 0;
- $item['section_time'] = [0, 0];
- break;
- case 2://购买后n天
- $item['section_time'] = [0, 0];
- if (!isset($item['days']) || !$item['days']) {
- throw new AdminException('填写时效天数');
- }
- break;
- case 3://固定时间
- $item['days'] = 0;
- if (!isset($item['section_time']) || !$item['section_time'] || !is_array($item['section_time']) || count($item['section_time']) != 2) {
- throw new AdminException('请选择固定有效时间段或时间格式错误');
- }
- [$start, $end] = $item['section_time'];
- $data['start_time'] = $start ? strtotime($start) : 0;
- $data['end_time'] = $end ? strtotime($end) : 0;
- if ($data['start_time'] && $data['end_time'] && $data['end_time'] <= $data['start_time']) {
- throw new AdminException('请重新选择:结束时间必须大于开始时间');
- }
- break;
- default:
- throw new AdminException('请选择核销时效类型');
- break;
- }
- }
- }
- foreach ($data['activity'] as $k => $v) {
- if ($v == '秒杀') {
- $data['activity'][$k] = 1;
- } elseif ($v == '砍价') {
- $data['activity'][$k] = 2;
- } elseif ($v == '拼团') {
- $data['activity'][$k] = 3;
- } else {
- $data['activity'][$k] = 0;
- }
- }
- $data['activity'] = implode(',', $data['activity']);
- $data['recommend_list'] = count($data['recommend_list']) ? implode(',', $data['recommend_list']) : '';
- $data['price'] = min(array_column($detail, 'price'));
- $data['award_price'] = max(array_column($detail, 'award_price'));
- $data['ot_price'] = min(array_column($detail, 'ot_price'));
- $data['cost'] = min(array_column($detail, 'cost'));
- if (!$data['cost']) {
- $data['cost'] = 0;
- }
- $data['cate_id'] = implode(',', $data['cate_id']);
- $data['label_id'] = implode(',', $data['label_id']);
- $data['image'] = $data['slider_image'][0];//封面图
- $slider_image = $data['slider_image'];
- $data['slider_image'] = json_encode($data['slider_image']);
- $data['stock'] = array_sum(array_column($detail, 'stock'));
- //是否售罄
- $data['is_sold'] = $data['stock'] ? 0 : 1;
- unset($data['description'], $data['coupon_ids'], $data['items'], $data['attrs'], $data['recommend']);
- /** @var StoreDescriptionServices $storeDescriptionServices */
- $storeDescriptionServices = app()->make(StoreDescriptionServices::class);
- /** @var StoreProductAttrServices $storeProductAttrServices */
- $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
- /** @var StoreProductCouponServices $storeProductCouponServices */
- $storeProductCouponServices = app()->make(StoreProductCouponServices::class);
- /** @var StoreDiscountsProductsServices $storeDiscountProduct */
- $storeDiscountProduct = app()->make(StoreDiscountsProductsServices::class);
- /** @var StoreProductVirtualServices $productVirtual */
- $productVirtual = app()->make(StoreProductVirtualServices::class);
- //同一链接不多次保存
- if (!$id && $data['soure_link']) {
- $productInfo = $this->dao->getOne(['soure_link' => $data['soure_link'], 'is_del' => 0], 'id');
- if ($productInfo) $id = (int)$productInfo['id'];
- }
- [$skuList, $id, $is_new, $data] = $this->transaction(function () use ($id, $data, $description, $storeDescriptionServices, $storeProductAttrServices, $storeProductCouponServices, $detail, $attr, $coupon_ids, $storeDiscountProduct, $productVirtual, $slider_image) {
- if ($id) {
- //上下架处理
- $this->setShow([$id], $data['is_show']);
- $oldInfo = $this->get($id)->toArray();
- if ($oldInfo['product_type'] != $data['product_type']) {
- throw new AdminException('商品类型不能切换!');
- }
- //修改不改变商品来源
- if ($oldInfo['type']) {
- $data['type'] = $oldInfo['type'];
- $data['relation_id'] = $oldInfo['relation_id'];
- }
- unset($data['sales']);
- $res = $this->dao->update($id, $data);
- if (!$res) throw new AdminException('修改失败');
- // 修改优惠套餐商品的运费模版id
- $storeDiscountProduct->update(['product_id' => $id], ['temp_id' => $data['temp_id']]);
- if (!empty($coupon_ids)) {
- $storeProductCouponServices->setCoupon($id, $coupon_ids);
- } else {
- $storeProductCouponServices->delete(['product_id' => $id]);
- }
- if ($oldInfo['type'] == 1 && !$oldInfo['pid'] && !$data['is_verify']) {
- /** @var StoreCartServices $cartService */
- $cartService = app()->make(StoreCartServices::class);
- $cartService->batchUpdate([$id], ['status' => 0], 'product_id');
- }
- $is_new = 1;
- } else {
- $data['add_time'] = time();
- $data['code_path'] = '';
- $data['spu'] = $this->createSpu();
- $res = $this->dao->save($data);
- if (!$res) throw new AdminException('添加失败');
- $id = (int)$res->id;
- if (!empty($coupon_ids)) $storeProductCouponServices->setCoupon($id, $coupon_ids);
- $is_new = 0;
- }
- //商品详情
- $storeDescriptionServices->saveDescription($id, $description);
- $skuList = $storeProductAttrServices->validateProductAttr($attr, $detail, $id, 0, (int)$data['is_vip']);
- foreach ($skuList['valueGroup'] as &$item) {
- if (!isset($item['sum_stock']) || !$item['sum_stock']) $item['sum_stock'] = $item['stock'] ?? 0;
- }
- $proudctVipPrice = 0;
- $detailTemp = array_column($skuList['valueGroup'], 'vip_price');
- if ($detailTemp) {
- $proudctVipPrice = min($detailTemp);
- }
- $this->dao->update($id, ['vip_price' => $proudctVipPrice]);
- $valueGroup = $storeProductAttrServices->saveProductAttr($skuList, $id);
- if (!$valueGroup) throw new AdminException('添加失败!');
- if ($data['product_type'] == 1) {
- $productVirtual->saveProductVirtual($id, $valueGroup);
- }
- return [$skuList, $id, $is_new, $data];
- });
- event('product.create', [$id, $data, $skuList, $is_new, $slider_image, $description, $is_copy, $relationData]);
- }
- /**
- * 放入回收站
- * @param int $id
- * @return string
- */
- public function del(int $id)
- {
- if (!$id) throw new AdminException('参数不正确');
- $productInfo = $this->dao->get($id);
- if (!$productInfo) throw new AdminException('商品数据不存在');
- $msg = '';
- $data = $update = [];
- if ($productInfo['is_del'] == 1) {
- $data['is_del'] = 0;
- $update = ['is_del' => 0];
- $msg = '成功恢复商品';
- } else {
- $data['is_del'] = 1;
- $data['is_show'] = 0;
- $update = ['is_del' => 1];
- $msg = '成功移到回收站';
- }
- $this->transaction(function () use ($id, $data, $productInfo, $update) {
- //门店商品处理
- switch ($productInfo['type']) {
- case 0://平台商品
- $this->dao->update(['pid' => $id], $update);
- break;
- case 1://门店商品
- /** @var SystemStoreServices $storeServices */
- $storeServices = app()->make(SystemStoreServices::class);
- $storeInfo = $storeServices->getStoreInfo((int)$productInfo['relation_id']);
- $data['is_verify'] = 0;
- //门店开启免审
- if (isset($storeInfo['product_verify_status']) && $storeInfo['product_verify_status']) {
- $data['is_verify'] = 1;
- }
- break;
- case 2://供应商
- $data['is_verify'] = 0;
- break;
- }
- $res = $this->dao->update($id, $data);
- if (!$res) throw new AdminException($productInfo['is_del'] == 1 ? '恢复失败,请稍候再试!' : '删除失败,请稍候再试!');
- });
- return $msg;
- }
- /**
- * 获取选择的商品列表
- * @param array $where
- * @param bool $isStock
- * @param int $limit
- * @return array
- */
- public function searchList(array $where, bool $isStock = false, int $limit = 0)
- {
- $store_stock = sys_config('store_stock');
- $where['store_stock'] = $store_stock > 0 ? $store_stock : 2;
- $data = $this->getProductList($where, $isStock, $limit, ['attrValue', 'descriptions']);
- if ($data['list']) {
- $cateIds = implode(',', array_column($data['list'], 'cate_id'));
- /** @var StoreProductCategoryServices $categoryService */
- $categoryService = app()->make(StoreProductCategoryServices::class);
- $cateList = $categoryService->getCateParentAndChildName($cateIds);
- /** @var StoreProductLabelServices $storeProductLabelServices */
- $storeProductLabelServices = app()->make(StoreProductLabelServices::class);
- foreach ($data['list'] as &$item) {
- $item['cate_name'] = '';
- if (isset($item['cate_id']) && $item['cate_id']) {
- $cate_ids = explode(',', $item['cate_id']);
- $cate_name = $categoryService->getCateName($cate_ids, $cateList);
- if ($cate_name) {
- $item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
- }
- }
- $item['give_integral'] = floatval($item['give_integral']);
- $item['price'] = floatval($item['price']);
- $item['vip_price'] = floatval($item['vip_price']);
- $item['ot_price'] = floatval($item['ot_price']);
- $item['postage'] = floatval($item['postage']);
- $item['cost'] = floatval($item['cost']);
- $item['delivery_type'] = is_string($item['delivery_type']) ? explode(',', $item['delivery_type']) : $item['delivery_type'];
- $item['store_label'] = '';
- if ($item['store_label_id']) {
- $storeLabelList = $storeProductLabelServices->getColumn([['relation_id', '=', 0], ['type', '=', 0], ['id', 'IN', $item['store_label_id']]], 'id,label_name');
- $item['store_label'] = $storeLabelList ? implode(',', array_column($storeLabelList, 'label_name')) : '';
- }
- }
- }
- return $data;
- }
- /**
- * 后台获取商品列表展示
- * @param array $where
- * @param bool $isStock
- * @param int $limit
- * @param array $with
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductList(array $where, bool $isStock = true, int $limit = 0, array $with = ['attrValue'])
- {
- $field = ['*'];
- if ($isStock) {
- $prefix = Config::get('database.connections.' . Config::get('database.default') . '.prefix');
- $field = [
- '*',
- '(SELECT count(*) FROM `' . $prefix . 'user_relation` WHERE `relation_id` = `' . $prefix . 'store_product`.`id` AND `type` = \'collect\') as collect',
- '(SELECT count(*) FROM `' . $prefix . 'user_relation` WHERE `relation_id` = `' . $prefix . 'store_product`.`id` AND `type` = \'like\') as likes',
- '(SELECT SUM(stock) FROM `' . $prefix . 'store_product_attr_value` WHERE `product_id` = `' . $prefix . 'store_product`.`id` AND `type` = 0) as stock',
- // '(SELECT SUM(sales) FROM `' . $prefix . 'store_product_attr_value` WHERE `product_id` = `' . $prefix . 'store_product`.`id` AND `type` = 0) as sales',
- '(SELECT count(*) FROM `' . $prefix . 'store_visit` WHERE `product_id` = `' . $prefix . 'store_product`.`id` AND `product_type` = \'product\') as visitor',
- ];
- }
- if ($limit) {
- [$page] = $this->getPageValue();
- } else {
- [$page, $limit] = $this->getPageValue();
- }
- $list = $this->dao->getSearchList($where, $page, $limit, $field, '', $with);
- $count = $this->dao->getCount($where);
- return compact('count', 'list');
- }
- /**
- * 获取商品规格
- * @param int $id
- * @param int $type
- * @return array
- */
- public function getProductRules(int $id, int $type = 0)
- {
- $productInfo = $this->dao->get($id);
- if (!$productInfo) {
- throw new ValidateException('商品不存在');
- }
- $product_type = $productInfo['product_type'] ?? $data['product_type'] ?? 0; //商品类型
- /** @var StoreProductAttrServices $storeProductAttrService */
- $storeProductAttrService = app()->make(StoreProductAttrServices::class);
- /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
- $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
- $productAttr = $storeProductAttrService->getProductAttr(['product_id' => $id, 'type' => 0]);
- if (!$productAttr) return [];
- $attr = [];
- foreach ($productAttr as $key => $value) {
- $attr[$key]['value'] = $value['attr_name'];
- $attr[$key]['detailValue'] = '';
- $attr[$key]['attrHidden'] = true;
- $attr[$key]['detail'] = $value['attr_values'];
- }
- $value = attr_format($attr)[1];
- $valueNew = [];
- $count = 0;
- // $sukValue = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => $type]);
- $sukValue = $sukDefaultValue = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => 0]);
- foreach ($value as $key => $item) {
- $detail = $item['detail'];
- // sort($item['detail'], SORT_STRING);
- $suk = implode(',', $item['detail']);
- if (!isset($sukDefaultValue[$suk])) continue;
- // if (!isset($sukValue[$suk])) {
- // $sukValue[$suk] = $sukDefaultValue[$suk];
- // }
- foreach (array_keys($detail) as $k => $title) {
- $header[$k]['title'] = $title;
- $header[$k]['align'] = 'center';
- $header[$k]['minWidth'] = 80;
- }
- $valueNew[$count]['value'] = '';
- foreach (array_values($detail) as $k => $v) {
- $valueNew[$count]['value' . ($k + 1)] = $v;
- $header[$k]['key'] = 'value' . ($k + 1);
- $valueNew[$count]['value'] .= $valueNew[$count]['value'] == '' ? $v : ',' . $v;
- }
- if ($type == 4) {
- $valueNew[$count]['integral'] = $sukValue[$suk]['integral'] ?? 0;
- $valueNew[$count]['product_id'] = $sukValue[$suk]['product_id'];
- }
- $valueNew[$count]['detail'] = $detail;
- $valueNew[$count]['pic'] = $sukValue[$suk]['pic'];
- $valueNew[$count]['price'] = floatval($sukValue[$suk]['price']);
- if ($type == 2) $valueNew[$count]['min_price'] = 0;
- if ($type == 3) $valueNew[$count]['r_price'] = floatval($sukValue[$suk]['price']);
- if ($type == 0) $valueNew[$count]['p_price'] = floatval($sukValue[$suk]['price']);
- $valueNew[$count]['cost'] = floatval($sukValue[$suk]['cost']);
- $valueNew[$count]['ot_price'] = floatval($sukValue[$suk]['ot_price']);
- $valueNew[$count]['stock'] = intval($sukValue[$suk]['stock']);
- $valueNew[$count]['quota'] = intval($sukValue[$suk]['quota']);
- $valueNew[$count]['bar_code'] = $sukValue[$suk]['bar_code'] ?? '';
- $valueNew[$count]['code'] = $sukValue[$suk]['code'] ?? '';
- $valueNew[$count]['weight'] = $sukValue[$suk]['weight'] ? floatval($sukValue[$suk]['weight']) : 0;
- $valueNew[$count]['volume'] = $sukValue[$suk]['volume'] ? floatval($sukValue[$suk]['volume']) : 0;
- $valueNew[$count]['brokerage'] = $sukValue[$suk]['brokerage'] ? floatval($sukValue[$suk]['brokerage']) : 0;
- $valueNew[$count]['brokerage_two'] = $sukValue[$suk]['brokerage_two'] ? floatval($sukValue[$suk]['brokerage_two']) : 0;
- $count++;
- }
- $header[] = ['title' => '图片', 'slot' => 'pic', 'align' => 'center', 'minWidth' => 120];
- if ($type == 1) {
- $header[] = ['title' => '秒杀价', 'key' => 'price', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '成本价', 'key' => 'cost', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '原价', 'key' => 'ot_price', 'align' => 'center', 'minWidth' => 80];
- } elseif ($type == 2) {
- $header[] = ['title' => '砍价起始金额', 'slot' => 'price', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '砍价最低价', 'slot' => 'min_price', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '成本价', 'key' => 'cost', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '原价', 'key' => 'ot_price', 'align' => 'center', 'minWidth' => 80];
- } elseif ($type == 3) {
- $header[] = ['title' => '拼团价', 'key' => 'price', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '成本价', 'key' => 'cost', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '日常售价', 'key' => 'r_price', 'align' => 'center', 'minWidth' => 80];
- } elseif ($type == 4) {
- $header[] = ['title' => '兑换积分', 'key' => 'integral', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '金额', 'key' => 'price', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- } else {
- $header[] = ['title' => '成本价', 'key' => 'cost', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '原价', 'key' => 'ot_price', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '售价', 'key' => 'p_price', 'align' => 'center', 'minWidth' => 80];
- }
- $header[] = ['title' => '库存', 'key' => 'stock', 'align' => 'center', 'minWidth' => 80];
- if ($type == 2) {
- $header[] = ['title' => '限量', 'slot' => 'quota', 'align' => 'center', 'minWidth' => 80];
- } else if ($type == 4) {
- $header[] = ['title' => '兑换次数', 'key' => 'quota', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- } else {
- $header[] = ['title' => '限量', 'key' => 'quota', 'type' => 1, 'align' => 'center', 'minWidth' => 80];
- }
- $header[] = ['title' => '重量(KG)', 'key' => 'weight', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '体积(m³)', 'key' => 'volume', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '商品条形码', 'key' => 'bar_code', 'align' => 'center', 'minWidth' => 80];
- $header[] = ['title' => '商品编码', 'key' => 'code', 'align' => 'center', 'minWidth' => 80];
- return ['items' => $attr, 'attrs' => $valueNew, 'header' => $header, 'product_type' => $product_type];
- }
- /**
- * 检查商品是否有活动
- * @param $id
- * @return bool
- */
- public function checkActivity($id = 0)
- {
- if ($id) {
- /** @var StoreSeckillServices $storeSeckillService */
- $storeSeckillService = app()->make(StoreSeckillServices::class);
- /** @var StoreBargainServices $storeBargainService */
- $storeBargainService = app()->make(StoreBargainServices::class);
- /** @var StoreCombinationServices $storeCombinationService */
- $storeCombinationService = app()->make(StoreCombinationServices::class);
- $res1 = $storeSeckillService->count(['product_id' => $id, 'is_del' => 0, 'status' => 1, 'seckill_time' => 1]);
- $res2 = $storeBargainService->count(['product_id' => $id, 'is_del' => 0, 'status' => 1, 'bargain_time' => 1]);
- $res3 = $storeCombinationService->count(['product_id' => $id, 'is_del' => 0, 'is_show' => 1, 'pinkIngTime' => 1]);
- if ($res1 || $res2 || $res3) throw new AdminException('商品有活动开启,无法进行此操作');
- }
- return true;
- }
- /**
- * 获取临时缓存商品数据
- * @param int $id
- * @return false|mixed|string|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- * @author 等风来
- * @email 136327134@qq.com
- * @date 2022/11/3
- */
- public function getCacheProductInfo(int $id)
- {
- $storeInfo = $this->dao->cacheTag()->remember((string)$id, function () use ($id) {
- $storeInfo = $this->dao->getOne(['id' => $id], '*', ['descriptions']);
- if (!$storeInfo) {
- throw new ValidateException('商品不存在');
- } else {
- $storeInfo = $storeInfo->toArray();
- }
- return $storeInfo;
- }, 600);
- return $storeInfo;
- }
- /**
- * 保存
- * @param array $data
- * @return mixed
- */
- public function create(array $data)
- {
- return $this->dao->save($data);
- }
- /**
- * 前台获取商品列表
- * @param array $where
- * @param int $uid
- * @param int $promotions_type
- * @return array|array[]
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getGoodsList(array $where, int $uid, int $promotions_type = 0)
- {
- $where['is_verify'] = 1;
- $where['is_show'] = 1;
- $where['is_del'] = 0;
- $collate_code_id = 0;
- if (isset($where['collate_code_id'])) {
- $collate_code_id = $where['collate_code_id'];
- }
- if (isset($where['store_name']) && $where['store_name']) {
- /** @var UserSearchServices $userSearchServices */
- $userSearchServices = app()->make(UserSearchServices::class);
- $searchIds = $userSearchServices->vicSearch($uid, $where['store_name'], $where);
- if ($searchIds) {//之前查询结果记录
- $where['ids'] = $searchIds;
- unset($where['store_name']);
- }
- }
- //优惠活动凑单
- if (isset($where['promotions_id']) && $where['promotions_id']) {
- /** @var StorePromotionsServices $storePromotionsServices */
- $storePromotionsServices = app()->make(StorePromotionsServices::class);
- $promotionsWhere = $storePromotionsServices->collectOrderProduct((int)$where['promotions_id']);
- $where = array_merge($where, $promotionsWhere);
- }
- unset($where['promotions_id']);
- if (isset($where['productId']) && $where['productId'] !== '') {
- $where['ids'] = explode(',', $where['productId']);
- $where['ids'] = array_unique(array_map('intval', $where['ids']));
- unset($where['productId']);
- }
- $where['star'] = 1;
- $where['is_vip_product'] = 0;
- $discount = 100;
- $level_name = '';
- if (!$promotions_type && $uid) {
- /** @var UserServices $user */
- $user = app()->make(UserServices::class);
- $userInfo = $user->getUserCacheInfo($uid);
- $is_vip = $userInfo['is_money_level'] ?? 0;
- $where['is_vip_product'] = $is_vip ? -1 : 0;
- //用户等级是否开启
- /** @var SystemUserLevelServices $systemLevel */
- $systemLevel = app()->make(SystemUserLevelServices::class);
- $levelInfo = $systemLevel->getLevelCache((int)($userInfo['level'] ?? 0));
- if (sys_config('member_func_status', 1) && $levelInfo) {
- $discount = $levelInfo['discount'] ?? 100;
- }
- $level_name = $levelInfo['name'] ?? '';
- }
- [$page, $limit] = $this->getPageValue();
- $field = ['id,relation_id,type,pid,delivery_type,product_type,store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(ficti, 0) as sales,price,stock,activity,ot_price,spec_type,recommend_image,unit_name,is_vip,vip_price,is_presale_product,is_vip_product,system_form_id,is_presale_product,presale_start_time,presale_end_time,is_limit,limit_num,video_open,video_link'];
- $list = $this->dao->getSearchList($where, $page, $limit, $field, '', ['couponId']);
- var_dump(StoreProduct::getLastSql());
- if ($list) {
- /** @var MemberCardServices $memberCardService */
- $memberCardService = app()->make(MemberCardServices::class);
- $vipStatus = $memberCardService->isOpenMemberCardCache('vip_price') && sys_config('svip_price_status', 1);
- /** @var SystemFormServices $systemFormServices */
- $systemFormServices = app()->make(SystemFormServices::class);
- $systemForms = $systemFormServices->getColumn([['id', 'in', array_unique(array_column($list, 'system_form_id'))], ['is_del', '=', 0]], 'id,value', 'id');
- foreach ($list as &$item) {
- $minData = $this->getMinPrice($uid, $item, $discount);
- $item['price_type'] = $minData['price_type'] ?? '';
- $item['level_name'] = $level_name;
- $item['vip_price'] = $minData['vip_price'] ?? 0;
- if ($item['price_type'] == 'member' && (!$item['is_vip'] || !$vipStatus)) {
- $item['vip_price'] = 0;
- }
- $custom_form = $systemForms[$item['system_form_id']]['value'] ?? [];
- $item['custom_form'] = is_string($custom_form) ? json_decode($custom_form, true) : $custom_form;
- $item['cart_button'] = $item['product_type'] > 0 || $item['is_presale_product'] || $item['system_form_id'] ? 0 : 1;
- if (isset($item['star']) && count($item['star'])) {
- $item['star'] = bcdiv((string)array_sum(array_column($item['star'], 'product_score')), (string)count($item['star']), 1);
- } else {
- $item['star'] = config('admin.product_default_star');
- }
- $item['presale_pay_status'] = $this->checkPresaleProductPay((int)$item['id'], $item);
- if (!$item['video_open']) {
- $item['video_link'] = '';
- }
- }
- $list = $this->getActivityList($list);
- $list = $this->getProduceOtherList($list, $uid, isset($where['status']) && !!$where['status'], $collate_code_id);
- $list = $this->getProductPromotions($list, $promotions_type ? [$promotions_type] : []);
- }
- return $list;
- }
- /**
- * 搜索获取商品品牌列表
- * @param array $where
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getBrandList(array $where)
- {
- $where['status'] = 1;
- /** @var StoreProductCategoryBrandServices $productCategoryBrandServices */
- $productCategoryBrandServices = app()->make(StoreProductCategoryBrandServices::class);
- return $productCategoryBrandServices->getList($where, 'distinct(`brand_id`) as id, brand_name');
- }
- /**
- * 获取商品所在优惠活动
- * @param array $list
- * @param array $promotions_type
- * @return array|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductPromotions(array $list, array $promotions_type = [])
- {
- if (!$list) {
- return $list;
- }
- $productIds = array_column($list, 'id');
- /** @var StorePromotionsServices $storePromotionsServices */
- $storePromotionsServices = app()->make(StorePromotionsServices::class);
- $with = ['products' => function ($query) {
- $query->field('promotions_id,product_id,is_all,unique');
- }];
- $field = 'id,promotions_type,name,desc,image,promotions_type,title,product_id,product_partake_type,discount,discount_type,start_time,stop_time,applicable_type,applicable_store_id';
- [$promotionsArr, $productDetails, $promotionsDetail] = $storePromotionsServices->getProductsPromotionsDetail($productIds, $field, $with, $promotions_type);
- $promotionsArr = array_combine(array_column($promotionsArr, 'id'), $promotionsArr);
- foreach ($list as &$item) {
- $item['product_id'] = $item['id'];
- $item['promotions'] = $item['activity_frame'] = $item['activity_background'] = [];
- if ($item['type'] == 1) {//门店商品
- if (isset($item['pid']) && $item['pid']) {//平台共享到门店商品
- $id = $item['pid'];
- } else {//门店独立商品
- continue;
- }
- } else {
- $id = $item['id'];
- }
- $item['promotions'] = $item['activity_frame'] = $item['activity_background'] = [];
- $promotionsIds = $productDetails[$id] ?? [];
- if ($promotionsIds) {
- foreach ($promotionsIds as $id) {
- $promotions = $promotionsArr[$id] ?? [];
- switch ($promotions['promotions_type']) {
- case 1:
- case 2:
- case 3:
- case 4:
- if (!$promotions_type) {//无指定优惠类型
- if ($item['promotions']) {
- if (($promotions['promotions_type'] ?? 0) <= ($item['promotions']['promotions_type'] ?? 0)) {
- if (($promotions['promotions_type']['discount'] ?? 0) > ($item['promotions']['discount'] ?? 0)) {
- $item['promotions'] = $promotions;
- }
- } else {
- break;
- }
- } else {
- $item['promotions'] = $promotions;
- }
- } else {
- if (!$item['promotions']) {
- $item['promotions'] = $promotions;
- } else {//同类活动展示最新的一个
- break;
- }
- break;
- }
- break;
- case 5://边框
- if (!$item['activity_frame']) {
- $item['activity_frame'] = [
- 'id' => $promotions['id'],
- 'name' => $promotions['name'],
- 'image' => $promotions['image'],
- ];
- } else {//同类活动展示最新的一个
- break;
- }
- break;
- case 6://背景
- if (!$item['activity_background']) {
- $item['activity_background'] = [
- 'id' => $promotions['id'],
- 'name' => $promotions['name'],
- 'image' => $promotions['image'],
- ];
- } else {//同类活动展示最新的一个
- break;
- }
- break;
- default:
- break;
- }
- }
- }
- }
- return $list;
- }
- /**
- * 获取某些模板所需得购物车数量
- * @param array $list
- * @param int $uid
- * @param bool $type
- * @return array
- */
- public function getProduceOtherList(array $list, int $uid, bool $type = true, int $collate_code_id = 0)
- {
- if (!$type || !$list) {
- return $list;
- }
- $productIds = array_column($list, 'id');
- if ($productIds) {
- /** @var StoreProductAttrValueServices $services */
- $services = app()->make(StoreProductAttrValueServices::class);
- $attList = $services->getSkuArray([
- 'product_id' => $productIds,
- 'type' => 0
- ], 'count(*)', 'product_id');
- $store_id = (int)$this->getItem('store_id', 0);
- $staff_id = (int)$this->getItem('staff_id', 0);
- $tourist_uid = (int)$this->getItem('tourist_uid', 0);
- if ($uid || $tourist_uid) {
- if ($collate_code_id) {
- /** @var UserCollagePartakeServices $cartServices */
- $cartServices = app()->make(UserCollagePartakeServices::class);
- $cartNumList = $cartServices->productIdByCartNum($productIds, $uid, $store_id, $collate_code_id);
- } else {
- /** @var StoreCartServices $cartServices */
- $cartServices = app()->make(StoreCartServices::class);
- $cartNumList = $cartServices->productIdByCartNum($productIds, $uid, $staff_id, $tourist_uid, $store_id);
- }
- $data = [];
- foreach ($cartNumList as $item) {
- $data[$item['product_id']][] = $item['cart_num'];
- }
- $newNumList = [];
- foreach ($data as $key => $item) {
- $newNumList[$key] = array_sum($item);
- }
- $cartNumList = $newNumList;
- } else {
- $cartNumList = [];
- }
- foreach ($list as &$item) {
- if (isset($item['spec_type']) && $item['spec_type']) {
- $item['is_att'] = isset($attList[$item['id']]) && $attList[$item['id']];
- } else {
- $item['is_att'] = false;
- }
- $item['cart_num'] = $cartNumList[$item['id']] ?? 0;
- }
- }
- return $list;
- }
- /**
- * 获取商品活动标签
- * @param array $list
- * @param bool $status
- * @return array|array[]|mixed
- */
- public function getActivityList(array $list, bool $status = true)
- {
- if (!$list) return [];
- if (!$status) {//一维数组
- $list = [$list];
- }
- $productIds = [];
- //处理平台共享到门店、门店独立商品活动
- foreach ($list as $product) {
- if (isset($product['type']) && isset($product['pid'])) {
- if ($product['type'] == 1) {//门店商品
- if ($product['pid']) {//平台共享到门店商品
- $productIds[] = $product['pid'];
- } else {//门店独立商品
- }
- } else {
- $productIds[] = $product['id'];
- }
- }
- }
- if ($productIds) {
- /** @var StoreSeckillServices $storeSeckillService */
- $storeSeckillService = app()->make(StoreSeckillServices::class);
- /** @var StoreBargainServices $storeBargainServices */
- $storeBargainServices = app()->make(StoreBargainServices::class);
- /** @var StoreCombinationServices $storeCombinationServices */
- $storeCombinationServices = app()->make(StoreCombinationServices::class);
- $seckillIdsList = $storeSeckillService->getSeckillIdsArrayCache($productIds);
- $pinkIdsList = $storeCombinationServices->getPinkIdsArrayCache($productIds);
- $bargrainIdsList = $storeBargainServices->getBargainIdsArrayCache($productIds);
- foreach ($list as &$item) {
- if ($item['type'] == 1) {//门店商品
- if ($item['pid']) {//平台共享到门店商品
- $id = $item['pid'];
- } else {//门店独立商品
- continue;
- }
- } else {
- $id = $item['id'];
- }
- $seckillId = $seckillIdsList && is_array($seckillIdsList) ? array_filter($seckillIdsList, function ($val) use ($item, $id) {
- if ($val['product_id'] === $id) {
- return $val;
- }
- }) : [];
- $item['activity'] = $this->activity($item['activity'],
- $item['id'],
- $pinkIdsList[$id] ?? 0,
- $seckillId,
- $bargrainIdsList[$id] ?? 0,
- $status);
- if (isset($item['couponId'])) {
- $item['checkCoupon'] = (bool)count($item['couponId']);
- unset($item['couponId']);
- } else {
- $item['checkCoupon'] = false;
- }
- }
- }
- if ($status) {
- return $list;
- } else {
- return $list[0]['activity'];
- }
- }
- /**
- * 获取商品在此时段活动优先类型
- * @param string $activity
- * @param int $id
- * @param int $combinationId
- * @param array $seckillId
- * @param int $bargainId
- * @param bool $status
- * @return array
- */
- public function activity(string $activity, int $id, int $combinationId, array $seckillId, int $bargainId, bool $status = true)
- {
- if (!$activity) {
- $activity = '0,1,2,3';//如果老商品没有活动顺序,默认活动顺序,秒杀-砍价-拼团
- }
- $activity = explode(',', $activity);
- if ($activity[0] == 0 && $status) return [];
- $activityId = [];
- $time = 0;
- if ($seckillId) {
- /** @var StoreSeckillTimeServices $storeSeckillTimeServices */
- $storeSeckillTimeServices = app()->make(StoreSeckillTimeServices::class);
- $timeList = $storeSeckillTimeServices->time_list();
- if ($timeList) {
- $timeList = array_combine(array_column($timeList, 'id'), $timeList);
- $today = date('Y-m-d');
- $currentHour = date('Hi');
- foreach ($seckillId as $v) {
- $time_ids = is_string($v['time_id']) ? explode(',', $v['time_id']) : $v['time_id'];
- if ($time_ids) {
- foreach ($time_ids as $time_id) {
- $timeInfo = $timeList[$time_id] ?? [];
- if ($timeInfo) {
- $start = str_replace(':', '', $timeInfo['start_time']);
- $end = str_replace(':', '', $timeInfo['end_time']);
- if ($currentHour >= $start && $currentHour < $end) {
- $activityId[1] = $v['id'];
- $time = strtotime($today . ' ' . $timeInfo['end_time']);
- break;
- }
- }
- }
- }
- }
- }
- }
- if ($bargainId) $activityId[2] = $bargainId;
- if ($combinationId) $activityId[3] = $combinationId;
- $data = [];
- foreach ($activity as $k => $v) {
- if (array_key_exists($v, $activityId)) {
- if ($status) {
- $data['type'] = $v;
- $data['id'] = $activityId[$v];
- if ($v == 1) $data['time'] = $time;
- break;
- } else {
- if ($v != 0) {
- $arr['type'] = $v;
- $arr['id'] = $activityId[$v];
- if ($v == 1) $arr['time'] = $time;
- $data[] = $arr;
- }
- }
- }
- }
- return $data;
- }
- /**
- * 获取热门商品
- * @param array $where
- * @param string $order
- * @return array|array[]
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProducts(array $where, string $order = '', int $num = 0, array $with = ['couponId', 'descriptions'])
- {
- [$page, $limit] = $this->getPageValue();
- if ($num) {
- $page = 1;
- $limit = $num;
- }
- $list = $this->dao->getSearchList($where, $page, $limit, ['id,pid,type,store_name,cate_id,image,IFNULL(sales, 0) + IFNULL(ficti, 0) as sales,price,stock,activity,unit_name'], $order, $with);
- $list = $this->getActivityList($list);
- $list = $this->getProductPromotions($list);
- return $list;
- }
- /**
- * 检测预售商品是否可以购买
- * @param int $id
- * @param array $productInfo
- * @return int
- */
- public function checkPresaleProductPay(int $id, array $productInfo = [])
- {
- if (!$id) return 0;
- if (!$productInfo) {
- $productInfo = $this->getCacheProductInfo($id);
- if (!$productInfo) {
- return 0;
- }
- }
- if (!isset($productInfo['is_presale_product']) || !isset($productInfo['presale_start_time']) || !isset($productInfo['presale_end_time'])) {
- return 0;
- }
- if ($productInfo['is_presale_product']) {
- if ($productInfo['presale_start_time'] > time()) {
- return 1;
- } elseif ($productInfo['presale_start_time'] <= time() && $productInfo['presale_start_time'] > time()) {
- return 2;
- } elseif ($productInfo['presale_end_time'] < time()) {
- return 3;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
- }
- /**
- * 获取商品详情
- * @param int $uid
- * @param int $id
- * @param int $type
- * @param int $promotions_type
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \throwable
- */
- public function productDetail(int $uid, int $id, int $type = 0, int $promotions_type = 0)
- {
- $data['uid'] = $uid;
- $storeInfo = $this->getCacheProductInfo($id);
- if (!$storeInfo) {
- throw new ValidateException('商品不存在');
- }
- $storeInfo['description'] = $storeInfo['description'] ?: '';
- /** @var DiyServices $diyServices */
- $diyServices = app()->make(DiyServices::class);
- $infoDiy = $diyServices->getProductDetailDiy();
- //diy控制参数
- if (!isset($infoDiy['is_specs']) || !$infoDiy['is_specs']) {
- $storeInfo['specs'] = [];
- }
- $storeInfo['brand_name'] = $this->productIdByBrandName((int)$storeInfo['id'], $storeInfo);
- $storeInfo['store_label'] = $storeInfo['ensure'] = [];
- if ($storeInfo['store_label_id']) {
- /** @var StoreProductLabelServices $storeProductLabelServices */
- $storeProductLabelServices = app()->make(StoreProductLabelServices::class);
- $storeInfo['store_label'] = $storeProductLabelServices->getLabelCache($storeInfo['store_label_id'], ['id', 'label_name']);
- }
- if ($storeInfo['ensure_id'] && isset($infoDiy['is_ensure']) && $infoDiy['is_ensure']) {
- /** @var StoreProductEnsureServices $storeProductEnsureServices */
- $storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
- $storeInfo['ensure'] = $storeProductEnsureServices->getEnsurCache($storeInfo['ensure_id'], ['id', 'name', 'image', 'desc']);
- }
- $discount = isset($storeInfo['promotions'][0]['promotions_type']) && $storeInfo['promotions'][0]['promotions_type'] == 1 ? $storeInfo['promotions'][0]['discount'] : -1;
- $configData = SystemConfigService::more(['site_url', 'tengxun_map_key', 'store_self_mention', 'routine_contact_type', 'site_name', 'share_qrcode', 'store_func_status', 'product_poster_title']);
- $siteUrl = $configData['site_url'] ?? '';
- if ($storeInfo['video_open']) {
- if ($storeInfo['video_link'] && strpos($storeInfo['video_link'], 'http') === false) {
- $storeInfo['video_link'] = $siteUrl . $storeInfo['video_link'];
- }
- } else {
- $storeInfo['video_link'] = '';
- }
- $storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
- $storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
- $storeInfo['fsales'] = $storeInfo['ficti'] + $storeInfo['sales'];
- // /** @var QrcodeServices $qrcodeService */
- // $qrcodeService = app()->make(QrcodeServices::class);
- // $storeInfo['code_base'] = $qrcodeService->getWechatQrcodePath($id . '_product_detail_wap.jpg', '/pages/goods_details/index?id=' . $id);
- /** @var UserRelationServices $userRelationServices */
- $userRelationServices = app()->make(UserRelationServices::class);
- $storeInfo['userCollect'] = $userRelationServices->isProductRelationCache(['uid' => $uid, 'relation_id' => $id, 'type' => 'collect', 'category' => UserRelationServices::CATEGORY_PRODUCT]);
- $storeInfo['userLike'] = 0;
- //预售相关
- $storeInfo['presale_pay_status'] = $this->checkPresaleProductPay($id, $storeInfo);
- $storeInfo['presale_start_time'] = $storeInfo['presale_start_time'] ? date('Y-m-d H:i', $storeInfo['presale_start_time']) : '';
- $storeInfo['presale_end_time'] = $storeInfo['presale_end_time'] ? date('Y-m-d H:i', $storeInfo['presale_end_time']) : '';
- //系统表单
- $storeInfo['custom_form'] = [];
- if ($storeInfo['system_form_id']) {
- /** @var SystemFormServices $systemFormServices */
- $systemFormServices = app()->make(SystemFormServices::class);
- $systemForm = $systemFormServices->value(['id' => $storeInfo['system_form_id']], 'value');
- if ($systemForm) {
- $storeInfo['custom_form'] = is_string($systemForm) ? json_decode($systemForm, true) : $systemForm;
- }
- }
- //有自定义表单或预售或虚拟不展示加入购物车按钮
- $storeInfo['cart_button'] = $storeInfo['custom_form'] || $storeInfo['is_presale_product'] || $storeInfo['product_type'] > 0 ? 0 : 1;
- /** @var StoreProductAttrServices $storeProductAttrServices */
- $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
- [$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetailCache($id, $uid, $type, 0, 0, $storeInfo, $discount);
- //无属性添加默认属性
- if (empty($productValue)) {
- $attr = [
- [
- 'value' => '规格',
- 'detailValue' => '',
- 'attrHidden' => '',
- 'detail' => ['默认']
- ]
- ];
- $detail[0] = [
- 'value1' => '默认',
- 'detail' => ['规格' => '默认'],
- 'pic' => $storeInfo['image'],
- 'price' => $storeInfo['price'],
- 'cost' => $storeInfo['cost'],
- 'ot_price' => $storeInfo['ot_price'],
- 'stock' => $storeInfo['stock'],
- 'bar_code' => '',
- 'code' => '',
- 'weight' => 0,
- 'volume' => 0,
- 'brokerage' => 0,
- 'brokerage_two' => 0,
- ];
- $skuList = $storeProductAttrServices->validateProductAttr($attr, $detail, $id);
- $storeProductAttrServices->saveProductAttr($skuList, $id, 0);
- }
- $attrValue = $productValue;
- if (!$storeInfo['spec_type']) {
- $productAttr = [];
- $productValue = [];
- }
- $data['productAttr'] = $productAttr;
- $data['productValue'] = $productValue;
- $storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
- /**
- * 判断配送方式
- */
- $storeInfo['delivery_type'] = $this->getDeliveryType((int)$storeInfo['id'], (int)$storeInfo['type'], (int)$storeInfo['relation_id'], $storeInfo['delivery_type']);
- $data['storeInfo'] = $storeInfo;
- /** @var MemberCardServices $memberCardService */
- $memberCardService = app()->make(MemberCardServices::class);
- $vipStatus = $memberCardService->isOpenMemberCardCache('vip_price') && sys_config('svip_price_status', 1);
- $price_count = count($infoDiy['price_type']);
- if ($price_count >= 1) {
- //两个都选 取最低的
- $minPrice = $this->getMinPrice($uid, $data['storeInfo'], null, count($infoDiy['price_type']) == 2);
- $price_count = count($infoDiy['price_type']);
- if ($price_count == 1) {//
- if (in_array(1, $infoDiy['price_type'])) {//svip
- $minPrice['price_type'] = 'member';
- } else {//用户等级
- $minPrice['price_type'] = 'level';
- $minPrice['vip_price'] = $minPrice['level_price'];
- }
- }
- } else {//一个都不展示
- $minPrice = ['vip_price' => 0, 'price_type' => '', 'level_name' => ''];
- }
- $data['storeInfo'] = array_merge($data['storeInfo'], $minPrice);
- if ($data['storeInfo']['price_type'] == 'member' && (!$data['storeInfo']['is_vip'] || !$vipStatus)) {
- $data['storeInfo']['vip_price'] = 0;
- }
- $data['priceName'] = 0;
- if ($uid) {
- $data['priceName'] = $this->getPacketPrice($storeInfo, $attrValue, $uid);
- }
- $data['reply'] = [];
- $data['replyChance'] = $data['replyCount'] = 0;
- if (isset($infoDiy['is_reply']) && $infoDiy['is_reply']) {
- /** @var StoreProductReplyServices $storeProductReplyService */
- $storeProductReplyService = app()->make(StoreProductReplyServices::class);
- $reply = $storeProductReplyService->getRecProductReplyCache($id, (int)($infoDiy['reply_num'] ?? 1));
- $data['reply'] = $reply ? get_thumb_water($reply, 'small', ['pics']) : [];
- [$replyCount, $goodReply, $replyChance] = $storeProductReplyService->getProductReplyData($id);
- $data['replyChance'] = $replyChance;
- $data['replyCount'] = $replyCount;
- }
- $data['mer_id'] = 0;
- $data['mapKey'] = $configData['tengxun_map_key'] ?? '';
- $data['store_func_status'] = (int)($configData['store_func_status'] ?? 1);//门店是否开启
- $data['store_self_mention'] = $data['store_func_status'] ? (int)($configData['store_self_mention'] ?? 1) : 0;//门店自提是否开启
- $data['routine_contact_type'] = $configData['routine_contact_type'] ?? 0;
- $data['site_name'] = $configData['site_name'] ?? '';
- $data['share_qrcode'] = $configData['share_qrcode'] ?? 0;
- $data['product_poster_title'] = $configData['product_poster_title'] ?? '';
- $data['is_store_buy'] = 0;
- $count = 0;
- //平台商品 && 支持门店(配送|自提)&& 适用门店(全部|部分)
- if ($storeInfo['type'] == 0 && array_intersect([2, 3], $storeInfo['delivery_type']) && in_array($storeInfo['applicable_type'], [1, 2])) {
- $where = ['is_del' => 0, 'is_show' => 1, 'is_verify' => 1, 'type' => 1];
- if ($storeInfo['applicable_type'] == 2) {
- $applicable_store_id = is_string($storeInfo['applicable_store_id']) ? explode(',', $storeInfo['applicable_store_id']) : $storeInfo['applicable_store_id'];
- if ($applicable_store_id) {//门店商品正常
- $where['relation_id'] = $applicable_store_id;
- $count = $this->dao->count($where);
- }
- } else {
- $count = $this->dao->count($where);
- }
- }
- if (!$storeInfo['stock'] && $count) {//平台无库存,支持门店购买
- $data['is_store_buy'] = 1;
- }
- //浏览记录
- ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $id], 'product']);
- return $data;
- }
- /**
- * 是否开启vip
- * @param bool $vip
- * @return bool
- */
- public function vipIsOpen(bool $vip = false, $vipStatus = -1)
- {
- if (!$vip) {
- return false;
- }
- $member_status = sys_config('member_card_status', 1);
- if (!$member_status) {
- return false;
- }
- if ($vipStatus == -1) {
- /** @var MemberCardServices $memberCardService */
- $memberCardService = app()->make(MemberCardServices::class);
- $vipStatus = $memberCardService->isOpenMemberCardCache('vip_price', false, $member_status);
- }
- return $vipStatus && $member_status && $vip && sys_config('svip_price_status', 1);
- }
- /**
- * 获取商品分销佣金最低和最高
- * @param $storeInfo
- * @param $productValue
- * @param int $uid
- * @return int|string
- */
- public function getPacketPrice($storeInfo, $productValue, int $uid)
- {
- if (!count($productValue)) {
- return 0;
- }
- /** @var UserServices $userServices */
- $userServices = app()->make(UserServices::class);
- if (!$userServices->checkUserPromoter($uid)) {
- return 0;
- }
- if (isset($storeInfo['is_sub']) && $storeInfo['is_sub'] == 1) {
- $maxPrice = (float)max(array_column($productValue, 'brokerage'));
- $minPrice = (float)min(array_column($productValue, 'brokerage'));
- } else {
- $maxPrice = max(array_column($productValue, 'price'));
- $minPrice = min(array_column($productValue, 'price'));
- $store_brokerage_ratio = sys_config('store_brokerage_ratio');
- $store_brokerage_ratio = (string)bcdiv((string)$store_brokerage_ratio, '100', 2);
- $maxPrice = (float)bcmul($store_brokerage_ratio, (string)$maxPrice, 2);
- $minPrice = (float)bcmul($store_brokerage_ratio, (string)$minPrice, 2);
- //大于1 取整(两位小数前端展示超出)
- $maxPrice = $maxPrice > 1 ? floor($maxPrice) : $maxPrice;
- $minPrice = $minPrice > 1 ? floor($minPrice) : $minPrice;
- }
- if ($minPrice == 0 && $maxPrice == 0) {
- $priceName = 0;
- } else if ($minPrice == 0 && $maxPrice)
- $priceName = $maxPrice;
- else if ($maxPrice == 0 && $minPrice)
- $priceName = $minPrice;
- else if ($maxPrice == $minPrice && $minPrice)
- $priceName = $maxPrice;
- else
- $priceName = $minPrice . '~' . $maxPrice;
- return strlen(trim($priceName)) ? $priceName : 0;
- }
- /**
- * 获取商品用户等级、svip最低价格,优惠类型
- * @param int $uid
- * @param $productInfo
- * @param $discount
- * @param bool $is_min
- * @return array
- */
- public function getMinPrice(int $uid, $productInfo, $discount = null, $is_min = true)
- {
- $level_name = '';
- $vip_price = 0;
- $price_type = '';
- $level_price = 0;
- if ($productInfo && !($productInfo['type'] == 1 && $productInfo['pid'] == 0)) {
- if (is_null($discount)) {
- $discount = 100;
- if ($uid) {
- /** @var UserServices $user */
- $user = app()->make(UserServices::class);
- $userInfo = $user->getUserCacheInfo($uid);
- //用户等级是否开启
- /** @var SystemUserLevelServices $systemLevel */
- $systemLevel = app()->make(SystemUserLevelServices::class);
- $levelInfo = $systemLevel->getLevelCache((int)($userInfo['level'] ?? 0));
- if (sys_config('member_func_status', 1) && $levelInfo) {
- $discount = $levelInfo['discount'] ?? 100;
- }
- $level_name = $levelInfo['name'] ?? '';
- }
- }
- if ($discount >= 0 && $discount < 100) {//等级价格
- $level_price = (float)bcmul((string)bcdiv((string)$discount, '100', 2), (string)$productInfo['price'], 2);
- } else {
- $level_price = $productInfo['price'];
- }
- if ($productInfo['is_vip']) {//svip价格
- $vip_price = $productInfo['vip_price'];
- }
- if (($discount != 100 || $productInfo['is_vip']) && $is_min) {//需要对比价格
- if ($discount != 100 && $productInfo['is_vip']) {
- if ($level_price < $productInfo['vip_price']) {
- $price_type = 'level';
- $vip_price = $level_price;
- } else {
- $price_type = 'member';
- $vip_price = $productInfo['vip_price'];
- }
- } else if ($discount != 100 && !$productInfo['is_vip']) {
- $price_type = 'level';
- $vip_price = $level_price;
- } else if ($discount == 100 && $productInfo['is_vip']) {
- $price_type = 'member';
- $vip_price = $productInfo['vip_price'];
- }
- }
- }
- return compact('level_name', 'vip_price', 'price_type', 'level_price');
- }
- /**
- * 计算商品优惠后金额、优惠价格
- * @param $price
- * @param int $uid
- * @param $userInfo
- * @param $vipStatus
- * @param int $discount
- * @param float $vipPrice
- * @param int $is_vip
- * @param false $is_show
- * @return array [优惠后的总金额,优惠金额]
- */
- public function setLevelPrice($price, int $uid, $userInfo, $vipStatus, $discount = 0, $vipPrice = 0.00, $is_vip = 0, $is_show = false)
- {
- if (!(float)$price) return [(float)$price, (float)$price, ''];
- if (!$vipStatus) $is_vip = 0;
- //已登录
- if ($uid) {
- if (!$userInfo) {
- /** @var UserServices $user */
- $user = app()->make(UserServices::class);
- $userInfo = $user->getUserCacheInfo($uid);
- }
- if ($discount === 0) {
- /** @var SystemUserLevelServices $systemLevel */
- $systemLevel = app()->make(SystemUserLevelServices::class);
- $discount = $systemLevel->getDiscount($uid, (int)$userInfo['level']);
- }
- } else {
- //没登录
- $discount = 100;
- }
- $discount = bcdiv((string)$discount, '100', 2);
- //执行减去会员优惠金额
- [$truePrice, $vip_truePrice, $type] = $this->isPayLevelPrice($uid, $userInfo, $vipStatus, $price, $discount, $vipPrice, $is_vip, $is_show);
- //返回优惠后的总金额
- $truePrice = $truePrice < 0.01 ? 0.01 : $truePrice;
- //优惠的金额
- $vip_truePrice = $vip_truePrice == $price ? bcsub((string)$vip_truePrice, '0.01', 2) : $vip_truePrice;
- return [(float)$truePrice, (float)$vip_truePrice, $type];
- }
- /**
- * 获取会员价格(付费会员价格和购买商品会员价格)
- * @param int $uid
- * @param $userInfo
- * @param $vipStatus
- * @param $price
- * @param string $discount
- * @param float $payVipPrice
- * @param int $is_vip
- * @param false $is_show
- * @return array
- */
- public function isPayLevelPrice(int $uid, $userInfo, $vipStatus, $price, string $discount, $payVipPrice = 0.00, $is_vip = 0, $is_show = false)
- {
- //is_vip == 0表示会员价格不启用,展示为零
- if ($is_vip == 0) $payVipPrice = 0;
- if (!$userInfo && $uid) {
- //检测用户是否是付费会员
- /** @var UserServices $userService */
- $userService = app()->make(UserServices::class);
- $userInfo = $userService->getUserCacheInfo($uid);
- }
- $noPayVipPrice = ($discount && $discount != 0.00) ? bcmul((string)$discount, (string)$price, 2) : $price;
- if ($payVipPrice < $noPayVipPrice && $payVipPrice > 0) {
- $vipPrice = $payVipPrice;
- $type = 'member';
- } else {
- $vipPrice = $noPayVipPrice;
- $type = 'level';
- }
- //如果$isSingle==true 返回优惠后的总金额,否则返回优惠的金额
- if ($vipStatus && $is_vip == 1) {
- //$is_show == false 是计算支付价格,true是展示
- if (!$is_show) {
- return [$vipPrice, bcsub((string)$price, (string)$vipPrice, 2), $type];
- } else {
- if ($userInfo && isset($userInfo['is_money_level']) && $userInfo['is_money_level'] > 0) {
- return [$vipPrice, bcsub((string)$price, (string)$vipPrice, 2), $type];
- } else {
- $type = 'level';
- return [$noPayVipPrice, bcsub((string)$price, (string)$noPayVipPrice, 2), $type];
- }
- }
- } else {
- $type = 'level';
- return [(float)$noPayVipPrice, (float)bcsub((string)$price, (string)$noPayVipPrice, 2), $type];
- }
- }
- /**
- * 商品列表
- * @param array $where
- * @param $limit
- * @param $field
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductLimit(array $where, $limit, $field)
- {
- return $this->dao->getProductLimit($where, $limit, $field);
- }
- /**
- * 通过条件获取商品列表
- * @param $where
- * @param $field
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductListByWhere($where, $field)
- {
- return $this->dao->getProductListByWhere($where, $field);
- }
- /**
- * 根据指定id获取商品列表
- * @param array $ids
- * @param string $field
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductColumn(array $ids, string $field = '')
- {
- $productData = [];
- $productInfoField = 'id,image,price,ot_price,vip_price,postage,give_integral,sales,stock,store_name,unit_name,is_show,is_del,is_postage,cost,is_sub,temp_id';
- if (!empty($ids)) {
- $productAll = $this->dao->idByProductList($ids, $field ?: $productInfoField);
- if (!empty($productAll))
- $productData = array_combine(array_column($productAll, 'id'), $productAll);
- }
- return $productData;
- }
- /**
- * 商品是否存在
- * @param int $productId
- * @return array|\think\Model|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function isValidProduct(int $productId)
- {
- return $this->dao->getOne(['id' => $productId, 'is_del' => 0, 'is_show' => 1, 'is_verify' => 1]);
- }
- /**
- * 获取商品库存
- * @param int $productId
- * @param string $uniqueId
- * @return int|mixed
- */
- public function getProductStock(int $productId, string $uniqueId = '')
- {
- /** @var StoreProductAttrValueServices $StoreProductAttrValue */
- $StoreProductAttrValue = app()->make(StoreProductAttrValueServices::class);
- return $uniqueId == '' ?
- $this->dao->value(['id' => $productId], 'stock') ?: 0
- : $StoreProductAttrValue->uniqueByStock($uniqueId);
- }
- /**
- * 下单、退款商品、规格库存变化清空缓存
- * @return void
- */
- public function clearProductCache()
- {
- $this->dao->cacheTag()->clear();
- /** @var StoreProductAttrServices $storeProductAttrServices */
- $storeProductAttrServices = app()->make(StoreProductAttrServices::class);
- $storeProductAttrServices->cacheTag()->clear();
- }
- /**
- * 减库存,加销量
- * @param int $num
- * @param int $productId
- * @param string $unique
- * @param int $store_id
- * @return bool
- */
- public function decProductStock(int $num, int $productId, string $unique = '', int $store_id = 0)
- {
- $res = true;
- /** @var StoreProductAttrValueServices $skuValueServices */
- $skuValueServices = app()->make(StoreProductAttrValueServices::class);
- if ($store_id) {
- /** @var StoreBranchProductServices $branchProductServices */
- $branchProductServices = app()->make(StoreBranchProductServices::class);
- //查询门店商品
- $info = $branchProductServices->isValidStoreProduct($productId, $store_id);
- $storeProductId = $info['id'] ?? 0;
- if ($productId && $storeProductId != $productId) {
- //原商品sku
- $suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $productId, 'type' => 0], 'suk');
- //门店商品ID
- $productId = $storeProductId;
- //门店商品sku unique
- $unique = $skuValueServices->value(['suk' => $suk, 'product_id' => $productId, 'type' => 0], 'unique');
- }
- }
- if ($unique) {
- $res = $res && $skuValueServices->decProductAttrStock($productId, $unique, $num);
- }
- $res = $res && $this->dao->decStockIncSales(['id' => $productId], $num);
- if ($res) {
- $this->workSendStock($productId);
- }
- $this->clearProductCache();
- return $res;
- }
- /**
- * 减销量,加库存
- * @param int $num
- * @param int $productId
- * @param string $unique
- * @param int $store_id
- * @return bool
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function incProductStock(int $num, int $productId, string $unique = '', int $store_id = 0)
- {
- $res = true;
- /** @var StoreProductAttrValueServices $skuValueServices */
- $skuValueServices = app()->make(StoreProductAttrValueServices::class);
- if ($store_id) {
- /** @var StoreBranchProductServices $branchProductServices */
- $branchProductServices = app()->make(StoreBranchProductServices::class);
- //查询门店商品
- $info = $branchProductServices->isValidStoreProduct($productId, $store_id);
- $storeProductId = $info['id'] ?? 0;
- if ($productId && $storeProductId != $productId) {
- //原商品sku
- $suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $productId, 'type' => 0], 'suk');
- //门店商品ID
- $productId = $storeProductId;
- //门店商品sku unique
- $unique = $skuValueServices->value(['suk' => $suk, 'product_id' => $productId, 'type' => 0], 'unique');
- }
- }
- if ($unique) {
- $res = $res && $skuValueServices->incProductAttrStock($productId, $unique, $num);
- }
- $res = $res && $this->dao->incStockDecSales(['id' => $productId], $num);
- $this->clearProductCache();
- return $res;
- }
- /**
- * 库存预警发送消息
- * @param int $productId
- */
- public function workSendStock(int $productId)
- {
- ProductStockTips::dispatch([$productId]);
- }
- /**
- * 获取推荐商品
- * @param int $uid
- * @param array $where
- * @param int $num
- * @param string $type
- * @return array|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \throwable
- */
- public function getRecommendProduct(int $uid, array $where = [], int $num = 0, string $type = 'mid')
- {
- [$page, $limit] = $this->getPageValue();
- $where['is_vip_product'] = 0;
- $where['is_verify'] = 1;
- $where['pid'] = 0;
- $where['is_show'] = 1;
- $where['is_del'] = 0;
- if ($uid) {
- /** @var UserServices $userServices */
- $userServices = app()->make(UserServices::class);
- $is_vip = $userServices->value(['uid' => $uid], 'is_money_level');
- $where['is_vip_product'] = $is_vip ? -1 : 0;
- }
- $field = ['id', 'type', 'pid', 'image', 'store_name', 'store_info', 'cate_id', 'price', 'ot_price', 'IFNULL(sales,0) + IFNULL(ficti,0) as sales', 'unit_name', 'sort', 'activity', 'stock', 'vip_price', 'is_vip', 'video_link'];
- $list = $this->dao->getRecommendProduct($where, $field, $num, $page, $limit, ['couponId']);
- if ($list) {
- $list = get_thumb_water($list, $type);
- $list = $this->getActivityList($list);
- $list = $this->getProductPromotions($list);
- /** @var MemberCardServices $memberCardService */
- $memberCardService = app()->make(MemberCardServices::class);
- $vipStatus = $memberCardService->isOpenMemberCardCache('vip_price', false) && sys_config('svip_price_status', 1);;
- foreach ($list as &$item) {
- if (!($vipStatus && $item['is_vip'])) {
- $item['vip_price'] = 0;
- }
- }
- }
- return $list;
- }
- /**
- * 商品名称 图片
- * @param array $productIds
- * @return array
- */
- public function getProductArray(array $where, string $field, string $key)
- {
- return $this->dao->getColumn($where, $field, $key);
- }
- /**
- * 获取商品详情
- * @param int $productId
- * @param string $field
- * @param array $with
- * @return array|\think\Model|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductInfo(int $productId, string $field = '*', array $with = [])
- {
- return $this->dao->getOne(['is_del' => 0, 'is_show' => 1, 'id' => $productId], $field, $with);
- }
- /** 生成商品复制口令关键字
- * @param int $productId
- * @return string
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductWords(int $productId)
- {
- $productInfo = $this->dao->getOne(['is_del' => 0, 'is_show' => 1, 'id' => $productId]);
- $keyWords = "";
- if ($productInfo) {
- $oneKey = "crmeb-fu致文本 Http:/ZБ";
- $twoKey = "Б轉移至☞" . sys_config('site_name') . "☜";
- $threeKey = "【" . $productInfo['store_name'] . "】";
- $mainKey = base64_encode($productId);
- $keyWords = $oneKey . $mainKey . $twoKey . $threeKey;
- }
- return $keyWords;
- }
- /**
- * 通过商品id获取商品分类
- * @param array $productId
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function productIdByProductCateName(array $productId)
- {
- $data = $this->dao->productIdByCateId($productId);
- $cateData = [];
- foreach ($data as $item) {
- $cateData[$item['id']] = implode(',', array_map(function ($i) {
- return $i['cate_name'];
- }, $item['cateName']));
- }
- return $cateData;
- }
- /**
- * 根据商品id获取品牌名称
- * @param $productId
- * @return mixed
- */
- public function productIdByBrandName($productId, $productInfo = [])
- {
- if ($productInfo) {
- $brand_id = $productInfo['brand_id'] ?? [];
- } else {
- $storeInfo = $this->getCacheProductInfo($productId);
- $brand_id = $storeInfo['brand_id'] ?? [];
- }
- /** @var StoreBrandServices $storeBrandServices */
- $storeBrandServices = app()->make(StoreBrandServices::class);
- $storeBrandInfo = $storeBrandServices->getCacheBrandInfo($brand_id);
- return $storeBrandInfo['brand_name'] ?? '';
- }
- /**
- * 自动上下架
- * @return bool
- */
- public function autoUpperShelves()
- {
- $this->dao->overUpperShelves(1);
- $this->dao->overUpperShelves(0);
- return true;
- }
- /**
- * 获取预售列表
- * @param int $uid
- * @param array $where
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getPresaleList(int $uid, array $where)
- {
- [$page, $limit] = $this->getPageValue();
- $data = $this->dao->getPresaleList($where, $page, $limit);
- if ($data['list']) {
- /** @var StoreProductCategoryServices $storeCategoryService */
- $storeCategoryService = app()->make(StoreProductCategoryServices::class);
- /** @var StoreCouponIssueServices $couponServices */
- $couponServices = app()->make(StoreCouponIssueServices::class);
- /** @var StoreBrandServices $storeBrandServices */
- $storeBrandServices = app()->make(StoreBrandServices::class);
- $brands = $storeBrandServices->getColumn([], 'id,pid', 'id');
- /** @var SystemFormServices $systemFormServices */
- $systemFormServices = app()->make(SystemFormServices::class);
- $systemForms = $systemFormServices->getColumn([['id', 'in', array_unique(array_column($data['list'], 'system_form_id'))], ['is_del', '=', 0]], 'id,value', 'id');
- foreach ($data['list'] as &$item) {
- $item['sales'] = $item['sales'] + $item['ficti'];
- $custom_form = $systemForms[$item['system_form_id']]['value'] ?? [];
- $item['custom_form'] = is_string($custom_form) ? json_decode($custom_form, true) : $custom_form;
- $cateId = $item['cate_id'];
- $cateId = explode(',', $cateId);
- $cateId = array_merge($cateId, $storeCategoryService->cateIdByPid($cateId));
- $cateId = array_diff($cateId, [0]);
- $brandId = [];
- if ($item['brand_id']) {
- $brandId = $brands[$item['brand_id']] ?? [];
- }
- $counpons = $couponServices->getIssueCouponListNew($uid, ['product_id' => $item['id'], 'cate_id' => $cateId, 'brand_id' => $brandId], 'id,coupon_title,coupon_price,use_min_price', 0, 1, 'coupon_price desc,sort desc,id desc');
- $item['coupon'] = $counpons[0] ?? [];
- }
- }
- return $data;
- }
- /**
- * 判断配送方式
- * @param int $product_id
- * @param int $type 商品类型 0平台 1门店 2供应商
- * @param int $relation_id 门店id
- * @param array $delivery_type 配送方式
- * @return array
- *
- * @date 2022/09/09
- * @author yyw
- */
- public function getDeliveryType(int $product_id, int $type, int $relation_id, array $delivery_type)
- {
- //门店总开关
- if (!sys_config('store_func_status', 1)) {
- if (in_array('2', $delivery_type)) unset($delivery_type[array_search('2', $delivery_type)]);
- if (in_array('3', $delivery_type)) unset($delivery_type[array_search('3', $delivery_type)]);
- } else {
- //获取总平台自提配置设置
- $store_self_mention = (bool)sys_config('store_self_mention');
- $store_mention = true;
- //获取门店自提配置
- if ($type === 1 && $relation_id) {
- /** @var SystemStoreServices $storeServices */
- $storeServices = app()->make(SystemStoreServices::class);
- $storeInfo = $storeServices->cacheRemember($relation_id, function () use ($storeServices, $relation_id) {
- $storeInfo = $storeServices->get(['id' => $relation_id, 'is_show' => 1, 'is_del' => 0]);
- return $storeInfo ? $storeInfo->toArray() : null;
- });
- $store_mention = ($storeInfo['is_store'] ?? 0) === 1;
- if (in_array(1, $delivery_type)) {//门店商品 支持平台配送 验证平台该商品
- $info = $this->getCacheProductInfo($product_id);
- if ($info && $info['type'] == 1) {
- $platInfo = $this->getCacheProductInfo((int)$info['pid']);
- if (!$platInfo || $platInfo['stock'] <= 0) {
- unset($delivery_type[array_search('1', $delivery_type)]);
- }
- }
- }
- }
- //判断当前商品配送方式
- if (!$store_self_mention || !$store_mention || !(in_array('2', $delivery_type))) {
- if (in_array('2', $delivery_type)) unset($delivery_type[array_search('2', $delivery_type)]);
- }
- }
- // Log::error(['$type'=>$type,'$relation_id'=>$relation_id,'$delivery_type'=>$delivery_type,'$store_self_mention'=>$store_self_mention,'$store_mention'=>$store_mention,'$delivery_type'=>$delivery_type]);
- return array_merge($delivery_type);
- }
- }
|