Merge branch 'v4.7.0dev' of https://gitee.com/ZhongBangKeJi/CRMEB into v4.7.0dev

This commit is contained in:
From-wh 2023-03-01 16:54:05 +08:00
commit daa400ee85
11 changed files with 592 additions and 399 deletions

View File

@ -14,6 +14,7 @@ namespace app\api;
use crmeb\exceptions\AdminException;
use crmeb\exceptions\ApiException;
use crmeb\exceptions\ApiStatusException;
use crmeb\exceptions\AuthException;
use think\db\exception\DbException;
use think\exception\Handle;
@ -86,11 +87,13 @@ class ApiExceptionHandle extends Handle
] : [];
$message = Env::get('app_debug', false) ? $e->getMessage() : '很抱歉,系统开小差了';
// 添加自定义异常处理机制
if ($e instanceof ApiStatusException) {
return app('json')->status($e->getApiStatus(), $message, $e->getApiData());
}
if ($e instanceof AuthException || $e instanceof AdminException || $e instanceof ApiException || $e instanceof ValidateException) {
return app('json')->make($e->getCode() ?: 400, $message, $massageData);
} else {
return app('json')->fail($message, $massageData);
}
return app('json')->fail($message, $massageData);
}
}

View File

@ -15,6 +15,8 @@ use app\services\pay\PayServices;
use app\services\shipping\ExpressServices;
use app\services\system\admin\SystemAdminServices;
use app\services\user\UserInvoiceServices;
use crmeb\exceptions\ApiException;
use crmeb\exceptions\ApiStatusException;
use crmeb\services\pay\extend\allinpay\AllinPay;
use app\services\activity\{lottery\LuckLotteryServices,
bargain\StoreBargainServices,
@ -166,7 +168,7 @@ class StoreOrderController
$uid = (int)$request->uid();
if ($checkOrder = $this->services->getOne(['order_id|unique' => $key, 'uid' => $uid, 'is_del' => 0]))
return app('json')->status('extend_order', 410209, ['orderId' => $checkOrder['order_id'], 'key' => $key]);
[$addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckill_id, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $invoice_id, $quitUrl, $advanceId, $virtual_type, $customForm] = $request->postMore([
[$addressId, $couponId, $payType, $useIntegral, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, $news, $invoice_id, $quitUrl, $advanceId, $virtual_type, $customForm] = $request->postMore([
[['addressId', 'd'], 0],
[['couponId', 'd'], 0],
['payType', ''],
@ -188,77 +190,76 @@ class StoreOrderController
['custom_form', []],
], true);
$payType = strtolower($payType);
$cartGroup = $this->services->getCacheOrderInfo($uid, $key);
if (!$cartGroup) {
return app('json')->fail(410208);
}
//下单前砍价验证
if ($bargainId) {
$bargainServices->checkBargainUser((int)$bargainId, $uid);
}
if ($pinkId) {
$pinkId = (int)$pinkId;
/** @var StorePinkServices $pinkServices */
$pinkServices = app()->make(StorePinkServices::class);
if ($pinkServices->isPink($pinkId, $uid))
return app('json')->status('ORDER_EXIST', 410210, ['orderId' => $this->services->getStoreIdPink($pinkId, $uid)]);
if ($this->services->getIsOrderPink($pinkId, $uid))
return app('json')->status('ORDER_EXIST', 410211, ['orderId' => $this->services->getStoreIdPink($pinkId, $uid)]);
if (!CacheService::checkStock(md5($pinkId), 1, 3) || !CacheService::popStock(md5($pinkId), 1, 3)) {
return app('json')->fail(410212);
}
}
$cartInfo = null;
if ($seckill_id || $combinationId || $bargainId || $advanceId) {
$cartInfo = $cartGroup['cartInfo'];
foreach ($cartInfo as $item) {
$type = 0;
if (!isset($item['product_attr_unique']) || !$item['product_attr_unique']) continue;
if ($item['seckill_id']) {
$type = 1;
} elseif ($item['bargain_id']) {
$type = 2;
} elseif ($item['combination_id']) {
$type = 3;
} elseif ($item['advance_id']) {
$type = 6;
}
if ($type && (!CacheService::checkStock($item['product_attr_unique'], (int)$item['cart_num'], $type) || !CacheService::popStock($item['product_attr_unique'], (int)$item['cart_num'], $type))) {
return app('json')->fail(410214, null, ['cart_num' => $item['cart_num'], 'unit_name' => $item['productInfo']['unit_name']]);
}
}
}
$virtual_type = $cartGroup['cartInfo'][0]['productInfo']['virtual_type'] ?? 0;
$order = $createServices->createOrder($uid, $key, $cartGroup, $request->user()->toArray(), $addressId, $payType, !!$useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckill_id, $bargainId, $shipping_type, $real_name, $phone, $storeId, !!$news, $advanceId, $virtual_type, $customForm, $invoice_id);
if ($order === false) {
if ($seckill_id || $combinationId || $advanceId || $bargainId) {
foreach ($cartInfo as $item) {
$value = $item['cart_info'];
$type = 0;
if (!isset($value['product_attr_unique']) || $value['product_attr_unique']) continue;
if ($value['seckill_id']) {
$type = 1;
} elseif ($value['bargain_id']) {
$type = 2;
} elseif ($value['combination_id']) {
$type = 3;
} elseif ($value['advance_id']) {
$type = 6;
}
if ($type) CacheService::setStock($value['product_attr_unique'], (int)$value['cart_num'], $type, false);
}
}
return app('json')->fail(410200);
}
// $cartGroup = $this->services->getCacheOrderInfo($uid, $key);
// if (!$cartGroup) {
// return app('json')->fail(410208);
// }
// //下单前砍价验证
// if ($bargainId) {
// $bargainServices->checkBargainUser((int)$bargainId, $uid);
// }
//
// if ($pinkId) {
// $pinkId = (int)$pinkId;
// /** @var StorePinkServices $pinkServices */
// $pinkServices = app()->make(StorePinkServices::class);
// if ($pinkServices->isPink($pinkId, $uid))
// return app('json')->status('ORDER_EXIST', 410210, ['orderId' => $this->services->getStoreIdPink($pinkId, $uid)]);
// if ($this->services->getIsOrderPink($pinkId, $uid))
// return app('json')->status('ORDER_EXIST', 410211, ['orderId' => $this->services->getStoreIdPink($pinkId, $uid)]);
// if (!CacheService::checkStock(md5($pinkId), 1, 3) || !CacheService::popStock(md5($pinkId), 1, 3)) {
// return app('json')->fail(410212);
// }
// }
//
// $cartInfo = null;
// if ($seckill_id || $combinationId || $bargainId || $advanceId) {
// $cartInfo = $cartGroup['cartInfo'];
// foreach ($cartInfo as $item) {
// $type = 0;
// if (!isset($item['product_attr_unique']) || !$item['product_attr_unique']) continue;
// if ($item['seckill_id']) {
// $type = 1;
// } elseif ($item['bargain_id']) {
// $type = 2;
// } elseif ($item['combination_id']) {
// $type = 3;
// } elseif ($item['advance_id']) {
// $type = 6;
// }
// if ($type && (!CacheService::checkStock($item['product_attr_unique'], (int)$item['cart_num'], $type) || !CacheService::popStock($item['product_attr_unique'], (int)$item['cart_num'], $type))) {
// return app('json')->fail(410214, null, ['cart_num' => $item['cart_num'], 'unit_name' => $item['productInfo']['unit_name']]);
//
// }
// }
// }
// $virtual_type = $cartGroup['cartInfo'][0]['productInfo']['virtual_type'] ?? 0;
$order = $createServices->createOrder($uid, $key, $request->user()->toArray(), $addressId, $payType, !!$useIntegral, $couponId, $mark, $combinationId, $pinkId, $seckillId, $bargainId, $shipping_type, $real_name, $phone, $storeId, !!$news, $advanceId, $customForm, $invoice_id);
// if ($order === false) {
// if ($seckill_id || $combinationId || $advanceId || $bargainId) {
// foreach ($cartInfo as $item) {
// $value = $item['cart_info'];
// $type = 0;
// if (!isset($value['product_attr_unique']) || $value['product_attr_unique']) continue;
// if ($value['seckill_id']) {
// $type = 1;
// } elseif ($value['bargain_id']) {
// $type = 2;
// } elseif ($value['combination_id']) {
// $type = 3;
// } elseif ($value['advance_id']) {
// $type = 6;
// }
// if ($type) CacheService::setStock($value['product_attr_unique'], (int)$value['cart_num'], $type, false);
// }
// }
// throw new ApiException(410200);
// }
$orderId = $order['order_id'];
$orderInfo = $this->services->getOne(['order_id' => $orderId]);
if (!$orderInfo || !isset($orderInfo['paid'])) {
return app('json')->fail(410194);
}
// $orderInfo = $this->services->getOne(['order_id' => $orderId]);
// if (!$orderInfo || !isset($orderInfo['paid'])) {
// return app('json')->fail(410194);
// }
return app('json')->status('success', 410203, compact('orderId', 'key'));
}
@ -338,7 +339,7 @@ class StoreOrderController
if ($payPriceStatus)//0元支付成功
return app('json')->status('success', 410195, ['order_id' => $orderInfo['order_id'], 'key' => $orderInfo['unique']]);
else
return app('json')->status('pay_error');
return app('json')->status('pay_error', 410216);
}
switch ($paytype) {

View File

@ -81,6 +81,12 @@ class StoreOrderStoreOrderStatusDao extends BaseDao
* @param array $where
* @param int $limit
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function getTakeOrderIds(array $where, int $limit = 0)
{

View File

@ -2,17 +2,10 @@
namespace app\listener\crontab;
use app\services\activity\combination\StorePinkServices;
use app\services\activity\live\LiveGoodsServices;
use app\services\activity\live\LiveRoomServices;
use app\services\agent\AgentManageServices;
use app\services\order\StoreOrderServices;
use app\services\order\StoreOrderTakeServices;
use app\services\product\product\StoreProductServices;
use app\services\system\attachment\SystemAttachmentServices;
use app\services\system\crontab\CrontabRunServices;
use app\services\system\crontab\SystemCrontabServices;
use crmeb\interfaces\ListenerInterface;
use think\facade\Log;
use think\helper\Str;
use Workerman\Crontab\Crontab;
/**
@ -22,133 +15,23 @@ class SystemCrontabListener implements ListenerInterface
{
public function handle($event): void
{
$systemCrontabServices = app()->make(SystemCrontabServices::class);
$crontabRunServices = app()->make(CrontabRunServices::class);
//自动写入文件方便检测是否启动定时任务命令
new Crontab('*/6 * * * * *', function () {
file_put_contents(root_path() . 'runtime/.timer', time());
});
/** @var SystemCrontabServices $systemTimerServices */
$systemCrontabServices = app()->make(SystemCrontabServices::class);
$list = $systemCrontabServices->selectList(['is_del' => 0, 'is_open' => 1])->toArray();
foreach ($list as &$item) {
//转化小驼峰
$functionName = Str::camel($item['mark']);
//获取定时任务时间字符串
$timeStr = $this->getTimerStr($item);
//未支付自动取消订单
if ($item['mark'] == 'order_cancel') {
new Crontab($timeStr, function () {
try {
app()->make(StoreOrderServices::class)->orderUnpaidCancel();
$this->crontabLog(' 执行未支付自动取消订单');
} catch (\Throwable $e) {
Log::error('自动取消订单失败,失败原因:' . $e->getMessage());
}
});
}
//拼团到期订单处理
elseif ($item['mark'] == 'pink_expiration') {
new Crontab($timeStr, function () {
try {
app()->make(StorePinkServices::class)->statusPink();
$this->crontabLog(' 执行拼团到期订单处理');
} catch (\Throwable $e) {
Log::error('拼团到期订单处理失败,失败原因:' . $e->getMessage());
}
});
}
//自动解绑上级绑定
elseif ($item['mark'] == 'agent_unbind') {
new Crontab($timeStr, function () {
try {
app()->make(AgentManageServices::class)->removeSpread();
$this->crontabLog(' 执行自动解绑上级绑定');
} catch (\Throwable $e) {
Log::error('自动解除上级绑定失败,失败原因:' . $e->getMessage());
}
});
}
//更新直播商品状态
elseif ($item['mark'] == 'live_product_status') {
new Crontab($timeStr, function () {
try {
app()->make(LiveGoodsServices::class)->syncGoodStatus();
$this->crontabLog(' 执行更新直播商品状态');
} catch (\Throwable $e) {
Log::error('更新直播商品状态失败,失败原因:' . $e->getMessage());
}
});
}
//更新直播间状态
elseif ($item['mark'] == 'live_room_status') {
new Crontab($timeStr, function () {
try {
app()->make(LiveRoomServices::class)->syncRoomStatus();
$this->crontabLog(' 执行更新直播间状态');
} catch (\Throwable $e) {
Log::error('更新直播间状态失败,失败原因:' . $e->getMessage());
}
});
}
//自动收货
elseif ($item['mark'] == 'take_delivery') {
new Crontab($timeStr, function () {
try {
app()->make(StoreOrderTakeServices::class)->autoTakeOrder();
$this->crontabLog(' 执行自动收货');
} catch (\Throwable $e) {
Log::error('自动收货失败,失败原因:' . $e->getMessage());
}
});
}
//查询预售到期商品自动下架
elseif ($item['mark'] == 'advance_off') {
new Crontab($timeStr, function () {
try {
app()->make(StoreProductServices::class)->downAdvance();
$this->crontabLog(' 执行预售到期商品自动下架');
} catch (\Throwable $e) {
Log::error('预售到期商品自动下架失败,失败原因:' . $e->getMessage());
}
});
}
//自动好评
elseif ($item['mark'] == 'product_replay') {
new Crontab($timeStr, function () {
try {
app()->make(StoreOrderServices::class)->autoComment();
$this->crontabLog(' 执行自动好评');
} catch (\Throwable $e) {
Log::error('自动好评失败,失败原因:' . $e->getMessage());
}
});
}
//清除昨日海报
elseif ($item['mark'] == 'clear_poster') {
new Crontab($timeStr, function () {
try {
app()->make(SystemAttachmentServices::class)->emptyYesterdayAttachment();
$this->crontabLog(' 执行清除昨日海报');
} catch (\Throwable $e) {
Log::error('清除昨日海报失败,失败原因:' . $e->getMessage());
}
});
}
//
else {
}
}
}
/**
* 定时任务日志
* @param $msg
*/
public function crontabLog($msg)
{
$timer_log_open = config("log.timer_log", false);
if ($timer_log_open){
$date = date('Y-m-d H:i:s', time());
Log::write($date . $msg, 'crontab');
new Crontab($timeStr, function () use ($crontabRunServices, $functionName) {
$crontabRunServices->$functionName();
});
}
}

View File

@ -13,10 +13,12 @@ namespace app\services\order;
use app\services\activity\advance\StoreAdvanceServices;
use app\services\activity\combination\StorePinkServices;
use app\services\agent\AgentLevelServices;
use app\services\activity\coupon\StoreCouponUserServices;
use app\services\agent\DivisionServices;
use app\services\pay\PayServices;
use app\services\pc\OrderServices;
use app\services\product\product\StoreCategoryServices;
use app\services\shipping\ShippingTemplatesFreeServices;
use app\services\shipping\ShippingTemplatesRegionServices;
@ -25,6 +27,7 @@ use app\services\user\UserInvoiceServices;
use app\services\wechat\WechatUserServices;
use app\services\BaseServices;
use crmeb\exceptions\ApiException;
use crmeb\exceptions\ApiStatusException;
use crmeb\services\CacheService;
use app\dao\order\StoreOrderDao;
use app\services\user\UserServices;
@ -116,11 +119,10 @@ class StoreOrderCreateServices extends BaseServices
* 创建订单
* @param $uid
* @param $key
* @param $cartGroup
* @param $userInfo
* @param $addressId
* @param $payType
* @param bool $useIntegral
* @param false $useIntegral
* @param int $couponId
* @param string $mark
* @param int $combinationId
@ -131,158 +133,231 @@ class StoreOrderCreateServices extends BaseServices
* @param string $real_name
* @param string $phone
* @param int $storeId
* @param bool $news
* @param false $news
* @param int $advanceId
* @param int $virtual_type
* @param array $customForm
* @param int $invoice_id
* @return mixed
* @throws \Psr\SimpleCache\InvalidArgumentException
* @throws \Throwable
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function createOrder($uid, $key, $cartGroup, $userInfo, $addressId, $payType, $useIntegral = false, $couponId = 0, $mark = '', $combinationId = 0, $pinkId = 0, $seckillId = 0, $bargainId = 0, $shippingType = 1, $real_name = '', $phone = '', $storeId = 0, $news = false, $advanceId = 0, $virtual_type = 0, $customForm = [], $invoice_id = 0)
public function createOrder($uid, $key, $userInfo, $addressId, $payType, $useIntegral = false, $couponId = 0, $mark = '', $combinationId = 0, $pinkId = 0, $seckillId = 0, $bargainId = 0, $shippingType = 1, $real_name = '', $phone = '', $storeId = 0, $news = false, $advanceId = 0, $customForm = [], $invoice_id = 0)
{
//下单前发票验证
if ($invoice_id) {
app()->make(UserInvoiceServices::class)->checkInvoice((int)$invoice_id, $uid);
/** @var StoreOrderServices $orderService */
$storeOrderServices = app()->make(StoreOrderServices::class);
$bargainServices = app()->make(StoreBargainServices::class);
$cartGroup = $storeOrderServices->getCacheOrderInfo($uid, $key);
if (!$cartGroup) {
throw new ApiException(410208);
}
//下单前砍价验证
if ($bargainId) {
$bargainServices->checkBargainUser((int)$bargainId, $uid);
}
/** @var StoreOrderComputedServices $computedServices */
$computedServices = app()->make(StoreOrderComputedServices::class);
$priceData = $computedServices->computedOrder($uid, $userInfo, $cartGroup, $addressId, $payType, $useIntegral, $couponId, true, $shippingType);
/** @var WechatUserServices $wechatServices */
$wechatServices = app()->make(WechatUserServices::class);
/** @var UserAddressServices $addressServices */
$addressServices = app()->make(UserAddressServices::class);
if ($shippingType == 1 && $virtual_type == 0) {
if (!$addressId) {
throw new ApiException(410045);
if ($pinkId) {
$pinkId = (int)$pinkId;
/** @var StorePinkServices $pinkServices */
$pinkServices = app()->make(StorePinkServices::class);
if ($pinkServices->isPink($pinkId, $uid))
throw new ApiStatusException('ORDER_EXIST', 410210, ['orderId' => $storeOrderServices->getStoreIdPink($pinkId, $uid)]);
if ($storeOrderServices->getIsOrderPink($pinkId, $uid))
throw new ApiStatusException('ORDER_EXIST', 410211, ['orderId' => $storeOrderServices->getStoreIdPink($pinkId, $uid)]);
if (!CacheService::checkStock(md5($pinkId), 1, 3) || !CacheService::popStock(md5($pinkId), 1, 3)) {
throw new ApiException(410212);
}
if (!$addressInfo = $addressServices->getOne(['uid' => $uid, 'id' => $addressId, 'is_del' => 0]))
throw new ApiException(410046);
$addressInfo = $addressInfo->toArray();
} else {
if ((!$real_name || !$phone) && $virtual_type == 0) {
throw new ApiException(410245);
}
$addressInfo['real_name'] = $real_name;
$addressInfo['phone'] = $phone;
$addressInfo['province'] = '';
$addressInfo['city'] = '';
$addressInfo['district'] = '';
$addressInfo['detail'] = '';
}
$cartInfo = $cartGroup['cartInfo'];
$priceGroup = $cartGroup['priceGroup'];
$cartIds = [];
$totalNum = 0;
$gainIntegral = 0;
foreach ($cartInfo as $cart) {
$cartIds[] = $cart['id'];
$totalNum += $cart['cart_num'];
if (!$seckillId) $seckillId = $cart['seckill_id'];
if (!$bargainId) $bargainId = $cart['bargain_id'];
if (!$combinationId) $combinationId = $cart['combination_id'];
if (!$advanceId) $advanceId = $cart['advance_id'];
$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 (count($cartInfo) == 1 && isset($cartInfo[0]['productInfo']['presale']) && $cartInfo[0]['productInfo']['presale'] == 1) {
$advance_id = $cartInfo[0]['product_id'];
} else {
$advance_id = 0;
}
$deduction = $seckillId || $bargainId || $combinationId;
if ($deduction) {
$couponId = 0;
$useIntegral = false;
}
//$shipping_type = 1 快递发货 $shipping_type = 2 门店自提
$storeSelfMention = sys_config('store_self_mention') ?? 0;
if (!$storeSelfMention) $shippingType = 1;
$cartInfo = null;
if ($seckillId || $combinationId || $bargainId || $advanceId) {
$cartInfo = $cartGroup['cartInfo'];
foreach ($cartInfo as $item) {
$type = 0;
if (!isset($item['product_attr_unique']) || !$item['product_attr_unique']) continue;
if ($item['seckill_id']) {
$type = 1;
} elseif ($item['bargain_id']) {
$type = 2;
} elseif ($item['combination_id']) {
$type = 3;
} elseif ($item['advance_id']) {
$type = 6;
}
if ($type && (!CacheService::checkStock($item['product_attr_unique'], (int)$item['cart_num'], $type) || !CacheService::popStock($item['product_attr_unique'], (int)$item['cart_num'], $type))) {
throw new ApiException(410214, ['cart_num' => $item['cart_num'], 'unit_name' => $item['productInfo']['unit_name']]);
$orderInfo = [
'uid' => $uid,
'order_id' => $this->getNewOrderId('cp'),
'real_name' => $addressInfo['real_name'],
'user_phone' => $addressInfo['phone'],
'user_address' => $addressInfo['province'] . ' ' . $addressInfo['city'] . ' ' . $addressInfo['district'] . ' ' . $addressInfo['detail'],
'cart_id' => $cartIds,
'total_num' => $totalNum,
'total_price' => $priceGroup['totalPrice'],
'total_postage' => $shippingType == 1 ? $priceGroup['storePostage'] : 0,
'coupon_id' => $couponId,
'coupon_price' => $priceData['coupon_price'],
'pay_price' => $priceData['pay_price'],
'pay_postage' => $priceData['pay_postage'],
'deduction_price' => $priceData['deduction_price'],
'paid' => 0,
'pay_type' => $payType,
'use_integral' => $priceData['usedIntegral'],
'gain_integral' => $gainIntegral,
'mark' => htmlspecialchars($mark),
'combination_id' => $combinationId,
'pink_id' => $pinkId,
'seckill_id' => $seckillId,
'bargain_id' => $bargainId,
'advance_id' => $advance_id,
'cost' => $priceGroup['costPrice'],
'add_time' => time(),
'unique' => $key,
'shipping_type' => $shippingType,
'channel_type' => $userInfo['user_type'],
'province' => strval($userInfo['user_type'] == 'wechat' || $userInfo['user_type'] == 'routine' ? $wechatServices->value(['uid' => $uid, 'user_type' => $userInfo['user_type']], 'province') : ''),
'spread_uid' => 0,
'spread_two_uid' => 0,
'virtual_type' => $virtual_type,
'pay_uid' => $uid,
'custom_form' => json_encode($customForm),
'division_id' => $userInfo['division_id'],
'agent_id' => $userInfo['agent_id'],
'staff_id' => $userInfo['staff_id'],
];
if ($shippingType == 2) {
$orderInfo['verify_code'] = $this->getStoreCode();
/** @var SystemStoreServices $storeServices */
$storeServices = app()->make(SystemStoreServices::class);
$orderInfo['store_id'] = $storeServices->getStoreDispose($storeId, 'id');
if (!$orderInfo['store_id']) {
throw new ApiException(410247);
}
}
}
/** @var StoreOrderCartInfoServices $cartServices */
$cartServices = app()->make(StoreOrderCartInfoServices::class);
/** @var StoreSeckillServices $seckillServices */
$seckillServices = app()->make(StoreSeckillServices::class);
$priceData['coupon_id'] = $couponId;
$order = $this->transaction(function () use ($cartIds, $orderInfo, $cartInfo, $key, $userInfo, $useIntegral, $priceData, $combinationId, $seckillId, $bargainId, $cartServices, $seckillServices, $uid, $addressId, $advanceId) {
//创建订单
$order = $this->dao->save($orderInfo);
if (!$order) {
throw new ApiException(410200);
}
//记录自提人电话和姓名
/** @var UserServices $userService */
$userService = app()->make(UserServices::class);
$userService->update(['uid' => $uid], ['real_name' => $orderInfo['real_name'], 'record_phone' => $orderInfo['user_phone']]);
//占用库存
$seckillServices->occupySeckillStock($cartInfo, $key);
//积分抵扣
if ($priceData['usedIntegral'] > 0) {
$this->deductIntegral($userInfo, $useIntegral, $priceData, (int)$userInfo['uid'], $order['id']);
}
//扣库存
$this->decGoodsStock($cartInfo, $combinationId, $seckillId, $bargainId, $advanceId);
//保存购物车商品信息
$cartServices->setCartInfo($order['id'], $uid, $cartInfo);
return $order;
});
//创建开票数据
if ($invoice_id) {
app()->make(StoreOrderInvoiceServices::class)->makeUp($uid, $order['order_id'], (int)$invoice_id);
$virtual_type = $cartGroup['cartInfo'][0]['productInfo']['virtual_type'] ?? 0;
try {
//下单前发票验证
if ($invoice_id) {
app()->make(UserInvoiceServices::class)->checkInvoice((int)$invoice_id, $uid);
}
/** @var StoreOrderComputedServices $computedServices */
$computedServices = app()->make(StoreOrderComputedServices::class);
$priceData = $computedServices->computedOrder($uid, $userInfo, $cartGroup, $addressId, $payType, $useIntegral, $couponId, true, $shippingType);
/** @var WechatUserServices $wechatServices */
$wechatServices = app()->make(WechatUserServices::class);
/** @var UserAddressServices $addressServices */
$addressServices = app()->make(UserAddressServices::class);
if ($shippingType == 1 && $virtual_type == 0) {
if (!$addressId) {
throw new ApiException(410045);
}
if (!$addressInfo = $addressServices->getOne(['uid' => $uid, 'id' => $addressId, 'is_del' => 0]))
throw new ApiException(410046);
$addressInfo = $addressInfo->toArray();
} else {
if ((!$real_name || !$phone) && $virtual_type == 0) {
throw new ApiException(410245);
}
$addressInfo['real_name'] = $real_name;
$addressInfo['phone'] = $phone;
$addressInfo['province'] = '';
$addressInfo['city'] = '';
$addressInfo['district'] = '';
$addressInfo['detail'] = '';
}
$cartInfo = $cartGroup['cartInfo'];
$priceGroup = $cartGroup['priceGroup'];
$cartIds = [];
$totalNum = 0;
$gainIntegral = 0;
foreach ($cartInfo as $cart) {
$cartIds[] = $cart['id'];
$totalNum += $cart['cart_num'];
if (!$seckillId) $seckillId = $cart['seckill_id'];
if (!$bargainId) $bargainId = $cart['bargain_id'];
if (!$combinationId) $combinationId = $cart['combination_id'];
if (!$advanceId) $advanceId = $cart['advance_id'];
$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 (count($cartInfo) == 1 && isset($cartInfo[0]['productInfo']['presale']) && $cartInfo[0]['productInfo']['presale'] == 1) {
$advance_id = $cartInfo[0]['product_id'];
} else {
$advance_id = 0;
}
$deduction = $seckillId || $bargainId || $combinationId;
if ($deduction) {
$couponId = 0;
$useIntegral = false;
}
//$shipping_type = 1 快递发货 $shipping_type = 2 门店自提
$storeSelfMention = sys_config('store_self_mention') ?? 0;
if (!$storeSelfMention) $shippingType = 1;
$orderInfo = [
'uid' => $uid,
'order_id' => $this->getNewOrderId('cp'),
'real_name' => $addressInfo['real_name'],
'user_phone' => $addressInfo['phone'],
'user_address' => $addressInfo['province'] . ' ' . $addressInfo['city'] . ' ' . $addressInfo['district'] . ' ' . $addressInfo['detail'],
'cart_id' => $cartIds,
'total_num' => $totalNum,
'total_price' => $priceGroup['totalPrice'],
'total_postage' => $shippingType == 1 ? $priceGroup['storePostage'] : 0,
'coupon_id' => $couponId,
'coupon_price' => $priceData['coupon_price'],
'pay_price' => $priceData['pay_price'],
'pay_postage' => $priceData['pay_postage'],
'deduction_price' => $priceData['deduction_price'],
'paid' => 0,
'pay_type' => $payType,
'use_integral' => $priceData['usedIntegral'],
'gain_integral' => $gainIntegral,
'mark' => htmlspecialchars($mark),
'combination_id' => $combinationId,
'pink_id' => $pinkId,
'seckill_id' => $seckillId,
'bargain_id' => $bargainId,
'advance_id' => $advance_id,
'cost' => $priceGroup['costPrice'],
'add_time' => time(),
'unique' => $key,
'shipping_type' => $shippingType,
'channel_type' => $userInfo['user_type'],
'province' => strval($userInfo['user_type'] == 'wechat' || $userInfo['user_type'] == 'routine' ? $wechatServices->value(['uid' => $uid, 'user_type' => $userInfo['user_type']], 'province') : ''),
'spread_uid' => 0,
'spread_two_uid' => 0,
'virtual_type' => $virtual_type,
'pay_uid' => $uid,
'custom_form' => json_encode($customForm),
'division_id' => $userInfo['division_id'],
'agent_id' => $userInfo['agent_id'],
'staff_id' => $userInfo['staff_id'],
];
if ($shippingType == 2) {
$orderInfo['verify_code'] = $this->getStoreCode();
/** @var SystemStoreServices $storeServices */
$storeServices = app()->make(SystemStoreServices::class);
$orderInfo['store_id'] = $storeServices->getStoreDispose($storeId, 'id');
if (!$orderInfo['store_id']) {
throw new ApiException(410247);
}
}
/** @var StoreOrderCartInfoServices $cartServices */
$cartServices = app()->make(StoreOrderCartInfoServices::class);
/** @var StoreSeckillServices $seckillServices */
$seckillServices = app()->make(StoreSeckillServices::class);
$priceData['coupon_id'] = $couponId;
$order = $this->transaction(function () use ($cartIds, $orderInfo, $cartInfo, $key, $userInfo, $useIntegral, $priceData, $combinationId, $seckillId, $bargainId, $cartServices, $seckillServices, $uid, $addressId, $advanceId) {
//创建订单
$order = $this->dao->save($orderInfo);
if (!$order) {
throw new ApiException(410200);
}
//记录自提人电话和姓名
/** @var UserServices $userService */
$userService = app()->make(UserServices::class);
$userService->update(['uid' => $uid], ['real_name' => $orderInfo['real_name'], 'record_phone' => $orderInfo['user_phone']]);
//占用库存
$seckillServices->occupySeckillStock($cartInfo, $key);
//积分抵扣
if ($priceData['usedIntegral'] > 0) {
$this->deductIntegral($userInfo, $useIntegral, $priceData, (int)$userInfo['uid'], $order['id']);
}
//扣库存
$this->decGoodsStock($cartInfo, $combinationId, $seckillId, $bargainId, $advanceId);
//保存购物车商品信息
$cartServices->setCartInfo($order['id'], $uid, $cartInfo);
return $order;
});
//创建开票数据
if ($invoice_id) {
app()->make(StoreOrderInvoiceServices::class)->makeUp($uid, $order['order_id'], (int)$invoice_id);
}
} catch (\Throwable $e) {
if ($seckillId || $combinationId || $advanceId || $bargainId) {
foreach ($cartInfo as $item) {
$value = $item['cart_info'];
$type = 0;
if (!isset($value['product_attr_unique']) || $value['product_attr_unique']) continue;
if ($value['seckill_id']) {
$type = 1;
} elseif ($value['bargain_id']) {
$type = 2;
} elseif ($value['combination_id']) {
$type = 3;
} elseif ($value['advance_id']) {
$type = 6;
}
if ($type) CacheService::setStock($value['product_attr_unique'], (int)$value['cart_num'], $type, false);
}
}
throw $e;
}
// 订单创建成功后置事件

View File

@ -0,0 +1,193 @@
<?php
namespace app\services\system\crontab;
use app\services\activity\combination\StorePinkServices;
use app\services\activity\live\LiveGoodsServices;
use app\services\activity\live\LiveRoomServices;
use app\services\agent\AgentManageServices;
use app\services\order\StoreOrderServices;
use app\services\order\StoreOrderTakeServices;
use app\services\product\product\StoreProductServices;
use app\services\system\attachment\SystemAttachmentServices;
use think\facade\Log;
/**
* 执行定时任务
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
class CrontabRunServices
{
/**
* 调用不存在的方法
* @param $name
* @param $arguments
* @return mixed|void
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function __call($name, $arguments)
{
$this->crontabLog($name . '方法不存在');
}
/**
* 定时任务日志
* @param $msg
*/
protected function crontabLog($msg)
{
$timer_log_open = config("log.timer_log", false);
if ($timer_log_open) {
$date = date('Y-m-d H:i:s', time());
Log::write($date . $msg, 'crontab');
}
}
/**
* 未支付自动取消订单
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function orderCancel()
{
try {
app()->make(StoreOrderServices::class)->orderUnpaidCancel();
$this->crontabLog(' 执行未支付自动取消订单');
} catch (\Throwable $e) {
$this->crontabLog('自动取消订单失败,失败原因:' . $e->getMessage());
}
}
/**
* 拼团到期订单处理
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function pinkExpiration()
{
try {
app()->make(StorePinkServices::class)->statusPink();
$this->crontabLog(' 执行拼团到期订单处理');
} catch (\Throwable $e) {
$this->crontabLog('拼团到期订单处理失败,失败原因:' . $e->getMessage());
}
}
/**
* 自动解除上级绑定
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function agentUnbind()
{
try {
app()->make(AgentManageServices::class)->removeSpread();
$this->crontabLog(' 执行自动解绑上级绑定');
} catch (\Throwable $e) {
$this->crontabLog('自动解除上级绑定失败,失败原因:' . $e->getMessage());
}
}
/**
* 更新直播商品状态
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function liveProductStatus()
{
try {
app()->make(LiveGoodsServices::class)->syncGoodStatus();
$this->crontabLog(' 执行更新直播商品状态');
} catch (\Throwable $e) {
$this->crontabLog('更新直播商品状态失败,失败原因:' . $e->getMessage());
}
}
/**
* 更新直播间状态
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function liveRoomStatus()
{
try {
app()->make(LiveRoomServices::class)->syncRoomStatus();
$this->crontabLog(' 执行更新直播间状态');
} catch (\Throwable $e) {
$this->crontabLog('更新直播间状态失败,失败原因:' . $e->getMessage());
}
}
/**
* 自动收货
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function takeDelivery()
{
try {
app()->make(StoreOrderTakeServices::class)->autoTakeOrder();
$this->crontabLog(' 执行自动收货');
} catch (\Throwable $e) {
$this->crontabLog('自动收货失败,失败原因:' . $e->getMessage());
}
}
/**
* 预售到期商品自动下架
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function advanceOff()
{
try {
app()->make(StoreProductServices::class)->downAdvance();
$this->crontabLog(' 执行预售到期商品自动下架');
} catch (\Throwable $e) {
$this->crontabLog('预售到期商品自动下架失败,失败原因:' . $e->getMessage());
}
}
/**
* 自动好评
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function productReplay()
{
try {
app()->make(StoreOrderServices::class)->autoComment();
$this->crontabLog(' 执行自动好评');
} catch (\Throwable $e) {
$this->crontabLog('自动好评失败,失败原因:' . $e->getMessage());
}
}
/**
* 清除昨日海报
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function clearPoster()
{
try {
app()->make(SystemAttachmentServices::class)->emptyYesterdayAttachment();
$this->crontabLog(' 执行清除昨日海报');
} catch (\Throwable $e) {
$this->crontabLog('清除昨日海报失败,失败原因:' . $e->getMessage());
}
}
}

View File

@ -14,6 +14,7 @@ use app\services\product\product\StoreProductServices;
use app\services\system\attachment\SystemAttachmentServices;
use crmeb\exceptions\AdminException;
use think\facade\Log;
use think\helper\Str;
class SystemCrontabServices extends BaseServices
{
@ -205,67 +206,19 @@ class SystemCrontabServices extends BaseServices
*/
public function crontabRun()
{
$crontabRunServices = app()->make(CrontabRunServices::class);
$time = time();
file_put_contents(root_path() . 'runtime/.timer', $time); //检测定时任务是否正常
$list = $this->dao->selectList(['is_open' => 1, 'is_del' => 0])->toArray();
foreach ($list as $item) {
if ($item['next_execution_time'] < $time) {
if ($item['mark'] == 'order_cancel') {
//未支付自动取消订单
app()->make(StoreOrderServices::class)->orderUnpaidCancel();
$this->crontabLog(' 执行未支付自动取消订单');
} elseif ($item['mark'] == 'pink_expiration') {
//拼团到期订单处理
app()->make(StorePinkServices::class)->statusPink();
$this->crontabLog(' 执行拼团到期订单处理');
} elseif ($item['mark'] == 'agent_unbind') {
//自动解绑上级绑定
app()->make(AgentManageServices::class)->removeSpread();
$this->crontabLog(' 执行自动解绑上级绑定');
} elseif ($item['mark'] == 'live_product_status') {
//更新直播商品状态
app()->make(LiveGoodsServices::class)->syncGoodStatus();
$this->crontabLog(' 执行更新直播商品状态');
} elseif ($item['mark'] == 'live_room_status') {
//更新直播间状态
app()->make(LiveRoomServices::class)->syncRoomStatus();
$this->crontabLog(' 执行更新直播间状态');
} elseif ($item['mark'] == 'take_delivery') {
//自动收货
app()->make(StoreOrderTakeServices::class)->autoTakeOrder();
$this->crontabLog(' 执行自动收货');
} elseif ($item['mark'] == 'advance_off') {
//查询预售到期商品自动下架
app()->make(StoreProductServices::class)->downAdvance();
$this->crontabLog(' 执行预售到期商品自动下架');
} elseif ($item['mark'] == 'product_replay') {
//自动好评
app()->make(StoreOrderServices::class)->autoComment();
$this->crontabLog(' 执行自动好评');
} elseif ($item['mark'] == 'clear_poster') {
//清除昨日海报
app()->make(SystemAttachmentServices::class)->emptyYesterdayAttachment();
$this->crontabLog(' 执行清除昨日海报');
}
//转化小驼峰方法名
$functionName = Str::camel($item['mark']);
//执行定时任务
$crontabRunServices->$functionName();
//写入本次执行时间和下次执行时间
$this->dao->update(['mark' => $item['mark']], ['last_execution_time' => $time, 'next_execution_time' => $this->getTimerCycleTime($item)]);
}
}
}
/**
* 定时任务日志
* @param $msg
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/02/21
*/
public function crontabLog($msg)
{
$timer_log_open = config("log.timer_log", false);
if ($timer_log_open) {
$date = date('Y-m-d H:i:s', time());
Log::write($date . $msg, 'crontab');
}
}
}

View File

@ -68,8 +68,15 @@ class UserServices extends BaseServices
/**
* 获取用户信息
* @param $id
* @param $field
* @param int $uid
* @param string $field
* @return array|\think\Model|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function getUserInfo(int $uid, $field = '*')
{
@ -1014,14 +1021,25 @@ class UserServices extends BaseServices
/**
* 赠送付费会员时长
* @param int $uid
* @return mixed
* */
* @param $id
* @return array
* @throws \FormBuilder\Exception\FormBuilderException
* @author 吴汐
* @email 442384644@qq.com
* @date 2023/03/01
*/
public function giveLevelTime($id)
{
if (!$this->getUserInfo($id)) {
$userInfo = $this->getUserInfo($id);
if (!$userInfo) {
throw new AdminException(400214);
}
$timeDiff = $userInfo['is_ever_level'] == 1 ? '永久' : date('Y-m-d H:i:s', $userInfo['overdue_time']);
$dayDiff = intval(($userInfo['overdue_time'] - time()) / 86400);
$field[] = Form::input('time_diff', '到期时间', $timeDiff)->style(['width' => '200px'])->readonly(true);
if ($userInfo['is_ever_level'] == 0) {
$field[] = Form::input('day_diff', '剩余天数', $dayDiff)->style(['width' => '200px'])->readonly(true);
}
$field[] = Form::number('days', '增加时长(天)')->precision(0)->style(['width' => '200px'])->required();
return create_form('赠送付费会员时长', $field, Url::buildUrl('/user/save_give_level_time/' . $id), 'PUT');
}

View File

@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\exceptions;
/**
* API应用错误信息
* Class ApiException
* @package crmeb\exceptions
*/
class ApiStatusException extends \RuntimeException
{
protected $apiStatus;
protected $apiData;
public function __construct($status, $message, $data = [], $replace = [], $code = 0, \Throwable $previous = null)
{
if (is_array($message)) {
$errInfo = $message;
$message = $errInfo[1] ?? '未知错误';
if ($code === 0) {
$code = $errInfo[0] ?? 400;
}
}
if (is_numeric($message)) {
$code = $message;
$message = getLang($message, $replace);
}
$this->apiData = $data;
$this->apiStatus = $status;
parent::__construct($message, $code, $previous);
}
/**
* @return mixed
*/
public function getApiStatus()
{
return $this->apiStatus;
}
/**
* @return array|mixed
*/
public function getApiData()
{
return $this->apiData;
}
}

View File

@ -33520,7 +33520,8 @@ INSERT INTO `eb_system_config` (`id`, `menu_name`, `type`, `input_type`, `config
(428, 'queue_open', 'radio', 'input', 26, '0=>关闭\n1=>开启', 1, '', 0, 0, '\"0\"', '消息队列', '是否启用消息队列,启用后提升程序运行速度,启用前必须配置Redis缓存,文档地址:https://doc.crmeb.com/single/crmeb_v4/7217', 0, 1),
(429, 'get_avatar', 'radio', 'input', 7, '0=>关闭\n1=>开启', 1, '', 0, 0, '\"0\"', '强制获取昵称头像', '是否在小程序用户授权之后,弹窗获取用户的昵称和头像', 0, 1),
(430, 'share_qrcode', 'radio', 'input', 2, '0=>商城\n1=>公众号', 1, '', 0, 0, '\"0\"', '公众号推广码类型', '公众号生成的推广码类型:商城:扫码直接进入商城,公众号:扫码进入公众号后推送商城的链接', 0, 1),
(431, 'member_brokerage', 'radio', 'input', 73, '1=>开启\n0=>关闭', 1, '', 0, 0, '\"0\"', '购买付费会员返佣', '购买付费会员是否按照设置的佣金比例进行返佣', 98, 1);
(431, 'member_brokerage', 'radio', 'input', 73, '1=>开启\n0=>关闭', 1, '', 0, 0, '\"0\"', '购买付费会员返佣', '购买付费会员是否按照设置的佣金比例进行返佣', 98, 1),
(432, 'user_brokerage_type', 'radio', 'input', 73, '0=>按照商品价格返佣\n1=>按照实际支付价格返佣', 1, '', 0, 0, '\"0\"', '返佣类型', '选择返佣类型,按照商品价格返佣(按照商品售价计算返佣金额)以及按照实际支付价格返佣(按照商品的实际支付价格计算返佣 )', 97, 1);
-- --------------------------------------------------------

View File

@ -3,7 +3,7 @@
<Alert closable="true">
<template slot="desc">
启动定时任务两种方式:<br />
1、使用命令启动:php think timer start --d<br />
1、使用命令启动:php think timer start --d;如果更改了执行周期、编辑是否开启、删除定时任务需要重新启动下定时任务确保生效;<br />
2、使用接口触发定时任务,建议每分钟调用一次,接口地址 https://您的域名/api/crontab/run
</template>
</Alert>