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.
2398 lines
123 KiB
2398 lines
123 KiB
<?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\promotions;
|
|
|
|
use app\dao\activity\promotions\StorePromotionsDao;
|
|
use app\services\activity\coupon\StoreCouponIssueServices;
|
|
use app\services\activity\coupon\StoreCouponUserServices;
|
|
use app\services\order\StoreOrderCreateServices;
|
|
use app\services\order\StoreOrderComputedServices;
|
|
use app\services\BaseServices;
|
|
use app\services\product\brand\StoreBrandServices;
|
|
use app\services\product\label\StoreProductLabelServices;
|
|
use app\services\product\product\StoreProductRelationServices;
|
|
use app\services\product\product\StoreProductServices;
|
|
use app\services\product\branch\StoreBranchProductServices;
|
|
use app\services\product\sku\StoreProductAttrValueServices;
|
|
use app\services\store\SystemStoreServices;
|
|
use app\services\user\label\UserLabelServices;
|
|
use app\services\order\StoreOrderServices;
|
|
use app\services\order\StoreOrderCartInfoServices;
|
|
use app\services\order\StoreCartServices;
|
|
use app\services\product\category\StoreProductCategoryServices;
|
|
use crmeb\exceptions\AdminException;
|
|
use think\exception\ValidateException;
|
|
use \crmeb\traits\OptionTrait;
|
|
|
|
|
|
/**
|
|
* 促销活动
|
|
* Class StorePromotionsServices
|
|
* @package app\services\activity\promotions
|
|
* @mixin StorePromotionsDao
|
|
*/
|
|
class StorePromotionsServices extends BaseServices
|
|
{
|
|
use OptionTrait;
|
|
|
|
/**
|
|
* 活动类型
|
|
* @var string[]
|
|
*/
|
|
protected $promotionsType = [
|
|
1 => '限时折扣',
|
|
2 => '第N件N折',
|
|
3 => '满减满折',
|
|
4 => '满送',
|
|
];
|
|
|
|
/**
|
|
* 优惠内容数据
|
|
* @var array
|
|
*/
|
|
protected $promotionsData = [
|
|
'threshold_type' => 1,//门槛类型1:满N元2:满N件
|
|
'threshold' => 0,//优惠门槛
|
|
'discount_type' => 1,//优惠类型1:满减2:满折
|
|
'n_piece_n_discount' => 3,//n件n折类型:1:第二件半件2:买1送1 3:自定义
|
|
'discount' => 0,//优惠
|
|
'give_integral' => 0,//赠送积分
|
|
'give_coupon_id' => [],//赠送优惠券ID
|
|
'give_product_id' => [],//赠送商品ID
|
|
];
|
|
|
|
/**
|
|
* StorePromotionsServices constructor.
|
|
* @param StorePromotionsDao $dao
|
|
*/
|
|
public function __construct(StorePromotionsDao $dao)
|
|
{
|
|
$this->dao = $dao;
|
|
}
|
|
|
|
/**
|
|
* 获取打折折扣 || 优惠折扣
|
|
* @param $num
|
|
* @param int $unit
|
|
* @param int $type 1:打折折扣 2:优惠折扣
|
|
* @return float
|
|
*/
|
|
public function computedDiscount($num, int $unit = 100, int $type = 1)
|
|
{
|
|
if ((float)$num < 0) {
|
|
$num = 0;
|
|
} elseif ((float)$num > 100) {
|
|
$num = 100;
|
|
}
|
|
$discount = bcdiv((string)$num, (string)$unit, 2);
|
|
if ($type == 2) {//优惠折扣 打9折扣优惠就是1折
|
|
$discount = bcsub('1', (string)$discount, 2);
|
|
}
|
|
return (float)$discount;
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取优惠活动标题,内容详情
|
|
* @param int $type
|
|
* @param int $promotions_cate
|
|
* @param array $promotions
|
|
* @return array
|
|
*/
|
|
public function getPromotionsDesc(int $type, int $promotions_cate, array $promotions)
|
|
{
|
|
$title = '';
|
|
$desc = [];
|
|
if ($promotions) {
|
|
switch ($type) {
|
|
case 1:
|
|
$title = '限时折扣';
|
|
$base = '限时打' . $this->computedDiscount($promotions[0]['discount'] ?? 0, 10) . '折';
|
|
if (isset($promotions['is_limit']) && isset($promotions['limit_num']) && (int)$promotions['is_limit'] && (int)$promotions['limit_num']) {
|
|
$base .= ',每人限购' . (int)$promotions['limit_num'] . '件';
|
|
}
|
|
$desc[] = $base;
|
|
break;
|
|
case 2:
|
|
switch ($promotions[0]['n_piece_n_discount'] ?? 3) {
|
|
case 1:
|
|
$title = '第二件半价';
|
|
break;
|
|
case 2:
|
|
$title = '买1送1';
|
|
break;
|
|
case 3:
|
|
$title = '第' . floatval($promotions[0]['threshold'] ?? 0) . '件' . $this->computedDiscount($promotions[0]['discount'] ?? 0, 10) . '折';
|
|
break;
|
|
}
|
|
$desc[] = '买' . floatval($promotions[0]['threshold'] ?? 0) . '件商品,其中一件享' . $this->computedDiscount($promotions[0]['discount'] ?? 0, 10) . '折优惠';
|
|
break;
|
|
case 3:
|
|
$title = '满减满折';
|
|
foreach ($promotions as $p) {
|
|
if ($promotions_cate == 2) {
|
|
$give = '每满' . floatval($p['threshold'] ?? 0);
|
|
} else {
|
|
$give = '满' . floatval($p['threshold'] ?? 0);
|
|
}
|
|
$give .= $p['threshold_type'] == 1 ? '元' : '件';
|
|
$give .= $p['discount_type'] == 1 ? ('减' . floatval($p['discount'] ?? 0) . '元') : '打' . $this->computedDiscount($p['discount'] ?? 0, 10) . '折';
|
|
$desc[] = $give;
|
|
}
|
|
break;
|
|
case 4:
|
|
$title = '满送活动';
|
|
foreach ($promotions as $p) {
|
|
if ($promotions_cate == 2) {
|
|
$base = '每满' . floatval($p['threshold'] ?? 0);
|
|
} else {
|
|
$base = '满' . floatval($p['threshold'] ?? 0);
|
|
}
|
|
$base .= $p['threshold_type'] == 1 ? '元送' : '件送';
|
|
if ($p['give_integral']) {
|
|
$desc[] = $base . floatval($p['give_integral'] ?? 0) . '积分';
|
|
}
|
|
if ($p['give_coupon_id']) {
|
|
$desc[] = $base . '优惠券';
|
|
}
|
|
if ($p['give_product_id']) {
|
|
$desc[] = $base . '赠品';
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return [$title, $desc];
|
|
}
|
|
|
|
/**
|
|
* 返回目前进行中的活动ids
|
|
* @param array $promotions_type
|
|
* @param string $field
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getAllShowActivityIds(array $promotions_type = [], string $field = 'id')
|
|
{
|
|
$where = ['type' => 1, 'store_id' => 0, 'pid' => 0, 'is_del' => 0, 'status' => 1, 'promotionsTime' => true];
|
|
if ($promotions_type) $where['promotions_type'] = $promotions_type;
|
|
$promotions = $this->dao->getList($where, $field);
|
|
$ids = [];
|
|
if ($promotions) {
|
|
if ($field == 'id') {
|
|
$ids = array_column($promotions, 'id');
|
|
} else {
|
|
$ids = $promotions;
|
|
}
|
|
}
|
|
return $ids;
|
|
}
|
|
|
|
/**
|
|
* 获取商品所属活动
|
|
* @param array $productIds
|
|
* @param array $promotions_type
|
|
* @param string $field
|
|
* @param array $with
|
|
* @param string $group
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getProductsPromotions(array $productIds, array $promotions_type = [], string $field = '*', array $with = [], string $group = '', int $store_id = 0)
|
|
{
|
|
if (!$productIds) {
|
|
return [[], []];
|
|
}
|
|
$promotionsIds = $this->getAllShowActivityIds($promotions_type, 'id,promotions_type,product_partake_type,applicable_type,applicable_store_id');
|
|
if (!$promotionsIds) {
|
|
return [[], []];
|
|
}
|
|
$ids = [];
|
|
$productArr = [];
|
|
/** @var StoreProductRelationServices $productRelationServices */
|
|
$productRelationServices = app()->make(StoreProductRelationServices::class);
|
|
foreach ($productIds as $productId) {
|
|
$productArr[$productId] = $productRelationServices->getProductRelationCache((int)$productId, [2, 3]);
|
|
}
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$preType = [];
|
|
foreach ($promotionsIds as $info) {
|
|
$pid = (int)$info['id'];
|
|
$applicable_store_id = is_array($info['applicable_store_id']) ? $info['applicable_store_id'] : explode(',', $info['applicable_store_id']);
|
|
//活动不适用该门店
|
|
if ($store_id && ($info['applicable_type'] == 0 || ($info['applicable_type'] == 2 && !in_array($store_id, $applicable_store_id)))) {
|
|
continue;
|
|
}
|
|
if ($group && in_array($info['promotions_type'], $preType)) {
|
|
continue;
|
|
}
|
|
if ($info['product_partake_type'] == 1) {//所有商品
|
|
$ids[] = $pid;
|
|
$preType[] = $info['promotions_type'];
|
|
} else {
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($pid);
|
|
if ($info['product_partake_type'] == 2) {
|
|
if (array_intersect($promotionsAuxiliaryData, $productIds)) {
|
|
$ids[] = $pid;
|
|
$preType[] = $info['promotions_type'];
|
|
}
|
|
} else {
|
|
foreach ($productArr as $productInfo) {
|
|
$data = [];
|
|
switch ($info['product_partake_type']) {
|
|
case 4://品牌
|
|
$data = $productInfo[2] ?? [];
|
|
break;
|
|
case 5://商品标签
|
|
$data = $productInfo[3] ?? [];
|
|
break;
|
|
}
|
|
if (array_intersect($promotionsAuxiliaryData, $data)) {//一个商品满足活动
|
|
$ids[] = $pid;
|
|
$preType[] = $info['promotions_type'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
$ids = array_unique($ids);
|
|
$result = [];
|
|
if ($ids) {
|
|
$order = 'promotions_type asc,update_time desc';
|
|
$promotions = $this->dao->getList(['ids' => $ids], $field, 0, 0, $with, $order);
|
|
if ($promotions) {
|
|
$data = $this->promotionsData;
|
|
$data['giveCoupon'] = [];
|
|
$data['giveProducts'] = [];
|
|
foreach ($promotions as &$item) {
|
|
if (!isset($item['promotions'])) {
|
|
$item['promotions'] = [];
|
|
}
|
|
$first = array_merge($data, array_intersect_key($item, $data));
|
|
array_unshift($item['promotions'], $first);
|
|
$item['promotions'] = $this->handelPromotions($item['promotions']);
|
|
$result[] = $item;
|
|
}
|
|
}
|
|
}
|
|
return [$result, $productArr];
|
|
}
|
|
|
|
/**
|
|
* 获取商品所有优惠活动 所属活动详情
|
|
* @param array $productIds
|
|
* @param string $field
|
|
* @param array $with
|
|
* @param array $promotions_type
|
|
* @param string $group
|
|
* @param int $store_id
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getProductsPromotionsDetail(array $productIds, string $field = '*', array $with = [], array $promotions_type = [], string $group = '', int $store_id = 0)
|
|
{
|
|
$productDetails = [];
|
|
$promotionsDetails = [];
|
|
$promotions = [];
|
|
if ($productIds) {
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
$newProductIds = $productServices->getColumn([['id', 'in', $productIds]], 'id,pid,type,relation_id', 'id');
|
|
//处理门店商品活动
|
|
$newIds = [];
|
|
if ($newProductIds) {
|
|
foreach ($newProductIds as $item) {
|
|
//门店自营商品 不参与活动
|
|
if ($item['type'] == 1) {
|
|
if ($item['pid']) {//平台共享到门店商品
|
|
$newIds[] = $item['pid'];
|
|
}
|
|
} else {
|
|
$newIds[] = $item['id'];
|
|
}
|
|
}
|
|
}
|
|
[$promotions, $productRelation] = $this->getProductsPromotions($newIds, $promotions_type, $field, $with, $group);
|
|
if ($promotions) {
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
foreach ($promotions as $info) {
|
|
$id = (int)$info['id'];
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($id);
|
|
$applicable_store_id = $info['applicable_store_id'] ? (is_string($info['applicable_store_id']) ? explode(',', $info['applicable_store_id']) : $info['applicable_store_id']) : [];
|
|
foreach ($productIds as $productId) {
|
|
$newProductId = $productId;
|
|
$detail = $newProductIds[$productId] ?? [];
|
|
if (!$detail) continue;
|
|
if ($detail['type'] == 1) {//门店商品
|
|
if ($detail['pid']) {//平台共享到门店商品
|
|
$newProductId = $detail['pid'];
|
|
} else {//门店自营商品 不参与活动
|
|
continue;
|
|
}
|
|
$product_store_id = $detail['relation_id'];
|
|
} else {//平台、供应商商品 存在在门店购买情况 需要验证
|
|
$product_store_id = $store_id;
|
|
}
|
|
//活动不适用该门店
|
|
if ($product_store_id && ($info['applicable_type'] == 0 || ($info['applicable_type'] == 2 && !in_array($product_store_id, $applicable_store_id)))) {
|
|
continue;
|
|
}
|
|
$products = $info['products'] ?? [];
|
|
$pIds = $products ? array_unique(array_column($products, 'product_id')) : [];
|
|
switch ($info['product_partake_type']) {
|
|
case 1://全部商品
|
|
$productDetails[$productId][] = $id;
|
|
$promotionsDetails[$id][] = $productId;
|
|
break;
|
|
case 2://选中商品参与
|
|
if (in_array($newProductId, $pIds)) {
|
|
$productDetails[$productId][] = $id;
|
|
$promotionsDetails[$id][] = $productId;
|
|
}
|
|
break;
|
|
case 3://选中商品不参与
|
|
$products = $info['products'] ?? [];
|
|
if ($products) $products = array_combine(array_column($products, 'product_id'), $products);
|
|
if (!in_array($newProductId, $pIds) || (isset($products[$newProductId]['is_all']) && $products[$newProductId]['is_all'] == 0)) {
|
|
$productDetails[$productId][] = $id;
|
|
$promotionsDetails[$id][] = $productId;
|
|
}
|
|
break;
|
|
case 4://品牌
|
|
$data = $productRelation[$newProductId][2] ?? [];
|
|
if (array_intersect($promotionsAuxiliaryData, $data)) {//一个商品满足活动
|
|
$productDetails[$productId][] = $id;
|
|
$promotionsDetails[$id][] = $productId;
|
|
}
|
|
break;
|
|
case 5://商品标签
|
|
$data = $productRelation[$newProductId][3] ?? [];
|
|
if (array_intersect($promotionsAuxiliaryData, $data)) {//一个商品满足活动
|
|
$productDetails[$productId][] = $id;
|
|
$promotionsDetails[$id][] = $productId;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return [$promotions, $productDetails, $promotionsDetails];
|
|
}
|
|
|
|
/**
|
|
* 检测活动内容,格式数据
|
|
* @param int $type
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
public function checkPromotions(int $type, array $data)
|
|
{
|
|
if (!$data) {
|
|
throw new AdminException('请添加活动优惠内容');
|
|
}
|
|
$data = array_merge($this->promotionsData, array_intersect_key($data, $this->promotionsData));
|
|
switch ($type) {
|
|
case 1:
|
|
case 2:
|
|
$data['promotions_cate'] = 1;
|
|
$data['discount_type'] = 2;
|
|
$data['give_coupon_id'] = $data['give_product_id'] = [];
|
|
if ($type == 2) {
|
|
$data['threshold_type'] = 2;
|
|
if (!$data['threshold']) {
|
|
throw new AdminException('请输入打折门槛');
|
|
}
|
|
}
|
|
if ($data['discount'] === '') {
|
|
throw new AdminException('请添加折扣');
|
|
}
|
|
if ($data['discount'] < 0 || $data['discount'] > 100) {
|
|
throw new AdminException('折扣必须为0~99数字');
|
|
}
|
|
break;
|
|
case 3:
|
|
$data['give_coupon_id'] = $data['give_product_id'] = [];
|
|
if (!$data['threshold']) {
|
|
throw new AdminException('请输入优惠门槛');
|
|
}
|
|
if ($data['discount'] === '') {
|
|
throw new AdminException($data['discount_type'] == 1 ? '请输入优惠金额' : '请输入打折折扣');
|
|
}
|
|
if ($data['discount_type'] == 2 && ($data['discount'] < 0 || $data['discount'] > 100)) {
|
|
throw new AdminException('折扣必须为0~99数字');
|
|
}
|
|
break;
|
|
case 4:
|
|
if (!$data['threshold']) {
|
|
throw new AdminException('请输入优惠门槛');
|
|
}
|
|
if (!$data['give_integral'] && !$data['give_coupon_id'] && !$data['give_product_id']) {
|
|
throw new AdminException('请至少选择一项赠送内容');
|
|
}
|
|
if ($data['give_coupon_id']) {
|
|
$couponsIds = array_column($data['give_coupon_id'], 'give_coupon_id');
|
|
$giveCoupon = array_combine($couponsIds, $data['give_coupon_id']);
|
|
/** @var StoreCouponIssueServices $storeCouponServices */
|
|
$storeCouponServices = app()->make(StoreCouponIssueServices::class);
|
|
$coupons = $storeCouponServices->getValidGiveCoupons($couponsIds, 'id,is_permanent,remain_count');
|
|
if (!$coupons || count($coupons) != count($couponsIds)) {
|
|
throw new AdminException('优惠券已失效请重新选择');
|
|
}
|
|
foreach ($coupons as $coupon) {
|
|
if (!isset($giveCoupon[$coupon['id']]['give_coupon_num']) || !$giveCoupon[$coupon['id']]['give_coupon_num']) {
|
|
throw new AdminException('请输入赠送优惠券数量');
|
|
}
|
|
if ($coupon['is_permanent'] == 0 && $coupon['remain_count'] < $giveCoupon[$coupon['id']]['give_coupon_num']) {
|
|
throw new AdminException('赠送优惠券数量不能超出优惠券限量');
|
|
}
|
|
}
|
|
}
|
|
if ($data['give_product_id']) {
|
|
$productIds = array_column($data['give_product_id'], 'give_product_id');
|
|
$giveProduct = array_combine($productIds, $data['give_product_id']);
|
|
/** @var StoreProductServices $storeProductServices */
|
|
$storeProductServices = app()->make(StoreProductServices::class);
|
|
$products = $storeProductServices->getSearchList(['ids' => $productIds], 0, 0, ['id,stock']);
|
|
if (!$products || count($products) != count(array_unique($productIds))) {
|
|
throw new AdminException('商品已失效请重新选择');
|
|
}
|
|
foreach ($products as $product) {
|
|
if (!isset($giveProduct[$product['id']]['give_product_num']) || !$giveProduct[$product['id']]['give_product_num']) {
|
|
throw new AdminException('请输入赠送商品数量');
|
|
}
|
|
if ($product['stock'] < $giveProduct[$product['id']]['give_product_num']) {
|
|
throw new AdminException('赠送商品数量不能超出商品库存');
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
throw new AdminException('暂不支持该类型优惠活动');
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
/**获取门店适用的活动
|
|
* @param $where
|
|
* @param $storeId
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getgetPromotionListInfo($where, $storeId)
|
|
{
|
|
$list = $this->dao->getList($where);
|
|
$listInfo = [];
|
|
foreach ($list as $key => &$info) {
|
|
if ($info['applicable_type'] == 2) {
|
|
$store_ids = is_array($info['applicable_store_id']) ? $info['applicable_store_id'] : explode(',', $info['applicable_store_id']);
|
|
if (!in_array($storeId, $store_ids)) continue;
|
|
}
|
|
if ($info['start_time'])
|
|
$start_time = $info['promotions_type'] == 1 ? date('Y-m-d H:i', (int)$info['start_time']) : date('Y-m-d', (int)$info['start_time']);
|
|
if ($info['stop_time'])
|
|
$stop_time = $info['promotions_type'] == 1 ? date('Y-m-d H:i', (int)$info['stop_time']) : date('Y-m-d', (int)$info['stop_time']);
|
|
if (isset($start_time) && isset($stop_time))
|
|
$info['section_time'] = [$start_time, $stop_time];
|
|
else
|
|
$info['section_time'] = [];
|
|
unset($info['start_time'], $info['stop_time']);
|
|
$info['is_label'] = $info['label_id'] ? 1 : 0;
|
|
|
|
$info['threshold'] = floatval($info['threshold']);
|
|
$info['discount'] = floatval($info['discount']);
|
|
$info['give_integral'] = intval($info['give_integral']);
|
|
$info['is_overlay'] = $info['overlay'] ? 1 : 0;
|
|
$info['promotions'] = $info['promotions'] ?? [];
|
|
$data = $this->promotionsData;
|
|
$first = array_merge($data, array_intersect_key($info, $data));
|
|
array_unshift($info['promotions'], $first);
|
|
|
|
$info['promotions'] = $this->handelPromotions($info['promotions']);
|
|
$listInfo[] = $info;
|
|
}
|
|
return $listInfo;
|
|
}
|
|
|
|
/**
|
|
* 获取列表
|
|
* @param array $where
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function systemPage(array $where)
|
|
{
|
|
[$page, $limit] = $this->getPageValue();
|
|
$list = $this->dao->getList($where, '*', $page, $limit, ['giveProducts' => function ($query) {
|
|
$query->field('promotions_id,product_id,limit_num,surplus_num')->with(['productInfo' => function ($query) {
|
|
$query->field('id,store_name');
|
|
}]);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('promotions_id,coupon_id,limit_num,surplus_num')->with(['coupon' => function ($query) {
|
|
$query->field('id,type,coupon_type,coupon_title,coupon_price,use_min_price');
|
|
}]);
|
|
}, 'promotions' => function ($query) {
|
|
$query->field('id,pid,promotions_type,promotions_cate,threshold_type,threshold,discount_type,n_piece_n_discount,discount,give_integral,give_coupon_id,give_product_id,give_product_unique')->with(['giveProducts' => function ($query) {
|
|
$query->field('promotions_id, product_id,limit_num,surplus_num')->with(['productInfo' => function ($query) {
|
|
$query->field('id,store_name');
|
|
}]);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('promotions_id, coupon_id,limit_num,surplus_num')->with(['coupon' => function ($query) {
|
|
$query->field('id,type,coupon_type,coupon_title,coupon_price,use_min_price');
|
|
}]);
|
|
}]);
|
|
}]);
|
|
$count = 0;
|
|
if ($list) {
|
|
$count = $this->dao->count($where);
|
|
$data = $this->promotionsData;
|
|
$data['giveCoupon'] = [];
|
|
$data['giveProducts'] = [];
|
|
/** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
/** @var StoreOrderServices $storeOrderServices */
|
|
$storeOrderServices = app()->make(StoreOrderServices::class);
|
|
/** @var StoreProductServices $storeProductServices */
|
|
$storeProductServices = app()->make(StoreProductServices::class);
|
|
/** @var StoreProductRelationServices $storeProductRelationServices */
|
|
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$getPromotions = function ($cartList, $oids) {
|
|
$promotionsPrice = 0;
|
|
$uids = [];
|
|
$oldUids = [];
|
|
$ids = [];
|
|
foreach ($cartList as $key => $cart) {
|
|
if (!in_array($cart['oid'], $oids)) continue;
|
|
$info = is_string($cart['cart_info']) ? json_decode($cart['cart_info'], true) : $cart['cart_info'];
|
|
$promotionsPrice = bcadd((string)$promotionsPrice, (string)bcmul((string)($info['promotions_true_price'] ?? 0), (string)$info['cart_num'], 2), 2);
|
|
if (!in_array($cart['oid'], $ids)) {
|
|
$ids[] = $cart['oid'];
|
|
if (!in_array($cart['uid'], $uids)) {
|
|
$uids[] = $cart['uid'];
|
|
} else {
|
|
$oldUids[] = $cart['uid'];
|
|
}
|
|
}
|
|
}
|
|
return [$promotionsPrice, $uids, $oldUids];
|
|
};
|
|
foreach ($list as &$item) {
|
|
if ($item['status']) {
|
|
if ($item['start_time'] > time())
|
|
$item['start_name'] = '未开始';
|
|
else if (bcadd((string)$item['stop_time'], '86400') < time())
|
|
$item['start_name'] = '已结束';
|
|
else if (bcadd((string)$item['stop_time'], '86400') > time() && $item['start_time'] < time()) {
|
|
$item['start_name'] = '进行中';
|
|
}
|
|
} else $item['start_name'] = '已结束';
|
|
$end_time = $item['stop_time'] ? date('Y/m/d', (int)$item['stop_time']) : '';
|
|
$item['_stop_time'] = $end_time;
|
|
$item['stop_status'] = $item['stop_time'] + 86400 < time() ? 1 : 0;
|
|
|
|
$item['sum_pay_price'] = 0.00;
|
|
$item['sum_promotions_price'] = 0.00;
|
|
$item['sum_order'] = 0;
|
|
$item['sum_user'] = 0;
|
|
$item['old_user'] = 0;
|
|
$item['new_user'] = 0;
|
|
$pids = array_merge([$item['id']], array_column($item['promotions'], 'id'));
|
|
$cartInfos = $storeOrderCartInfoServices->getColumn(['promotions_id' => $pids], 'oid,uid,cart_info', 'id', true);
|
|
if ($cartInfos) {
|
|
$oids = $storeOrderServices->getColumn(['id' => array_unique(array_column($cartInfos, 'oid')), 'is_del' => 0, 'pid' => 0, 'is_system_del' => 0, 'refund_status' => [0, 3]], 'id', '');
|
|
$item['sum_pay_price'] = $storeOrderServices->sum(['id' => $oids, 'is_del' => 0, 'pid' => 0, 'is_system_del' => 0, 'refund_status' => [0, 3]], 'pay_price', true);
|
|
[$promotionsPrice, $uids, $oldUids] = $getPromotions($cartInfos, $oids);
|
|
$item['sum_promotions_price'] = $promotionsPrice;
|
|
$item['sum_order'] = $storeOrderServices->count(['id' => $oids, 'is_del' => 0, 'pid' => 0, 'is_system_del' => 0, 'refund_status' => [0, 3]]);
|
|
$item['sum_user'] = count($uids);
|
|
$item['old_user'] = count(array_unique($oldUids));
|
|
$item['new_user'] = bcsub((string)$item['sum_user'], (string)$item['old_user'], 0);
|
|
}
|
|
|
|
$first = array_merge($data, array_intersect_key($item, $data));
|
|
array_unshift($item['promotions'], $first);
|
|
$item['promotions'] = $this->handelPromotions($item['promotions']);
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($item['id']);
|
|
switch ($item['product_partake_type']) {
|
|
case 1://所有商品
|
|
$item['product_count'] = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'type' => [0, 2], 'is_verify' => 1]);
|
|
break;
|
|
case 2://选中商品参与
|
|
$product_ids = $promotionsAuxiliaryData;
|
|
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'is_verify' => 1]) : 0;
|
|
break;
|
|
case 3:
|
|
$item['product_count'] = 0;
|
|
break;
|
|
case 4://品牌
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'type' => [0, 2], 'is_verify' => 1]) : 0;
|
|
break;
|
|
case 5://商品标签
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$item['product_count'] = $product_ids ? $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $product_ids, 'type' => [0, 2], 'is_verify' => 1]) : 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return compact('list', 'count');
|
|
}
|
|
|
|
/**
|
|
* 获取信息
|
|
* @param int $id
|
|
* @return array|\think\Model|null
|
|
* @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, ['*'], ['products' => function ($query) {
|
|
$query->field('promotions_id,product_id,unique')->with(['productInfo', 'attrValue']);
|
|
}, 'brands' => function ($query) {
|
|
$query->field('promotions_id,brand_id')->with(['brandInfo' => function ($q) {
|
|
$q->field('id,brand_name');
|
|
}]);
|
|
}, 'productLabels' => function ($query) {
|
|
$query->field('promotions_id,store_label_id')->with(['productLabelInfo' => function ($q) {
|
|
$q->field('id,label_name');
|
|
}]);
|
|
}, 'giveProducts' => function ($query) {
|
|
$query->field('type,promotions_id,product_id,limit_num,unique')->with(['productInfo' => function ($q) {
|
|
$q->field('id,store_name');
|
|
}, 'giveAttrValue']);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('type,promotions_id,coupon_id,limit_num')->with(['coupon']);
|
|
}, 'promotions' => function ($query) {
|
|
$query->field('id,pid,promotions_type,promotions_cate,threshold_type,threshold,discount_type,n_piece_n_discount,discount,give_integral,give_coupon_id,give_product_id,give_product_unique')->with(['giveProducts' => function ($query) {
|
|
$query->field('type,promotions_id, product_id,limit_num,unique')->with(['productInfo' => function ($q) {
|
|
$q->field('id,store_name');
|
|
}, 'giveAttrValue']);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('type,promotions_id, coupon_id,limit_num')->with(['coupon']);
|
|
}]);
|
|
}]);
|
|
if (!$info) {
|
|
throw new AdminException('数据不存在');
|
|
}
|
|
$info = $info->toArray();
|
|
if ($info['start_time'])
|
|
$start_time = $info['promotions_type'] == 1 ? date('Y-m-d H:i', (int)$info['start_time']) : date('Y-m-d', (int)$info['start_time']);
|
|
if ($info['stop_time'])
|
|
$stop_time = $info['promotions_type'] == 1 ? date('Y-m-d H:i', (int)$info['stop_time']) : date('Y-m-d', (int)$info['stop_time']);
|
|
if (isset($start_time) && isset($stop_time))
|
|
$info['section_time'] = [$start_time, $stop_time];
|
|
else
|
|
$info['section_time'] = [];
|
|
unset($info['start_time'], $info['stop_time']);
|
|
$info['is_label'] = $info['label_id'] ? 1 : 0;
|
|
if ($info['is_label']) {
|
|
$label_id = is_array($info['label_id']) ? $info['label_id'] : explode(',', $info['label_id']);
|
|
/** @var UserLabelServices $userLabelServices */
|
|
$userLabelServices = app()->make(UserLabelServices::class);
|
|
$info['label_id'] = $userLabelServices->getLabelList(['ids' => $label_id], ['id', 'label_name']);
|
|
} else {
|
|
$info['label_id'] = [];
|
|
}
|
|
|
|
$info['threshold'] = floatval($info['threshold']);
|
|
$info['discount'] = floatval($info['discount']);
|
|
$info['give_integral'] = intval($info['give_integral']);
|
|
$info['is_overlay'] = $info['overlay'] ? 1 : 0;
|
|
$info['promotions'] = $info['promotions'] ?? [];
|
|
$info['products'] = $info['products'] ?? [];
|
|
$info['giveCoupon'] = $info['giveCoupon'] ?? [];
|
|
$info['giveProducts'] = $info['giveProducts'] ?? [];
|
|
if ($info['products']) {
|
|
/** @var StoreProductLabelServices $storeProductLabelServices */
|
|
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
|
$products = [];
|
|
foreach ($info['products'] as &$item) {
|
|
$product = is_object($item) ? $item->toArray() : $item;
|
|
$product = array_merge($product, $product['productInfo'] ?? []);
|
|
$product['store_label'] = '';
|
|
if (isset($product['store_label_id']) && $product['store_label_id']) {
|
|
$storeLabelList = $storeProductLabelServices->getColumn([['relation_id', '=', 0], ['type', '=', 0], ['id', 'IN', $product['store_label_id']]], 'id,label_name');
|
|
$product['store_label'] = $storeLabelList ? implode(',', array_column($storeLabelList, 'label_name')) : '';
|
|
}
|
|
$unique = is_string($product['unique']) ? explode(',', $product['unique']) : $product['unique'];
|
|
foreach ($product['attrValue'] as $key => $value) {
|
|
if (!in_array($value['unique'], $unique)) {
|
|
unset($product['attrValue'][$key]);
|
|
}
|
|
}
|
|
$product['attrValue'] = array_merge($product['attrValue']);
|
|
unset($product['productInfo']);
|
|
$products[] = $product;
|
|
}
|
|
if ($products) {
|
|
$cateIds = implode(',', array_column($products, 'cate_id'));
|
|
/** @var StoreProductCategoryServices $categoryService */
|
|
$categoryService = app()->make(StoreProductCategoryServices::class);
|
|
$cateList = $categoryService->getCateParentAndChildName($cateIds);
|
|
foreach ($products as $key => &$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) : '';
|
|
}
|
|
}
|
|
foreach ($item['attrValue'] as $key => &$value) {
|
|
$value['store_label'] = $item['store_label'] ?? '';
|
|
$value['cate_name'] = $item['cate_name'] ?? '';
|
|
}
|
|
}
|
|
}
|
|
|
|
unset($info['products']);
|
|
$info['products'] = $products;
|
|
}
|
|
$data = $this->promotionsData;
|
|
$data['giveCoupon'] = [];
|
|
$data['giveProducts'] = [];
|
|
$first = array_merge($data, array_intersect_key($info, $data));
|
|
array_unshift($info['promotions'], $first);
|
|
|
|
$info['promotions'] = $this->handelPromotions($info['promotions']);
|
|
$info['brand_id'] = isset($info['brands']) && $info['brands'] ? array_column($info['brands'], 'brand_id') : [];
|
|
$info['store_label_id'] = [];
|
|
if (isset($info['productLabels']) && $info['productLabels']) {
|
|
foreach ($info['productLabels'] as $label) {
|
|
if (isset($label['productLabelInfo']) && $label['productLabelInfo']) {
|
|
$info['store_label_id'][] = $label['productLabelInfo'];
|
|
}
|
|
}
|
|
}
|
|
//适用门店
|
|
$info['stores'] = [];
|
|
if (isset($info['applicable_type']) && ($info['applicable_type'] == 1 || ($info['applicable_type'] == 2 && isset($info['applicable_store_id']) && $info['applicable_store_id']))) {//查询门店信息
|
|
$where = ['is_del' => 0];
|
|
if ($info['applicable_type'] == 2) {
|
|
$store_ids = is_array($info['applicable_store_id']) ? $info['applicable_store_id'] : explode(',', $info['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']);
|
|
$info['stores'] = $storeData['list'] ?? [];
|
|
}
|
|
unset($info['brands'], $info['productLabels']);
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* 处理阶梯优惠赠送商品、优惠券
|
|
* @param array $promotions
|
|
* @return array
|
|
*/
|
|
public function handelPromotions(array $promotions)
|
|
{
|
|
if ($promotions) {
|
|
foreach ($promotions as &$p) {
|
|
$p['threshold'] = (float)$p['threshold'];
|
|
$p['discount'] = (float)$p['discount'];
|
|
if (isset($p['giveCoupon']) && $p['giveCoupon']) {
|
|
$coupons = [];
|
|
foreach ($p['giveCoupon'] as &$coupon) {
|
|
$coupon = is_object($coupon) ? $coupon->toArray() : $coupon;
|
|
$coupon = array_merge($coupon, $coupon['coupon'] ?? []);
|
|
unset($coupon['coupon']);
|
|
$coupons[] = $coupon;
|
|
}
|
|
unset($p['giveCoupon']);
|
|
$p['giveCoupon'] = $coupons;
|
|
}
|
|
if (isset($p['giveProducts']) && $p['giveProducts']) {
|
|
$products = [];
|
|
foreach ($p['giveProducts'] as &$product) {
|
|
$product = is_object($product) ? $product->toArray() : $product;
|
|
$product = array_merge($product, $product['productInfo'] ?? []);
|
|
$product = array_merge($product, $product['giveAttrValue'] ?? []);
|
|
unset($product['productInfo'], $product['giveAttrValue']);
|
|
$products[] = $product;
|
|
}
|
|
unset($p['giveProducts']);
|
|
$p['giveProducts'] = $products;
|
|
}
|
|
}
|
|
}
|
|
return $promotions;
|
|
}
|
|
|
|
/**
|
|
* 保存促销活动
|
|
* @param int $id
|
|
* @param array $data
|
|
* @return bool
|
|
*/
|
|
public function saveData(int $id, array $data)
|
|
{
|
|
if (!$data['section_time'] || count($data['section_time']) != 2) {
|
|
throw new AdminException('请选择活动时间');
|
|
}
|
|
[$start_time, $end_time] = $data['section_time'];
|
|
if (strtotime($end_time) < time()) {
|
|
throw new AdminException('活动结束时间不能小于当前时间');
|
|
}
|
|
if ($id) {
|
|
$info = $this->dao->get((int)$id);
|
|
if (!$info) {
|
|
throw new AdminException('数据不存在');
|
|
}
|
|
}
|
|
$data['start_time'] = strtotime($start_time);
|
|
$data['stop_time'] = $data['promotions_type'] == 1 ? strtotime($end_time) : strtotime($end_time) + 86399;
|
|
$data['label_id'] = $data['label_id'] ? implode(',', $data['label_id']) : '';
|
|
$data['overlay'] = $data['overlay'] ? implode(',', $data['overlay']) : '';
|
|
$promotionsAuxiliaryData = [];
|
|
switch ($data['product_partake_type']) {
|
|
case 1://全部
|
|
$data['product_id'] = [];
|
|
break;
|
|
case 2://指定ID参与
|
|
case 3://指定ID不参与
|
|
$promotionsAuxiliaryData = $productData = $data['product_id'];
|
|
$productIds = $productData ? array_column($productData, 'product_id') : [];
|
|
$data['product_id'] = $productIds ? implode(',', $productIds) : '';
|
|
/** @var StoreProductServices $storeProductServices */
|
|
$storeProductServices = app()->make(StoreProductServices::class);
|
|
$count = $storeProductServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $productIds]);
|
|
$productCount = count(array_unique($productIds));
|
|
if ($count != $productCount) {
|
|
throw new AdminException('选择商品中有已下架或移入回收站');
|
|
}
|
|
break;
|
|
case 4://指定品牌
|
|
$data['brand_id'] = array_unique($data['brand_id']);
|
|
/** @var StoreBrandServices $storeBrandServices */
|
|
$storeBrandServices = app()->make(StoreBrandServices::class);
|
|
$brandCount = $storeBrandServices->count(['is_show' => 1, 'is_del' => 0, 'id' => $data['brand_id']]);
|
|
if (count(array_unique($data['brand_id'])) != $brandCount) {
|
|
throw new AdminException('选择商品品牌中有已下架或删除的');
|
|
}
|
|
$promotionsAuxiliaryData['brand_id'] = $data['brand_id'];
|
|
break;
|
|
case 5://指定商品标签
|
|
$data['store_label_id'] = array_unique($data['store_label_id']);
|
|
/** @var StoreProductLabelServices $storeProductLabelServices */
|
|
$storeProductLabelServices = app()->make(StoreProductLabelServices::class);
|
|
$labelCount = $storeProductLabelServices->count(['id' => $data['store_label_id']]);
|
|
if (count(array_unique($data['store_label_id'])) != $labelCount) {
|
|
throw new ValidateException('选择商品标签中有已下架或删除的');
|
|
}
|
|
$promotionsAuxiliaryData['store_label_id'] = $data['store_label_id'];
|
|
break;
|
|
default:
|
|
throw new ValidateException('暂不支持该类型商品');
|
|
break;
|
|
}
|
|
|
|
$promotions = $data['promotions'];
|
|
$threshold = -1;
|
|
foreach ($promotions as &$value) {
|
|
if ($threshold != -1 && $value['threshold'] <= $threshold) {
|
|
throw new AdminException('优惠门槛只能递增(例如二级必须大于一级优惠)');
|
|
}
|
|
$threshold = $value['threshold'];
|
|
$value = $this->checkPromotions((int)$data['promotions_type'], $value);
|
|
$value['threshold_type'] = $data['threshold_type'];
|
|
}
|
|
[$title, $desc] = $this->getPromotionsDesc((int)$data['promotions_type'], (int)$data['promotions_cate'], $data['promotions_type'] == 1 ? array_merge($promotions, ['is_limit' => $data['is_limit'], 'limit_num' => $data['limit_num']]) : $promotions);
|
|
$data['title'] = $title;
|
|
$data['desc'] = implode(',', $desc);
|
|
|
|
$first = array_shift($promotions);
|
|
$giveCoupon = $first['give_coupon_id'] ?? [];
|
|
$giveProduct = $first['give_product_id'] ?? [];
|
|
unset($first['give_coupon_id'], $first['give_product_id']);
|
|
$first['give_coupon_id'] = $giveCoupon ? implode(',', array_unique(array_column($giveCoupon, 'give_coupon_id'))) : '';
|
|
$first['give_product_id'] = $giveProduct ? implode(',', array_unique(array_column($giveProduct, 'give_product_id'))) : '';
|
|
$first['give_product_unique'] = $giveProduct ? implode(',', array_unique(array_column($giveProduct, 'unique'))) : '';
|
|
$data = array_merge($data, $first);
|
|
|
|
unset($data['section_time'], $data['promotions']);
|
|
$this->transaction(function () use ($id, $data, $promotions, $promotionsAuxiliaryData, $giveCoupon, $giveProduct) {
|
|
$time = time();
|
|
$data['update_time'] = $time;
|
|
if ($id) {
|
|
$this->dao->update($id, $data);
|
|
//删除之前阶梯数据
|
|
$this->dao->delete(['pid' => $id]);
|
|
} else {
|
|
$data['add_time'] = $time;
|
|
$res = $this->dao->save($data);
|
|
$id = $res->id;
|
|
}
|
|
/** @var StorePromotionsAuxiliaryServices $storePromotionsAuxiliaryServices */
|
|
$storePromotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$storePromotionsAuxiliaryServices->savePromotionsRelation((int)$id, (int)$data['product_partake_type'], $promotionsAuxiliaryData, $giveCoupon, $giveProduct);
|
|
|
|
if ($promotions) {
|
|
foreach ($promotions as $item) {
|
|
$giveCoupon = $item['give_coupon_id'] ?? [];
|
|
$giveProduct = $item['give_product_id'] ?? [];
|
|
unset($item['give_coupon_id'], $item['give_product_id']);
|
|
$item['give_coupon_id'] = $giveCoupon ? implode(',', array_unique(array_column($giveCoupon, 'give_coupon_id'))) : '';
|
|
$item['give_product_id'] = $giveProduct ? implode(',', array_unique(array_column($giveProduct, 'give_product_id'))) : '';
|
|
$item['give_product_unique'] = $giveProduct ? implode(',', array_unique(array_column($giveProduct, 'unique'))) : '';
|
|
|
|
$item['pid'] = $id;
|
|
$item['promotions_type'] = (int)$data['promotions_type'];
|
|
$item['promotions_cate'] = (int)$data['promotions_cate'];
|
|
$item['add_time'] = $time;
|
|
$res = $this->dao->save($item);
|
|
$storePromotionsAuxiliaryServices->savePromotionsRelation((int)$res->id, (int)$data['product_partake_type'], $promotionsAuxiliaryData, $giveCoupon, $giveProduct);
|
|
}
|
|
}
|
|
|
|
});
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 验证购买商品规格是否在优惠活动适用商品选择规格中
|
|
* @param array $productIds
|
|
* @param array $cartList
|
|
* @param array $promotions
|
|
* @return array
|
|
*/
|
|
public function checkProductCanUsePromotions(array $productIds, array $cartList, array $promotions)
|
|
{
|
|
$ids = $uniques = [];
|
|
if (!$productIds || !$cartList || !$promotions) return [$ids, $uniques];
|
|
$useProducts = $promotions['products'] ?? [];
|
|
if ($useProducts) {
|
|
$useProducts = array_combine(array_column($useProducts, 'product_id'), $useProducts);
|
|
}
|
|
foreach ($cartList as $cart) {
|
|
if (!in_array($cart['product_id'], $productIds)) continue;
|
|
$productUnique = $cart['product_attr_unique'] ?? '';
|
|
$productInfo = $cart['productInfo'] ?? [];
|
|
$product_id = $cart['product_id'] ?? 0;
|
|
$useUniques = $useProducts[$product_id]['unique'] ?? [];
|
|
if (!$productUnique || !$productInfo) continue;
|
|
if ($productInfo['type'] == 1 && $productInfo['pid'] > 0) {//平台共享到门店商品 查询平台商品unique
|
|
$unique = $this->getProductUnique($productUnique, (int)$productInfo['id'], (int)$productInfo['pid']);
|
|
$productUnique = $unique ?: $productUnique;
|
|
$useUniques = $useProducts[$productInfo['pid']]['unique'] ?? [];
|
|
}
|
|
if (in_array($promotions['product_partake_type'], [2, 3])) {
|
|
if ($promotions['product_partake_type'] == 2) {
|
|
$uniques[$product_id] = $useUniques;
|
|
if (!in_array($productUnique, $useUniques)) {
|
|
continue;
|
|
}
|
|
} else {
|
|
$uniques[$product_id] = $useUniques;
|
|
if (in_array($productUnique, $useUniques)) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
$ids[] = $product_id;
|
|
}
|
|
return [$ids, $uniques];
|
|
}
|
|
|
|
/**
|
|
* 检查优惠活动限量
|
|
* @param StoreOrderCartInfoServices $storeOrderCartInfoServices
|
|
* @param int $uid
|
|
* @param int $id
|
|
* @param array $productIds
|
|
* @param array $promotions
|
|
* @return array
|
|
*/
|
|
public function checkPromotionsLimit(StoreOrderCartInfoServices $storeOrderCartInfoServices, int $uid, int $id, array $productIds, array $promotions)
|
|
{
|
|
if (!$productIds) {
|
|
return [];
|
|
}
|
|
if ($uid && $promotions['promotions_type'] == 1 && $promotions['is_limit']) {//限时折扣 存在限量
|
|
//获取包含子级获取ids
|
|
$ids = array_unique(array_merge([$id], array_column($promotions['promotions'] ?? [], 'id')));
|
|
$data = [];
|
|
foreach ($productIds as $key => $product_id) {
|
|
if ($storeOrderCartInfoServices->count(['uid' => $uid, 'product_id' => $product_id, 'promotions_id' => $ids]) < $promotions['limit_num']) {
|
|
$data[] = $product_id;
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
return $productIds;
|
|
}
|
|
|
|
/**
|
|
* 计算几个商品总金额 并返回商品信息
|
|
* @param int $promotions_type
|
|
* @param array $productIds
|
|
* @param array $cartList
|
|
* @param array $uniquesArr
|
|
* @param int $product_partake_type
|
|
* @param bool $isGive
|
|
* @return array
|
|
*/
|
|
protected function getPromotionsProductInfo(int $promotions_type, array $productIds, array $cartList, array $uniquesArr = [], int $product_partake_type = 1, bool $isGive = false)
|
|
{
|
|
$sumPrice = $sumCount = 0;
|
|
$p = [];
|
|
if (!$cartList || !$productIds) {
|
|
return [$sumPrice, $sumCount, $p];
|
|
}
|
|
$productComputedArr = $this->getItem('productComputedArr', []);
|
|
$computedArr = $this->getItem('computedArr', []);
|
|
foreach ($cartList as $product) {
|
|
if (!in_array($product['product_id'], $productIds)) continue;
|
|
$cart_num = $product['cart_num'] ?? 1;
|
|
$unique = $product['product_attr_unique'] ?? '';
|
|
$product_id = $product['product_id'];
|
|
$productInfo = $product['productInfo'] ?? [];
|
|
if (!$unique || !$product_id || !$productInfo) continue;
|
|
if (!$this->checkProductUnque($unique, $productInfo, $uniquesArr[$product_id] ?? [], $product_partake_type)) {
|
|
continue;
|
|
}
|
|
if ($isGive) {
|
|
$key = 'true_price';
|
|
} else {
|
|
if ($promotions_type == 1) {
|
|
$key = 'price';
|
|
} else {
|
|
if (isset($productComputedArr[$product_id]['typeArr']) && in_array(1, $productComputedArr[$product_id]['typeArr'])) {
|
|
$key = 'price';
|
|
} else {
|
|
$key = 'true_price';
|
|
}
|
|
}
|
|
}
|
|
if ($key == 'price') {
|
|
$price = isset($product['productInfo']['attrInfo']['price']) ? $product['productInfo']['attrInfo']['price'] : ($product['productInfo']['price'] ?? 0);
|
|
} else {
|
|
$price = $product['truePrice'];
|
|
}
|
|
$isOverlay = $productComputedArr[$product_id]['is_overlay'] ?? false;
|
|
if ($isOverlay && $computedArr) {
|
|
foreach ($computedArr as $key => $computedDetail) {
|
|
if (isset($computedDetail[$unique]['promotions_true_price'])) {
|
|
$price = bcsub((string)$price, (string)$computedDetail[$unique]['promotions_true_price'], 2);
|
|
}
|
|
}
|
|
}
|
|
$product['price'] = floatval($price) > 0 ? $price : 0;
|
|
$sumPrice = bcadd((string)$sumPrice, (string)bcmul((string)$price, (string)$cart_num, 2), 2);
|
|
if ($isGive && isset($product['coupon_price'])) {
|
|
$sumPrice = bcsub((string)$sumPrice, (string)$product['coupon_price'], 2);
|
|
}
|
|
$sumCount = bcadd((string)$sumCount, (string)$cart_num, 0);
|
|
|
|
$p[] = $product;
|
|
}
|
|
return [$sumPrice, $sumCount, $p];
|
|
}
|
|
|
|
/**
|
|
* 验证是否叠加其他活动
|
|
* @param int $promotions_type
|
|
* @param array $overlay
|
|
* @return bool
|
|
*/
|
|
public function checkOverlay(int $promotions_type, array $overlay)
|
|
{
|
|
$data = [1, 2, 3];
|
|
return boolval(array_intersect($overlay, array_diff($data, [$promotions_type])));
|
|
}
|
|
|
|
/**
|
|
* 获取商品活动是否叠加计算
|
|
* @param array $promotionsList
|
|
* @param array $productDetails
|
|
* @param array $promotionsDetail
|
|
* @return array[]
|
|
*/
|
|
public function getProductComputedPromotions(array $promotionsList, array $productDetails, array $promotionsDetail)
|
|
{
|
|
$productArr = [];
|
|
$promotionsArr = [];
|
|
$productComputedArr = [];
|
|
if (!$promotionsList) {
|
|
return [$productArr, $promotionsArr, $productComputedArr];
|
|
}
|
|
//验证是否能叠加使用
|
|
foreach ($productDetails as $product_id => $promotionsIds) {
|
|
$pIds = [];
|
|
$overlayPIds = [];
|
|
$unOverlayPIds = [];
|
|
$prevType = [];
|
|
$preOverlay = [];
|
|
$isOverlay = true;
|
|
foreach ($promotionsIds as $id) {
|
|
$promotions = $promotionsList[$id] ?? [];
|
|
if (!$promotions) continue;
|
|
$overlay = is_string($promotions['overlay']) ? explode(',', $promotions['overlay']) : $promotions['overlay'];
|
|
//同一个商品 同一类型活动取最新一个
|
|
if (!in_array($promotions['promotions_type'], $prevType)) {
|
|
if (!$prevType) {
|
|
$overlayPIds[] = $unOverlayPIds[] = $id;
|
|
$prevType[] = $promotions['promotions_type'];
|
|
$preOverlay[$promotions['promotions_type']] = $overlay;
|
|
} else {
|
|
//有限时折扣
|
|
if (isset($preOverlay[1]) && !$this->checkOverlay(1, $preOverlay[1])) {
|
|
if ($promotions['promotions_type'] == 4) {
|
|
$prevType[] = $promotions['promotions_type'];
|
|
$preOverlay[$promotions['promotions_type']] = $overlay;
|
|
$unOverlayPIds[] = $id;
|
|
}
|
|
} else {
|
|
if ($promotions['promotions_type'] == 4) {
|
|
$prevType[] = $promotions['promotions_type'];
|
|
$preOverlay[$promotions['promotions_type']] = $overlay;
|
|
$overlayPIds[] = $id;
|
|
$unOverlayPIds[] = $id;
|
|
} else {
|
|
foreach ($preOverlay as $key => $value) {
|
|
if (in_array($key, $overlay) && in_array($promotions['promotions_type'], $value)) {
|
|
$overlayPIds[] = $id;
|
|
} else {
|
|
$unOverlayPIds[] = $id;
|
|
}
|
|
}
|
|
}
|
|
$prevType[] = $promotions['promotions_type'];
|
|
$preOverlay[$promotions['promotions_type']] = $overlay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$overlayPIds = array_unique($overlayPIds);
|
|
$unOverlayPIds = array_unique($unOverlayPIds);
|
|
if (count($overlayPIds) > 1) {
|
|
$isOverlay = true;
|
|
$pIds = $overlayPIds;
|
|
} else if (count($overlayPIds) == 1 && count($unOverlayPIds) == 1) {
|
|
$isOverlay = false;
|
|
$pIds = $overlayPIds;
|
|
} else {
|
|
$isOverlay = false;
|
|
$pIds = $unOverlayPIds;
|
|
}
|
|
|
|
$productComputedArr[$product_id]['is_overlay'] = $pIds && $isOverlay;
|
|
$typeArr = [];
|
|
//重新整理商品关联ids数据
|
|
foreach ($pIds as $id) {
|
|
$promotions = $promotionsList[$id] ?? [];
|
|
if ($promotions) {
|
|
$productArr[$product_id][] = $id;
|
|
$typeArr[] = $promotions['promotions_type'];
|
|
}
|
|
}
|
|
//存在限时折扣 不叠加
|
|
if (count($typeArr) > 1 && in_array(1, $typeArr) && !$productComputedArr[$product_id]['is_overlay']) {
|
|
$typeArr = [];
|
|
$productArr[$product_id] = [];
|
|
foreach ($pIds as $id) {
|
|
$promotions = $promotionsList[$id] ?? [];
|
|
if ($promotions) {
|
|
if (in_array($promotions['promotions_type'], [1, 4])) {
|
|
$productArr[$product_id][] = $id;
|
|
$typeArr[] = $promotions['promotions_type'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$productComputedArr[$product_id]['typeArr'] = $typeArr;
|
|
}
|
|
//重新整理活动关联商品ids数据
|
|
foreach ($promotionsDetail as $promotions_id => $productIds) {
|
|
foreach ($productIds as $pid) {
|
|
$pIds = $productArr[$pid] ?? [];
|
|
if ($pIds && in_array($promotions_id, $pIds)) {
|
|
$promotionsArr[$promotions_id][] = $pid;
|
|
}
|
|
}
|
|
}
|
|
return [$productArr, $promotionsArr, $productComputedArr];
|
|
}
|
|
|
|
/**
|
|
* 组合使用的优惠活动详情
|
|
* @param int $uid
|
|
* @param int $store_id
|
|
* @param array $usePromotionsIds
|
|
* @param array $promotionsArr
|
|
* @param array $computedArr
|
|
* @return array
|
|
*/
|
|
public function getUsePromotiosnInfo(int $uid, int $store_id, array $usePromotionsIds, array $promotionsArr, array $computedArr)
|
|
{
|
|
$usePromotions = [];
|
|
if (!$usePromotionsIds || !$promotionsArr || !$computedArr) {
|
|
return $usePromotions;
|
|
}
|
|
$giveCoupon = $giveProduct = $giveCartList = [];
|
|
$giveIntegral = 0;
|
|
foreach ($usePromotionsIds as $id) {
|
|
$promotionsInfo = $promotionsArr[$id] ?? [];
|
|
if (!$promotionsInfo) continue;
|
|
$details = $computedArr[$id] ?? [];
|
|
$promotionsInfo['details'] = $details;
|
|
$promotionsInfo = array_merge($promotionsInfo, $details['give'] ?? []);
|
|
$promotionsInfo['is_valid'] = $details['is_valid'] ?? 0;
|
|
$promotionsInfo['reach_threshold'] = $details['reach_threshold'] ?? 0;
|
|
$promotionsInfo['sum_promotions_price'] = $details['sum_promotions_price'] ?? 0;
|
|
$promotionsInfo['differ_threshold'] = $details['differ_threshold'] ?? 0;//下一级优惠差多少元|件
|
|
$promotionsInfo['differ_price'] = $details['differ_price'] ?? 0;//下一级优惠金额
|
|
$promotionsInfo['differ_discount'] = $details['differ_discount'] ?? 0;//下一级享受折扣
|
|
$giveProductIds = $giveCart = [];
|
|
if (isset($promotionsInfo['give_product']) && $promotionsInfo['give_product']) {
|
|
$giveCart = $this->createGiveProductCart($uid, (int)$id, $promotionsInfo['give_product'], $promotionsInfo, $store_id);
|
|
if ($giveCart) {
|
|
$giveProductIds = array_column($giveProductIds, 'product_id');
|
|
$giveCartList = array_merge($giveCartList, $giveCart);
|
|
}
|
|
}
|
|
$promotionsInfo['product_ids'] = $promotionsDetail[$id] ?? [];
|
|
$promotionsInfo['product_ids'] = array_merge($promotionsInfo['product_ids'], $giveProductIds);
|
|
|
|
$promotionsInfo['give_product'] = $giveProductIds;
|
|
|
|
$giveCoupon = array_merge($giveCoupon, $promotionsInfo['give_coupon'] ?? []);
|
|
$giveProduct = array_merge($giveProduct, $promotionsInfo['give_product'] ?? []);
|
|
$giveIntegral = bcadd((string)$giveIntegral, (string)($promotionsInfo['give_integral'] ?? 0), 0);
|
|
$usePromotions[] = $promotionsInfo;
|
|
}
|
|
return [$usePromotions, $giveIntegral, $giveCoupon, $giveCartList];
|
|
}
|
|
|
|
/**
|
|
* 根据门店|平台商品 unique 获取另一端商品unique
|
|
* @param string $unique
|
|
* @param int $product_id
|
|
* @param int $type
|
|
* @return false|string
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getProductUnique(string $unique, int $product_id, int $new_product_id, int $type = 0)
|
|
{
|
|
/** @var StoreProductAttrValueServices $skuValueServices */
|
|
$skuValueServices = app()->make(StoreProductAttrValueServices::class);
|
|
//商品sku
|
|
$suk = $skuValueServices->value(['unique' => $unique, 'product_id' => $product_id, 'type' => $type], 'suk');
|
|
$productUnique = $skuValueServices->value(['suk' => $suk, 'product_id' => $new_product_id, 'type' => $type], 'unique');
|
|
return $productUnique ?: '';
|
|
}
|
|
|
|
/**
|
|
* 验证购物车商品规格是否在活动中
|
|
* @param string $unique
|
|
* @param array $productInfo
|
|
* @param array $uniques
|
|
* @param int $product_partake_type
|
|
* @return bool
|
|
*/
|
|
public function checkProductUnque(string $unique, array $productInfo, array $uniques, int $product_partake_type = 1)
|
|
{
|
|
if (!$unique) {
|
|
return false;
|
|
}
|
|
if ((in_array($product_partake_type, [2, 3]) && !$uniques) || !is_array($uniques)) {
|
|
return false;
|
|
}
|
|
if ($productInfo['type'] == 1 && $productInfo['pid'] > 0) {//平台共享到门店商品 查询平台商品unique
|
|
$productUnique = $this->getProductUnique($unique, (int)$productInfo['id'], (int)($productInfo['pid'] ?? 0));
|
|
$unique = $productUnique ?: $unique;
|
|
}
|
|
switch ($product_partake_type) {
|
|
case 1:
|
|
case 4:
|
|
case 5:
|
|
break;
|
|
case 2:
|
|
if (!$uniques) {
|
|
return true;
|
|
}
|
|
if (!in_array($unique, $uniques)) {
|
|
return false;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (!$uniques) {
|
|
return true;
|
|
}
|
|
if (in_array($unique, $uniques)) {
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* 计算商品优惠价格
|
|
* @param int $uid
|
|
* @param array $cartList
|
|
* @param int $store_id
|
|
* @param int $couponId
|
|
* @param bool $isCart
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function computedPromotions(int $uid, array $cartList, int $store_id = 0, int $couponId = 0, bool $isCart = false)
|
|
{
|
|
$giveIntegral = $couponPrice = 0;
|
|
$giveCoupon = $giveCartList = $usePromotions = $useCounpon = [];
|
|
if ($cartList) {
|
|
$productIds = array_column($cartList, 'product_id');
|
|
// $productArr = array_combine($productIds, $cartList);
|
|
$with = ['products' => function ($query) {
|
|
$query->field('promotions_id,product_id,is_all,unique');
|
|
}, 'giveProducts' => function ($query) {
|
|
$query->field('type,promotions_id,product_id,limit_num,surplus_num,unique')->with(['productInfo' => function ($query) {
|
|
$query->field('id,store_name');
|
|
}]);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('type,promotions_id,coupon_id,limit_num,surplus_num')->with(['coupon' => function ($query) {
|
|
$query->field('id,type,coupon_type,coupon_title,coupon_price,use_min_price,remain_count,is_permanent');
|
|
}]);
|
|
}, 'promotions' => function ($query) {
|
|
$query->field('id,pid,promotions_type,promotions_cate,threshold_type,threshold,discount_type,n_piece_n_discount,discount,give_integral,give_coupon_id,give_product_id,give_product_unique')->with(['giveProducts' => function ($query) {
|
|
$query->field('type,promotions_id,product_id,limit_num,surplus_num,unique')->with(['productInfo' => function ($query) {
|
|
$query->field('id,store_name');
|
|
}]);
|
|
}, 'giveCoupon' => function ($query) {
|
|
$query->field('type,promotions_id, coupon_id,limit_num,surplus_num')->with(['coupon' => function ($query) {
|
|
$query->field('id,type,coupon_type,coupon_title,coupon_price,use_min_price,remain_count,is_permanent');
|
|
}]);
|
|
}]);
|
|
}];
|
|
//获取购物车商品所有活动
|
|
[$promotionsArr, $productDetails, $promotionsDetail] = $this->getProductsPromotionsDetail($productIds, '*', $with, [1, 2, 3, 4], '', $store_id);
|
|
$computedArr = [];
|
|
$usePromotionsIds = [];
|
|
if ($promotionsArr) {
|
|
$promotionsArr = array_combine(array_column($promotionsArr, 'id'), $promotionsArr);
|
|
//获取商品活动是否叠加计算
|
|
[$productDetails, $promotionsDetail, $productComputedArr] = $this->getProductComputedPromotions($promotionsArr, $productDetails, $promotionsDetail);
|
|
//计算优惠金额
|
|
$computedArr = $this->doComputeV1($uid, $cartList, $promotionsDetail, $promotionsArr, $productComputedArr);
|
|
foreach ($cartList as &$cart) {
|
|
$sum_promotions_true_price = 0;
|
|
$product_id = (int)($cart['product_id'] ?? 0);
|
|
$unique = $cart['product_attr_unique'] ?? '';
|
|
$productInfo = $cart['productInfo'] ?? [];
|
|
$promotionsIds = $productDetails[$product_id] ?? [];
|
|
$cart['promotions_id'] = [];
|
|
if (!$promotionsIds || !$unique || !$productInfo) {
|
|
continue;
|
|
}
|
|
$price = isset($cart['productInfo']['attrInfo']['price']) ? $cart['productInfo']['attrInfo']['price'] : ($cart['productInfo']['price'] ?? 0);
|
|
//叠加
|
|
$typeArr = $productComputedArr[$product_id]['typeArr'] ?? [];
|
|
$isOverly = isset($productComputedArr[$product_id]['is_overlay']) && $productComputedArr[$product_id]['is_overlay'];
|
|
foreach ($promotionsIds as $promotions_id) {
|
|
$promotionsInfo = $promotionsArr[$promotions_id] ?? [];
|
|
$trueDetail = $computedArr[$promotions_id] ?? [];
|
|
if (!$promotionsInfo || !$trueDetail) continue;
|
|
if (!$this->checkProductUnque($unique, $productInfo, $trueDetail['uniques'][$product_id] ?? [], (int)$promotionsInfo['product_partake_type'])) {
|
|
continue;
|
|
}
|
|
$trueArr = $trueDetail[$unique] ?? [];
|
|
if (!isset($trueDetail['is_valid']) || $trueDetail['is_valid'] == 0) {
|
|
if ($isCart) {//购物车不满足也展示
|
|
$cart['promotions_id'][] = $promotions_id;
|
|
}
|
|
} else {
|
|
//活动叠加商品 单件总计优惠金额
|
|
if ($isOverly) {
|
|
$cart['promotions_id'][] = $promotions_id;
|
|
$sum_promotions_true_price = bcadd((string)$sum_promotions_true_price, (string)($trueArr['promotions_true_price'] ?? 0), 2);
|
|
} else { //不叠加取最优惠
|
|
if ($isCart) {
|
|
$cart['promotions_id'][] = $promotions_id;
|
|
}
|
|
if ($sum_promotions_true_price < ($trueArr['promotions_true_price'] ?? 0)) {
|
|
$sum_promotions_true_price = $trueArr['promotions_true_price'] ?? 0;
|
|
if (!$isCart) {
|
|
$cart['promotions_id'] = [$promotions_id];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($sum_promotions_true_price) {
|
|
//是否有限时折扣
|
|
if (in_array(1, $typeArr)) {
|
|
$true_price = (float)bcsub((string)$price, (string)$sum_promotions_true_price, 2);
|
|
if ($true_price < 0) {
|
|
$true_price = 0;
|
|
}
|
|
//比较与用户等级、svip优惠后金额
|
|
if ($true_price && $cart['truePrice'] > $true_price) {
|
|
$cart['truePrice'] = $true_price;
|
|
$cart['promotions_true_price'] = $sum_promotions_true_price;
|
|
$cart['price_type'] = 'promotions';
|
|
$cart['vip_truePrice'] = 0;
|
|
} else { //使用了用户等级、svip价格 去掉优惠活动关联
|
|
$cart['promotions_id'] = [];
|
|
}
|
|
} else {//svip 用户等级价格上继续优惠
|
|
$true_price = (float)bcsub((string)$cart['truePrice'], (string)$sum_promotions_true_price, 2);
|
|
$cart['truePrice'] = $true_price > 0 ? $true_price : 0;
|
|
$cart['promotions_true_price'] = $sum_promotions_true_price;
|
|
$cart['price_type'] = 'promotions';
|
|
}
|
|
}
|
|
$usePromotionsIds = array_unique(array_merge($usePromotionsIds, $cart['promotions_id']));
|
|
//排出不叠加 去最优的其他优惠活动金额
|
|
foreach ($promotionsIds as $promotions_id) {
|
|
//使用了优惠会跳过
|
|
if (in_array($promotions_id, $cart['promotions_id'])) continue;
|
|
$trueDetail = $computedArr[$promotions_id] ?? [];
|
|
$trueArr = $trueDetail[$unique] ?? [];
|
|
if (!$trueDetail || !$trueArr) {
|
|
continue;
|
|
}
|
|
$true_price = $trueArr['promotions_true_price'] ?? 0;
|
|
$sum_promotions_price = bcsub((string)($trueDetail['sum_promotions_price'] ?? '0'), (string)bcmul((string)$true_price, (string)$cart['cart_num'], 2), 2);
|
|
$computedArr[$promotions_id]['sum_promotions_price'] = $sum_promotions_price >= 0 ? $sum_promotions_price : 0;
|
|
//这个商品的没有使用优惠活动
|
|
unset($computedArr[$promotions_id][$unique]);
|
|
}
|
|
}
|
|
}
|
|
//使用优惠券
|
|
$coupon_id = 0;
|
|
if ($uid) {
|
|
if ($usePromotionsIds) [$usePromotions, $giveIntegral, $giveCoupon, $giveCartList] = $this->getUsePromotiosnInfo($uid, $store_id, $usePromotionsIds, $promotionsArr, $computedArr);
|
|
if ($couponId) {
|
|
[$useCounpon, $couponPrice] = $this->useCoupon($couponId, $uid, $cartList, $usePromotions, $store_id);
|
|
$coupon_id = $couponId;
|
|
} else {
|
|
//获取最优优惠券
|
|
if ($isCart) {
|
|
/** @var StoreCouponIssueServices $couponServices */
|
|
$couponServices = app()->make(StoreCouponIssueServices::class);
|
|
$couponServices->setItem('isVip', $this->getItem('isVip', 0));
|
|
$useCounpon = $couponServices->getCanUseCoupon($uid, $cartList, $usePromotions, $store_id);
|
|
$couponServices->reset();
|
|
$couponPrice = $useCounpon['true_coupon_price'] ?? 0;
|
|
$coupon_id = $useCounpon['used']['id'] ?? 0;
|
|
}
|
|
}
|
|
//计算每一件商品优惠券优惠金额
|
|
if ($coupon_id && $useCounpon && $couponPrice) {
|
|
/** @var StoreOrderComputedServices $computedServices */
|
|
$computedServices = app()->make(StoreOrderComputedServices::class);
|
|
$payPrice = $computedServices->getOrderSumPrice($cartList);
|
|
if ($couponPrice > $payPrice) {
|
|
$couponPrice = $payPrice;
|
|
}
|
|
/** @var StoreOrderCreateServices $createServices */
|
|
$createServices = app()->make(StoreOrderCreateServices::class);
|
|
$priceData = ['coupon_id' => $coupon_id, 'coupon_price' => $couponPrice];
|
|
$cartList = $createServices->computeOrderProductCoupon($cartList, $priceData, $usePromotions, $store_id);
|
|
}
|
|
}
|
|
|
|
//获取赠送积分、优惠券、商品
|
|
[$cartList, $computedArr, $useGivePromotionsIds] = $this->getPromotionsGive($uid, $cartList, $computedArr, $promotionsDetail, $productDetails, $promotionsArr, $isCart);
|
|
$usePromotionsIds = array_unique(array_merge($usePromotionsIds, $useGivePromotionsIds));
|
|
//整合返回数据
|
|
if ($usePromotionsIds) [$usePromotions, $giveIntegral, $giveCoupon, $giveCartList] = $this->getUsePromotiosnInfo($uid, $store_id, $usePromotionsIds, $promotionsArr, $computedArr);
|
|
}
|
|
return [$cartList, $couponPrice, $useCounpon, $usePromotions, $giveIntegral, $giveCoupon, $giveCartList];
|
|
}
|
|
|
|
/**
|
|
* 实际计算商品优惠金额
|
|
* @param int $uid
|
|
* @param array $cartList
|
|
* @param array $promotionsDetail
|
|
* @param array $promotionsArr
|
|
* @param array $productComputedArr
|
|
* @return array
|
|
*/
|
|
public function doComputeV1(int $uid, array $cartList, array $promotionsDetail, array $promotionsArr, array $productComputedArr)
|
|
{
|
|
$computedArr = [];
|
|
if (!$cartList || !$promotionsDetail) {
|
|
return $computedArr;
|
|
}
|
|
/** @var StoreOrderCartInfoServices $storeOrderCartInfoServices */
|
|
$storeOrderCartInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
foreach ($promotionsDetail as $promotions_id => $productIds) {
|
|
$promotions = $promotionsArr[$promotions_id] ?? [];
|
|
$productCount = count($productIds);
|
|
if (!$promotions || !$productCount || $promotions['promotions_type'] == 4) continue;
|
|
//验证商品规格是否满足活动
|
|
[$productIds, $uniques] = $this->checkProductCanUsePromotions($productIds, $cartList, $promotions);
|
|
if (!$productIds) {
|
|
continue;
|
|
}
|
|
//验证限量
|
|
if ($uid) {
|
|
$productIds = $this->checkPromotionsLimit($storeOrderCartInfoServices, $uid, (int)$promotions_id, $productIds, $promotions);
|
|
if (!$productIds) {
|
|
continue;
|
|
}
|
|
}
|
|
$promotions_type = (int)$promotions['promotions_type'] ?? 1;
|
|
$this->setItem('productComputedArr', $productComputedArr)->setItem('computedArr', $computedArr);
|
|
[$sumPrice, $sumCount, $promotionsProductArr] = $this->getPromotionsProductInfo($promotions_type, $productIds, $cartList, $uniques, (int)$promotions['product_partake_type']);
|
|
$this->reset();
|
|
$compute_price = $sum_promotions_true_price = $sum_promotions_price = 0;
|
|
$data = ['is_valid' => 0, 'reach_threshold' => 0, 'differ_threshold' => 0, 'promotions_type' => $promotions['promotions_type'], 'sum_promotions_price' => 0, 'product_id' => [], 'uniques' => $uniques];
|
|
switch ($promotions['promotions_type']) {
|
|
case 1://限制折扣
|
|
$p = $promotions['promotions'][0] ?? [];
|
|
if ($p) {
|
|
$promotionsDiscount = $this->computedDiscount($p['discount'], 100, 2);
|
|
$sum_promotions_price = 0;
|
|
|
|
if ($promotions['is_limit']) {//是否限量
|
|
$limit_num = $promotions['limit_num'];
|
|
if ($limit_num <= 0) break;
|
|
$sumCount = 0;
|
|
foreach ($promotionsProductArr as $product) {
|
|
$product_id = $product['product_id'];
|
|
$unique = $product['product_attr_unique'];
|
|
$price = $product['price'];
|
|
$cartNum = $newCartNum = $product['cart_num'] ?? 1;
|
|
if ($sumCount >= $limit_num) {
|
|
break;
|
|
}
|
|
if (bcadd((string)$sumCount, (string)$cartNum) > $limit_num) {//加上下一个商品数量 大于限购数量
|
|
$newCartNum = bcsub((string)$limit_num, (string)$sumCount);
|
|
$sumCount = $limit_num;
|
|
}
|
|
$promotions_true_price = (float)bcmul((string)$price, (string)$promotionsDiscount, 2);
|
|
if ($promotions_true_price < 0.01) {//实际优惠小于0.01 就不计算优惠
|
|
$promotions_true_price = 0;
|
|
}
|
|
//部分享受折扣
|
|
if ($cartNum != $newCartNum) {
|
|
$promotions_true_price = bcdiv((string)bcmul((string)$promotions_true_price, (string)$newCartNum, 4), (string)$cartNum, 2);
|
|
}
|
|
$data[$unique] = ['product_id' => $product_id, 'uniqid' => $unique, 'price' => $price, 'promotions_true_price' => $promotions_true_price];
|
|
$sum_promotions_price = bcadd((string)$sum_promotions_price, (string)bcmul((string)$promotions_true_price, (string)$cartNum, 2), 2);
|
|
}
|
|
|
|
} else {
|
|
foreach ($promotionsProductArr as $product) {
|
|
$product_id = $product['product_id'];
|
|
$unique = $product['product_attr_unique'];
|
|
$price = $product['price'];
|
|
$promotions_true_price = (float)bcmul((string)$price, (string)$promotionsDiscount, 2);
|
|
if ($promotions_true_price < 0.01) {//实际优惠小于0.01 就不计算优惠
|
|
$promotions_true_price = 0;
|
|
}
|
|
$data[$unique] = ['product_id' => $product_id, 'uniqid' => $unique, 'price' => $price, 'promotions_true_price' => $promotions_true_price];
|
|
$sum_promotions_price = bcadd((string)$sum_promotions_price, (string)bcmul((string)$promotions_true_price, (string)($product['cart_num'] ?? 1), 2), 2);
|
|
}
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['sum_promotions_price'] = $sum_promotions_price;
|
|
}
|
|
break;
|
|
case 2://n件n折
|
|
$p = $promotions['promotions'][0] ?? [];
|
|
if ($p) {
|
|
$promotionsDiscount = $this->computedDiscount($p['discount'], 100, 2);
|
|
if ($sumCount >= $p['threshold']) {//满足
|
|
$useProductArr = $promotionsProductArr;
|
|
//商品价格升序
|
|
array_multisort(array_column($promotionsProductArr, 'price'), SORT_ASC, $promotionsProductArr);
|
|
$minPrice = $promotionsProductArr[0]['price'] ?? 0;
|
|
//算出n件实际优惠金额
|
|
$sum_promotions_price = (float)bcmul((string)$minPrice, (string)$promotionsDiscount, 2);
|
|
if ($sum_promotions_price < 0.01) {
|
|
$sum_promotions_price = 0;
|
|
}
|
|
if ($sum_promotions_price) {
|
|
$useCount = $productCount;
|
|
$useSumPrice = $sumPrice;
|
|
$count = count($useProductArr);
|
|
$compute_price = 0;
|
|
array_multisort(array_column($useProductArr, 'cart_num'), SORT_DESC, $useProductArr);
|
|
foreach ($useProductArr as $value) {
|
|
$product_id = $value['product_id'];
|
|
$unique = $value['product_attr_unique'];
|
|
$price = $value['price'];
|
|
if ($count > 1) {
|
|
$promotions_true_price = bcmul((string)bcdiv((string)$price, (string)$useSumPrice, 4), (string)$sum_promotions_price, 2);
|
|
$compute_price = bcadd((string)$compute_price, (string)bcmul((string)$promotions_true_price, (string)$value['cart_num'], 2), 2);
|
|
} else {
|
|
$one_promotions_sum_price = bcsub((string)$sum_promotions_price, (string)$compute_price, 2);
|
|
$promotions_true_price = bcdiv((string)$one_promotions_sum_price, (string)$value['cart_num'], 2);
|
|
}
|
|
$data[$unique] = ['product_id' => $product_id, 'uniqid' => $unique, 'price' => $price, 'promotions_true_price' => $promotions_true_price];
|
|
$count--;
|
|
}
|
|
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['reach_threshold'] = $p['threshold'];
|
|
$data['sum_promotions_price'] = $sum_promotions_price;
|
|
} else {
|
|
$data['differ_discount'] = $p['discount'];
|
|
$data['differ_threshold'] = bcsub((string)$p['threshold'], (string)$sumCount, 0);
|
|
}
|
|
}
|
|
break;
|
|
case 3://满减折
|
|
if ($promotions['promotions_cate'] == 1) {//阶梯 享受最高
|
|
$valid = $invalid = [];
|
|
foreach ($promotions['promotions'] as $key => $p) {
|
|
if (($p['threshold_type'] == 1 ? $sumPrice : $sumCount) >= $p['threshold']) {
|
|
$valid = $p;
|
|
} else {
|
|
$invalid = $p;
|
|
break;
|
|
}
|
|
}
|
|
if ($valid) {
|
|
if ($valid['discount_type'] == 1) {//免减
|
|
$sum_promotions_price = (string)$valid['discount'];
|
|
} else {//折扣
|
|
$promotionsDiscount = $this->computedDiscount($valid['discount'], 100, 2);
|
|
$sum_promotions_price = 0;
|
|
}
|
|
array_multisort(array_column($promotionsProductArr, 'cart_num'), SORT_DESC, $promotionsProductArr);
|
|
foreach ($promotionsProductArr as $product) {
|
|
$product_id = $product['product_id'];
|
|
$unique = $product['product_attr_unique'];
|
|
$price = $product['price'];
|
|
if ($valid['discount_type'] == 1) {
|
|
if ($productCount > 1) {
|
|
$promotions_true_price = bcmul((string)bcdiv((string)$price, (string)$sumPrice, 4), (string)$sum_promotions_price, 2);
|
|
$compute_price = bcadd((string)$compute_price, (string)bcmul((string)$promotions_true_price, (string)$product['cart_num'], 2), 2);
|
|
} else {
|
|
$one_promotions_sum_price = bcsub((string)$sum_promotions_price, (string)$compute_price, 2);
|
|
$promotions_true_price = bcdiv((string)$one_promotions_sum_price, (string)$product['cart_num'], 2);
|
|
}
|
|
} else {
|
|
$promotions_true_price = (float)bcmul((string)$price, (string)$promotionsDiscount, 2);
|
|
if ($promotions_true_price < 0.01) {//实际优惠小于0.01 就不计算优惠
|
|
$promotions_true_price = 0;
|
|
}
|
|
$sum_promotions_price = bcadd((string)$sum_promotions_price, (string)bcmul((string)$promotions_true_price, (string)($product['cart_num'] ?? 1), 2), 2);
|
|
}
|
|
$data[$unique] = ['product_id' => $product_id, 'uniqid' => $unique, 'price' => $price, 'promotions_true_price' => $promotions_true_price];
|
|
$productCount--;
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['reach_threshold'] = $valid['threshold'];
|
|
$data['sum_promotions_price'] = $sum_promotions_price;
|
|
}
|
|
if ($invalid) {
|
|
if ($valid) $data['is_valid'] = 2;
|
|
if ($invalid['discount_type'] == 1) {//免减
|
|
$data['differ_price'] = $invalid['discount'];
|
|
} else {
|
|
$data['differ_discount'] = $invalid['discount'];
|
|
}
|
|
$data['differ_threshold'] = bcsub((string)$invalid['threshold'], (string)($invalid['threshold_type'] == 1 ? $sumPrice : $sumCount), 0);
|
|
}
|
|
} else {//循环
|
|
$p = $promotions['promotions'][0] ?? [];
|
|
$validCount = floor((float)bcdiv((string)($p['threshold_type'] == 1 ? $sumPrice : $sumCount), (string)$p['threshold'], 2));
|
|
if ($validCount) {//满足次数
|
|
$promotionsDiscount = $this->computedDiscount($p['discount'], 100, 2);
|
|
$sum_promotions_price = 0;
|
|
$useProductArr = $promotionsProductArr;
|
|
if ($p['discount_type'] == 2 && $p['threshold_type'] == 2) {//满n件 打n折
|
|
// $suprplusDiscount = bcsub((string)$productCount, bcmul((string)$validCount, (string)$p['threshold'], 0), 0);
|
|
//商品价格升序
|
|
array_multisort(array_column($promotionsProductArr, 'price'), SORT_ASC, $promotionsProductArr);
|
|
$minPrice = $promotionsProductArr[0]['price'] ?? 0;
|
|
//算出n件实际优惠金额
|
|
$sum_promotions_price = (float)bcmul((string)$minPrice, (string)$promotionsDiscount, 2);
|
|
if ($sum_promotions_price < 0.01) {
|
|
$sum_promotions_price = 0;
|
|
}
|
|
$sum_promotions_price = bcmul((string)$validCount, (string)$sum_promotions_price, 2);
|
|
} else {
|
|
if ($p['discount_type'] == 1) {//免减(n元、n件)
|
|
$sum_promotions_price = bcmul((string)$validCount, (string)$p['discount'], 2);
|
|
} else {//打折
|
|
if ($p['threshold_type'] == 1) {//满n元
|
|
$sum_promotions_price = bcmul((string)bcmul((string)$validCount, (string)$p['threshold'], 2), (string)$promotionsDiscount, 2);
|
|
}
|
|
}
|
|
}
|
|
$useCount = 0;
|
|
array_multisort(array_column($useProductArr, 'cart_num'), SORT_DESC, $useProductArr);
|
|
foreach ($useProductArr as $product) {
|
|
$price = $product['price'];
|
|
$product_id = $product['product_id'];
|
|
$unique = $product['product_attr_unique'];
|
|
// if ($p['discount_type'] == 2 && $p['threshold_type'] == 2) { //满n件打n折
|
|
// if ($p['threshold'] > $useCount) {
|
|
// $promotions_true_price = (float)bcmul((string)$price, (string)$promotionsDiscount, 2);
|
|
// if ($promotions_true_price < 0.01) {//实际优惠小于0.01 就不计算优惠
|
|
// $promotions_true_price = 0;
|
|
// }
|
|
// } else {
|
|
// $promotions_true_price = 0;
|
|
// }
|
|
// $sum_promotions_price = bcadd((string)$sum_promotions_price, (string)$promotions_true_price, 2);
|
|
// $useCount = (int)bcadd((string)$useCount, (string)$product['cart_num']);
|
|
// } else {
|
|
if ($productCount > 1) {
|
|
$promotions_true_price = bcmul((string)bcdiv((string)$price, (string)$sumPrice, 4), (string)$sum_promotions_price, 2);
|
|
$compute_price = bcadd((string)$compute_price, (string)bcmul((string)$promotions_true_price, (string)$product['cart_num'], 2), 2);
|
|
} else {
|
|
$one_promotions_sum_price = bcsub((string)$sum_promotions_price, (string)$compute_price, 2);
|
|
$promotions_true_price = bcdiv((string)$one_promotions_sum_price, (string)$product['cart_num'], 2);
|
|
}
|
|
// }
|
|
$data[$unique] = ['product_id' => $product_id, 'uniqid' => $unique, 'price' => $price, 'promotions_true_price' => $promotions_true_price];
|
|
$productCount--;
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['reach_threshold'] = $p['threshold'];
|
|
$data['sum_promotions_price'] = $sum_promotions_price;
|
|
} else {
|
|
if ($p['discount_type'] == 1) {//免减
|
|
$data['differ_price'] = $p['discount'];
|
|
} else {
|
|
$data['differ_discount'] = $p['discount'];
|
|
}
|
|
$data['differ_threshold'] = bcsub((string)$p['threshold'], (string)($p['threshold_type'] == 1 ? $sumPrice : $sumCount), 0);
|
|
}
|
|
}
|
|
break;
|
|
case 4://满送
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
$data['give'] = ['give_integral' => 0, 'give_coupon' => [], 'give_product' => []];
|
|
$computedArr[$promotions_id] = $data;
|
|
}
|
|
return $computedArr;
|
|
}
|
|
|
|
/**
|
|
* 使用优惠卷
|
|
* @param int $couponId
|
|
* @param int $uid
|
|
* @param array $cartInfo
|
|
* @param array $promotions
|
|
* @param int $store_id
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function useCoupon(int $couponId, int $uid, array $cartInfo, array $promotions, int $store_id = 0)
|
|
{
|
|
//使用优惠劵
|
|
$couponPrice = 0;
|
|
$couponInfo = [];
|
|
if ($couponId && $cartInfo) {
|
|
/** @var StoreCouponUserServices $couponServices */
|
|
$couponServices = app()->make(StoreCouponUserServices::class);
|
|
$couponInfo = $couponServices->getOne([['id', '=', $couponId], ['uid', '=', $uid], ['is_fail', '=', 0], ['status', '=', 0], ['start_time', '<=', time()], ['end_time', '>=', time()]], '*', ['issue']);
|
|
if (!$couponInfo) {
|
|
throw new ValidateException('选择的优惠劵无效!');
|
|
}
|
|
$type = $couponInfo['coupon_applicable_type'] ?? 0;
|
|
$flag = false;
|
|
$price = 0;
|
|
$count = 0;
|
|
$promotionsList = [];
|
|
if ($promotions) {
|
|
$promotionsList = array_combine(array_column($promotions, 'id'), $promotions);
|
|
}
|
|
//验证是否适用门店
|
|
if ($store_id && isset($couponInfo['applicable_type']) && isset($couponInfo['applicable_store_id'])) {
|
|
$applicable_store_id = is_array($couponInfo['applicable_store_id']) ? $couponInfo['applicable_store_id'] : explode(',', $couponInfo['applicable_store_id']);
|
|
//活动不适用该门店
|
|
if ($couponInfo['applicable_type'] == 0 || ($couponInfo['applicable_type'] == 2 && !in_array($store_id, $applicable_store_id))) {
|
|
throw new ValidateException('优惠劵暂不支持该门店使用!');
|
|
}
|
|
}
|
|
$isOverlay = function ($cart) use ($promotionsList) {
|
|
$productInfo = $cart['productInfo'] ?? [];
|
|
if (!$productInfo) {
|
|
return false;
|
|
}
|
|
//门店独立商品 不使用优惠券
|
|
$isBranchProduct = isset($productInfo['type']) && isset($productInfo['pid']) && $productInfo['type'] == 1 && !$productInfo['pid'];
|
|
if ($isBranchProduct) {
|
|
return false;
|
|
}
|
|
if (isset($cart['promotions_id']) && $cart['promotions_id']) {
|
|
foreach ($cart['promotions_id'] as $key => $promotions_id) {
|
|
$promotions = $promotionsList[$promotions_id] ?? [];
|
|
if ($promotions && $promotions['promotions_type'] != 4) {
|
|
$overlay = is_string($promotions['overlay']) ? explode(',', $promotions['overlay']) : $promotions['overlay'];
|
|
if (!in_array(5, $overlay)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
switch ($type) {
|
|
case 0:
|
|
foreach ($cartInfo as $cart) {
|
|
if (!$isOverlay($cart)) continue;
|
|
$price = bcadd((string)$price, bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
|
$count++;
|
|
}
|
|
break;
|
|
case 1://品类券
|
|
/** @var StoreProductCategoryServices $storeCategoryServices */
|
|
$storeCategoryServices = app()->make(StoreProductCategoryServices::class);
|
|
$cateGorys = $storeCategoryServices->getAllById((int)$couponInfo['category_id']);
|
|
if ($cateGorys) {
|
|
$cateIds = array_column($cateGorys, 'id');
|
|
foreach ($cartInfo as $cart) {
|
|
if (!$isOverlay($cart)) continue;
|
|
if (isset($cart['productInfo']['cate_id']) && array_intersect(explode(',', $cart['productInfo']['cate_id']), $cateIds)) {
|
|
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
|
$count++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
foreach ($cartInfo as $cart) {
|
|
if (!$isOverlay($cart)) continue;
|
|
$product_id = isset($cart['productInfo']['pid']) && $cart['productInfo']['pid'] ? $cart['productInfo']['pid'] : ($cart['product_id'] ?? 0);
|
|
if ($product_id && in_array($product_id, explode(',', $couponInfo['product_id']))) {
|
|
$price = bcadd((string)$price, bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
|
$count++;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
/** @var StoreBrandServices $storeBrandServices */
|
|
$storeBrandServices = app()->make(StoreBrandServices::class);
|
|
$brands = $storeBrandServices->getAllById((int)$couponInfo['brand_id']);
|
|
if ((int)$couponInfo['brand_id'] && $brands) {
|
|
$brandIds = array_column($brands, 'id');
|
|
foreach ($cartInfo as $cart) {
|
|
if (!$isOverlay($cart)) continue;
|
|
if (isset($cart['productInfo']['brand_id']) && $cart['productInfo']['brand_id'] && in_array($cart['productInfo']['brand_id'], $brandIds)) {
|
|
$price = bcadd((string)$price, (string)bcmul((string)$cart['truePrice'], (string)$cart['cart_num'], 2), 2);
|
|
$count++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if ($count && $couponInfo['use_min_price'] <= $price) {
|
|
$flag = true;
|
|
}
|
|
if (!$flag) {
|
|
return [[], 0];
|
|
// throw new ValidateException('不满足优惠劵的使用条件!');
|
|
}
|
|
//满减券
|
|
if ($couponInfo['coupon_type'] == 1) {
|
|
$couponPrice = $couponInfo['coupon_price'] > $price ? $price : $couponInfo['coupon_price'];
|
|
} else {
|
|
if ($couponInfo['coupon_price'] <= 0) {//0折
|
|
$couponPrice = $price;
|
|
} else if ($couponInfo['coupon_price'] >= 100) {
|
|
$couponPrice = 0;
|
|
} else {
|
|
$truePrice = (float)bcmul((string)$price, bcdiv((string)$couponInfo['coupon_price'], '100', 2), 2);
|
|
$couponPrice = (float)bcsub((string)$price, (string)$truePrice, 2);
|
|
}
|
|
}
|
|
}
|
|
return [$couponInfo, $couponPrice];
|
|
}
|
|
|
|
/**
|
|
* 实际获取优惠活动赠送赠品
|
|
* @param int $uid
|
|
* @param array $cartList
|
|
* @param array $computedArr
|
|
* @param array $promotionsDetail
|
|
* @param array $productDetails
|
|
* @param array $promotionsArr
|
|
* @param bool $isCart
|
|
* @return array
|
|
*/
|
|
public function getPromotionsGive(int $uid, array $cartList, array $computedArr, array $promotionsDetail, array $productDetails, array $promotionsArr, bool $isCart = false)
|
|
{
|
|
$usePromotionsIds = [];
|
|
if (!$cartList || !$promotionsDetail) {
|
|
return [$cartList, $computedArr, $usePromotionsIds];
|
|
}
|
|
foreach ($promotionsDetail as $promotions_id => $productIds) {
|
|
$promotions = $promotionsArr[$promotions_id] ?? [];
|
|
$productCount = count($productIds);
|
|
if (!$promotions || !$productCount || $promotions['promotions_type'] != 4) continue;
|
|
//验证商品规格是否满足活动
|
|
[$productIds, $uniques] = $this->checkProductCanUsePromotions($productIds, $cartList, $promotions);
|
|
if (!$productIds) {
|
|
continue;
|
|
}
|
|
$promotions_type = (int)$promotions['promotions_type'] ?? 1;
|
|
[$sumPrice, $sumCount, $promotionsProductArr] = $this->getPromotionsProductInfo($promotions_type, $productIds, $cartList, $uniques, (int)$promotions['product_partake_type'], true);
|
|
|
|
$give_product_id = [];
|
|
$give_coupon_ids = [];
|
|
$give_integral = 0;
|
|
$data = ['is_valid' => 0, 'reach_threshold' => 0, 'differ_threshold' => 0, 'promotions_type' => $promotions['promotions_type'], 'sum_promotions_price' => 0, 'product_id' => []];
|
|
if ($promotions['promotions_cate'] == 1) {//阶梯
|
|
$valid = $invalid = [];
|
|
foreach ($promotions['promotions'] as $key => $p) {
|
|
if (($p['threshold_type'] == 1 ? $sumPrice : $sumCount) >= $p['threshold']) {
|
|
$valid = $p;
|
|
} else {
|
|
$invalid = $p;
|
|
break;
|
|
}
|
|
}
|
|
if ($valid) {
|
|
if ($valid['give_integral']) {
|
|
$give_integral = bcadd((string)$give_integral, (string)$valid['give_integral'], 0);
|
|
}
|
|
if ($valid['give_coupon_id']) {
|
|
$coupon_ids = is_string($valid['give_coupon_id']) ? explode(',', $valid['give_coupon_id']) : $valid['give_coupon_id'];
|
|
$give_coupon_ids = array_merge($give_coupon_ids, $coupon_ids);
|
|
}
|
|
if ($valid['giveProducts']) {
|
|
foreach ($valid['giveProducts'] as $value) {
|
|
if (isset($give_product_id[$value['unique']])) {
|
|
$give_product_id[$value['unique']]['cart_num'] = $give_product_id[$value['unique']]['cart_num'] + 1;
|
|
} else {
|
|
$give_product_id[$value['unique']] = ['promotions_id' => $value['promotions_id'], 'unique' => $value['unique'], 'product_id' => $value['product_id'], 'cart_num' => 1];
|
|
}
|
|
}
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['reach_threshold'] = $valid['threshold'];
|
|
}
|
|
if ($invalid) {
|
|
if ($valid) $data['is_valid'] = 2;
|
|
$data['differ_threshold'] = bcsub((string)$invalid['threshold'], (string)($invalid['threshold_type'] == 1 ? $sumPrice : $sumCount), 0);
|
|
}
|
|
} else {//循环
|
|
$p = $promotions['promotions'][0] ?? [];
|
|
$validCount = floor((float)bcdiv((string)($p['threshold_type'] == 1 ? $sumPrice : $sumCount), (string)$p['threshold'], 2));
|
|
if ($validCount) {//满足次数
|
|
if ($p['give_integral']) {
|
|
$give_integral = bcadd((string)$give_integral, (string)bcmul((string)$validCount, (string)$p['give_integral'], 0), 0);
|
|
}
|
|
if ($p['give_coupon_id']) {
|
|
$coupon_ids = is_string($p['give_coupon_id']) ? explode(',', $p['give_coupon_id']) : $p['give_coupon_id'];
|
|
$give_coupon_ids = array_merge($give_coupon_ids, $coupon_ids);
|
|
}
|
|
if ($p['giveProducts']) {
|
|
foreach ($p['giveProducts'] as $value) {
|
|
if (isset($give_product_id[$value['unique']])) {
|
|
$give_product_id[$value['unique']]['cart_num'] = bcadd((string)$give_product_id[$value['unique']]['cart_num'], (string)$validCount);
|
|
} else {
|
|
$give_product_id[$value['unique']] = ['promotions_id' => $value['promotions_id'], 'unique' => $value['unique'], 'product_id' => $value['product_id'], 'cart_num' => $validCount];
|
|
}
|
|
}
|
|
}
|
|
$data['is_valid'] = 1;
|
|
$data['reach_threshold'] = $p['threshold'];
|
|
} else {
|
|
$data['differ_threshold'] = bcsub((string)$p['threshold'], (string)($p['threshold_type'] == 1 ? $sumPrice : $sumCount), 0);
|
|
}
|
|
}
|
|
$ids = [];
|
|
//验证优惠券限量
|
|
if ($give_coupon_ids) {
|
|
foreach ($give_coupon_ids as $give_coupon_id) {
|
|
foreach ($promotions['promotions'] as $value) {
|
|
$giveCoupon = $value['giveCoupon'] ?? [];
|
|
if ($giveCoupon) $giveCoupon = array_combine(array_column($giveCoupon, 'coupon_id'), $giveCoupon);
|
|
if ($giveCoupon && ($giveCoupon[$give_coupon_id]['surplus_num'] ?? 0) >= 1) {
|
|
$ids[] = $give_coupon_id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$data['give'] = ['give_integral' => $give_integral, 'give_coupon' => $ids, 'give_product' => $give_product_id];
|
|
$computedArr[$promotions_id] = $data;
|
|
if (!$isCart && $data['is_valid'] > 0) {
|
|
$usePromotionsIds[] = $promotions_id;
|
|
} elseif ($isCart) {
|
|
$usePromotionsIds[] = $promotions_id;
|
|
}
|
|
}
|
|
foreach ($cartList as &$cart) {
|
|
$product_id = $cart['product_id'] ?? 0;
|
|
$promotionsIds = $productDetails[$product_id] ?? [];
|
|
if (!$promotionsIds) {
|
|
continue;
|
|
}
|
|
$useIds = array_intersect($promotionsIds, $usePromotionsIds);
|
|
$cart['promotions_id'] = array_unique(array_merge($cart['promotions_id'] ?? [], $useIds));
|
|
}
|
|
return [$cartList, $computedArr, $usePromotionsIds];
|
|
}
|
|
|
|
/**
|
|
* 生成赠送商品购物车数据
|
|
* @param int $uid
|
|
* @param int $promotions_id
|
|
* @param array $giveProduct
|
|
* @param array promotions
|
|
* @param int $store_id
|
|
* @return array
|
|
*/
|
|
public function createGiveProductCart(int $uid, int $promotions_id, array $giveProduct, array $promotions, int $store_id = 0)
|
|
{
|
|
$cart = [];
|
|
if ($giveProduct) {
|
|
/** @var StoreOrderCreateServices $storeOrderCreateService */
|
|
$storeOrderCreateService = app()->make(StoreOrderCreateServices::class);
|
|
/** @var StoreCartServices $storeCartServices */
|
|
$storeCartServices = app()->make(StoreCartServices::class);
|
|
$promotionsArr = $promotions['promotions'] ?? [];
|
|
foreach ($giveProduct as $unique => $give) {
|
|
$product_id = $give['product_id'] ?? 0;
|
|
$cart_num = $give['cart_num'] ?? 1;
|
|
if (!$product_id) {
|
|
continue;
|
|
}
|
|
try {
|
|
[$attrInfo, $product_attr_unique, $bargainPriceMin, $cart_num, $productInfo] = $storeCartServices->checkProductStock($uid, (int)$product_id, (int)$cart_num, $store_id, $unique, true);
|
|
} catch (\Throwable $e) {
|
|
continue;
|
|
}
|
|
$is_limit = false;
|
|
foreach ($promotionsArr as $key => $value) {
|
|
$giveProducts = $value['giveProducts'] ?? [];
|
|
if ($giveProducts) $giveProducts = array_combine(array_column($giveProducts, 'product_id'), $giveProducts);
|
|
if ($giveProducts && $cart_num <= ($giveProducts[$product_id]['surplus_num'] ?? 0)) {
|
|
$is_limit = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$is_limit) {
|
|
continue;
|
|
}
|
|
|
|
$key = $storeOrderCreateService->getNewOrderId((string)$uid);
|
|
$info['id'] = $key;
|
|
$info['type'] = 0;
|
|
$info['product_type'] = $productInfo['product_type'];
|
|
$info['promotions_id'] = [$give['promotions_id'] ?? $promotions_id];
|
|
$info['activity_id'] = 0;
|
|
$info['discount_product_id'] = 0;
|
|
$info['product_id'] = $product_id;
|
|
$info['is_gift'] = 1;
|
|
$info['is_valid'] = 1;
|
|
$info['product_attr_unique'] = $product_attr_unique;
|
|
$info['cart_num'] = $cart_num;
|
|
$info['productInfo'] = $productInfo ? $productInfo->toArray() : [];
|
|
$info['productInfo']['express_delivery'] = false;
|
|
$info['productInfo']['store_mention'] = false;
|
|
$info['productInfo']['store_delivery'] = false;
|
|
if (isset($info['productInfo']['delivery_type'])) {
|
|
$info['productInfo']['delivery_type'] = is_string($info['productInfo']['delivery_type']) ? explode(',', $info['productInfo']['delivery_type']) : $info['productInfo']['delivery_type'];
|
|
if (in_array(1, $info['productInfo']['delivery_type'])) {
|
|
$info['productInfo']['express_delivery'] = true;
|
|
}
|
|
if (in_array(2, $info['productInfo']['delivery_type'])) {
|
|
$info['productInfo']['store_mention'] = true;
|
|
}
|
|
if (in_array(3, $info['productInfo']['delivery_type'])) {
|
|
$info['productInfo']['store_delivery'] = true;
|
|
}
|
|
}
|
|
$info['productInfo']['attrInfo'] = $attrInfo->toArray();
|
|
$info['attrStatus'] = (bool)$info['productInfo']['attrInfo'];
|
|
$info['sum_price'] = $info['productInfo']['attrInfo']['price'] ?? $info['productInfo']['price'] ?? 0;
|
|
$info['truePrice'] = 0;
|
|
$info['vip_truePrice'] = 0;
|
|
$info['trueStock'] = $info['productInfo']['attrInfo']['stock'] ?? 0;
|
|
$info['costPrice'] = $info['productInfo']['attrInfo']['cost'] ?? 0;
|
|
$info['limit_num'] = $giveProducts[$product_id]['limit_num'] ?? 0;
|
|
|
|
$cart[] = $info;
|
|
}
|
|
}
|
|
return $cart;
|
|
}
|
|
|
|
/**
|
|
* 根据类型获取商品列表
|
|
* @param int $type
|
|
* @param int $uid
|
|
* @param int $promotions_id
|
|
* @param int $store_id
|
|
* @param int $staff_id
|
|
* @param int $tourist_uid
|
|
* @return array|array[]|null
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getTypeList(int $type, int $uid, int $promotions_id = 0)
|
|
{
|
|
$store_id = (int)$this->getItem('store_id', 0);
|
|
$staff_id = (int)$this->getItem('staff_id', 0);
|
|
$tourist_uid = (int)$this->getItem('tourist_uid', 0);
|
|
$store_name = $this->getItem('store_name', '');
|
|
$ids = $this->getItem('ids', []);
|
|
$not_ids = $this->getItem('not_ids', []);
|
|
$where = [];
|
|
$where['type'] = 1;
|
|
$where['store_id'] = 0;
|
|
$where['pid'] = 0;
|
|
$where['is_del'] = 0;
|
|
$where['status'] = 1;
|
|
$where['promotionsTime'] = true;
|
|
$where['promotions_type'] = $type;
|
|
if ($promotions_id) {
|
|
$where['id'] = $promotions_id;
|
|
}
|
|
$product_where = [];
|
|
$product_where['store_name'] = $store_name;
|
|
$product_where['pids'] = $ids;
|
|
$product_where['not_pids'] = $not_ids;
|
|
//门店不展示卡密商品
|
|
$product_where['product_type'] = [0, 2, 4];
|
|
//存在一个全部商品折扣优惠活动 直接返回商品
|
|
|
|
if ($ids && !$this->dao->count($where + ['product_partake_type' => 1])) {
|
|
//正选并集
|
|
$mergeIds = function ($promotions) {
|
|
$data = [];
|
|
foreach ($promotions as $item) {
|
|
$productIds = is_string($item['product_id']) ? explode(',', $item['product_id']) : $item['product_id'];
|
|
$data = array_merge($data, $productIds);
|
|
}
|
|
return $data;
|
|
};
|
|
$promotions = $this->getList($where + ['product_partake_type' => 2], 'id,product_id');
|
|
$product_where['pids'] = $promotions ? $mergeIds($promotions) : [];
|
|
$notPromotions = $this->getList($where + ['product_partake_type' => 3], 'id,product_id');
|
|
//反选交集
|
|
/** @var StorePromotionsAuxiliaryServices $auxiliaryService */
|
|
$auxiliaryService = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$intersectIds = function ($promotions) use ($auxiliaryService) {
|
|
$data = [];
|
|
foreach ($promotions as $item) {
|
|
$productIds = is_string($item['product_id']) ? explode(',', $item['product_id']) : $item['product_id'];
|
|
if (!$productIds) {
|
|
continue;
|
|
}
|
|
$productIds = $auxiliaryService->getColumn(['promotions_id' => $item['id'], 'type' => 1, 'is_all' => 1, 'product_id' => $productIds], 'product_id', '', true);
|
|
if (!$productIds) {
|
|
continue;
|
|
}
|
|
if ($data) {
|
|
$data = array_intersect($data, $productIds);
|
|
} else {
|
|
$data = $productIds;
|
|
}
|
|
}
|
|
return $data;
|
|
};
|
|
$product_where['not_pids'] = array_merge($product_where['not_pids'], $notPromotions ? $intersectIds($notPromotions) : []);
|
|
}
|
|
$list = [];
|
|
$count = 0;
|
|
if ($product_where['pids'] && $this->dao->count($where)) {
|
|
$product_where['pids'] = array_merge(array_diff($product_where['pids'], $product_where['not_pids']));
|
|
unset($product_where['not_pids']);
|
|
/** @var StoreBranchProductServices $branchProductServices */
|
|
$branchProductServices = app()->make(StoreBranchProductServices::class);
|
|
return $branchProductServices->getCashierProductListV2($product_where, $store_id, $uid, $staff_id, $tourist_uid);
|
|
}
|
|
return compact('list', 'count');
|
|
}
|
|
|
|
/**
|
|
* 根据活动类别查询商品
|
|
* @param array $type
|
|
* @return array|array[]
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function collectProductByType(array $type = [])
|
|
{
|
|
if ($type) {
|
|
$where['promotions_type'] = $type;
|
|
}
|
|
$where['type'] = 1;
|
|
$where['store_id'] = 0;
|
|
$where['pid'] = 0;
|
|
$where['is_del'] = 0;
|
|
$where['status'] = 1;
|
|
$where['promotionsTime'] = true;
|
|
//存在一个全部商品折扣优惠活动 直接返回商品
|
|
if ($this->dao->count($where + ['product_partake_type' => 1])) {
|
|
$product_where = [];
|
|
} else {
|
|
/** @var StoreProductRelationServices $storeProductRelationServices */
|
|
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$promotionsIds = $this->getAllShowActivityIds($type, 'id,promotions_type,product_partake_type');
|
|
$product_ids = [];
|
|
$product_where = ['ids' => []];
|
|
foreach ($promotionsIds as $item) {
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($item['id']);
|
|
switch ($item['product_partake_type']) {
|
|
case 1://所有商品
|
|
break;
|
|
case 2://选中商品参与
|
|
$product_ids = $promotionsAuxiliaryData;
|
|
break;
|
|
case 3:
|
|
$item['product_count'] = 0;
|
|
break;
|
|
case 4://品牌
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
break;
|
|
case 5://商品标签
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
break;
|
|
}
|
|
$product_where['ids'] = array_merge($product_where['ids'], $product_ids ? $product_ids : []);
|
|
}
|
|
}
|
|
return $product_where;
|
|
}
|
|
|
|
/**
|
|
* 获取凑单商品ids
|
|
* @param int $promotions_id
|
|
* @return array
|
|
*/
|
|
public function collectProductById(int $promotions_id)
|
|
{
|
|
$product_where = [];
|
|
$promotions = $this->dao->get($promotions_id, ['*']);
|
|
if ($promotions) {
|
|
$promotions = $promotions->toArray();
|
|
/** @var StoreProductRelationServices $storeProductRelationServices */
|
|
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($promotions_id);
|
|
switch ($promotions['product_partake_type']) {
|
|
case 1://所有商品
|
|
break;
|
|
case 2://选中商品参与
|
|
$product_ids = $promotionsAuxiliaryData;
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
case 3:
|
|
$ids = is_string($promotions['product_id']) ? explode(',', $promotions['product_id']) : $promotions['product_id'];
|
|
if ($ids) {//商品全部规格 不参与 才不显示该商品
|
|
/** @var StorePromotionsAuxiliaryServices $auxiliaryService */
|
|
$auxiliaryService = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$ids = $auxiliaryService->getColumn(['promotions_id' => $promotions['id'], 'type' => 1, 'is_all' => 1, 'product_id' => $ids], 'product_id', '', true);
|
|
}
|
|
$product_where['not_ids'] = $ids;
|
|
break;
|
|
case 4://品牌
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
case 5://商品标签
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
}
|
|
}
|
|
return $product_where;
|
|
}
|
|
|
|
/**
|
|
* 获取凑单商品ids
|
|
* @param int $promotions_id
|
|
* @return array
|
|
*/
|
|
public function collectOrderProduct(int $promotions_id)
|
|
{
|
|
$product_where = [];
|
|
$promotions = $this->dao->get($promotions_id, ['*']);
|
|
if ($promotions) {
|
|
$promotions = $promotions->toArray();
|
|
/** @var StoreProductRelationServices $storeProductRelationServices */
|
|
$storeProductRelationServices = app()->make(StoreProductRelationServices::class);
|
|
/** @var StorePromotionsAuxiliaryServices $promotionsAuxiliaryServices */
|
|
$promotionsAuxiliaryServices = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$promotionsAuxiliaryData = $promotionsAuxiliaryServices->getPromotionsAuxiliaryCache($promotions_id);
|
|
switch ($promotions['product_partake_type']) {
|
|
case 1://所有商品
|
|
break;
|
|
case 2://选中商品参与
|
|
$product_ids = $promotionsAuxiliaryData;
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
case 3:
|
|
$ids = is_string($promotions['product_id']) ? explode(',', $promotions['product_id']) : $promotions['product_id'];
|
|
if ($ids) {//商品全部规格 不参与 才不显示该商品
|
|
/** @var StorePromotionsAuxiliaryServices $auxiliaryService */
|
|
$auxiliaryService = app()->make(StorePromotionsAuxiliaryServices::class);
|
|
$ids = $auxiliaryService->getColumn(['promotions_id' => $promotions['id'], 'type' => 1, 'is_all' => 1, 'product_id' => $ids], 'product_id', '', true);
|
|
}
|
|
$product_where['not_ids'] = $ids;
|
|
break;
|
|
case 4://品牌
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 2, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
case 5://商品标签
|
|
$product_ids = $promotionsAuxiliaryData ? $storeProductRelationServices->getIdsByWhere(['type' => 3, 'relation_id' => $promotionsAuxiliaryData]) : [];
|
|
$product_where['ids'] = $product_ids;
|
|
break;
|
|
}
|
|
}
|
|
return $product_where;
|
|
}
|
|
|
|
}
|
|
|