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.
860 lines
42 KiB
860 lines
42 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
|
// +----------------------------------------------------------------------
|
|
// | Author: CRMEB Team <admin@crmeb.com>
|
|
// +----------------------------------------------------------------------
|
|
|
|
namespace app\services\order\cashier;
|
|
|
|
|
|
use app\jobs\activity\StorePromotionsJob;
|
|
use app\jobs\user\MicroPayOrderJob;
|
|
use app\services\activity\collage\UserCollagePartakeServices;
|
|
use app\services\activity\collage\UserCollageCodeServices;
|
|
use app\services\BaseServices;
|
|
use app\services\activity\coupon\StoreCouponUserServices;
|
|
use app\services\activity\coupon\StoreCouponIssueServices;
|
|
use app\services\order\StoreCartServices;
|
|
use app\services\order\StoreOrderCartInfoServices;
|
|
use app\services\order\StoreOrderComputedServices;
|
|
use app\services\order\StoreOrderCreateServices;
|
|
use app\services\order\StoreOrderSuccessServices;
|
|
use app\services\pay\PayServices;
|
|
use app\services\pay\YuePayServices;
|
|
use app\services\product\branch\StoreBranchProductServices;
|
|
use app\services\product\product\StoreProductServices;
|
|
use app\services\product\sku\StoreProductAttrValueServices;
|
|
use app\services\store\SystemStoreServices;
|
|
use app\services\store\SystemStoreStaffServices;
|
|
use app\services\user\level\SystemUserLevelServices;
|
|
use app\services\user\level\UserLevelServices;
|
|
use app\services\user\UserAddressServices;
|
|
use app\services\user\UserInvoiceServices;
|
|
use app\services\user\UserServices;
|
|
use crmeb\services\CacheService;
|
|
use crmeb\traits\OptionTrait;
|
|
use think\exception\ValidateException;
|
|
use function Swoole\Coroutine\batch;
|
|
|
|
/**
|
|
* 收银台订单
|
|
* Class CashierOrderServices
|
|
* @package app\services\order\cashier
|
|
*/
|
|
class CashierOrderServices extends BaseServices
|
|
{
|
|
|
|
use OptionTrait;
|
|
|
|
//余额支付
|
|
const YUE_PAY = 1;
|
|
//线上支付
|
|
const ONE_LINE_PAY = 2;
|
|
//现金支付
|
|
const CASH_PAY = 3;
|
|
|
|
/**
|
|
* 缓存订单信息
|
|
* @param int $uid
|
|
* @param array $cartInfo
|
|
* @param array $priceGroup
|
|
* @param array $other
|
|
* @param array $addr
|
|
* @param array $invalidCartInfo
|
|
* @param array $deduction
|
|
* @param int $cacheTime
|
|
* @return string
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
*/
|
|
public function cacheOrderInfo(int $uid, array $cartInfo, array $priceGroup, array $other = [], array $addr = [], array $invalidCartInfo = [], array $deduction = [], int $cacheTime = 600)
|
|
{
|
|
/** @var StoreOrderCreateServices $storeOrderCreateService */
|
|
$storeOrderCreateService = app()->make(StoreOrderCreateServices::class);
|
|
$key = md5($storeOrderCreateService->getNewOrderId((string)$uid) . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8));
|
|
CacheService::redisHandler()->set('admin_user_order_' . $uid . $key, compact('cartInfo', 'priceGroup', 'other', 'addr', 'invalidCartInfo', 'deduction'), $cacheTime);
|
|
return $key;
|
|
}
|
|
|
|
/**
|
|
* 获取订单缓存信息
|
|
* @param int $uid
|
|
* @param string $key
|
|
* @return |null
|
|
*/
|
|
public function getCacheOrderInfo(int $uid, string $key)
|
|
{
|
|
$cacheName = 'admin_user_order_' . $uid . $key;
|
|
if (!CacheService::redisHandler()->has($cacheName)) return null;
|
|
return CacheService::redisHandler()->get($cacheName);
|
|
}
|
|
|
|
/**
|
|
* 获取订单确认数据
|
|
* @param array $user
|
|
* @param $cartId
|
|
* @param bool $new
|
|
* @param int $addressId
|
|
* @param int $shipping_type
|
|
* @param int $store_id
|
|
* @param int $coupon_id
|
|
* @return array
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getOrderConfirmData(int $uid, $cartId, bool $new, int $addressId, int $shipping_type = 1, int $coupon_id = 0, int $store_id = 0)
|
|
{
|
|
$addr = $data = $user = [];
|
|
if ($uid) {
|
|
/** @var UserServices $userServices */
|
|
$userServices = app()->make(UserServices::class);
|
|
$user = $userServices->getUserCacheInfo($uid);
|
|
}
|
|
/** @var UserAddressServices $addressServices */
|
|
$addressServices = app()->make(UserAddressServices::class);
|
|
if ($addressId) {
|
|
$addr = $addressServices->getAdderssCache($addressId);
|
|
}
|
|
//没传地址id或地址已删除未找到 ||获取默认地址
|
|
if (!$addr && $uid) {
|
|
$addr = $addressServices->getUserDefaultAddressCache($uid);
|
|
}
|
|
if ($store_id) {
|
|
/** @var SystemStoreServices $storeServices */
|
|
$storeServices = app()->make(SystemStoreServices::class);
|
|
$storeServices->getStoreInfo($store_id);
|
|
}
|
|
/** @var StoreCartServices $cartServices */
|
|
$cartServices = app()->make(StoreCartServices::class);
|
|
//获取购物车信息
|
|
$cartGroup = $cartServices->getUserProductCartListV1($uid, $cartId, $new, $addr, $shipping_type, $store_id, $coupon_id);
|
|
$storeFreePostage = floatval(sys_config('store_free_postage')) ?: 0;//满额包邮金额
|
|
$data['storeFreePostage'] = $storeFreePostage;
|
|
$validCartInfo = $cartGroup['valid'];
|
|
$giveCartList = $cartGroup['giveCartList'] ?? [];
|
|
/** @var StoreOrderComputedServices $computedServices */
|
|
$computedServices = app()->make(StoreOrderComputedServices::class);
|
|
$priceGroup = $computedServices->getOrderPriceGroup($uid, $validCartInfo, $addr, $storeFreePostage);
|
|
$priceGroup['couponPrice'] = $cartGroup['couponPrice'] ?? 0;
|
|
$priceGroup['firstOrderPrice'] = $cartGroup['firstOrderPrice'] ?? 0;
|
|
$validCartInfo = array_merge($priceGroup['cartInfo'] ?? $validCartInfo, $giveCartList);
|
|
$other = [
|
|
'offlinePostage' => sys_config('offline_postage'),
|
|
'integralRatio' => sys_config('integral_ratio'),
|
|
'give_integral' => $cartGroup['giveIntegral'] ?? 0,
|
|
'give_coupon' => $cartGroup['giveCoupon'] ?? [],
|
|
'give_product' => $cartGroup['giveProduct'],
|
|
'promotions' => $cartGroup['promotions']
|
|
];
|
|
$deduction = $cartGroup['deduction'];
|
|
$data['product_type'] = $deduction['product_type'] ?? 0;
|
|
$data['valid_count'] = count($validCartInfo);
|
|
$data['addressInfo'] = $addr;
|
|
$data['type'] = $deduction['type'] ?? 0;
|
|
$data['activity_id'] = $deduction['activity_id'] ?? 0;
|
|
$data['seckill_id'] = $deduction['type'] == 1 ? $deduction['activity_id'] : 0;
|
|
$data['bargain_id'] = $deduction['type'] == 2 ? $deduction['activity_id'] : 0;
|
|
$data['combination_id'] = $deduction['type'] == 3 ? $deduction['activity_id'] : 0;
|
|
$data['storeIntegralId'] = $deduction['type'] == 4 ? $deduction['activity_id'] : 0;
|
|
$data['discount_id'] = $deduction['type'] == 5 ? $deduction['activity_id'] : 0;
|
|
$data['newcomer_id'] = $deduction['type'] == 7 ? $deduction['activity_id'] : 0;
|
|
$data['deduction'] = in_array($deduction['product_type'], [1, 2]) || $deduction['activity_id'] > 0;
|
|
$data['cartInfo'] = array_merge($cartGroup['cartInfo'], $giveCartList);
|
|
// $data['giveCartInfo'] = $giveCartList;
|
|
$data['custom_form'] = [];
|
|
$data['give_integral'] = $other['give_integral'];
|
|
$data['give_coupon'] = [];
|
|
if ($other['give_coupon']) {
|
|
/** @var StoreCouponIssueServices $couponIssueService */
|
|
$couponIssueService = app()->make(StoreCouponIssueServices::class);
|
|
$data['give_coupon'] = $couponIssueService->getColumn([['id', 'IN', $other['give_coupon']]], 'id,coupon_title');
|
|
}
|
|
$data['orderKey'] = $this->cacheOrderInfo($uid, $validCartInfo, $priceGroup, $other, $addr, $cartGroup['invalid'] ?? [], $deduction);
|
|
unset($priceGroup['cartInfo']);
|
|
$data['priceGroup'] = $priceGroup;
|
|
|
|
$userInfo = ['uid' => $user['uid'] ?? 0, 'nickname' => $user['nickname'] ?? '', 'avatar' => $user['avatar'] ?? '', 'phone' => $user['phone'] ?? '', 'now_money' => $user['now_money'] ?? 0, 'integral' => $user['integral'] ?? 0];
|
|
//会员
|
|
$userInfo['isMember'] = isset($user['is_money_level']) && $user['is_money_level'] > 0 ? 1 : 0;
|
|
//等级
|
|
$userInfo['level'] = $user['level'] ?? 0;
|
|
$userInfo['level_status'] = 0;
|
|
$userInfo['level_grade'] = '';
|
|
$userInfo['vip'] = isset($priceGroup['vipPrice']) && $priceGroup['vipPrice'] > 0;
|
|
$userInfo['vip_id'] = 0;
|
|
$userInfo['discount'] = 0;
|
|
//用户等级是否开启
|
|
if (sys_config('member_func_status', 1)) {
|
|
/** @var UserLevelServices $levelServices */
|
|
$levelServices = app()->make(UserLevelServices::class);
|
|
$userLevel = $levelServices->getUerLevelInfoByUid($uid);
|
|
if ($userInfo['vip'] || $userLevel) {
|
|
$userInfo['vip'] = true;
|
|
$userInfo['vip_id'] = $userLevel['id'] ?? 0;
|
|
$userInfo['discount'] = $userLevel['discount'] ?? 0;
|
|
}
|
|
if ($userInfo['level']) {
|
|
/** @var SystemUserLevelServices $levelServices */
|
|
$levelServices = app()->make(SystemUserLevelServices::class);
|
|
$levelInfo = $levelServices->getOne(['id' => $userInfo['level']], 'id,name,grade');
|
|
$userInfo['level_grade'] = $levelInfo['grade'] ?? '';
|
|
$userInfo['level_status'] = 1;
|
|
}
|
|
}
|
|
$userInfo['real_name'] = $user['real_name'] ?? $user['nickname'] ?? '';
|
|
$userInfo['record_pone'] = $user['record_pone'] ?? $user['phone'] ?? '';
|
|
$data['userInfo'] = $userInfo;
|
|
$data['offlinePostage'] = $other['offlinePostage'];
|
|
$data['integralRatio'] = $other['integralRatio'];
|
|
$data['integral_ratio_status'] = (int)(sys_config('integral_ratio_status', 1) && in_array($data['type'], [0, 6]));
|
|
|
|
$data['store_func_status'] = (int)(sys_config('store_func_status', 1));//门店是否开启
|
|
$data['store_self_mention'] = false;//门店自提
|
|
$data['store_delivery_status'] = false;//门店配送
|
|
if ($data['store_func_status']) {
|
|
//门店自提是否开启
|
|
/** @var SystemStoreServices $systemStoreServices */
|
|
$systemStoreServices = app()->make(SystemStoreServices::class);
|
|
$data['store_self_mention'] = sys_config('store_self_mention') && $systemStoreServices->count(['type' => 0, 'is_store' => 1]);
|
|
$data['store_delivery_status'] = !!$systemStoreServices->count(['type' => 0]);
|
|
}
|
|
$data['store_func_status'] = $data['store_func_status'] && ($data['store_self_mention'] || $data['store_delivery_status']);
|
|
|
|
$data['system_store'] = [];//门店信息
|
|
/** @var UserInvoiceServices $userInvoice */
|
|
$userInvoice = app()->make(UserInvoiceServices::class);
|
|
$invoice_func = $userInvoice->invoiceFuncStatus();
|
|
$data['invoice_func'] = $invoice_func['invoice_func'];
|
|
$data['special_invoice'] = $invoice_func['special_invoice'];
|
|
/** @var UserServices $userServices */
|
|
$userServices = app()->make(UserServices::class);
|
|
$data['svip_status'] = $svip_status = $userServices->checkUserIsSvip($uid);
|
|
$svip_price = 0.00;
|
|
//开启付费会员 且用户不是付费会员 //计算 开通付费会员节省金额
|
|
if (sys_config('member_card_status', 1) && !$svip_status) {
|
|
$payPrice = $cartServices->getPayPrice((string)$priceGroup['totalPrice'], (string)($priceGroup['couponPrice'] ?? 0), (string)($priceGroup['firstOrderPrice'] ?? 0));
|
|
[$vipPayPrice, $payPostage, $storePostageDiscount] = $cartServices->computeUserVipCart($uid, $cartId, $shipping_type, $new, $store_id, false, $coupon_id, $addr);
|
|
$svip_price = (float)max(bcadd((string)bcsub((string)$payPrice, (string)$vipPayPrice, 2), (string)$storePostageDiscount, 2), 0);
|
|
}
|
|
$data['svip_price'] = $svip_price;
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 计算某个门店中收银台的金额
|
|
* @param int $uid
|
|
* @param int $storeId
|
|
* @param array $cartIds
|
|
* @param bool $integral
|
|
* @param bool $coupon
|
|
* @param array $userInfo
|
|
* @param int $coupon_id
|
|
* @param bool $new
|
|
* @param array $cartGroup
|
|
* @param int $addressId
|
|
* @param string $payType
|
|
* @param int $shippingType
|
|
* @return array
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function computeOrder(int $uid = 0, int $storeId = 0, array $cartIds = [], bool $integral = false, bool $coupon = false, array $userInfo = [], int $coupon_id = 0, bool $new = false, array $cartGroup = [], int $addressId = 0, string $payType = 'yue', int $shippingType = 4)
|
|
{
|
|
if (!$userInfo && $uid) {
|
|
/** @var UserServices $userService */
|
|
$userService = app()->make(UserServices::class);
|
|
$userInfo = $userService->getUserInfo($uid);
|
|
if (!$userInfo) {
|
|
throw new ValidateException('用户不存在');
|
|
}
|
|
$userInfo = $userInfo->toArray();
|
|
}
|
|
$payPostage = 0;
|
|
$storePostageDiscount = 0;
|
|
$firstOrderPrice = 0;
|
|
/** @var StoreOrderComputedServices $computeOrderService */
|
|
$computeOrderService = app()->make(StoreOrderComputedServices::class);
|
|
if ($cartGroup && $shippingType != 4) {
|
|
$cartInfo = $cartGroup['cartInfo'];
|
|
$priceGroup = $cartGroup['priceGroup'];
|
|
$deduction = $cartGroup['deduction'];
|
|
$other = $cartGroup['other'];
|
|
$promotions = $other['promotions'] ?? [];
|
|
$payPrice = (float)$priceGroup['totalPrice'];
|
|
$payIntegral = (int)$priceGroup['totalIntegral'] ?? 0;
|
|
$couponPrice = (float)$priceGroup['couponPrice'];
|
|
$firstOrderPrice = (float)$priceGroup['firstOrderPrice'];
|
|
|
|
$sumPrice = $priceGroup['sumPrice'];//获取订单原总金额
|
|
$totalPrice = $priceGroup['totalPrice'];//获取订单svip、用户等级优惠之后总金额
|
|
$costPrice = $priceGroup['costPrice'];//获取订单成本价
|
|
$vipPrice = $priceGroup['vipPrice'];//获取订单会员优惠金额
|
|
$promotionsPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'promotions_true_price');//优惠活动优惠
|
|
|
|
$addr = $cartGroup['addr'] ?? [];
|
|
$postage = $priceGroup;
|
|
if (!$addr || $addr['id'] != $addressId) {
|
|
/** @var UserAddressServices $addressServices */
|
|
$addressServices = app()->make(UserAddressServices::class);
|
|
$addr = $addressServices->getAdderssCache($addressId);
|
|
//改变地址重新计算邮费
|
|
$postage = [];
|
|
}
|
|
|
|
$type = (int)$deduction['type'] ?? 0;
|
|
$results = batch([
|
|
'promotions' => function () use ($cartInfo, $type) {
|
|
$promotionsPrice = 0;
|
|
if ($type == 8) return $promotionsPrice;
|
|
foreach ($cartInfo as $key => $cart) {
|
|
if (isset($cart['promotions_true_price']) && isset($cart['price_type']) && $cart['price_type'] == 'promotions') {
|
|
$promotionsPrice = bcadd((string)$promotionsPrice, (string)bcmul((string)$cart['promotions_true_price'], (string)$cart['cart_num'], 2), 2);
|
|
}
|
|
}
|
|
return $promotionsPrice;
|
|
},
|
|
'postage' => function () use ($uid, $shippingType, $payType, $cartInfo, $addr, $payPrice, $postage, $other, $type, $computeOrderService) {
|
|
return $computeOrderService->computedPayPostage($uid, $shippingType, $payType, $cartInfo, $addr, $payPrice, $postage, $other);
|
|
},
|
|
]);
|
|
|
|
[$p, $payPostage, $storePostageDiscount, $storeFreePostage, $isStoreFreePostage] = $results['postage'];
|
|
|
|
} else {
|
|
/** @var StoreCartServices $cartServices */
|
|
$cartServices = app()->make(StoreCartServices::class);
|
|
//获取购物车信息
|
|
$cartGroup = $cartServices->getUserProductCartListV1($uid, $cartIds, $new, [], 4, $storeId, $coupon_id);
|
|
$cartInfo = array_merge($cartGroup['valid'], $cartGroup['giveCartList']);
|
|
if (!$cartInfo) {
|
|
throw new ValidateException('购物车暂无货物!');
|
|
}
|
|
$deduction = $cartGroup['deduction'];
|
|
$promotions = $cartGroup['promotions'] ?? [];
|
|
$other = [
|
|
'offlinePostage' => sys_config('offline_postage'),
|
|
'integralRatio' => sys_config('integral_ratio'),
|
|
'give_integral' => $cartGroup['giveIntegral'] ?? 0,
|
|
'give_coupon' => $cartGroup['giveCoupon'] ?? [],
|
|
'give_product' => $cartGroup['giveProduct'],
|
|
'promotions' => $cartGroup['promotions']
|
|
];
|
|
$cartGroup['other'] = $other;
|
|
$sumPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'sum_price');//获取订单原总金额
|
|
$totalPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'truePrice');//获取订单svip、用户等级优惠之后总金额
|
|
$costPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'costPrice');//获取订单成本价
|
|
$vipPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'vip_truePrice');//获取订单会员优惠金额
|
|
$promotionsPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'promotions_true_price');//优惠活动优惠
|
|
|
|
$payPrice = (float)$totalPrice;
|
|
$couponPrice = floatval($cartGroup['couponPrice'] ?? 0);
|
|
}
|
|
$promotionsDetail = [];
|
|
if ($promotions) {
|
|
foreach ($promotions as $key => $value) {
|
|
if (isset($value['details']['sum_promotions_price']) && $value['details']['sum_promotions_price']) {
|
|
$promotionsDetail[] = ['id' => $value['id'], 'name' => $value['name'], 'title' => $value['title'], 'desc' => $value['desc'], 'promotions_price' => $value['details']['sum_promotions_price'], 'promotions_type' => $value['promotions_type']];
|
|
}
|
|
}
|
|
if ($promotionsDetail) {
|
|
$typeArr = array_column($promotionsDetail, 'promotions_type');
|
|
array_multisort($typeArr, SORT_ASC, $promotionsDetail);
|
|
}
|
|
}
|
|
$is_cashier_yue_pay_verify = (int)sys_config('is_cashier_yue_pay_verify'); // 收银台余额支付是否需要验证【是/否】
|
|
|
|
if ($couponPrice < $payPrice) {
|
|
$payPrice = (float)bcsub((string)$payPrice, (string)$couponPrice, 2);
|
|
} else {
|
|
$couponPrice = $payPrice;
|
|
$payPrice = 0;
|
|
}
|
|
if ($firstOrderPrice < $payPrice) {//首单优惠金额
|
|
$payPrice = bcsub((string)$payPrice, (string)$firstOrderPrice, 2);
|
|
} else {
|
|
$payPrice = 0;
|
|
}
|
|
$SurplusIntegral = $usedIntegral = 0;
|
|
$deductionPrice = '0';
|
|
//使用积分
|
|
if ($userInfo && $integral) {
|
|
[
|
|
$payPrice,
|
|
$deductionPrice,
|
|
$usedIntegral,
|
|
$SurplusIntegral
|
|
] = $computeOrderService->useIntegral(true, $userInfo, $payPrice, [
|
|
'offlinePostage' => sys_config('offline_postage'),
|
|
'integralRatio' => sys_config('integral_ratio')
|
|
]);
|
|
}
|
|
|
|
$payPrice = (float)bcadd((string)$payPrice, (string)$payPostage, 2);
|
|
|
|
return [
|
|
'payPrice' => floatval($payPrice),//支付金额
|
|
'vipPrice' => floatval($vipPrice),//会员优惠金额
|
|
'totalPrice' => floatval($totalPrice),//会员优惠后订单金额
|
|
'costPrice' => floatval($costPrice),//成本金额
|
|
'sumPrice' => floatval($sumPrice),//订单总金额
|
|
'couponPrice' => $couponPrice,//优惠券金额
|
|
'pay_postage' => $payPostage ?? 0,
|
|
'storePostageDiscount' => $storePostageDiscount ?? 0,
|
|
'promotionsPrice' => floatval($promotionsPrice),//优惠活动金额
|
|
'promotionsDetail' => $promotionsDetail,//优惠
|
|
'deductionPrice' => floatval($deductionPrice),//积分抵扣多少钱
|
|
'surplusIntegral' => $SurplusIntegral,//抵扣了多少积分
|
|
'usedIntegral' => $usedIntegral,//使用了多少积分
|
|
'deduction' => $deduction,
|
|
'cartInfo' => $cartInfo,//购物列表
|
|
'is_cashier_yue_pay_verify' => $is_cashier_yue_pay_verify,//收银台余额支付验证 1 验证 0不验证
|
|
'cartGroup' => $cartGroup//计算结果
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 收银台用户优惠券
|
|
* @param int $uid
|
|
* @param int $storeId
|
|
* @param array $cartIds
|
|
* @return mixed
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getCouponList(int $uid, int $storeId, array $cartIds)
|
|
{
|
|
/** @var StoreCartServices $cartService */
|
|
$cartService = app()->make(StoreCartServices::class);
|
|
$cart = $cartService->getUserCartList($uid, 1, $cartIds, $storeId, -1, 4, 0, 0, 0, false);
|
|
$cartInfo = $cart['valid'];
|
|
if (!$cartInfo) {
|
|
throw new ValidateException('购物车暂无货物!');
|
|
}
|
|
/** @var StoreCouponissueServices $couponIssueServices */
|
|
$couponIssueServices = app()->make(StoreCouponissueServices::class);
|
|
return $couponIssueServices->getCanUseCoupon($uid, $cartInfo, $cart['promotions'] ?? [], $storeId, false);
|
|
}
|
|
|
|
/**
|
|
* 二位数组冒泡排序
|
|
* @param array $arr
|
|
* @param string $key
|
|
* @return array
|
|
*/
|
|
protected function mpSort(array $arr, string $key)
|
|
{
|
|
for ($i = 0; $i < count($arr); $i++) {
|
|
for ($j = $i; $j < count($arr); $j++) {
|
|
if ($arr[$i][$key] > $arr[$j][$key]) {
|
|
$temp = $arr[$i];
|
|
$arr[$i] = $arr[$j];
|
|
$arr[$j] = $temp;
|
|
}
|
|
}
|
|
}
|
|
return $arr;
|
|
}
|
|
|
|
/**
|
|
* 自动解析扫描二维码
|
|
* @param string $barCode
|
|
* @param int $storeId
|
|
* @param int $uid
|
|
* @param int $staff_id
|
|
* @param int $touristUid
|
|
* @return array
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getAnalysisCode(string $barCode, int $storeId, int $uid, int $staff_id, int $touristUid = 0)
|
|
{
|
|
/** @var UserServices $userService */
|
|
$userService = app()->make(UserServices::class);
|
|
$userInfo = $userService->get(['bar_code' => $barCode], ['uid', 'avatar', 'nickname', 'now_money', 'integral']);
|
|
if ($userInfo) {
|
|
return ['userInfo' => $userInfo->toArray()];
|
|
} else {
|
|
/** @var SystemStoreStaffServices $staffServices */
|
|
$staffServices = app()->make(SystemStoreStaffServices::class);
|
|
$staffServices->getStaffInfo($staff_id);
|
|
|
|
/** @var StoreProductAttrValueServices $storeProductAttrService */
|
|
$storeProductAttrService = app()->make(StoreProductAttrValueServices::class);
|
|
$attProductInfo = $storeProductAttrService->getAttrByBarCode((string)$barCode);
|
|
if (!$attProductInfo) {
|
|
throw new ValidateException('没有扫描到商品');
|
|
}
|
|
/** @var StoreProductServices $productService */
|
|
$productService = app()->make(StoreProductServices::class);
|
|
$productInfo = $productService->get(['is_show' => 1, 'is_del' => 0, 'id' => $attProductInfo->product_id], [
|
|
'image', 'store_name', 'store_info', 'bar_code', 'price', 'id as product_id', 'id'
|
|
]);
|
|
if (!$productInfo) {
|
|
throw new ValidateException('商品未查到');
|
|
}
|
|
/** @var StoreBranchProductServices $storeProductService */
|
|
$storeProductService = app()->make(StoreBranchProductServices::class);
|
|
if (!$storeProductService->count(['store_id' => $storeId, 'product_id' => $attProductInfo->product_id])) {
|
|
throw new ValidateException('该商品在此门店不存在');
|
|
}
|
|
/** @var StoreProductAttrValueServices $valueService */
|
|
$valueService = app()->make(StoreProductAttrValueServices::class);
|
|
$valueInfo = $valueService->getOne(['unique' => $attProductInfo->unique]);
|
|
if (!$valueInfo) {
|
|
throw new ValidateException('商品属性不存在');
|
|
}
|
|
$productInfo = $productInfo->toArray();
|
|
$productInfo['attr_value'] = [
|
|
'ot_price' => $valueInfo->ot_price,
|
|
'price' => $valueInfo->price,
|
|
'sales' => $valueInfo->sales,
|
|
'vip_price' => $valueInfo->vip_price,
|
|
'stock' => $attProductInfo->stock,
|
|
];
|
|
if ($uid || $touristUid) {
|
|
/** @var StoreCartServices $cartService */
|
|
$cartService = app()->make(StoreCartServices::class);
|
|
$cartService->setItem('store_id', $storeId);
|
|
$cartService->setItem('tourist_uid', $touristUid);
|
|
$cartId = $cartService->addCashierCart($uid, $attProductInfo->product_id, 1, $attProductInfo->unique, $staff_id);
|
|
$cartService->reset();
|
|
if (!$cartId) {
|
|
throw new ValidateException('自动添加购物车失败');
|
|
}
|
|
} else {
|
|
$cartId = 0;
|
|
}
|
|
return ['productInfo' => $productInfo, 'cartId' => $cartId];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成订单
|
|
* @param int $uid
|
|
* @param int $storeId
|
|
* @param int $staffId
|
|
* @param array $cartIds
|
|
* @param string $payType
|
|
* @param bool $integral
|
|
* @param bool $coupon
|
|
* @param string $remarks
|
|
* @return mixed
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function createOrder(int $uid, array $userInfo, array $computeData, int $storeId, int $staffId, array $cartIds, string $payType, bool $integral = false, bool $coupon = false, string $remarks = '', string $changePrice = '0', bool $isPrice = false, int $coupon_id = 0, int $seckillId = 0, $collate_code_id = 0, int $addressId = 0, array $addressInfo = [], $shippingType = 4, $clerk_id = 0)
|
|
{
|
|
/** @var SystemStoreStaffServices $staffService */
|
|
$staffService = app()->make(SystemStoreStaffServices::class);
|
|
$staffInfo = [];
|
|
if ($storeId && $staffId && !$staffInfo = $staffService->getOne(['store_id' => $storeId, 'id' => $staffId, 'is_del' => 0, 'status' => 1])) {
|
|
throw new ValidateException('您选择的店员不存在');
|
|
}
|
|
if ($staffInfo) {
|
|
$clerk_id = $staffInfo['uid'];
|
|
}
|
|
if (!$storeId && $staffId) {
|
|
$clerk_id = $staffId;
|
|
$staffId = 0;
|
|
}
|
|
//兼容门店虚拟用户下单
|
|
$field = ['real_name', 'phone', 'province', 'city', 'district', 'street', 'detail'];
|
|
if ($uid && !$addressId && !$addressInfo) {
|
|
/** @var UserAddressServices $addreService */
|
|
$addreService = app()->make(UserAddressServices::class);
|
|
$addressInfo = $addreService->getUserDefaultAddress($uid, implode(',', $field));
|
|
if ($addressInfo) {
|
|
$addressInfo = $addressInfo->toArray();
|
|
}
|
|
}
|
|
if (!$addressInfo) {
|
|
foreach ($field as $key) {
|
|
$addressInfo[$key] = '';
|
|
}
|
|
}
|
|
$cartGroup = $computeData['cartGroup'] ?? [];
|
|
$cartInfo = $computeData['cartInfo'];
|
|
$totalPrice = $computeData['totalPrice'];
|
|
$couponId = $coupon_id;
|
|
$couponPrice = $computeData['couponPrice'] ?? '0.00';
|
|
$useIntegral = $computeData['usedIntegral'];
|
|
$deduction = $computeData['deduction'];
|
|
$other = $cartGroup['other'];
|
|
$gainIntegral = $totalNum = 0;
|
|
|
|
$priceData = [
|
|
'coupon_id' => $couponId,
|
|
'coupon_price' => $couponPrice,
|
|
'usedIntegral' => $useIntegral,
|
|
'deduction_price' => $computeData['deductionPrice'] ?? '0.00',
|
|
'promotions_price' => $computeData['promotionsPrice'],
|
|
'pay_postage' => 0,
|
|
'pay_price' => $computeData['payPrice']
|
|
];
|
|
|
|
$promotions_give = [
|
|
'give_integral' => $other['give_integral'] ?? 0,
|
|
'give_coupon' => $other['give_coupon'] ?? [],
|
|
'give_product' => $other['give_product'] ?? [],
|
|
'promotions' => $other['promotions'] ?? []
|
|
];
|
|
|
|
$type = (int)$deduction['type'] ?? 0;
|
|
$seckillId = $seckillId ?: ($type == 1 ? ($deduction['activity_id'] ?? 0) : 0);
|
|
foreach ($cartInfo as $cart) {
|
|
$totalNum += $cart['cart_num'];
|
|
$cartInfoGainIntegral = isset($cart['productInfo']['give_integral']) ? bcmul((string)$cart['cart_num'], (string)$cart['productInfo']['give_integral'], 0) : 0;
|
|
$gainIntegral = bcadd((string)$gainIntegral, (string)$cartInfoGainIntegral, 0);
|
|
|
|
if ($seckillId) {
|
|
if (!isset($cart['product_attr_unique']) || !$cart['product_attr_unique']) continue;
|
|
$type = $cart['type'];
|
|
if (in_array($type, [1, 2, 3]) &&
|
|
(
|
|
!CacheService::checkStock($cart['product_attr_unique'], (int)$cart['cart_num'], $type) ||
|
|
!CacheService::popStock($cart['product_attr_unique'], (int)$cart['cart_num'], $type)
|
|
)
|
|
) {
|
|
throw new ValidateException('您购买的商品库存已不足' . $cart['cart_num'] . $cart['productInfo']['unit_name']);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($collate_code_id) {
|
|
$collateCodeId = (int)$deduction['collate_code_id'] ?? 0;
|
|
if ($collateCodeId && $type == 10) {
|
|
if ($collateCodeId != $collate_code_id) throw new ValidateException('拼单/桌码ID有误!');
|
|
$seckillId = $collate_code_id;
|
|
}
|
|
}
|
|
/** @var StoreOrderCreateServices $orderServices */
|
|
$orderServices = app()->make(StoreOrderCreateServices::class);
|
|
$key = md5(json_encode($cartIds) . uniqid() . time());
|
|
$product_type = (int)$deduction['product_type'] ?? 0;
|
|
$orderInfo = [
|
|
'uid' => $uid,
|
|
'type' => $type,
|
|
'order_id' => $orderServices->getNewOrderId(),
|
|
'real_name' => $addressInfo['real_name'] ? $addressInfo['real_name'] : $userInfo['nickname'] ?? '',
|
|
'user_phone' => $addressInfo['phone'] ? $addressInfo['phone'] : $userInfo['phone'] ?? '',
|
|
'user_address' => isset($addressInfo['addressInfo']) && $addressInfo['addressInfo'] ? $addressInfo['addressInfo'] : $addressInfo['province'] . ' ' . $addressInfo['city'] . ' ' . $addressInfo['district'] . ' ' . $addressInfo['street'] . ' ' . $addressInfo['detail'],
|
|
'cart_id' => $cartIds,
|
|
'clerk_id' => $clerk_id,
|
|
'store_id' => $storeId,
|
|
'staff_id' => $staffId,
|
|
'total_num' => $totalNum,
|
|
'total_price' => $computeData['sumPrice'] ?? $totalPrice,
|
|
'total_postage' => $computeData['pay_postage'],
|
|
'coupon_id' => $couponId,
|
|
'coupon_price' => $couponPrice,
|
|
'promotions_price' => $priceData['promotions_price'],
|
|
'pay_price' => $isPrice ? $changePrice : $computeData['payPrice'],
|
|
'pay_postage' => $computeData['pay_postage'],
|
|
'deduction_price' => $computeData['deductionPrice'],
|
|
'change_price' => $isPrice ? bcsub((string)$computeData['payPrice'], (string)$changePrice, 2) : '0.00',
|
|
'paid' => 0,
|
|
'pay_type' => $payType == self::YUE_PAY ? 'yue' : '',
|
|
'use_integral' => $useIntegral,
|
|
'gain_integral' => $gainIntegral,
|
|
'mark' => htmlspecialchars($remarks),
|
|
'product_type' => $product_type,
|
|
'activity_id' => $seckillId,
|
|
'pink_id' => 0,
|
|
'cost' => $computeData['costPrice'],
|
|
'is_channel' => 2,
|
|
'add_time' => time(),
|
|
'unique' => $key,
|
|
'shipping_type' => $shippingType,
|
|
'channel_type' => $userInfo['user_type'] ?? '',
|
|
'province' => '',
|
|
'spread_uid' => 0,
|
|
'spread_two_uid' => 0,
|
|
'promotions_give' => json_encode($promotions_give),
|
|
'give_integral' => $promotions_give['give_integral'] ?? 0,
|
|
'give_coupon' => implode(',', $promotions_give['give_coupon'] ?? []),
|
|
];
|
|
if ($product_type == 4) {//次卡商品收银台购买
|
|
$orderInfo['verify_code'] = $orderServices->getStoreCode();
|
|
$orderInfo['shipping_type'] = 2;//修改门店自提
|
|
}
|
|
if ($shippingType == 2) {
|
|
$orderInfo['verify_code'] = $orderServices->getStoreCode();
|
|
/** @var SystemStoreServices $storeServices */
|
|
$storeServices = app()->make(SystemStoreServices::class);
|
|
$orderInfo['store_id'] = $storeServices->getStoreDisposeCache($storeId, 'id');
|
|
if (!$orderInfo['store_id']) {
|
|
throw new ValidateException('暂无门店无法选择门店自提');
|
|
}
|
|
}
|
|
/** @var StoreOrderCartInfoServices $cartServices */
|
|
$cartServices = app()->make(StoreOrderCartInfoServices::class);
|
|
|
|
$order = $orderServices->save($orderInfo);
|
|
if (!$order) {
|
|
throw new ValidateException('订单生成失败');
|
|
}
|
|
//使用优惠券
|
|
if ($couponId) {
|
|
/** @var StoreCouponUserServices $couponServices */
|
|
$couponServices = app()->make(StoreCouponUserServices::class);
|
|
$res1 = $couponServices->useCoupon($couponId, (int)($userInfo['uid'] ?? 0), $cartInfo, [], $storeId);
|
|
if (!$res1) {
|
|
throw new ValidateException('使用优惠劵失败!');
|
|
}
|
|
}
|
|
//积分抵扣
|
|
$orderServices->deductIntegral($userInfo, $useIntegral, [
|
|
'SurplusIntegral' => $computeData['surplusIntegral'],
|
|
'usedIntegral' => $computeData['usedIntegral'],
|
|
'deduction_price' => $computeData['deductionPrice'],
|
|
], (int)($userInfo['uid'] ?? 0), $key);
|
|
//修改门店库存
|
|
$orderServices->decGoodsStock($cartInfo, $type, $seckillId, $storeId);
|
|
//保存购物车商品信息
|
|
$cartServices->setCartInfo($order['id'], $cartInfo, $userInfo['uid'] ?? 0, $promotions_give['promotions'] ?? []);
|
|
$order = $order->toArray();
|
|
|
|
if (in_array($type, [9, 10]) && $collate_code_id > 0 && $order) {
|
|
//关联订单和拼单、桌码
|
|
/** @var UserCollageCodeServices $collageServices */
|
|
$collageServices = app()->make(UserCollageCodeServices::class);
|
|
$collageServices->update($collate_code_id, ['oid' => $order['id'], 'status' => 2]);
|
|
//清除未结算商品
|
|
/** @var UserCollagePartakeServices $partakeService */
|
|
$partakeService = app()->make(UserCollagePartakeServices::class);
|
|
$partakeService->update(['collate_code_id' => $collate_code_id, 'is_settle' => 0], ['status' => 0]);
|
|
}
|
|
|
|
$news = false;
|
|
$addressId = $type = $activity_id = 0;
|
|
$delCart = true;
|
|
|
|
//扣除优惠活动赠品限量
|
|
StorePromotionsJob::dispatchDo('changeGiveLimit', [$promotions_give]);
|
|
$group = compact('cartInfo', 'priceData', 'addressId', 'cartIds', 'news', 'delCart', 'changePrice');
|
|
event('order.create', [$order, $group, compact('type', 'activity_id'), 0]);
|
|
return $order;
|
|
}
|
|
|
|
/**
|
|
* 收银台支付
|
|
* @param string $orderId
|
|
* @param string $payType
|
|
* @param string $userCode
|
|
* @param string $authCode
|
|
* @return array
|
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
|
*/
|
|
public function paySuccess(string $orderId, string $payType, string $userCode, string $authCode = '')
|
|
{
|
|
/** @var StoreOrderSuccessServices $orderService */
|
|
$orderService = app()->make(StoreOrderSuccessServices::class);
|
|
$orderInfo = $orderService->get(['order_id' => $orderId]);
|
|
if (!$orderInfo) {
|
|
throw new ValidateException('没有查询到订单信息');
|
|
}
|
|
if ($orderInfo->paid) {
|
|
throw new ValidateException('订单已支付');
|
|
}
|
|
if ($orderInfo->is_del) {
|
|
throw new ValidateException('订单已取消');
|
|
}
|
|
switch ($payType) {
|
|
case PayServices::YUE_PAY://余额支付
|
|
$is_cashier_yue_pay_verify = (int)sys_config('is_cashier_yue_pay_verify'); // 收银台余额支付是否需要验证【是/否】
|
|
if (!$orderInfo['uid']) {
|
|
throw new ValidateException('余额支付用户信息不存在无法支付');
|
|
}
|
|
if (!$userCode && $is_cashier_yue_pay_verify) {
|
|
throw new ValidateException('缺少扫码支付参数');
|
|
}
|
|
/** @var UserServices $userService */
|
|
$userService = app()->make(UserServices::class);
|
|
$userInfo = $userService->getUserInfo($orderInfo->uid, ['uid', 'bar_code']);
|
|
|
|
if (!$userInfo) {
|
|
throw new ValidateException('余额支付用户不存在');
|
|
}
|
|
if ($userInfo['bar_code'] != $userCode && $is_cashier_yue_pay_verify) {
|
|
throw new ValidateException('二维码已使用或不正确,请确认后重新扫码');
|
|
}
|
|
/** @var YuePayServices $payService */
|
|
$payService = app()->make(YuePayServices::class);
|
|
$pay = $payService->yueOrderPay($orderInfo->toArray(), $orderInfo->uid);
|
|
if ($pay['status'] === true)
|
|
return ['status' => 'SUCCESS'];
|
|
else if ($pay['status'] === 'pay_deficiency') {
|
|
throw new ValidateException($pay['msg']);
|
|
} else {
|
|
return ['status' => 'ERROR', 'message' => is_array($pay) ? $pay['msg'] ?? '余额支付失败' : $pay];
|
|
}
|
|
case PayServices::WEIXIN_PAY://微信支付
|
|
case PayServices::ALIAPY_PAY://支付宝支付
|
|
if (!$authCode) {
|
|
throw new ValidateException('缺少支付付款二维码CODE');
|
|
}
|
|
|
|
$pay = new PayServices();
|
|
$site_name = sys_config('site_name');
|
|
/** @var StoreOrderCartInfoServices $orderInfoServices */
|
|
$orderInfoServices = app()->make(StoreOrderCartInfoServices::class);
|
|
$body = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo['id']);
|
|
$body = substrUTf8($site_name . '--' . $body, 30);
|
|
try {
|
|
//扫码支付
|
|
$response = $pay->setAuthCode($authCode)->pay($payType, '', $orderInfo->order_id, $orderInfo->pay_price, 'product', $body);
|
|
} catch (\Throwable $e) {
|
|
\think\facade\Log::error('收银端' . $payType . '扫码支付失败,原因:' . $e->getMessage());
|
|
return ['status' => 'ERROR', 'message' => '支付失败,原因:' . $e->getMessage()];
|
|
}
|
|
//支付成功paid返回1
|
|
if ($response['paid']) {
|
|
if (!$orderService->paySuccess($orderInfo->toArray(), $payType, ['trade_no' => $response['payInfo']['transaction_id'] ?? ''])) {
|
|
return ['status' => 'ERROR', 'message' => '支付失败'];
|
|
}
|
|
//支付成功刪除購物車
|
|
/** @var StoreCartServices $cartServices */
|
|
$cartServices = app()->make(StoreCartServices::class);
|
|
$cartServices->deleteCartStatus($orderInfo['cart_id'] ?? []);
|
|
return ['status' => 'SUCCESS'];
|
|
} else {
|
|
if ($payType === PayServices::WEIXIN_PAY) {
|
|
if (isset($response['payInfo']['err_code']) && in_array($response['payInfo']['err_code'], ['AUTH_CODE_INVALID', 'NOTENOUGH'])) {
|
|
return ['status' => 'ERROR', 'message' => '支付失败'];
|
|
}
|
|
//微信付款码支付需要同步更改状态
|
|
$secs = 5;
|
|
if (isset($order_info['payInfo']['err_code']) && $order_info['payInfo']['err_code'] === 'USERPAYING') {
|
|
$secs = 10;
|
|
}
|
|
//放入队列执行
|
|
MicroPayOrderJob::dispatchSece($secs, [$orderInfo['order_id'], 0]);
|
|
}
|
|
return ['status' => 'PAY_ING', 'message' => $response['message']];
|
|
}
|
|
break;
|
|
case PayServices::CASH_PAY://收银台现金支付
|
|
if (!$orderService->paySuccess($orderInfo->toArray(), $payType)) {
|
|
return ['status' => 'ERROR', 'message' => '支付失败'];
|
|
} else {
|
|
return ['status' => 'SUCCESS'];
|
|
}
|
|
break;
|
|
default:
|
|
throw new ValidateException('暂无支付方式,无法支付');
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|