123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- <?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\sku;
- use app\dao\product\sku\StoreProductAttrDao;
- use app\services\BaseServices;
- use app\services\order\StoreCartServices;
- use app\services\product\product\StoreProductServices;
- use crmeb\exceptions\AdminException;
- use crmeb\traits\OptionTrait;
- /**
- * Class StoreProductAttrService
- * @package app\services\product\sku
- * @mixin StoreProductAttrDao
- */
- class StoreProductAttrServices extends BaseServices
- {
- use OptionTrait;
- /**
- * StoreProductAttrServices constructor.
- * @param StoreProductAttrDao $dao
- */
- public function __construct(StoreProductAttrDao $dao)
- {
- $this->dao = $dao;
- }
- /**
- * 生成规格唯一值
- * @param int $id
- * @param string $sku
- * @return false|string
- */
- public function createAttrUnique(int $id, string $sku)
- {
- return substr(md5($id . $sku . uniqid(true)), 12, 8);
- }
- /**
- * 根据根据前端规格数据获取sku
- * @param array $value
- * @param string
- */
- public function getSku(array $value)
- {
- $sku = '';
- if ($value) {
- $detail = [];
- $count = count($value['detail'] ?? []);
- for ($i=1; $i<=$count ; $i++) {
- $detail[] = trim($value['value' . $i]);
- }
- $sku = implode(',', $detail);
- }
- return $sku;
- }
- /**
- * 添加商品属性数据判断
- * @param array $attrList
- * @param array $valueList
- * @param int $productId
- * @param int $type
- * @param int $is_vip
- * @param int $validate
- * @return array
- */
- public function validateProductAttr(array $attrList, array $valueList, int $productId, int $type = 0, int $is_vip = 0, int $validate = 1)
- {
- $result = ['attr' => $attrList, 'value' => $valueList];
- $attrValueList = [];
- $attrNameList = [];
- foreach ($attrList as $index => $attr) {
- if (!isset($attr['value'])) {
- throw new AdminException('请输入规则名称!');
- }
- $attr['value'] = trim($attr['value']);
- if (!isset($attr['value'])) {
- throw new AdminException('请输入规则名称!!');
- }
- if (!isset($attr['detail']) || !count($attr['detail'])) {
- throw new AdminException('请输入属性名称!');
- }
- foreach ($attr['detail'] as $k => $attrValue) {
- $attrValue = trim($attrValue);
- if (empty($attrValue)) {
- throw new AdminException('请输入正确的属性');
- }
- $attr['detail'][$k] = $attrValue;
- $attrValueList[] = $attrValue;
- $attr['detail'][$k] = $attrValue;
- }
- $attrNameList[] = $attr['value'];
- $attrList[$index] = $attr;
- }
- $attrCount = count($attrList);
- foreach ($valueList as $index => $value) {
- if (!isset($value['detail']) || count($value['detail']) != $attrCount) {
- throw new AdminException('请填写正确的商品信息');
- }
- if (!isset($value['price']) || !is_numeric($value['price']) || floatval($value['price']) != $value['price']) {
- throw new AdminException('请填写正确的商品价格');
- }
- if ($type == 4) {
- if (!isset($value['integral']) || !is_numeric($value['integral']) || floatval($value['integral']) != $value['integral']) {
- throw new AdminException('请填写正确的商品兑换积分');
- }
- if (isset($value['price']) && $value['price'] <= 0 && isset($value['integral']) && $value['integral'] <= 0) {
- throw new AdminException('积分商品兑换积分和价格不能同时为空');
- }
- }
- if (!isset($value['stock']) || !is_numeric($value['stock']) || intval($value['stock']) != $value['stock']) {
- throw new AdminException('请填写正确的商品库存');
- }
- //供应商结算价 不用成本价
- if (!($value['settle_price'] ?? 0) && (!isset($value['cost']) || !is_numeric($value['cost']) || floatval($value['cost']) != $value['cost'])) {
- throw new AdminException('请填写正确的商品成本价格');
- }
- if ($validate && (!isset($value['pic']) || empty($value['pic']))) {
- throw new AdminException('请上传商品规格图片');
- }
- if ($is_vip && (!isset($value['vip_price']) || !$value['vip_price'])) {
- throw new AdminException('会员价格不能为0');
- }
- foreach ($value['detail'] as $attrName => $attrValue) {
- //如果attrName 存在空格 则这个规格key 会出现两次
- unset($valueList[$index]['detail'][$attrName]);
- $attrName = trim($attrName);
- $attrValue = trim($attrValue);
- if (!in_array($attrName, $attrNameList, true)) {
- throw new AdminException($attrName . '规则不存在');
- }
- if (!in_array($attrValue, $attrValueList, true)) {
- throw new AdminException($attrName . '属性不存在');
- }
- if (empty($attrName)) {
- throw new AdminException('请输入正确的属性');
- }
- $valueList[$index]['detail'][$attrName] = $attrValue;
- }
- }
- $attrGroup = [];
- $valueGroup = [];
- foreach ($attrList as $k => $value) {
- $attrGroup[] = [
- 'product_id' => $productId,
- 'attr_name' => $value['value'],
- 'attr_values' => $value['detail'],
- 'type' => $type
- ];
- }
- /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
- $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
- $skuArray = $storeProductAttrValueServices->getSkuArray(['product_id' => $productId, 'type' => $type], 'unique', 'suk');
- foreach ($valueList as $k => $value) {
- // sort($value['detail'], SORT_STRING);
- $sku = implode(',', $value['detail']);
- $valueGroup[$sku] = [
- 'product_id' => $productId,
- 'suk' => $this->getSku($value),
- 'price' => $value['price'],
- 'integral' => isset($value['integral']) ? $value['integral'] : 0,
- 'settle_price' => $value['settle_price'] ?? 0.00,//供应商结算价
- 'cost' => ($value['settle_price'] ?? 0.00) ?: $value['cost'],//供应端:去除成本价
- 'ot_price' => $value['ot_price'],
- 'stock' => $value['stock'],
- 'unique' => $skuArray[$sku] ?? $this->createAttrUnique($productId, $sku),
- 'image' => $value['pic'],
- 'bar_code' => $value['bar_code'] ?? '',
- 'weight' => $value['weight'] ?? 0,
- 'volume' => $value['volume'] ?? 0,
- 'brokerage' => $value['brokerage'] ?? 0,
- 'brokerage_two' => $value['brokerage_two'] ?? 0,
- 'type' => $type,
- 'quota' => $value['quota'] ?? 0,
- 'quota_show' => $value['quota'] ?? 0,
- 'vip_price' => $value['vip_price'] ?? 0,
- 'award_price' => $value['award_price'] ?? 0,
- 'code' => $value['code'] ?? '',
- 'product_type' => $value['product_type'] ?? 0,
- 'virtual_list' => $value['virtual_list'] ?? [],
- 'disk_info' => $value['disk_info'] ?? '',
- 'write_times' => $value['write_times'] ?? 1,
- 'write_valid' => $value['write_valid'] ?? 1,
- 'write_days' => $value['write_days'] ?? $value['days'] ?? 0,
- 'write_start' => ($value['section_time'][0] ?? '') ? strtotime($value['section_time'][0] ?? '') : 0,
- 'write_end' => ($value['section_time'][1] ?? '') ? strtotime($value['section_time'][1] ?? '') : 0,
- ];
- }
- if (!count($attrGroup) || !count($valueGroup)) {
- throw new AdminException('请设置至少一个属性!');
- }
- return compact('result', 'attrGroup', 'valueGroup');
- }
- /**
- * 保存商品规格
- * @param array $data
- * @param int $id
- * @param int $type
- * @return bool|mixed|\think\Collection
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function saveProductAttr(array $data, int $id, int $type = 0)
- {
- $this->setAttr($data['attrGroup'], $id, $type);
- /** @var StoreProductAttrResultServices $storeProductAttrResultServices */
- $storeProductAttrResultServices = app()->make(StoreProductAttrResultServices::class);
- $storeProductAttrResultServices->setResult($data['result'], $id, $type);
- /** @var StoreProductAttrValueServices $storeProductAttrValueServices */
- $storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
- $valueGroup = $data['valueGroup'] ?? [];
- $updateSuks = array_column($valueGroup, 'suk');
- $oldSuks = [];
- $oldAttrValue = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => $type], '*', 'suk');
- if ($oldAttrValue) $oldSuks = array_column($oldAttrValue, 'suk');
- $delSuks = array_merge(array_diff($oldSuks, $updateSuks));
- $dataAll = [];
- $res1 = $res2 = $res3 = true;
- foreach ($valueGroup as $item) {
- if ($oldSuks && in_array($item['suk'], $oldSuks) && isset($oldAttrValue[$item['suk']])) {
- $attrId = $oldAttrValue[$item['suk']]['id'];
- unset($item['suk'], $item['unique']);
- $item['virtual_list'] =json_encode($item['virtual_list']);
- $res1 = $res1 && $storeProductAttrValueServices->update($attrId, $item);
- } else {
- $dataAll[] = $item;
- }
- }
- if ($delSuks) {
- $res2 = $storeProductAttrValueServices->del($id, $type, $delSuks);
- }
- if ($dataAll) {
- $res3 = $storeProductAttrValueServices->saveAll($dataAll);
- }
- if ($res1 && $res2 && $res3) {
- // $unique = array_column($valueGroup, 'unique');
- // $storeProductAttrValueServices->updateSumStock($unique ?? []);
- return $valueGroup;
- } else {
- throw new AdminException('商品规格信息保存失败');
- }
- }
- /**
- * 获取商品规格
- * @param array $where
- * @return array
- */
- public function getProductAttr(array $where)
- {
- return $this->dao->getProductAttr($where);
- }
- /**
- * 获取商品规格详情
- * @param int $id
- * @param int $uid
- * @param int $cartNum //是否查询购物车数量
- * @param int $type //活动类型 attr_value表
- * @param int $productId
- * @param array $productInfo
- * @param int $discount //限时折扣
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductAttrDetailCache(int $id, int $uid, int $cartNum = 0, int $type = 0, int $productId = 0, array $productInfo = [], int $discount = -1)
- {
- $attrDetail = $this->dao->cacheTag()->remember('attr_' . $id . '_' . $type . '_' . $productId, function () use ($productId, $id, $type) {
- $attrDetail = $this->dao->getProductAttr(['product_id' => $id, 'type' => $type]);
- if (!$attrDetail && $type > 0 && $productId) {//活动商品未获取到规格信息
- $attrDetail = $this->dao->getProductAttr(['product_id' => $productId, 'type' => 0]);
- }
- return $attrDetail;
- }, 600);
- /** @var StoreProductAttrValueServices $storeProductAttrValueService */
- $storeProductAttrValueService = app()->make(StoreProductAttrValueServices::class);
- $_values = $this->dao->cacheTag()->remember('attr_value_' . $id . '_' . $type, function () use ($storeProductAttrValueService, $id, $type) {
- return $storeProductAttrValueService->getProductAttrValue(['product_id' => $id, 'type' => $type]);
- }, 600);
- if ($productId == 0) {
- $productId = $id;
- }
- /** @var StoreProductServices $storeProductService */
- $storeProductService = app()->make(StoreProductServices::class);
- $vip_price = true;
- if (!$storeProductService->vipIsOpen(!!($productInfo['is_vip'] ?? 0))) $vip_price = false;
- $cartNumList = [];
- $activityAttr = [];
- if ($cartNum) {
- /** @var StoreCartServices $storeCartService */
- $storeCartService = app()->make(StoreCartServices::class);
- $unique = array_column($_values, 'unique');
- $cartNumList = $storeCartService->cacheTag('Cart_Nums_' . $uid)->remember(md5(json_encode($unique)),
- function () use ($storeCartService, $unique, $id, $uid) {
- return $storeCartService->getUserCartNums($unique, $id, $uid);
- }
- , 600);
- }
- $values = [];
- $field = $type ? 'stock,price' : 'stock';
- $storeProducts = $this->dao->cacheTag()->remember('attr_sku_' . $productId . '_' . $type, function () use ($storeProductAttrValueService, $productId, $field) {
- return $storeProductAttrValueService->getSkuArray(['product_id' => $productId, 'type' => 0], $field, 'suk');
- });
- foreach ($_values as $value) {
- if ($cartNum) {
- $value['cart_num'] = $cartNumList[$value['unique']] ?? 0;
- }
- if (!$vip_price) $value['vip_price'] = 0;
- $value['product_stock'] = $storeProducts[$value['suk']]['stock'] ?? 0;
- if ($discount != -1) $value['price'] = bcmul((string)$value['price'], (string)bcdiv((string)$discount, '100', 2), 2);
- if ($type) {
- $value['product_price'] = $storeProducts[$value['suk']]['price'] ?? 0;
- $attrs = explode(',', $value['suk']);
- $count = count($attrs);
- for ($i = 0; $i < $count; $i++) {
- $activityAttr[$i][] = $attrs[$i];
- }
- }
- $values[$value['suk']] = $value;
- }
- foreach ($attrDetail as $k => $v) {
- $attr = $v['attr_values'];
- //活动商品只展示参与活动sku
- if ($type && $activityAttr && $a = array_merge(array_intersect($v['attr_values'], $activityAttr[$k]))) {
- $attrDetail[$k]['attr_values'] = $a;
- $attr = $a;
- }
- foreach ($attr as $kk => $vv) {
- $attrDetail[$k]['attr_value'][$kk]['attr'] = $vv;
- $attrDetail[$k]['attr_value'][$kk]['check'] = false;
- }
- }
- return [$attrDetail, $values];
- }
- /**
- * 获取商品规格详情
- * @param int $id
- * @param int $uid
- * @param int $cartNum //是否查询购物车数量
- * @param int $type //活动类型 attr_value表
- * @param int $productId
- * @param array $productInfo
- * @param int $discount //限时折扣
- * @return array
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\DbException
- * @throws \think\db\exception\ModelNotFoundException
- */
- public function getProductAttrDetail(int $id, int $uid, int $cartNum = 0, int $type = 0, int $productId = 0, array $productInfo = [], int $discount = -1)
- {
- $attrDetail = $this->dao->getProductAttr(['product_id' => $id, 'type' => $type]);
- if (!$attrDetail && $type > 0 && $productId) {//活动商品未获取到规格信息
- $attrDetail = $this->dao->getProductAttr(['product_id' => $productId, 'type' => 0]);
- }
- /** @var StoreProductAttrValueServices $storeProductAttrValueService */
- $storeProductAttrValueService = app()->make(StoreProductAttrValueServices::class);
- $_values = $storeProductAttrValueService->getProductAttrValue(['product_id' => $id, 'type' => $type]);
- if ($productId == 0) $productId = $id;
- /** @var StoreProductServices $storeProductService */
- $storeProductService = app()->make(StoreProductServices::class);
- if (!$productInfo) {
- $productInfo = $storeProductService->get($productId, ['is_vip']);
- }
- $vip_price = true;
- if (!$storeProductService->vipIsOpen(!!$productInfo['is_vip'])) $vip_price = false;
- $cartNumList = [];
- $activityAttr = [];
- if ($cartNum) {
- /** @var StoreCartServices $storeCartService */
- $storeCartService = app()->make(StoreCartServices::class);
- //真实用户
- if ($uid) {
- $cartNumList = $storeCartService->getUserCartNums(array_column($_values, 'unique'), $id, $uid);
- } else {
- //虚拟用户
- $touristUid = $this->getItem('touristUid');
- if ($touristUid) {
- $cartNumList = $storeCartService->getUserCartNums(array_column($_values, 'unique'), $id, $touristUid, 'tourist_uid');
- }
- }
- }
- $values = [];
- $field = $type ? 'stock,price' : 'stock';
- $storeProducts = $storeProductAttrValueService->getSkuArray(['product_id' => $productId, 'type' => 0], $field, 'suk');
- foreach ($_values as $value) {
- if ($cartNum) {
- $value['cart_num'] = $uid || $touristUid ? ($cartNumList[$value['unique']] ?? 0) : 0;
- }
- if (!$vip_price) $value['vip_price'] = 0;
- $value['product_stock'] = $storeProducts[$value['suk']]['stock'] ?? 0;
- if ($discount != -1) $value['price'] = bcmul((string)$value['price'], (string)bcdiv((string)$discount, '100', 2), 2);
- if ($type) {
- $value['product_price'] = $storeProducts[$value['suk']]['price'] ?? 0;
- $attrs = explode(',', $value['suk']);
- $count = count($attrs);
- for ($i = 0; $i < $count; $i++) {
- $activityAttr[$i][] = $attrs[$i];
- }
- }
- $values[$value['suk']] = $value;
- }
- foreach ($attrDetail as $k => $v) {
- $attr = $v['attr_values'];
- //活动商品只展示参与活动sku
- if ($type && $activityAttr && $a = array_merge(array_intersect($v['attr_values'], $activityAttr[$k]))) {
- $attrDetail[$k]['attr_values'] = $a;
- $attr = $a;
- }
- foreach ($attr as $kk => $vv) {
- $attrDetail[$k]['attr_value'][$kk]['attr'] = $vv;
- $attrDetail[$k]['attr_value'][$kk]['check'] = false;
- }
- }
- return [$attrDetail, $values];
- }
- /**
- * 删除一条数据
- * @param int $id
- * @param int $type
- */
- public function del(int $id, int $type)
- {
- $this->dao->del($id, $type);
- }
- /**
- * 设置规格
- * @param array $data
- * @param int $id
- * @param int $type
- * @return bool
- * @throws \Exception
- */
- public function setAttr(array $data, int $id, int $type)
- {
- if ($data) {
- $this->dao->del($id, $type);
- $res = $this->dao->saveAll($data);
- if (!$res) throw new AdminException('规格保存失败');
- }
- return true;
- }
- }
|