CRMEB_PRO_M/app/services/activity/newcomer/StoreNewcomerServices.php

666 lines
25 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\activity\newcomer;
use app\dao\activity\newcomer\StoreNewcomerDao;
use app\jobs\product\ProductLogJob;
use app\services\activity\coupon\StoreCouponIssueServices;
use app\services\activity\coupon\StoreCouponUserServices;
use app\services\BaseServices;
use app\services\diy\DiyServices;
use app\services\order\StoreOrderServices;
use app\services\product\branch\StoreBranchProductServices;
use app\services\product\ensure\StoreProductEnsureServices;
use app\services\product\label\StoreProductLabelServices;
use app\services\product\product\StoreDescriptionServices;
use app\services\product\product\StoreProductReplyServices;
use app\services\product\product\StoreProductServices;
use app\services\product\sku\StoreProductAttrServices;
use app\services\product\sku\StoreProductAttrValueServices;
use app\services\user\UserRelationServices;
use app\services\user\UserServices;
use app\services\wechat\WechatUserServices;
use crmeb\exceptions\AdminException;
use crmeb\services\SystemConfigService;
use think\exception\ValidateException;
/**
* Class StoreNewcomerServices
* @package app\services\activity\newcomer
* @mixin StoreNewcomerDao
*/
class StoreNewcomerServices extends BaseServices
{
/**
* 商品活动类型
*/
const TYPE = 7;
/**
* StoreNewcomerServices constructor.
* @param StoreNewcomerDao $dao
*/
public function __construct(StoreNewcomerDao $dao)
{
$this->dao = $dao;
}
/**
* 获取新人礼商品详情
* @param int $id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getInfo(int $id)
{
$info = $this->dao->get($id, ['*'], ['product']);
$res = [];
if ($info) {
$res = $info->toArray();
$product = $res['product'] ?? [];
unset($res['product'], $product['id'], $product['price']);
$res = array_merge($res, $product);
}
return $res;
}
/**
* 获取新人专享商品
* @param array $where
* @param string $field
* @param array $with
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCustomerProduct(array $where = [], string $field = '*', array $with = ['product', 'attrValue'])
{
[$page, $limit] = $this->getPageValue();
$where['is_del'] = 0;
$list = $this->dao->getList($where, $field, $page, $limit, $with);
$res = [];
if ($list) {
foreach ($list as &$item) {
$product = $item['product'] ?? [];
if ($product) {
unset($item['product'], $product['id'], $product['price']);
$item = array_merge($item, $product);
$res[] = $item;
}
}
}
return $res;
}
/**
* 保存新人礼专属商品
* @param $data
* @return bool
*/
public function saveNewcomer($data)
{
$productIds = [];
$oldProductIds = $this->dao->getColumn(['is_del' => 0], 'id,product_id');
if ($oldProductIds) $oldProductIds = array_column($oldProductIds, 'product_id');
if ($data) {
$productIds = array_column($data, 'product_id');
$this->transaction(function () use ($data) {
foreach ($data as $product) {
$this->saveData(0, $product);
}
});
}
$deleteIds = array_merge(array_diff($oldProductIds, $productIds));
//清空现有新人礼商品
if ($deleteIds) {
$this->dao->update(['is_del' => 0, 'product_id' => $deleteIds], ['is_del' => 1 ,'update_time' => time()]);
}
return true;
}
/**
* 保存数据
* @param int $id
* @param array $info
*/
public function saveData(int $id, array $info)
{
if (!$info || !isset($info['product_id']) || !$info['product_id']) {
throw new ValidateException('请重新选择新人专享商品');
}
$attr = $info['attr'];
if ($attr) {
foreach ($attr as $a) {
if (!isset($a['unique']) || !isset($a['price'])) throw new ValidateException('请重新选择新人专享商品');
if (!$a['price']) {
throw new ValidateException('请填写商品专享价');
}
}
} else {
if (!$info['price']) {
throw new ValidateException('请填写商品专享价');
}
}
/** @var StoreProductServices $storeProductServices */
$storeProductServices = app()->make(StoreProductServices::class);
$productInfo = $storeProductServices->getOne(['is_show' => 1, 'is_del' => 0, 'is_verify' => 1, 'id' => $info['product_id']]);
if (!$productInfo) {
throw new AdminException('原商品已下架或移入回收站');
}
if ($productInfo['is_vip_product'] || $productInfo['is_presale_product']) {
throw new AdminException('该商品是预售或svip专享');
}
if (!$id) {
$newcomer = $this->dao->getOne(['product_id' => $info['product_id'], 'is_del' => 0]);
$id = $newcomer['id'] ?? 0;
}
$data = [];
$data['product_id'] = $productInfo['id'];
$data['type'] = $productInfo['type'] ?? 0;
$data['product_type'] = $productInfo['product_type'];
$data['relation_id'] = $productInfo['relation_id'] ?? 0;
$data['price'] = $info['price'] ?? 0;
if ($attr) $data['price'] = min(array_column($attr, 'price'));
/** @var StoreProductAttrValueServices $productAttrValueServices */
$productAttrValueServices = app()->make(StoreProductAttrValueServices::class);
/** @var StoreProductAttrServices $productAttrServices */
$productAttrServices = app()->make(StoreProductAttrServices::class);
$attrValue = $productAttrValueServices->getList(['product_id' => $info['product_id'], 'type' => 0]);
$skus = array_column($attr, 'unique');
$attr = array_combine($skus, $attr);
$this->transaction(function () use ($id, $data, $attrValue, $skus, $attr, $productAttrValueServices, $productAttrServices) {
$newcomerAttrValue = [];
if ($id) {
$data['update_time'] = time();
$res = $this->dao->update($id, $data);
$newcomerAttrValue = $productAttrValueServices->getList(['product_id' => $id, 'type' => 7]);
if (!$res) throw new AdminException('修改失败');
} else {
$data['add_time'] = time();
$res = $this->dao->save($data);
if (!$res) throw new AdminException('添加失败');
$id = (int)$res->id;
}
$detail = [];
foreach ($attrValue as $item) {
if (in_array($item['unique'], $skus)) {
$item['product_id'] = $id;
$item['type'] = 7;
if (isset($attr[$item['unique']]['price'])) $item['price'] = $attr[$item['unique']]['price'];
$item['unique'] = $productAttrServices->createAttrUnique((int)$id, $item['suk']);
unset($item['id']);
$detail[] = $item;
}
}
if ($newcomerAttrValue) {
foreach ($newcomerAttrValue as $item) {
if (in_array($item['unique'], $skus)) {
$item['product_id'] = $id;
$item['type'] = 7;
if (isset($attr[$item['unique']]['price'])) $item['price'] = $attr[$item['unique']]['price'];
unset($item['id']);
$detail[] = $item;
}
}
}
$productAttrValueServices->delete(['product_id' => $id, 'type' => 7]);
if ($detail) $productAttrValueServices->saveAll($detail);
});
}
/**
* 获取新人专享商品详情
* @param int $id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function newcomerDetail(int $uid, int $id)
{
$storeInfo = $this->getInfo($id);
if (!$storeInfo) {
throw new ValidateException('新人商品已下架或删除');
}
/** @var DiyServices $diyServices */
$diyServices = app()->make(DiyServices::class);
$infoDiy = $diyServices->getProductDetailDiy();
//diy控制参数
if (!isset($infoDiy['showService']) || !in_array(3, $infoDiy['showService'])) {
$storeInfo['specs'] = [];
}
$configData = SystemConfigService::more(['site_url', 'routine_contact_type', 'site_name', 'share_qrcode', 'store_self_mention', 'store_func_status', 'product_poster_title']);
$siteUrl = $configData['site_url'] ?? '';
$storeInfo['image'] = set_file_url($storeInfo['image'], $siteUrl);
$storeInfo['image_base'] = set_file_url($storeInfo['image'], $siteUrl);
/** @var StoreDescriptionServices $descriptionServices */
$descriptionServices = app()->make(StoreDescriptionServices::class);
$storeInfo['description'] = $descriptionServices->getDescription(['product_id' => $storeInfo['product_id']]);
//品牌名称
/** @var StoreProductServices $storeProductServices */
$storeProductServices = app()->make(StoreProductServices::class);
$productInfo = $storeProductServices->getCacheProductInfo((int)$storeInfo['product_id']);
$storeInfo['brand_name'] = $storeProductServices->productIdByBrandName((int)$storeInfo['product_id'], $productInfo);
$delivery_type = $storeInfo['delivery_type'] ?? $productInfo['delivery_type'];
$storeInfo['delivery_type'] = is_string($delivery_type) ? explode(',', $delivery_type) : $delivery_type;
/**
* 判断配送方式
*/
$storeInfo['delivery_type'] = $storeProductServices->getDeliveryType((int)$storeInfo['type'], (int)$storeInfo['type'], (int)$storeInfo['relation_id'],$storeInfo['delivery_type']);
$storeInfo['total'] = $productInfo['sales'] + $productInfo['ficti'];
$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', 'style_type', 'color', 'bg_color', 'border_color', 'icon']);
}
if ($storeInfo['ensure_id'] && isset($infoDiy['showService']) && in_array(2, $infoDiy['showService'])) {
/** @var StoreProductEnsureServices $storeProductEnsureServices */
$storeProductEnsureServices = app()->make(StoreProductEnsureServices::class);
$storeInfo['ensure'] = $storeProductEnsureServices->getColumn([['id', 'in', $storeInfo['ensure_id']]], 'id,name,image,desc');
}
/** @var StoreOrderServices $storeOrderServices */
$storeOrderServices = app()->make(StoreOrderServices::class);
$data['buy_num'] = $storeOrderServices->getBuyCount($uid, 7, $id);
/** @var UserRelationServices $userRelationServices */
$userRelationServices = app()->make(UserRelationServices::class);
$storeInfo['userCollect'] = $userRelationServices->isProductRelationCache(['uid' => $uid, 'relation_id' => $storeInfo['product_id'], 'type' => 'collect', 'category' => UserRelationServices::CATEGORY_PRODUCT]);
$storeInfo['userLike'] = 0;
$storeInfo['uid'] = $uid;
//商品详情
$storeInfo['small_image'] = get_thumb_water($storeInfo['image']);
$data['storeInfo'] = $storeInfo;
$data['reply'] = [];
$data['replyChance'] = $data['replyCount'] = 0;
if (isset($infoDiy['showReply']) && $infoDiy['showReply']) {
/** @var StoreProductReplyServices $storeProductReplyService */
$storeProductReplyService = app()->make(StoreProductReplyServices::class);
$reply = $storeProductReplyService->getRecProductReply((int)$storeInfo['product_id'], (int)($infoDiy['replyNum'] ?? 1));
$data['reply'] = $reply ? get_thumb_water($reply, 'small', ['pics']) : [];
[$replyCount, $goodReply, $replyChance] = $storeProductReplyService->getProductReplyData((int)$storeInfo['product_id']);
$data['replyChance'] = $replyChance;
$data['replyCount'] = $replyCount;
}
/** @var StoreProductAttrServices $storeProductAttrServices */
$storeProductAttrServices = app()->make(StoreProductAttrServices::class);
[$productAttr, $productValue] = $storeProductAttrServices->getProductAttrDetail($id, $uid, 0, 7, $storeInfo['product_id']);
$data['productAttr'] = $productAttr;
$data['productValue'] = $productValue;
$data['routine_contact_type'] = $configData['routine_contact_type'] ?? 0;
$data['store_func_status'] = (int)($configData['store_func_status'] ?? 1);//门店是否开启
$data['store_self_mention'] = $data['store_func_status'] ? (int)($configData['store_self_mention'] ?? 0) : 0;//门店自提是否开启
$data['site_name'] = $configData['site_name'] ?? '';
$data['share_qrcode'] = $configData['share_qrcode'] ?? 0;
$data['product_poster_title'] = $configData['product_poster_title'] ?? '';
//浏览记录
ProductLogJob::dispatch(['visit', ['uid' => $uid, 'id' => $id, 'product_id' => $storeInfo['product_id']], 'newcomer']);
return $data;
}
/**
* 修改秒杀库存
* @param int $num
* @param int $newcomerId
* @param string $unique
* @param int $store_id
* @return bool
*/
public function decNewcomerStock(int $num, int $newcomerId, string $unique = '', int $store_id = 0)
{
$product_id = $this->dao->value(['id' => $newcomerId], 'product_id');
$res = true;
if ($product_id && $unique) {
/** @var StoreProductAttrValueServices $skuValueServices */
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
//新人商品sku
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $newcomerId, 'type' => 7], 'suk');
//平台普通商品sku unique
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
/** @var StoreProductServices $services */
$services = app()->make(StoreProductServices::class);
//减去当前普通商品sku的库存增加销量
$res = false !== $services->decProductStock($num, (int)$product_id, (string)$productUnique, $store_id);
}
return $res;
}
/**
* 加库存减销量
* @param int $num
* @param int $newcomerId
* @param string $unique
* @param int $store_id
* @return bool
*/
public function incNewcomerStock(int $num, int $newcomerId, string $unique = '', int $store_id = 0)
{
$product_id = $this->dao->value(['id' => $newcomerId], 'product_id');
$res = true;
if ($product_id && $unique) {
/** @var StoreProductAttrValueServices $skuValueServices */
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
//新人商品sku
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $newcomerId, 'type' => 7], 'suk');
//平台商品sku unique
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $product_id, 'type' => 0], 'unique');
/** @var StoreProductServices $services */
$services = app()->make(StoreProductServices::class);
//减去当前普通商品sku的库存增加销量
$res = $services->incProductStock($num, (int)$product_id, (string)$productUnique, $store_id);
}
return $res;
}
/**
* 下单|加入购物车验证秒杀商品库存
* @param int $uid
* @param int $newcomerId
* @param int $cartNum
* @param string $unique
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function checkNewcomerStock(int $uid, int $newcomerId, int $cartNum = 1, string $unique = '')
{
if (!$this->checkUserNewcomer($uid)) {
throw new ValidateException('您已无法享受新人专享价');
}
/** @var StoreProductAttrValueServices $attrValueServices */
$attrValueServices = app()->make(StoreProductAttrValueServices::class);
if ($unique == '') {
$unique = $attrValueServices->value(['product_id' => $newcomerId, 'type' => 7], 'unique');
}
//检查商品活动状态
$newcomerInfo = $this->getInfo($newcomerId);
if (!$newcomerInfo) {
throw new ValidateException('该活动已下架');
}
$attrInfo = $attrValueServices->getOne(['product_id' => $newcomerId, 'unique' => $unique, 'type' => 7]);
if (!$attrInfo || $attrInfo['product_id'] != $newcomerId) {
throw new ValidateException('请选择有效的商品属性');
}
$suk = $attrInfo['suk'];
$productAttrInfo = $attrValueServices->getOne(['suk' => $suk, 'product_id' => $newcomerInfo['product_id'], 'type' => 0]);
if (!$productAttrInfo) {
throw new ValidateException('请选择有效的商品属性');
}
//库存要验证愿商品库存
if ($cartNum > $productAttrInfo['stock']) {
throw new ValidateException('该商品库存不足' . $cartNum);
}
return [$attrInfo, $unique, $newcomerInfo];
}
/**
* 验证用户是否可以享受首单优惠
* @param int $uid
* @param $userInfo
* @return array
*/
public function checkUserFirstDiscount(int $uid, $userInfo = [])
{
if (!$uid) {
return [];
}
//开启新人礼
if (!sys_config('newcomer_status')) {
return [];
}
//开启首单优惠
if (!sys_config('first_order_status')) {
return [];
}
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
if (!$userInfo) {
$userInfo = $userServices->getUserInfo($uid);
if (!$userInfo) {
return [];
}
}
if (isset($userInfo['is_first_order']) && $userInfo['is_first_order'] != 0) {
return [];
}
$timeStatus = sys_config('newcomer_limit_status', 1);
if ($timeStatus) {//设置限时,且超过时间不再享受
$time = sys_config('newcomer_limit_time');
if ($time) {
$time = (int)bcsub((string)time(), (string)bcmul((string)$time, '86400'));
if ($time > $userInfo['add_time']) {
return [];
}
}
}
//根据手机号码查询此用户注销过
if ($userInfo['phone'] != '' && $userServices->getWithTrashedCount(['phone' => $userInfo['phone']])) {
return [];
}
//根据openid查询此用户注销过
$wechatUserServices = app()->make(WechatUserServices::class);
$openidArray = $wechatUserServices->getColumn(['uid' => $uid], 'openid', 'id');
if ($wechatUserServices->getCount([['openid', 'in', $openidArray], ['is_del', '=', 1]])) {
return [];
}
/** @var StoreOrderServices $storeOrderServices */
$storeOrderServices = app()->make(StoreOrderServices::class);
$count = $storeOrderServices->getCount([['type', 'not in', [7]], ['uid', '=', $uid], ['paid', '=', 1]]);
if ($count) {//有过订单
return [];
}
$discount = sys_config('first_order_discount', 100);
$discount_limit = sys_config('first_order_discount_limit', 0);
return [$discount, $discount_limit];
}
/**
* 验证用户是否可以购买新人专享
* @param int $uid
* @param $userInfo
* @return bool
*/
public function checkUserNewcomer(int $uid, $userInfo = [])
{
if (!$uid) {
return false;
}
//开启新人礼
if (!sys_config('newcomer_status')) {
return false;
}
//开启新人专享
if (!sys_config('register_price_status')) {
return false;
}
if (!$userInfo) {
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$userInfo = $userServices->getUserInfo($uid);
if (!$userInfo) {
return false;
}
}
if (isset($userInfo['is_newcomer']) && $userInfo['is_newcomer'] != 0) {
return false;
}
$timeStatus = sys_config('newcomer_limit_status', 1);
if ($timeStatus) {//设置限时,且超过时间不再享受
$time = sys_config('newcomer_limit_time');
if ($time) {
$time = (int)bcsub((string)time(), (string)bcmul((string)$time, '86400'));
if ($time > $userInfo['add_time']) {
return false;
}
}
}
/** @var StoreOrderServices $orderServices */
$orderServices = app()->make(StoreOrderServices::class);
$count = $orderServices->count(['uid' => $uid, 'type' => 9, 'paid' => 1]);
if ($count) {
return false;
}
return true;
}
/**
* 用户会员卡激活状态
* @param int $uid
* @return bool|mixed
*/
public function setUserLevel(int $uid)
{
if (!$uid) {
return false;
}
//未开启会员 || 不需要激活 直接设置为已激活状态
if (!sys_config('member_func_status') || !sys_config('level_activate_status')) {
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
return $userServices->update($uid, ['level_status' => 1]);
}
return true;
}
/**
* 用户注册设置:首单优惠、新人专享是否可用 -1不可用 0未使用 1已使用
* @param int $uid
* @return false|mixed
*/
public function setUserNewcomer(int $uid)
{
if (!$uid) {
return false;
}
//是否开启新人礼
$newcomer_status = sys_config('newcomer_status');
$update = [];
if ($newcomer_status) {
//开启首单优惠
$first_order = sys_config('first_order_status');
$update['is_first_order'] = $first_order ? 0 : -1;
//开启新人专享
$is_newcomer = sys_config('register_price_status');
$update['is_newcomer'] = $is_newcomer ? 0 : -1;
} else {//不可用,数据记录已使用
$update = ['is_first_order' => -1, 'is_newcomer' => -1];
}
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
return $userServices->update($uid, $update);
}
/**
* 下单修改用户首单优惠
* @param int $uid
* @param $orderInfo
* @return bool
*/
public function updateUserNewcomer(int $uid, $orderInfo)
{
if (!$uid || !$orderInfo) {
return false;
}
$update = [];
//首单优惠
if (isset($orderInfo['first_order_price']) && $orderInfo['first_order_price'] > 0) {
$update['is_first_order'] = 1;
}
//新人专享
if (isset($orderInfo['type']) && $orderInfo['type'] == 7) {
$update['is_newcomer'] = 1;
}
if ($update) {
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$userServices->update($uid, $update);
$userServices->cacheTag()->clear();
}
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 getDiyNewcomerList(int $uid = 0, array $where = [])
{
$newcomer_products = $newcomer_integral = $newcomer_coupon = [];
if ($uid) {//验证权限
//验证用户是否享受过新人礼
if (!$this->checkUserNewcomer($uid)) {
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
}
} else {//验证是否开启 无登录:如果开启新人礼默认要展示
//开启新人礼 || 开启新人专享
if (!sys_config('newcomer_status') || !sys_config('register_price_status')) {
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
}
}
$data = SystemConfigService::more([
'register_integral_status',
'register_give_integral',
'register_coupon_status',
'register_give_coupon'
]);
$ids = $data['register_give_coupon'] ?? [];
$newcomer_coupon = [];
if ($data['register_coupon_status'] && $ids) {
[$page, $limit] = $this->getPageValue();
if ($uid) {//查询之前赠送他的
/** @var StoreCouponUserServices $couponServices */
$couponServices = app()->make(StoreCouponUserServices::class);
$coupon = $couponServices->getList(['cid' => $ids, 'uid' => $uid], '*', ['issue'], $page, $limit);
if ($coupon) $coupon = $couponServices->tidyCouponList($coupon);
} else {
/** @var StoreCouponIssueServices $couponServices */
$couponServices = app()->make(StoreCouponIssueServices::class);
$coupon = $couponServices->getList(['id' => $ids], $page, $limit);
}
$newcomer_coupon = $coupon;
}
$newcomer_integral = $data['register_integral_status'] ? $data['register_give_integral'] : 0;
$newcomer_products = $this->getCustomerProduct($where, 'id,type,product_id,relation_id,product_type,price', ['product' => function ($query) {
$query->field('id,image,store_name,stock,sales,ot_price');
}]);
return compact('newcomer_products', 'newcomer_integral', 'newcomer_coupon');
}
}