徐总多门店
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.
 
 
 
 
 
 
jiuhaoshenghuo/app/services/order/cashier/CashierOrderServices.php

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('暂无支付方式,无法支付');
}
}
}