You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/store/model/groupon/Goods.php

292 lines
11 KiB

<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\store\model\groupon;
use app\store\model\Goods as GoodsModel;
use app\store\model\GoodsSpecRel as GoodsSpecRelModel;
use app\store\model\groupon\GoodsSku as GoodsSkuModel;
use app\common\model\groupon\Goods as GrouponGoodsModel;
use app\common\enum\goods\SpecType as SpecTypeEnum;
use app\common\enum\groupon\ActiveType as ActiveTypeEnum;
use app\common\library\helper;
use cores\exception\BaseException;
/**
* 拼团商品模型
* Class Goods
* @package app\store\model\groupon
*/
class Goods extends GrouponGoodsModel
{
const EVENT_ADD = 'add';
const EVENT_EDIT = 'edit';
/**
* 获取列表
* @param array $param
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList(array $param): \think\Paginator
{
// 设置基础查询条件
$query = $this->setBaseQuery($this->alias, [['goods', 'goods_id']]);
// 检索查询条件
$filter = $this->getFilter($param);
// 获取活动列表
$list = $query->where($filter)
->where("{$this->alias}.is_delete", '=', 0)
->order(["{$this->alias}.sort" => 'asc', "{$this->alias}.create_time" => 'desc'])
->paginate(15);
// 设置商品数据
return !$list->isEmpty() ? $this->setGoodsListData($list, true) : $list;
}
/**
* 检索查询条件
* @param array $param
* @return array
*/
private function getFilter(array $param): array
{
// 设置默认查询参数
$params = $this->setQueryDefaultValue($param, [
'search' => '', // 商品名称
'activeType' => 0, // 拼团类型
'status' => 0, // 拼单状态
]);
// 检索查询条件
$filter = [];
!empty($params['search']) && $filter[] = ['goods.goods_name', 'like', "%{$params['search']}%"];
$params['activeType'] > 0 && $filter[] = ["{$this->alias}.active_type", '=', (int)$params['activeType']];
$params['status'] > 0 && $filter[] = ["{$this->alias}.status", '=', (int)$params['status']];
return $filter;
}
/**
* 获取拼团商品详情
* @param int $grouponGoodsId 拼团商品ID
* @return Goods|array|null
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getDetail(int $grouponGoodsId)
{
// 获取商品记录
$goodsInfo = static::detail($grouponGoodsId, ['skuList']);
empty($goodsInfo) && throwError('很抱歉,商品信息不存在');
// 商品多规格处理
if ($goodsInfo['spec_type'] == SpecTypeEnum::MULTI) {
// 拼团商品SKU填充主商品参数(商品价格、库存数量、商品sku编码)
$goodsInfo['skuList'] = GoodsSkuModel::getCommonSkuList($goodsInfo['skuList'], $goodsInfo['goods_id']);
// 商品规格属性列表
$goodsInfo['specList'] = GoodsSpecRelModel::getSpecList($goodsInfo['goods_id']);
}
return $goodsInfo;
}
/**
* 添加拼团商品
* @param array $data
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function add(array $data): bool
{
// 验证主商品能否被添加为拼团商品
if (!$this->validateGoodsId((int)$data['goods_id'])) {
return false;
}
// 获取主商品基本信息
$goodsInfo = (new GoodsModel)->getBasic((int)$data['goods_id']);
// 记录商品ID、规格类型、拼团价格及库存
$data['goods_id'] = $goodsInfo['goods_id'];
$data['spec_type'] = $goodsInfo['spec_type'];
$data['groupon_price'] = $goodsInfo['goods_price_min'];
// 默认的阶梯价格
if ($data['active_type'] == ActiveTypeEnum::STEPS) {
$data['steps_price_config'] = array_map(function () use ($goodsInfo) {
return $goodsInfo['goods_price_min'];
}, $data['steps_config']);
}
// 创建拼团商品数据
$data = $this->createData($data, self::EVENT_ADD);
// 事务处理
$this->transaction(function () use ($data) {
// 添加商品
$this->save($data);
// 更新商品sku信息
GoodsSkuModel::add((int)$this['groupon_goods_id'], $this['spec_type'], $data['newSkuList']);
});
return true;
}
/**
* 编辑商品
* @param array $data
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function edit(array $data): bool
{
// 记录商品ID和规格类型
$data['active_type'] = $this['active_type'];
$data['goods_id'] = $this['goods_id'];
$data['spec_type'] = $this['spec_type'];
// 创建拼团商品数据
$data = $this->createData($data, self::EVENT_EDIT);
// 事务处理
$this->transaction(function () use ($data) {
// 更新商品
$this->save($data);
// 更新商品sku信息
GoodsSkuModel::edit((int)$this['groupon_goods_id'], $this['spec_type'], $data['newSkuList']);
});
return true;
}
/**
* 创建商品数据
* @param array $data
* @param string $event
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createData(array $data, string $event): array
{
// 默认数据
$data = array_merge([
'newSkuList' => [],
'betweenTime' => [],
'store_id' => self::$storeId,
], $data);
// 规格和sku数据处理
$data['newSkuList'] = $this->getNewSkuList($data, $event);
// 是否为阶梯团
$isSteps = $data['active_type'] == ActiveTypeEnum::STEPS;
// 商品价格 最低最高
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
[$data['groupon_price_min'], $data['groupon_price_max']] = GoodsSkuModel::getGoodsPrices($data['newSkuList'], $isSteps);
} elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
// 阶梯价格
if ($isSteps) {
$data['groupon_price_min'] = min($data['steps_price_config']);
$data['groupon_price_max'] = max($data['steps_price_config']);
} else {
$data['groupon_price_min'] = $data['groupon_price_max'] = $data['groupon_price'];
}
}
// 格式化活动时间
$times = between_time($data['betweenTime'], true);
$data['start_time'] = $times['start_time'];
$data['end_time'] = $times['end_time'];
return $data;
}
/**
* 生成新的SKU列表数据
* @param array $data
* @param string $event
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getNewSkuList(array $data, string $event = self::EVENT_ADD): array
{
if ($event === self::EVENT_ADD) {
// 生成默认的skuList
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
return GoodsSkuModel::getDefaultSkuList($data['goods_id']);
}
return helper::pick($data, ['groupon_price', 'steps_price_config']);
}
return $this->getNewSkuListByEdit($data, $event);
}
/**
* 生成新的SKU列表数据(用于编辑事件)
* @param array $data
* @param string $event
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getNewSkuListByEdit(array $data, string $event = self::EVENT_ADD): array
{
// 规格和sku数据处理
if ($data['spec_type'] == SpecTypeEnum::MULTI) {
// 生成skuList ( 携带goods_sku_id )
return GoodsSkuModel::getNewSkuList($data['goods_id'], $data['specData']['skuList']);
} elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
// 生成skuItem
return helper::pick($data, ['groupon_price', 'steps_price_config']);
}
return [];
}
/**
* 验证主商品能否被添加为拼团商品
* @param int $goodsId 主商品ID
* @return bool
*/
private function validateGoodsId(int $goodsId): bool
{
if (empty($goodsId)) {
$this->error = '很抱歉,您还没有选择商品';
return false;
}
// 验证是否存在拼团商品
if ($this->isExistGoodsId($goodsId)) {
$this->error = '很抱歉,该商品已存在,无需重复添加';
return false;
}
return true;
}
/**
* 验证指定商品是否已添加拼团商品
* @param int $goodsId 主商品ID
* @return bool
*/
public static function isExistGoodsId(int $goodsId): bool
{
return (bool)(new static)->where('goods_id', '=', $goodsId)
->where('is_delete', '=', 0)
->value('groupon_goods_id');
}
/**
* 软删除
* @return mixed
*/
public function setDelete()
{
return $this->transaction(function () {
// 删除所有的sku记录
GoodsSkuModel::deleteAll(['groupon_goods_id' => $this['groupon_goods_id']]);
// 标记当前拼团商品已删除
return $this->save(['is_delete' => 1]);
});
}
}