286 lines
8.1 KiB
PHP
286 lines
8.1 KiB
PHP
<?php
|
|
/**
|
|
* The file was created by Assimon.
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
use App\Exceptions\RuleValidationException;
|
|
use App\Models\Carmis;
|
|
use App\Models\Goods;
|
|
use App\Models\GoodsGroup;
|
|
|
|
/**
|
|
* 商品服务层
|
|
*
|
|
* Class GoodsService
|
|
* @package App\Service
|
|
* @author: Assimon
|
|
* @email: Ashang@utf8.hk
|
|
* @blog: https://utf8.hk
|
|
* Date: 2021/5/30
|
|
*/
|
|
class GoodsService
|
|
{
|
|
|
|
/**
|
|
* 获取所有分类并加载该分类下的商品
|
|
*
|
|
* @return array|null
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function withGroup(): ?array
|
|
{
|
|
$goods = GoodsGroup::query()
|
|
->select(['id', 'gp_name', 'is_open', 'is_open_group_pwd', 'group_pwd', 'ord', 'created_at', 'updated_at', 'deleted_at'])
|
|
->with(['goods' => function($query) {
|
|
$query->withCount(['carmis' => function($query) {
|
|
$query->where('status', Carmis::STATUS_UNSOLD);
|
|
}])->where('is_open', Goods::STATUS_OPEN)->orderBy('ord', 'DESC');
|
|
}])
|
|
->where('is_open', GoodsGroup::STATUS_OPEN)
|
|
->orderBy('ord', 'DESC')
|
|
->get();
|
|
|
|
$goods->each(function (GoodsGroup $group) {
|
|
$isLocked = $this->isGroupPasswordProtected($group) && !$this->hasGroupAccess($group->id);
|
|
$group->setAttribute('is_group_locked', $isLocked ? GoodsGroup::STATUS_OPEN : GoodsGroup::STATUS_CLOSE);
|
|
if ($isLocked) {
|
|
$group->setRelation('goods', collect());
|
|
}
|
|
});
|
|
|
|
// 将自动
|
|
return $goods ? $goods->toArray() : null;
|
|
}
|
|
|
|
/**
|
|
* 商品详情
|
|
*
|
|
* @param int $id 商品id
|
|
* @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function detail(int $id)
|
|
{
|
|
$goods = Goods::query()
|
|
->with(['coupon', 'group'])
|
|
->withCount(['carmis' => function($query) {
|
|
$query->where('status', Carmis::STATUS_UNSOLD);
|
|
}])->where('id', $id)->first();
|
|
return $goods;
|
|
}
|
|
|
|
/**
|
|
* 分类是否开启密码访问
|
|
*
|
|
* @param GoodsGroup|null $group
|
|
* @return bool
|
|
*/
|
|
public function isGroupPasswordProtected(?GoodsGroup $group): bool
|
|
{
|
|
return !empty($group)
|
|
&& $group->is_open_group_pwd == GoodsGroup::STATUS_OPEN
|
|
&& !empty($group->group_pwd);
|
|
}
|
|
|
|
/**
|
|
* 当前会话是否已解锁分类
|
|
*
|
|
* @param int $groupID 分类id
|
|
* @return bool
|
|
*/
|
|
public function hasGroupAccess(int $groupID): bool
|
|
{
|
|
$groupIDs = session('dujiaoka_group_pwd_access', []);
|
|
return in_array($groupID, $groupIDs);
|
|
}
|
|
|
|
/**
|
|
* 验证分类访问密码
|
|
*
|
|
* @param int $groupID 分类id
|
|
* @param string $password 访问密码
|
|
* @return array
|
|
*/
|
|
public function verifyGroupPassword(int $groupID, string $password): array
|
|
{
|
|
$group = GoodsGroup::query()
|
|
->with(['goods' => function($query) {
|
|
$query->withCount(['carmis' => function($query) {
|
|
$query->where('status', Carmis::STATUS_UNSOLD);
|
|
}])->where('is_open', Goods::STATUS_OPEN)->orderBy('ord', 'DESC');
|
|
}])
|
|
->where('is_open', GoodsGroup::STATUS_OPEN)
|
|
->where('id', $groupID)
|
|
->first();
|
|
|
|
if (empty($group)) {
|
|
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_does_not_exist'));
|
|
}
|
|
|
|
if (!$this->isGroupPasswordProtected($group)) {
|
|
$this->grantGroupAccess($group->id);
|
|
return $this->formatGroupForResponse($group);
|
|
}
|
|
|
|
if (!hash_equals((string) $group->group_pwd, (string) $password)) {
|
|
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_password_error'));
|
|
}
|
|
|
|
$this->grantGroupAccess($group->id);
|
|
return $this->formatGroupForResponse($group);
|
|
}
|
|
|
|
/**
|
|
* 格式化分类接口返回数据
|
|
*
|
|
* @param GoodsGroup $group 分类模型
|
|
* @return array
|
|
*/
|
|
private function formatGroupForResponse(GoodsGroup $group): array
|
|
{
|
|
$data = $group->toArray();
|
|
foreach ($data['goods'] as &$goods) {
|
|
$goods['picture_url'] = picture_ulr($goods['picture']);
|
|
}
|
|
unset($goods);
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 验证商品所属分类访问权限
|
|
*
|
|
* @param Goods $goods 商品模型
|
|
* @return void
|
|
*/
|
|
public function validatorGoodsGroupAccess(Goods $goods): void
|
|
{
|
|
$group = $goods->group;
|
|
if ($this->isGroupPasswordProtected($group) && !$this->hasGroupAccess($group->id)) {
|
|
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_password_required'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 取消当前会话访问指定分类的授权
|
|
*
|
|
* @param int $groupID 分类id
|
|
* @return void
|
|
*/
|
|
public function forgetGroupAccess(int $groupID): void
|
|
{
|
|
$groupIDs = session('dujiaoka_group_pwd_access', []);
|
|
$groupIDs = array_values(array_filter($groupIDs, function ($id) use ($groupID) {
|
|
return (int) $id !== $groupID;
|
|
}));
|
|
|
|
session(['dujiaoka_group_pwd_access' => $groupIDs]);
|
|
}
|
|
|
|
/**
|
|
* 授权当前会话访问分类
|
|
*
|
|
* @param int $groupID 分类id
|
|
* @return void
|
|
*/
|
|
private function grantGroupAccess(int $groupID): void
|
|
{
|
|
$groupIDs = session('dujiaoka_group_pwd_access', []);
|
|
if (!in_array($groupID, $groupIDs)) {
|
|
$groupIDs[] = $groupID;
|
|
session(['dujiaoka_group_pwd_access' => $groupIDs]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 格式化商品信息
|
|
*
|
|
* @param Goods $goods 商品模型
|
|
* @return Goods
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function format(Goods $goods)
|
|
{
|
|
// 格式化批发配置以及输入框配置
|
|
$goods->wholesale_price_cnf = $goods->wholesale_price_cnf ?
|
|
format_wholesale_price($goods->wholesale_price_cnf) :
|
|
null;
|
|
// 如果存在其他配置输入框且为代充
|
|
$goods->other_ipu = $goods->other_ipu_cnf ?
|
|
format_charge_input($goods->other_ipu_cnf) :
|
|
null;
|
|
return $goods;
|
|
}
|
|
|
|
/**
|
|
* 验证商品状态
|
|
*
|
|
* @param Goods $goods
|
|
* @return Goods
|
|
* @throws RuleValidationException
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function validatorGoodsStatus(Goods $goods): Goods
|
|
{
|
|
if (empty($goods)) {
|
|
throw new RuleValidationException(__('dujiaoka.prompt.goods_does_not_exist'));
|
|
}
|
|
// 上架判断.
|
|
if ($goods->is_open != Goods::STATUS_OPEN) {
|
|
throw new RuleValidationException(__('dujiaoka.prompt.the_goods_is_not_on_the_shelves'));
|
|
}
|
|
return $goods;
|
|
}
|
|
|
|
/**
|
|
* 库存减去
|
|
*
|
|
* @param int $id 商品id
|
|
* @param int $number 出库数量
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function inStockDecr(int $id, int $number = 1): bool
|
|
{
|
|
return Goods::query()->where('id', $id)->decrement('in_stock', $number);
|
|
}
|
|
|
|
/**
|
|
* 商品销量加
|
|
*
|
|
* @param int $id 商品id
|
|
* @param int $number 数量
|
|
* @return bool
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function salesVolumeIncr(int $id, int $number = 1): bool
|
|
{
|
|
return Goods::query()->where('id', $id)->increment('sales_volume', $number);
|
|
}
|
|
|
|
}
|