CRMEB_PRO_M/app/services/order/cashier/CashierOrderServices.php

861 lines
42 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

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

<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
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('暂无支付方式,无法支付');
}
}
}