Files

1016 lines
38 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\common\library\order;
use think\Model;
use app\common\model\goods\Handle;
use app\common\exception\Exception;
use app\common\model\order\Item as OrderItem;
use think\Db;
use app\common\model\order\Order as orderModel;
class OrderCreate
{
/**
* 类型,create:创建订单,calc:计算费用
*/
protected $calc_type = 'create';
protected $order_type = 'goods';
protected $goodsList = [];
protected $user = null;
protected $msg = null;
/**
* 订单相关费用
*/
protected $orderData = [
'goods_total_price_marking' => '0', // 商品原始总价
'goods_total_price' => '0', // 商品总价
'coupon_discount_fee' => '0', // 优惠券优惠金额
'discount_price' => 0, // 当前订单,总优惠金额(优惠券 + 活动优惠)
'coupon' => null, // 所使用的优惠券
'coupon_goods_ids' => [],
'dispatch_price' => '0', // 运费总价
'score_amount' => 0, // 订单总积分
'order_total_price' => 0, // 订单总费用
'real_price' => 0, // 应支付总金额 (减去优惠之后的)
"vip_discount_price"=>0,//会员优惠
"score_fee"=>0,//支付积分
'goods_count'=>0,
'user_id'=>0,
'live_id'=>'',
'live_goods_action_id'=>''
];
protected $scoreGoodsModel = null;
public function __construct($params = [])
{
$this->user = user_info();
if($this->user){
$this->orderData['user_id'] = $this->user->id;
}
if($params){
$this->calcParams($params);
}
}
/**
* 创建订单
* @param $result
* @return mixed
*/
public function createOrder($result)
{
$order = $this->createHandle($result);
return $order;
}
/**
* 创建订单
* @param $result
* @return mixed
*/
public function createHandle($orderCalculate=[],$orderSource='')
{
//订单来源
if(!$orderSource){
$orderSource = \app\common\library\Platform::getPlatform();
}
// 如果需要支付积分,扣除积分
if ($this->order_type=='score' && $orderCalculate['score_amount']) {
//扣积分
$user = \app\common\model\User::getUserInfo($this->user->id);
if(!$user || $user['score'] < $orderCalculate['score_amount']){
//抛出异常 积分不足
new \app\common\exception\Exception('当前积分余额不足');
}
\app\common\model\User::score((-1 * $orderCalculate['score_amount']),$this->user->id,"积分兑换商品");
}
$order = Db::transaction(function () use ($orderCalculate,$orderSource) {
$orderData = [];
$orderData['order_no'] = orderModel::getSn($this->user->id ?? 0);
$orderData['user_id'] = $this->user->id ?? 0;
$orderData['need_post'] = 0;
$orderData['order_type'] = $this->order_type;
$orderData['goods_total_price_marking'] = $this->orderData['goods_total_price_marking'];
$orderData['goods_total_price'] = $this->orderData['goods_total_price'];
$orderData['dispatch_price'] = $this->orderData['dispatch_price'];
$orderData['order_total_price'] = $this->orderData['order_total_price'];
$orderData['real_price'] = $this->orderData['real_price'];
$orderData['discount_price'] = $this->orderData['discount_price'];
$orderData['goods_count'] = $orderCalculate['goods_count'];
$orderData['vip_discount_price'] = $this->orderData['vip_discount_price'];
$orderData['coupon_discount_fee'] = $this->orderData['coupon_discount_fee'] ?? 0;
$orderData['coupon_user_id'] = isset($orderCalculate['coupon']) && $orderCalculate['coupon'] ? $orderCalculate['coupon']['id'] : 0;
$orderData['coupon_id'] = isset($orderCalculate['coupon']) && $orderCalculate['coupon']->coupon->id ? $orderCalculate['coupon']->coupon->id : 0;
$orderData['status'] = \app\common\constant\order\Status::STATUS_UNPAID;
$orderData['buyer_remark'] = $this->remark ?? '';
$orderData['source'] = $orderSource;
$orderData['uniacid'] = UNIACID;
$orderData['createtime'] = time();
$orderData['live_id'] = $this->orderData['live_id'];
$orderData['score_amount'] = $orderCalculate['score_amount'];
$orderData['score_fee'] = $orderCalculate['score_amount'];
$orderData['is_virtual_pay'] = isset($orderCalculate['is_virtual_pay']) ? intval($orderCalculate['is_virtual_pay']) : 0;
if ($orderData['is_virtual_pay'] && $orderData['real_price'] < 1) {
$orderData['real_price'] = 1;
}
$order = orderModel::insertGetId($orderData);
// 将优惠券使用掉
if (isset($orderCalculate['coupon']) && $orderCalculate['coupon']) {
$orderCalculate['coupon']->use_order_id = $order;
$orderCalculate['coupon']->use_time = time();
$orderCalculate['coupon']->allowField(true)->save();
}
// 添加 订单 item(使用原始goodsList,不乘汇率)
foreach ($this->goodsList as $key => $buyinfo) {
$item = [];
$item['item_id'] = $buyinfo['item_id'];
$item['item_name'] = $buyinfo['item_name'];
$item['count'] = $buyinfo['count'];
$item['total_price_marking'] = $buyinfo['total_price_marking'];
$item['total_price'] = $buyinfo['total_price'];
$item['goods_type'] = $buyinfo['goodsType'];
$item['unit_price'] = $buyinfo['unit_price'];
$item['discount_price'] = $buyinfo['discount_price'];
$item['real_price'] = $buyinfo['real_price'];
if ($orderData['is_virtual_pay'] && $item['real_price'] < 1) {
$item['real_price'] = 1;
}
$item['snapshoot'] = is_array($buyinfo['snapshoot']) ? json_encode($buyinfo['snapshoot']) : $buyinfo['snapshoot'];
$item['vip_discount_price'] = $buyinfo['vip_discount_price'];
$item['coupon_discount_fee'] = $buyinfo['coupon_discount_fee'];
$item['createtime'] = $orderData['createtime'];
$item['send_status'] = $orderData['status'];
$item['order_no'] = $orderData['order_no'];
$item['user_id'] = $orderData['user_id'];
$item['score_amount'] = $orderData['score_amount'];
if($this->order_type == 'vipcard' || $this->order_type == 'activity' || $this->order_type == 'live_gift'){
$item['extend_data'] = $buyinfo['extend_data'];
}
$item['uniacid'] = UNIACID;
OrderItem::insert($item);
if($item['goods_type'] == 'activity'){
$ticketInfo = json_decode($item['snapshoot'],true);
if($ticketInfo['form_user_id'] != $item['user_id']){
throw new \app\common\exception\Exception('报名信息错误,请返回重试');
}
}
}
// 保存订单地址(实物商品)
if ($this->order_type == 'physical' && isset($this->orderData['address_id']) && $this->orderData['address_id']) {
$this->saveOrderAddress($order, $orderData);
}
if($orderSource == 'channels' && \app\common\library\Platform::getSystemType() == 'single' && \app\admin\library\project\App::isInstall('channels')){
$hookParams = [
'params'=>$orderCalculate['channels_params'],
'order'=>$orderData
];
\think\Hook::listen('channels_order_push',$hookParams);
}
// 重新获取订单
$order = orderModel::where('id', $order)->find();
\app\common\model\order\Log::set($orderData['order_no'],"订单创建完成,等待支付");
\think\Hook::listen('agent',$orderData['order_no']);
//同步订单号到直播商品
if($this->orderData['live_goods_action_id']){
$liveGoodsAction = [
'live_goods_action_id'=>$this->orderData['live_goods_action_id'],
'order_no'=>$orderData['order_no'],
'user_id'=>$orderData['user_id']
];
\think\Hook::listen('live_goods_order',$liveGoodsAction);
}
return $order;
});
return $order;
}
/**
* 获取请求参数,初始化,并设置默认值
*
* @param array $params
* @return array
*/
public function calcParams($params)
{
$this->order_type = $params['order_type'] ?? 'goods';
if($this->order_type == 'score'){
$this->scoreGoodsModel = new \app\api\model\app\score\Goods;
}
$this->goodsList = $params['goods_list'] ?? [];
$this->coupon_id = $params['coupon_id'] ?? 0;
$this->remark = $params['buyer_remark'] ?? '';
$this->money = (isset($params['money']) && $params['money'] > 0) ? $params['money'] : 0;
$this->orderData['live_goods_action_id'] = '';
if(isset($params['live_id'])){
$this->orderData['live_id'] = $params['live_id'];
}
if(isset($params['live_goods_action_id'])){
$this->orderData['live_goods_action_id'] = $params['live_goods_action_id'];
}
if(isset($params['address_id'])){
$this->orderData['address_id'] = $params['address_id'];
}
// 获取商品信息
$this->goodsListInit();
}
/**
* 格式化订单商品
* @return void
*/
public function goodsListInit()
{
foreach ($this->goodsList as $key => &$buyinfo) {
$buyinfo['extend'] = isset($buyinfo['extend']) ? $buyinfo['extend'] : '';
$detail = Handle::getGoodsDetail($buyinfo['goodsId'],$buyinfo['goodsType'],$buyinfo['count'],$buyinfo['extend']);
if (!$detail || $detail['status'] != 1) {
throw new Exception('商品不存在或已下架');
}
if($buyinfo['goodsType'] == 'vipcard'){
$buyinfo['goodsId'] = explode("_",$buyinfo['goodsId'])[0];
}
if($buyinfo['goodsType'] == 'physical'){
$buyinfo['goodsId'] = explode("_",$buyinfo['goodsId'])[0];
}
if($this->order_type == 'score'){
$detail['score_goods'] = $this->scoreGoodsModel->where([
'goods_id'=>$buyinfo['goodsId']
])->find();
}
$buyinfo['coupon_discount_fee'] = 0;
$buyinfo['discount_price'] = 0;
$buyinfo['detail'] = $detail;
// $this->goodsList[] = $buyinfo;
// $buyinfo['goods'] = $buyinfo;
}
}
/**
* 是否计算促销
*
* @return bool
*/
private function isCalcPromos()
{
if ($this->order_type == 'score') {
return false; // 积分商品不能参与促销
} else {
return true;
}
}
/**
* 计算订单
*
* @return void
*/
public function calc($calc_type = 'calc')
{
$this->calc_type = $calc_type;
// 检查系统必要条件
// check_env(['bcmath', 'queue']);
// 检查是否可下单
$this->calcCheck();
// 计算订单各种费用
$this->calcAmount();
// 计算优惠券费用
if ($this->coupon_id) {
$this->calcCoupon();
}
foreach ($this->goodsList as $key => $buyinfo) {
//单个商品的优惠金额
$this->goodsList[$key]['real_price'] = $this->goodsList[$key]['total_price'] - $this->goodsList[$key]['discount_price'];
}
// 订单应付金额
$this->orderData['order_total_price'] = bcadd($this->orderData['goods_total_price'], $this->orderData['dispatch_price'], 2);
$this->orderData['discount_price'] = bcadd($this->orderData['coupon_discount_fee'], $this->orderData['vip_discount_price'], 2);
$this->orderData['real_price'] = bcsub($this->orderData['order_total_price'], $this->orderData['discount_price'], 2);
$this->orderData['real_price'] = $this->orderData['real_price'] < 0 ? 0 : $this->orderData['real_price'];
return $this->calcReturn();
}
/**
* 返回订单数据
* @return []|array
*/
public function calcReturn() {
$isVirtualPay = $this->isUseVirtualPay();
$result = [
'goods_total_price_marking' => $this->orderData['goods_total_price_marking'],
'vip_discount_price'=>$this->orderData['vip_discount_price'],
'goods_total_price' => $this->orderData['goods_total_price'],
'dispatch_price' => $this->orderData['dispatch_price'],
'order_total_price' => $this->orderData['order_total_price'],
'real_price' => $this->orderData['real_price'],
'discount_price' => $this->orderData['discount_price'],
'coupon_discount_fee' => $this->orderData['coupon_discount_fee']
];
// 处理小数点保留两位小数
foreach ($result as $key => $amount) {
$result[$key] = number_format($amount, 2, '.', '');
}
$orderGoodsList = $this->goodsList;
if ($isVirtualPay) {
$result = $this->convertVirtualPayResultPrices($result);
$orderGoodsList = $this->convertVirtualPayGoodsPrices($orderGoodsList);
}
// 合并不需要处理小数点的
$result = array_merge($result, [
'score_amount' => $this->orderData['score_amount'],
'goods_count' => $this->orderData['goods_count'],
'is_virtual_pay' => $isVirtualPay,
'orderGoodsList' => $orderGoodsList
]);
// 如果是下单,合并 优惠券, 收货地址
if ($this->calc_type == 'create') {
$result = array_merge($result, [
"coupon" => $this->orderData['coupon']
]);
} else {
$result = array_merge($result, ['msg' => $this->msg]);
}
return $result;
}
/**
* 转换订单金额字段为代币展示金额。
* @param array $result
* @return array
*/
protected function convertVirtualPayResultPrices($result)
{
return \app\common\library\pay\VirtualPayService::convertPriceFields($result, [
'goods_total_price_marking',
'vip_discount_price',
'goods_total_price',
'dispatch_price',
'order_total_price',
'real_price',
'discount_price',
'coupon_discount_fee'
]);
}
/**
* 转换订单商品金额字段为代币展示金额。
* @param array $goodsList
* @return array
*/
protected function convertVirtualPayGoodsPrices($goodsList)
{
foreach ($goodsList as &$buyinfo) {
$buyinfo = \app\common\library\pay\VirtualPayService::convertPriceFields($buyinfo, [
'coupon_discount_fee',
'discount_price',
'real_price',
'total_price_marking',
'total_price',
'unit_price',
'vip_discount_price'
]);
if (isset($buyinfo['detail'])) {
$detail = $buyinfo['detail'];
if (!is_array($detail)) {
$detail = $detail instanceof \think\Model ? $detail->toArray() : (array)$detail;
}
$detail = \app\common\library\pay\VirtualPayService::convertPriceFields($detail, [
'price',
'price_marking',
'pay_price',
'min_price'
]);
$buyinfo['detail'] = $detail;
$buyinfo['snapshoot'] = json_encode($detail);
}
}
unset($buyinfo);
return $goodsList;
}
/**
* 根据订单内商品实际类型判断是否使用微信虚拟支付。
* @return int
*/
protected function isUseVirtualPay()
{
foreach ($this->goodsList as $buyinfo) {
$goodsType = isset($buyinfo['detail']['type']) ? $buyinfo['detail']['type'] : ($buyinfo['goodsType'] ?? '');
if (!$goodsType) {
continue;
}
if (\app\common\library\pay\VirtualPayService::isUseVirtualPay($goodsType)) {
return 1;
}
}
return 0;
}
/**
* 计算优惠券的优惠
*
* @return void
*/
public function calcCoupon()
{
// 获取优惠券
$this->getCoupon($this->coupon_id);
if ($this->orderData['coupon']) {
$this->orderData['coupon']->coupon_money = $this->orderData['coupon']->coupon_money > $this->orderData['goods_total_price'] ? $this->orderData['goods_total_price'] : $this->orderData['coupon']->coupon_money;
$this->orderData['coupon_discount_fee'] = $this->orderData['coupon']->coupon_money; // 获取优惠券时计算的金额
$this->orderData['coupon_goods_ids'] = $this->orderData['coupon']->goods_ids; // 获取优惠券时参与的商品
// 将当前优惠券优惠金额平分到使用优惠券的商品上
foreach ($this->goodsList as &$buyInfo) {
if (in_array($buyInfo['goodsId'], $this->orderData['coupon_goods_ids'])) {
$avgDiscountPrice = bcdiv($this->orderData['coupon_discount_fee'], $this->orderData['goods_total_price'], 6);
$buyInfo['coupon_discount_fee'] = bcmul($buyInfo['total_price'], $avgDiscountPrice, 6);
$buyInfo['coupon_discount_fee'] = round($buyInfo['coupon_discount_fee'], 2);
$buyInfo['discount_price'] += $buyInfo['coupon_discount_fee'];
}
}
} else {
$this->exception('优惠券不可用');
}
}
/**
* 计算订单各种费用
*
* @return array
*/
public function calcAmount()
{
// 计算商品金额
foreach ($this->goodsList as $key => $buyinfo) {
$detail = $buyinfo['detail'];
$this->orderData['goods_count'] += $buyinfo['count'];
// 当前商品原始总价
$current_goods_total_price_marking = ($detail['price_marking'] * $buyinfo['count']);
$this->orderData['goods_total_price_marking'] += $current_goods_total_price_marking;
// 当前商品现在总价
// 当前商品所需积分
$current_score_amount = 0;
//会员折扣金额
$current_vip_discount_price = 0;
$current_goods_total_price = 0;
switch ($this->order_type){
case 'score':
// 积分商城规格
$current_score_amount = ($detail['score_goods']['score'] * $buyinfo['count']);
$this->orderData['score_amount'] += $current_score_amount;
$current_goods_total_price = 0;
break;
case 'activity':
// 线下活动
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
$this->goodsList[$key]['extend_data'] = \fast\Random::numeric(14);
break;
case 'exercises':
// 题库练习
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
break;
case 'live_gift':
// 直播礼物
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
$this->goodsList[$key]['extend_data'] = $buyinfo['extend']['course_id'].'_'.$buyinfo['extend']['message_topic'];
break;
case 'goods':
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
//获取付费VIP折扣
if($this->user){
$vipUserGoodsDiscount = \app\common\model\app\vip\CardPrivilege::getPrivilegeGoodsDiscount($this->user->id,$detail['id']);
if($vipUserGoodsDiscount){
//会员折扣金额
$current_vip_discount_price += number_format(($current_goods_total_price * (10 - $vipUserGoodsDiscount) / 10), 2, '.', '');;
}
}
break;
case 'physical':
//购买实物商品的订单 规格格式为商品价格_商品数量
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
$this->goodsList[$key]['extend_data'] = $detail['price'].'_'.$buyinfo['count'];
// 检查库存是否满足购买数量
$goodsId = $detail['id'] ?? 0;
$specType = $detail['spec_type'] ?? 'single';
$buyCount = $buyinfo['count'] ?? 1;
$skuPriceQuery = \app\admin\model\app\physical\SkuPrice::where('goods_id', $goodsId)
->where('uniacid', UNIACID);
if ($specType == 'single') {
$skuPrice = $skuPriceQuery->order('id', 'asc')->find();
} else {
$skuText = $detail['sku_text'] ?? '';
$skuPrice = $skuPriceQuery->where('goods_sku_text', $skuText)->find();
}
if (!$skuPrice) {
throw new Exception('商品规格不存在');
}
if ($skuPrice['stock'] < $buyCount) {
throw new Exception('商品库存不足');
}
// 检查限购
$goods = \app\admin\model\app\physical\Goods::where('id', $goodsId)
->where('uniacid', UNIACID)
->find();
if ($goods) {
$singleLimit = $goods['single_limit'] ?? 0;
$lifetimeLimit = $goods['lifetime_limit'] ?? 0;
// 检查单次限购
if ($singleLimit > 0 && $buyCount > $singleLimit) {
throw new Exception('单次限购' . $singleLimit . '件');
}
// 检查终身限购
if ($lifetimeLimit > 0 && $this->user) {
$purchasedCount = \app\common\model\order\Item::where('user_id', $this->user->id)
->where('item_id', $goodsId)
->where('goods_type', 'physical')
->where('refund_status', '<>', 3)
->sum('count');
if (($purchasedCount + $buyCount) > $lifetimeLimit) {
throw new Exception('终身限购' . $lifetimeLimit . '件,已购买' . $purchasedCount . '件');
}
}
}
break;
case 'composite':
if (!\app\admin\library\project\App::isInstall('composite')) {
throw new \app\common\exception\Exception('组合商品未安装');
}
// 组合商品:extend_data 存储规格ID和规格价格的组合
$this->goodsList[$key]['extend_data'] = $detail['spec_id'].'_'.$detail['price'];
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
// 组合原价(划线价)
if (isset($detail['price_marking'])) {
$current_goods_total_price_marking = ($detail['price_marking'] * $buyinfo['count']);
}
break;
case 'vipcard':
//购买会员卡的订单 规格格式为会员卡价格_又下时间
$this->goodsList[$key]['extend_data'] = $detail['price'].'_'.$detail['time'];
//判断会员卡配置 换购,状态
$cardConfig = \app\common\model\app\Config::getConfig('vip');
if($cardConfig['status'] != 1){
throw new Exception('会员卡购买通道暂时关闭');
}
//付费会员卡逻辑
$userVipInfo = \app\common\model\app\vip\CardUser::getUserVipInfo($this->user->id);
//判断会员卡换购状态
if($cardConfig['exchange'] != 1){
if($userVipInfo && $userVipInfo['card_id'] != $detail['id']){
throw new Exception('暂不支持会员卡换购');
}
}
//限购
if($detail['limit'] != 0){
$orderCount = OrderItem::with(['order'=>function($query){
$query->where([
'status'=>\app\common\constant\order\Status::STATUS_SUCCESS
]);
}])->where([
'extend_data'=>$this->goodsList[$key]['extend_data'],
'item_id'=>$detail['id'],
'user_id'=>$this->user->id
])->count();
if($orderCount >= $detail['limit']){
throw new Exception("该会员卡规格限购{$detail['limit']}次,当前已购{$orderCount}次");
}
}
$current_goods_total_price = ($detail['price'] * $buyinfo['count']);
$this->orderData['goods_total_price'] += $current_goods_total_price;
break;
}
//会员折扣金额
$this->goodsList[$key]['vip_discount_price'] = $current_vip_discount_price;
$this->goodsList[$key]['discount_price'] += $current_vip_discount_price;
$this->orderData['vip_discount_price'] += $current_vip_discount_price;
//商品划线价格
$this->goodsList[$key]['total_price_marking'] = $current_goods_total_price_marking;
//商品总价
$this->goodsList[$key]['total_price'] = $current_goods_total_price;
//商品单价
$this->goodsList[$key]['unit_price'] = $detail['price'];
$this->goodsList[$key]['item_id'] = $detail['id'];
$this->goodsList[$key]['item_name'] = $detail['name'];
//积分支付数
$this->goodsList[$key]['score_amount'] = $current_score_amount;
$this->goodsList[$key]['snapshoot'] = json_encode($detail);
}
}
/**
* 下单前检测,商品状态,秒杀,拼团活动状态,必要的选择项(比如下单收货地址),收货地址等
*
* @param array $params,请求参数
* @return array
*/
public function calcCheck()
{
if (!count($this->goodsList)) {
$this->exception('请选择要购买的商品');
}
if ($this->order_type == 'score' && count($this->goodsList) > 1) {
$this->exception('积分商品必须单独购买');
}
// 购买课程前表单校验
if (\app\admin\library\project\App::isInstall('form')) {
foreach ($this->goodsList as $goodsItem) {
$goodsId = $goodsItem['goodsId'] ?? 0;
if (!$goodsId) continue;
// 通过 content_id 匹配,不按 content_type(课程类商品 order 的 goodsType 是 course
// 而 bind 表存储的实际类型如 column/video 等,直接匹配会查不到)
$bindForms = \app\admin\model\app\form\Bind::alias('bind')
->join('app_form f', 'bind.form_id = f.id')
->where('bind.content_id', $goodsId)
->where('f.bind_type', 'before_buy')
->where('f.status', 1)
->field('bind.form_id, f.name')
->select();
if (!empty($bindForms)) {
foreach ($bindForms as $bindForm) {
$submitted = \app\admin\model\app\form\Log::where([
'form_id' => $bindForm['form_id'],
'user_id' => $this->orderData['user_id']
])->count();
if (!$submitted) {
$this->exception("请先完成购买前表单:{$bindForm['name']}");
}
}
}
}
}
}
/**
* 检测用户优惠券是否可用
*
* @param array|object $coupon
* @param string $type
* @return array|object
*/
private function checkCoupon($coupon)
{
$can_use = true;
$cannot_use_msg = '';
// (积分或者活动 并且 优惠券不支持优惠叠加)
if($this->order_type == 'score'){
$can_use = false;
$cannot_use_msg = '积分商品不可使用优惠券';
return compact('can_use', 'cannot_use_msg');
}
if ($this->orderData['vip_discount_price'] > 0 && $coupon->coupon->double_discount_status == 2) {
$can_use = false;
$cannot_use_msg = '该优惠券不可与会员叠加使用';
return compact('can_use', 'cannot_use_msg');
}
if($coupon->coupon->status == 3){
$can_use = false;
$cannot_use_msg = '该优惠券已作废';
return compact('can_use', 'cannot_use_msg');
}
$goods_total_price = 0;
$goodsIds = []; // 符合优惠券规则的 商品 ids
$goods_bind_ids = json_encode($coupon->goods_bind_ids);
$goods_bind_ids = str_replace("column","course",$goods_bind_ids);
$goods_bind_ids = str_replace("video","course",$goods_bind_ids);
$goods_bind_ids = str_replace("article","course",$goods_bind_ids);
$goods_bind_ids = str_replace("audio","course",$goods_bind_ids);
$goods_bind_ids = str_replace("live","course",$goods_bind_ids);
$goods_bind_ids = json_decode($goods_bind_ids,true);
if ($coupon->use_scope == 'all_use') {
// 计算商品总金额
foreach ($this->goodsList as $buyInfo) {
$buyInfo['goods_total_price'] = $buyInfo['detail']['price'] * $buyInfo['count'];
$goods_total_price = bcadd($goods_total_price, $buyInfo['total_price'], 2);
$goodsIds[] = $buyInfo['goodsId'];
}
} elseif ($coupon->use_scope == 'goods') {
// 计算指定商品的总金额是否满足
foreach ($this->goodsList as $buyInfo) {
if($buyInfo['goodsType'] == 'activity'){
$buyInfo['goodsId'] = $buyInfo['detail']['id'];
}
if (in_array($buyInfo['goodsId']."_".$buyInfo['goodsType'], $goods_bind_ids)) {
$goods_total_price = bcadd($goods_total_price, $buyInfo['total_price'], 2);
$goodsIds[] = $buyInfo['goodsId'];
}
}
} elseif ($coupon->use_scope == 'disabled_goods') {
// 计算非指定的商品的总金额是否满足
foreach ($this->goodsList as $buyInfo) {
if($buyInfo['goodsType'] == 'activity'){
$buyInfo['goodsId'] = $buyInfo['detail']['id'];
}
if (!in_array($buyInfo['goodsId']."_".$buyInfo['goodsType'], $goods_bind_ids)) {
$goods_total_price = bcadd($goods_total_price, $buyInfo['total_price'], 2);
$goodsIds[] = $buyInfo['goodsId'];
}
}
}
if($goods_total_price == 0){
$can_use = false;
$cannot_use_msg = '优惠券不支持该商品';
return compact('can_use', 'cannot_use_msg');
}
if (floatval($coupon->enough) <= $goods_total_price) {
$coupon->coupon_money = $coupon->amount;
$coupon->goods_total_price = $goods_total_price; // 参与优惠券的商品的总金额
$coupon->goods_ids = $goodsIds;
if ($coupon->type == 'discount') {
$scale = bcmul($coupon->coupon->discount, 0.1, 3);
$scale = $scale > 1 ? 1 : ($scale < 0 ? 0 : $scale);
$coupon_money = bcmul(bcsub(1, $scale, 3), $goods_total_price, 2);
// 优惠金额最大为 coupon->max_amount;
$coupon['coupon_money'] = floatval($coupon->max_amount) && $coupon_money > $coupon->max_amount ? $coupon->max_amount : $coupon_money;
}
$this->orderData['coupon'] = $coupon;
} else {
$can_use = false;
if ($goods_total_price > 0) {
$cannot_use_msg = '商品金额不满足优惠券门槛';
} else {
$cannot_use_msg = '优惠券不支持该商品';
}
}
return compact('can_use', 'cannot_use_msg');
}
/**
* 获取用户的优惠券列表,可用和不可用的做区分
* @return array
*/
public function getCoupons($calc_type = 'coupons')
{
$user = user_info();
$this->calc_type = $calc_type;
// 检查是否可下单
$this->calcCheck();
// 计算订单各种费用
$this->calcAmount();
// 用户可用优惠券列表
$coupons = \app\admin\model\app\coupon\CouponUser::with('coupon')->where('user_id', $user->id)->canUse()->select();
$cannot_use = [];
$can_use = [];
foreach ($coupons as $key => $coupon) {
$result = $this->checkCoupon($coupon);
if (isset($result['can_use']) && $result['can_use']) {
$can_use[] = $coupon;
} else {
$coupon->cannot_use_msg = $result['cannot_use_msg'];
$cannot_use[] = $coupon;
}
}
return compact('can_use', 'cannot_use');
}
public function getCoupon($coupon_id)
{
$user = user_info();
// 选用的优惠券
$coupon = \app\admin\model\app\coupon\CouponUser::with('coupon')->where('user_id', $user->id)->canUse()->find($coupon_id);
if ($coupon) {
$result = $this->checkCoupon($coupon);
return (isset($result['can_use']) && $result['can_use']) ? $coupon : null;
}
return null;
}
/**
* 判断并处理异常
*
* @param string $msg 处理结果
* @param boolean $force 是否强制抛出异常
* @return boolean
*/
private function exception($msg, $force = false)
{
if ($this->calc_type == 'create' || $force) {
// 如果是创建订单,或者强制抛出异常
throw new \app\common\exception\Exception($msg);
} else {
// 预下单,记录第一条错误信息
if (!$this->msg) {
$this->msg = $msg;
}
}
return false;
}
/**
* 保存订单地址
*
* @param int $orderId 订单ID
* @param array $orderData 订单数据
* @return void
*/
private function saveOrderAddress($orderId, $orderData)
{
$addressId = $this->orderData['address_id'];
// 获取用户地址
$address = \think\Db::name('user_address')
->where('id', $addressId)
->where('user_id', $this->user->id)
->where('uniacid', UNIACID)
->find();
if (!$address) {
throw new \app\common\exception\Exception('收货地址不存在');
}
// 转换为数组
$address = is_object($address) ? $address->toArray() : $address;
// 保存订单地址
$orderAddressData = [
'order_id' => $orderId,
'user_id' => $this->user->id,
'consignee' => $address['name'],
'mobile' => $address['mobile'],
'province_name' => $address['province'],
'city_name' => $address['city'],
'district_name' => $address['district'],
'address' => $address['address'],
'province_id' => $address['province_id'] ?? 0,
'city_id' => $address['city_id'] ?? 0,
'district_id' => $address['district_id'] ?? 0,
'uniacid' => UNIACID,
'createtime' => time(),
'updatetime' => time()
];
\think\Db::name('app_physical_order_address')->insert($orderAddressData);
}
}