初始化项目

This commit is contained in:
2026-09-01 22:15:50 +08:00
commit b5a26a8848
11217 changed files with 1710987 additions and 0 deletions
@@ -0,0 +1,952 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order;
use app\api\model\Order as OrderModel;
use app\api\model\User as UserModel;
use app\api\model\Merchant as MerchantModel;
use app\api\model\Goods as GoodsModel;
use app\api\model\Setting as SettingModel;
use app\api\model\UserCoupon as UserCouponModel;
use app\api\service\User as UserService;
use app\api\service\Payment as PaymentService;
use app\api\service\user\Grade as UserGradeService;
use app\api\service\coupon\GoodsDeduct as GoodsDeductService;
use app\api\service\points\GoodsDeduct as PointsDeductService;
use app\api\service\order\source\checkout\Factory as CheckoutFactory;
use app\common\enum\Setting as SettingEnum;
use app\common\enum\order\PayType as OrderPayTypeEnum;
use app\common\enum\order\OrderStatus as OrderStatusEnum;
use app\common\enum\order\OrderSource as OrderSourceEnum;
use app\common\enum\order\DeliveryType as DeliveryTypeEnum;
use app\common\lock\RedisLock;
use app\common\service\BaseService;
use app\common\service\delivery\Express as ExpressService;
use app\common\service\goods\source\Factory as StockFactory;
use app\common\library\helper;
use app\common\service\Order as OrderService;
use app\store\model\Company as CompanyModel;
use cores\exception\BaseException;
use think\facade\Db;
use app\common\service\SybOil;
use app\common\model\OrderGoods as OrderGoodsModel;
/**
* 订单结算台服务类
* Class Checkout
* @package app\api\service\order
*/
class Checkout extends BaseService
{
/* $model OrderModel 订单模型 */
public $model;
/* @var UserModel $user 当前用户信息 */
private $user;
// 订单结算商品列表
private $goodsList = [];
/**
* 订单结算api参数
* @var array
*/
private $param = [
'delivery' => null, // 配送方式
'couponId' => 0, // 用户的优惠券ID
'isUsePoints' => 0, // 是否使用积分抵扣
'remark' => '', // 买家留言
'payType' => OrderPayTypeEnum::WECHAT, // 支付方式
];
/**
* 订单结算的规则
* @var array
*/
private $checkoutRule = [
'isUserGrade' => true, // 会员等级折扣
'isCoupon' => true, // 优惠券抵扣
'isUsePoints' => true, // 是否使用积分抵扣
];
/**
* 订单来源
* @var array
*/
private $orderSource = [
'source' => OrderSourceEnum::MAIN,
'source_id' => 0,
];
/**
* 订单结算数据
* @var array
*/
private $orderData = [];
/**
* 构造函数
* Checkout constructor.
* @throws BaseException
*/
public function __construct()
{
parent::__construct();
$this->user = UserService::getCurrentLoginUser(true);
$this->model = new OrderModel;
$this->storeId = $this->getStoreId();
}
/**
* 设置结算台请求的参数
* @param $param
* @return array
*/
public function setParam($param): array
{
$this->param = array_merge($this->param, $param);
return $this->getParam();
}
/**
* 获取结算台请求的参数
* @return array
*/
public function getParam(): array
{
return $this->param;
}
/**
* 订单结算的规则
* @param $data
* @return $this
*/
public function setCheckoutRule($data): Checkout
{
$this->checkoutRule = array_merge($this->checkoutRule, $data);
return $this;
}
/**
* 设置订单来源(普通订单)
* @param $data
* @return $this
*/
public function setOrderSource($data): Checkout
{
$this->orderSource = array_merge($this->orderSource, $data);
return $this;
}
/**
* 订单确认-结算台
* @param $goodsList
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function onCheckout($goodsList): array
{
// 订单确认-立即购买
$this->goodsList = $goodsList;
return $this->checkout();
}
/**
* 订单结算台
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function checkout(): array
{
// 整理订单数据
$this->orderData = $this->getOrderData();
// 验证商品状态, 是否允许购买
$this->validateGoodsList();
// 订单商品总数量
$orderTotalNum = (int)helper::getArrayColumnSum($this->goodsList, 'total_num');
// 设置订单商品会员折扣价
$this->setOrderGoodsGradeMoney();
// 设置订单商品总金额(不含优惠折扣)
$this->setOrderTotalPrice();
// 当前用户可用的优惠券列表
$couponList = $this->getUserCouponList((float)$this->orderData['orderTotalPrice']);
// 计算优惠券抵扣
$this->setOrderCouponMoney($couponList, (int)$this->param['couponId']);
// 计算可用积分抵扣
$this->setOrderPoints();
// 计算订单商品的实际付款金额
$this->setOrderGoodsPayPrice();
// 设置默认配送方式
if (!$this->param['delivery']) {
$deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
$this->param['delivery'] = current($deliveryType);
}
// 处理配送方式
if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) {
$this->setOrderExpress();
}
// 计算订单最终金额
$this->setOrderPayPrice();
// 计算订单积分赠送数量
$this->setOrderPointsBonus();
// 返回订单数据
return array_merge([
'goodsList' => $this->goodsList, // 商品信息
'orderTotalNum' => $orderTotalNum, // 商品总数量
'couponList' => array_values($couponList), // 优惠券列表
'hasError' => $this->hasError(),
'errorMsg' => $this->getError(),
], $this->orderData);
}
/**
* 计算订单可用积分抵扣
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function setOrderPoints(): void
{
// 设置默认的商品积分抵扣信息
$this->setDefaultGoodsPoints();
// 积分设置
$setting = SettingModel::getItem('points');
// 条件:后台开启下单使用积分抵扣
if (!$setting['is_shopping_discount'] || !$this->checkoutRule['isUsePoints']) {
return;
}
// 条件:订单金额满足[?]元
if (helper::bccomp($setting['discount']['full_order_price'], $this->orderData['orderTotalPrice']) === 1) {
return;
}
// 计算订单商品最多可抵扣的积分数量
$this->setOrderGoodsMaxPointsNum();
// 订单最多可抵扣的积分总数量
$maxPointsNumCount = (int)helper::getArrayColumnSum($this->goodsList, 'max_points_num');
// 实际可抵扣的积分数量
$actualPointsNum = min($maxPointsNumCount, $this->user['points']);
if ($actualPointsNum < 1) {
return;
}
// 计算订单商品实际抵扣的积分数量和金额
$GoodsDeduct = new PointsDeductService($this->goodsList);
$GoodsDeduct->setGoodsPoints($maxPointsNumCount, $actualPointsNum);
// 积分抵扣总金额
$orderPointsMoney = helper::getArrayColumnSum($this->goodsList, 'points_money');
$this->orderData['pointsMoney'] = helper::number2($orderPointsMoney);
// 积分抵扣总数量
$this->orderData['pointsNum'] = $actualPointsNum;
// 允许积分抵扣
$this->orderData['isAllowPoints'] = true;
}
/**
* 计算订单商品最多可抵扣的积分数量
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function setOrderGoodsMaxPointsNum(): void
{
// 积分设置
$setting = SettingModel::getItem('points');
foreach ($this->goodsList as &$goods) {
// 商品不允许积分抵扣
if (!$goods['is_points_discount']) continue;
// 积分抵扣比例
$deductionRatio = helper::bcdiv($setting['discount']['max_money_ratio'], 100);
// 最多可抵扣的金额
$totalPayPrice = helper::bcsub($goods['total_price'], $goods['coupon_money']);
$maxPointsMoney = helper::bcmul($totalPayPrice, $deductionRatio);
// 最多可抵扣的积分数量
$goods['max_points_num'] = helper::bcdiv($maxPointsMoney, $setting['discount']['discount_ratio'], 0);
}
}
/**
* 设置默认的商品积分抵扣信息
* @return void
*/
private function setDefaultGoodsPoints(): void
{
foreach ($this->goodsList as &$goods) {
// 最多可抵扣的积分数量
$goods['max_points_num'] = 0;
// 实际抵扣的积分数量
$goods['pointsNum'] = 0;
// 实际抵扣的金额
$goods['points_money'] = 0.00;
}
}
/**
* 整理订单数据(结算台初始化)
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getOrderData(): array
{
// 整理当前订单商品类型
$types = helper::getArrayColumn($this->goodsList, 'oilCardType');
// 系统支持的配送方式 (后台设置)
$deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
return [
// 当前配送类型
'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0],
// 默认地址
'address' => $this->user['address_default'],
// 是否存在收货地址
'existAddress' => $this->user['address_id'] > 0,
// 配送费用
'expressPrice' => 0.00,
// 当前用户收货城市是否存在配送规则中
'isIntraRegion' => true,
// 是否允许使用积分抵扣
'isAllowPoints' => false,
// 是否使用积分抵扣
'isUsePoints' => $this->param['isUsePoints'],
// 积分抵扣金额
'pointsMoney' => 0.00,
// 赠送的积分数量
'pointsBonus' => 0,
// 支付方式
'payType' => $this->param['payType'],
// 订单类型
'order_type' => $types[0] ?? '',
// 系统设置 TODO: 废弃
'setting' => $this->getSetting(),
];
}
/**
* 获取订单页面中使用到的系统设置
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getSetting(): array
{
// 系统支持的配送方式 (后台设置)
$deliveryType = SettingModel::getItem(SettingEnum::DELIVERY)['delivery_type'];
// 积分设置
$pointsSetting = SettingModel::getItem(SettingEnum::POINTS);
return [
'deliveryType' => $deliveryType, // 支持的配送方式
'points_name' => $pointsSetting['points_name'], // 积分名称
'points_describe' => $pointsSetting['describe'], // 积分说明
];
}
// 获取订单结算时的个人信息
public function getPersonal(): array
{
return [
'user_id' => $this->user['user_id'],
'balance' => $this->user['balance'],
'points' => $this->user['points'],
'address_id' => $this->user['address_id'],
];
}
/**
* 当前用户可用的优惠券列表
* @param float $orderTotalPrice 总金额
* @return array|mixed
* @throws \think\db\exception\DbException
*/
private function getUserCouponList(float $orderTotalPrice)
{
// 是否开启优惠券折扣
if (!$this->checkoutRule['isCoupon']) {
return [];
}
// 整理当前订单所有商品ID集
$orderGoodsIds = helper::getArrayColumn($this->goodsList, 'goods_id');
// 当前用户可用的优惠券列表
$couponList = UserCouponModel::getUserCouponList($this->user['user_id'], $orderTotalPrice);
// 判断当前优惠券是否满足订单使用条件 (优惠券适用范围)
return UserCouponModel::couponListApplyRange($couponList, $orderGoodsIds);
}
/**
* 验证订单商品的状态
* @return void
*/
private function validateGoodsList(): void
{
$Checkout = CheckoutFactory::getFactory(
$this->user,
$this->goodsList,
$this->orderSource['source'],
$this->orderData
);
$status = $Checkout->validateGoodsList();
$status == false && $this->setError($Checkout->getError());
}
/**
* 设置订单的商品总金额(不含优惠折扣)
*/
private function setOrderTotalPrice()
{
// 订单商品的总金额(不含优惠券折扣)
$this->orderData['orderTotalPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price'));
}
/**
* 设置订单的实际支付金额(含配送费)
*/
private function setOrderPayPrice()
{
// 订单金额(含优惠折扣)
$this->orderData['orderPrice'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price'));
// 订单实付款金额(订单金额 + 运费)
$this->orderData['orderPayPrice'] = helper::number2(helper::bcadd($this->orderData['orderPrice'], $this->orderData['expressPrice']));
}
/**
* 计算订单积分赠送数量
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function setOrderPointsBonus(): void
{
// 初始化商品积分赠送数量
foreach ($this->goodsList as &$goods) {
$goods['points_bonus'] = 0;
}
// 积分设置
$setting = SettingModel::getItem('points');
// 条件:后台开启开启购物送积分
if (!$setting['is_shopping_gift']) {
return;
}
// 设置商品积分赠送数量
foreach ($this->goodsList as &$goods) {
// 积分赠送比例
$ratio = helper::bcdiv($setting['gift_ratio'], 100);
// 计算抵扣积分数量
$goods['points_bonus'] = !$goods['is_points_gift'] ? 0 : helper::bcmul($goods['total_pay_price'], $ratio, 0);
}
// 订单积分赠送数量
$this->orderData['pointsBonus'] = (int)helper::getArrayColumnSum($this->goodsList, 'points_bonus');
}
/**
* 计算订单商品的实际付款金额
* @return void
*/
private function setOrderGoodsPayPrice(): void
{
// 商品总价 - 优惠抵扣
foreach ($this->goodsList as &$goods) {
// 减去优惠券抵扣金额
$value = helper::bcsub($goods['total_price'], $goods['coupon_money']);
// 减去积分抵扣金额
if ($this->orderData['isAllowPoints'] && $this->orderData['isUsePoints']) {
$value = helper::bcsub($value, $goods['points_money']);
}
$goods['total_pay_price'] = helper::number2($value);
}
}
/**
* 设置订单商品会员折扣价
* @return void
* @throws BaseException
*/
private function setOrderGoodsGradeMoney(): void
{
// 设置默认数据
helper::setDataAttribute($this->goodsList, [
// 标记参与会员折扣
'is_user_grade' => false,
// 会员等级抵扣的金额
'grade_ratio' => 0,
// 会员折扣的商品单价
'grade_goods_price' => 0.00,
// 会员折扣的总额差
'grade_total_money' => 0.00,
], true);
// 是否开启会员等级折扣
if (!$this->checkoutRule['isUserGrade']) {
return;
}
// 获取当前登录用户的会员等级信息
$gradeInfo = UserGradeService::getCurrentGradeInfo();
// 判断商品是否参与会员折扣
if (empty($gradeInfo)) {
return;
}
// 计算抵扣金额
foreach ($this->goodsList as &$goods) {
// 判断商品是否参与会员折扣
if (!$goods['is_enable_grade']) {
continue;
}
// 折扣比例
$discountRatio = $gradeInfo['equity']['discount'];
// 商品单独设置了会员折扣
if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$this->user['grade_id']])) {
$discountRatio = $goods['alone_grade_equity'][$gradeInfo['grade_id']];
}
if (empty($discountRatio)) {
continue;
}
// 会员折扣后的商品总金额
$gradeTotalPrice = UserGradeService::getDiscountPrice($goods['total_price'], $discountRatio);
helper::setDataAttribute($goods, [
'is_user_grade' => true,
'grade_ratio' => $discountRatio,
'grade_goods_price' => UserGradeService::getDiscountPrice($goods['goods_price'], $discountRatio),
'grade_total_money' => helper::bcsub($goods['total_price'], $gradeTotalPrice),
'total_price' => $gradeTotalPrice,
], false);
}
}
/**
* 设置订单优惠券抵扣信息
* @param array $couponList 当前用户可用的优惠券列表
* @param int $userCouponId 当前选择的优惠券ID
* @return void
* @throws BaseException
*/
private function setOrderCouponMoney(array $couponList, int $userCouponId): void
{
// 默认选择优惠券
if (empty($userCouponId)) {
foreach ($couponList as $item) {
if (!empty($item['is_apply'])) { // 如果 is_apply 为 true 或非空
$userCouponId = $item['user_coupon_id'] ?? 0;
break; // 找到第一个就退出
}
}
}
// 设置默认数据:订单信息
helper::setDataAttribute($this->orderData, [
'couponId' => 0, // 用户的优惠券ID
'couponMoney' => 0, // 优惠券抵扣金额
], false);
// 设置默认数据:订单商品列表
helper::setDataAttribute($this->goodsList, [
'coupon_money' => 0, // 优惠券抵扣金额
], true);
// 验证选择的优惠券ID是否合法
if (!$this->verifyOrderCouponId($userCouponId, $couponList)) {
return;
}
// 获取优惠券信息
$couponInfo = $this->getCouponInfo($userCouponId, $couponList);
// 计算订单商品优惠券抵扣金额
$goodsListTemp = helper::getArrayColumns($this->goodsList, ['goods_id', 'goods_sku_id', 'total_price']);
$CouponMoney = new GoodsDeductService;
$rangeGoodsList = $CouponMoney->setGoodsList($goodsListTemp)
->setCouponInfo($couponInfo)
->setGoodsCouponMoney()
->getRangeGoodsList();
// 分配订单商品优惠券抵扣金额
foreach ($this->goodsList as &$goods) {
$goodsKey = "{$goods['goods_id']}-{$goods['goods_sku_id']}";
if (isset($rangeGoodsList[$goodsKey])) {
$goods['coupon_money'] = helper::bcdiv($rangeGoodsList[$goodsKey]['coupon_money'], 100);
}
}
// 记录订单优惠券信息
$this->orderData['couponId'] = $userCouponId;
$this->orderData['couponMoney'] = helper::number2(helper::bcdiv($CouponMoney->getActualReducedMoney(), 100));
}
/**
* 验证用户选择的优惠券ID是否合法
* @param int $userCouponId
* @param $couponList
* @return bool
* @throws BaseException
*/
private function verifyOrderCouponId(int $userCouponId, $couponList): bool
{
// 是否开启优惠券折扣
if (!$this->checkoutRule['isCoupon']) {
return false;
}
// 如果没有可用的优惠券,直接返回
if ($userCouponId <= 0 || empty($couponList)) {
return false;
}
// 判断优惠券是否存在
$couponInfo = $this->getCouponInfo($userCouponId, $couponList);
if (!$couponInfo) {
throwError('未找到优惠券信息');
}
// 判断优惠券适用范围是否合法
if (!$couponInfo['is_apply']) {
throwError($couponInfo['not_apply_info']);
}
return true;
}
/**
* 查找指定的优惠券信息
* @param int $userCouponId 优惠券ID
* @param array $couponList 优惠券列表
* @return false|mixed
*/
private function getCouponInfo(int $userCouponId, array $couponList)
{
return helper::getArrayItemByColumn($couponList, 'user_coupon_id', $userCouponId);
}
/**
* 订单配送-快递配送
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function setOrderExpress(): void
{
// 设置默认数据:配送费用
helper::setDataAttribute($this->goodsList, [
'expressPrice' => 0,
], true);
// 当前用户收货城市id
$cityId = $this->user['address_default'] ? (int)$this->user['address_default']['city_id'] : 0;
// 初始化配送服务类
$ExpressService = new ExpressService($cityId, $this->goodsList);
// 验证商品是否在配送范围
$isIntraRegion = $ExpressService->isIntraRegion();
if ($cityId > 0 && $isIntraRegion == false) {
$notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName();
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内");
}
// 订单总运费金额
$this->orderData['isIntraRegion'] = $isIntraRegion;
$this->orderData['expressPrice'] = $ExpressService->getDeliveryFee();
}
/**
* 创建新订单
* @param array $order 订单信息
* @return bool
*/
public function createOrder(array $order): bool
{
// 表单验证
if (!$this->validateOrderForm($order)) {
return false;
}
// 创建新的订单
$status = $this->model->transaction(function () use ($order) {
// 创建订单事件
if ($this->createOrderEvent($order)) {
// 余额支付标记订单已支付
if ($order['payType'] == OrderPayTypeEnum::BALANCE && !$this->model->onPaymentByBalance($this->model['order_no'])) {
throwError($this->error);
}else{
return true;
}
} else {
// 抛出异常以触发事务回滚
throwError($this->error);
}
});
return $status;
}
/**
* 创建订单事件
* @param $order
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function createOrderEvent($order): bool
{
// 新增订单记录
$status = $this->add($order, $this->param['remark']);
/*if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
// 记录收货地址
$this->saveOrderAddress($order['address']);
}*/
// 保存订单商品信息
$goodsStatus = $this->saveOrderGoods($order);
// 更新商品库存 (针对下单减库存的商品)
$this->updateGoodsStockNum($order);
// 设置优惠券使用状态
$order['couponId'] > 0 && UserCouponModel::setIsUse((int)$order['couponId']);
// 积分抵扣情况下扣除用户积分
if ($order['isAllowPoints'] && $order['isUsePoints'] && $order['pointsNum'] > 0) {
$describe = "用户消费:{$this->model['order_no']}";
UserModel::setIncPoints($this->user['user_id'], -$order['pointsNum'], $describe);
}
// 获取订单详情
// $detail = OrderModel::getUserOrderDetail((int)$this->model['order_id']);
return $status && $goodsStatus;
}
/**
* 构建支付请求的参数
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function onOrderPayment(): array
{
return PaymentService::orderPayment($this->model, $this->param['payType']);
}
/**
* 表单验证 (订单提交)
* @param array $order 订单信息
* @return bool
*/
private function validateOrderForm(array $order): bool
{
/*if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
if (empty($order['address'])) {
$this->error = '您还没有选择配送地址';
return false;
}
}*/
// 余额支付时判断用户余额是否足够
/*if ($order['payType'] != OrderPayTypeEnum::BALANCE) {
$this->error = '目前仅支持余额支付';
return false;
}*/
// 余额支付时判断用户余额是否足够
if ($order['payType'] == OrderPayTypeEnum::BALANCE) {
if ($this->user['balance'] < $order['orderPayPrice']) {
$this->error = '您的余额不足,无法使用余额支付';
return false;
}
}
return true;
}
/**
* 当前订单是否存在和使用积分抵扣
* @param $order
* @return bool
*/
private function isExistPointsDeduction($order): bool
{
return $order['isAllowPoints'] && $order['isUsePoints'];
}
/**
* 新增订单记录
* @param $order
* @param string $remark
* @return bool|false
*/
private function add($order, string $remark = ''): bool
{
// 当前订单是否存在和使用积分抵扣
$isExistPointsDeduction = $this->isExistPointsDeduction($order);
// 订单数据
$data = [
'user_id' => $this->user['user_id'],
'order_no' => $this->model->orderNo(),
'order_type' => $order['order_type'],
'total_price' => $order['orderTotalPrice'],
'order_price' => $order['orderPrice'],
'coupon_id' => $order['couponId'],
'coupon_money' => $order['couponMoney'],
'points_money' => $isExistPointsDeduction ? $order['pointsMoney'] : 0.00,
'points_num' => $isExistPointsDeduction ? $order['pointsNum'] : 0,
'pay_price' => $order['orderPayPrice'],
'delivery_type' => $order['delivery'],
'pay_type' => $order['payType'],
'buyer_remark' => trim($remark),
'order_source' => $this->orderSource['source'],
'order_source_id' => $this->orderSource['source_id'],
'points_bonus' => $order['pointsBonus'],
'order_status' => OrderStatusEnum::NORMAL,
'platform' => getPlatform(),
'store_id' => $this->storeId,
];
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) {
$data['express_price'] = $order['expressPrice'];
}
// 计算返佣
if($this->user['referrer_id'] > 0) {
// 分销设置
$setting = SettingModel::getItem('promotion');
// 查询一级返佣
$spread = MerchantModel::detail($this->user['referrer_id']);
$data['spread_uid'] = $spread['merchant_id'];
$data['one_brokerage_ratio'] = round($setting['one_brokerage_ratio']/100,2);
$data['one_brokerage'] = round($data['pay_price']*$data['one_brokerage_ratio'],2);
// 查询二级返佣
if($spread['parent_merchant_id'] > 0) {
$spreadTwo = MerchantModel::detail($spread['parent_merchant_id']);
$data['spread_two_uid'] = $spreadTwo['merchant_id'];
$data['two_brokerage_ratio'] = round($setting['two_brokerage_ratio']/100,2);
$data['two_brokerage'] = round($data['pay_price']*$data['two_brokerage_ratio'],2);
}
}
// 保存订单记录
return $this->model->save($data);
}
public static function createOrderNo(): string
{
// 获取当前时间戳到毫秒(13位)
$time = (int)(microtime(true) * 1000); // 返回形如 1716544103986
// 拼接一个 4 位随机数
$rand = mt_rand(1000, 9999);
return (string)($time . $rand); // 拼接成纯数字字符串
}
/**
* 保存订单商品信息
* @param $order
* @return bool
*/
private function saveOrderGoods($order): bool
{
// 当前订单是否存在和使用积分抵扣
$isExistPointsDeduction = $this->isExistPointsDeduction($order);
// 订单商品列表
$goodsList = [];
// 查询一级返佣
$spread = MerchantModel::detail($this->user['referrer_id']);
$spread_uid = $spread ? $spread['merchant_id'] : 0;
$spread_two_uid = 0;
// 查询二级返佣
if($spread && $spread['parent_merchant_id'] > 0) {
$spreadTwo = MerchantModel::detail($spread['parent_merchant_id']);
$spread_two_uid = $spreadTwo ? $spreadTwo['merchant_id'] : 0;
}
// 分销设置
$setting = SettingModel::getItem('promotion');
// 一级分销
$one_brokerage_ratio = round($setting['one_brokerage_ratio']/100,2);
// 二级分销
$two_brokerage_ratio = round($setting['two_brokerage_ratio']/100,2);
foreach ($order['goodsList'] as $goods) {
/* @var GoodsModel $goods */
$item = [
'oilCardNo' => 'OIL' . self::createOrderNo(),
'user_id' => $this->user['user_id'],
'spread_uid' => $spread_uid,
'spread_two_uid' => $spread_two_uid,
'one_brokerage_ratio' => $one_brokerage_ratio,
'one_brokerage' => ($goods['total_price'] > 0 && $one_brokerage_ratio > 0) ? round($goods['total_price'] * $one_brokerage_ratio, 2) : 0,
'two_brokerage_ratio' => $two_brokerage_ratio,
'two_brokerage' => ($goods['total_price'] > 0 && $two_brokerage_ratio > 0) ? round($goods['total_price'] * $two_brokerage_ratio,2) : 0,
'province' => $goods['province'],
'store_id' => $this->storeId,
'goods_id' => $goods['goods_id'],
'goods_name' => $goods['goods_name'],
'goods_no' => $goods['goods_no'] ?: '',
'image_id' => $this->getGoodsImageId($goods),
'deduct_stock_type' => $goods['deduct_stock_type'],
'spec_type' => $goods['spec_type'],
'goods_sku_id' => $goods['skuInfo']['goods_sku_id'],
'goods_props' => $goods['skuInfo']['goods_props'] ?: '',
'content' => $goods['content'] ?? '',
'goods_sku_no' => $goods['skuInfo']['goods_sku_no'] ?: '',
'goods_price' => $goods['skuInfo']['goods_price'],
'line_price' => $goods['skuInfo']['line_price'],
'goods_weight' => $goods['skuInfo']['goods_weight'],
'is_user_grade' => (int)$goods['is_user_grade'],
'grade_ratio' => $goods['grade_ratio'],
'grade_goods_price' => $goods['grade_goods_price'],
'grade_total_money' => $goods['grade_total_money'],
'coupon_money' => $goods['coupon_money'],
'points_money' => $isExistPointsDeduction ? $goods['points_money'] : 0.00,
'points_num' => $isExistPointsDeduction ? $goods['points_num'] : 0,
'points_bonus' => $goods['points_bonus'],
'total_num' => $goods['total_num'],
'total_price' => $goods['total_price'],
'total_pay_price' => $goods['total_pay_price'],
'oilCardType' => $goods['oilCardType'],
'expiration_time' => strtotime("+15 days")
];
// 记录订单商品来源id
$item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0;
$goodsList[] = $item;
}
$this->model->goods()->saveAll($goodsList) !== false;
return true;
}
/**
* 获取订单商品的封面图(优先sku封面图)
* @param $goods
* @return int
*/
private function getGoodsImageId($goods): int
{
return $goods['skuInfo']['image_id'] ?: (int)current($goods['goods_images'])['file_id'];
}
/**
* 更新商品库存 (针对下单减库存的商品)
* @param $order
* @return void
*/
private function updateGoodsStockNum($order): void
{
StockFactory::getFactory($this->model['order_source'])->updateGoodsStock($order['goodsList']);
}
/**
* 记录收货地址
* @param $address
* @return void
*/
private function saveOrderAddress($address): void
{
$this->model->address()->save([
'user_id' => $this->user['user_id'],
'store_id' => $this->storeId,
'name' => $address['name'],
'phone' => $address['phone'],
'province_id' => $address['province_id'],
'city_id' => $address['city_id'],
'region_id' => $address['region_id'],
'detail' => $address['detail'],
]);
}
}
@@ -0,0 +1,366 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order;
use app\api\model\Goods as GoodsModel;
use app\common\library\helper;
use app\common\lock\RedisLock;
use app\common\model\Coupon;
use app\common\service\SybOil;
use app\common\service\IdingjuOil;
use app\store\model\Company as CompanyModel;
use app\store\model\Coupon as CouponModel;
use app\store\model\GoodsCoupon as GoodsCouponModel;
use app\common\model\UserCoupon as UserCouponModel;
use think\facade\Db;
use think\facade\Event;
use app\common\service\BaseService;
use app\api\model\User as UserModel;
use app\api\model\Order as OrderModel;
use app\api\model\user\BalanceLog as BalanceLogModel;
use app\common\service\goods\source\Factory as StockFactory;
use app\common\enum\OrderType as OrderTypeEnum;
use app\common\enum\order\PayStatus as PayStatusEnum;
use app\common\enum\order\PayType as OrderPayTypeEnum;
use app\common\enum\user\balanceLog\Scene as SceneEnum;
/**
* 订单支付成功服务类
* Class PaySuccess
* @package app\api\service\order
*/
class PaySuccess extends BaseService
{
// 订单模型
public $model;
// 当前用户信息
private $user;
/**
* 构造函数
* PaySuccess constructor.
* @param $orderNo
*/
public function __construct($orderNo)
{
parent::__construct();
// 实例化订单模型
$this->model = OrderModel::getPayDetail($orderNo);
// 获取用户信息
$this->user = UserModel::detail($this->model['user_id']);
}
/**
* 获取订单详情
* @return OrderModel|null
*/
public function getOrderInfo()
{
return $this->model;
}
/**
* 订单支付成功业务处理
* @param $payType
* @param array $payData
* @return bool
*/
public function onPaySuccess($payType, $payData = [])
{
if (empty($this->model)) {
$this->error = '未找到该订单信息';
return false;
}
// 更新付款状态
$status = $this->updatePayStatus($payType, $payData);
// 订单支付成功事件
if ($status == true) {
Event::trigger('OrderPaySuccess', ['order' => $this->model, 'orderType' => OrderTypeEnum::ORDER]);
}
return $status;
}
/**
* 更新付款状态
* @param $payType
* @param array $payData
* @return bool
*/
private function updatePayStatus($payType, $payData = [])
{
// 验证余额支付时用户余额是否满足
if ($payType == OrderPayTypeEnum::BALANCE) {
if ($this->user['balance'] < $this->model['pay_price']) {
$this->error = '用户余额不足,无法使用余额支付';
return false;
}
}
// 获取订单详情
$detail = OrderModel::getUserOrderDetail((int)$this->model['order_id']);
// 触发分油接口
$shareStatus = $this->shareOil($detail);
if (!$shareStatus) {
// 记录日志
log_record(['name' => '分油失败', [
'order_id' => $this->model['order_id'],
]]);
// return false;
}
// 事务处理
$this->model->transaction(function () use ($payType, $payData, $detail) {
// 更新订单状态
$this->updateOrderInfo($payType, $payData);
// 累积用户总消费金额
UserModel::setIncPayMoney($detail['user_id'], (float)$this->model['pay_price']);
// 记录订单支付信息
$this->updatePayInfo($payType);
});
return true;
}
public function processUserOrders($companyId) {
$redisLock = new RedisLock('user_order_lock');
$maxAttempts = 10; // 最大尝试次数
$attempt = 0;
$sleepTime = 500000; // 每次尝试失败后的等待时间(微秒),500000微秒 = 0.5秒
while ($attempt < $maxAttempts) {
$lockAcquired = $redisLock->acquireLock();
if ($lockAcquired) {
break;
}
$attempt++;
usleep($sleepTime); // 等待一段时间再尝试
}
if (!$lockAcquired) {
throwError('网络繁忙请稍后');
}
$todayStart = strtotime(date('Y-m-d 00:00:00'));
// 查找一个未被调用的用户
$account = Db::name('account')
->alias('a')
->join('company c', 'a.company_id = c.company_id')
->where('a.last_called_at', '<', $todayStart)
->where('a.is_delete', '=', 0)
->where('a.state', '=', 0)
->where('a.company_id', '=', $companyId)
->where('c.status', '=', 10)
->field('a.*')
->limit(1)
->find();
if (!$account) {
throwError("没有可用的用户");
}
// 更新用户的 `last_called_at`
Db::name('account')
->where('account_id', $account['account_id'])
->update(['last_called_at' => time(), 'state' => 1]);
$redisLock->releaseLock();
return $account;
}
/**
* 分油
* @param $order
* @return bool
*/
// private function shareOil($order): bool
// {
// $SybOil = new SybOil();
// foreach ($order->goods as $goods) {
// /* @var GoodsModel $goods */
// if($goods['oilCardType']) {
// $data['amount'] = $goods['total_price']; // 金额
// try {
// // 查找一个未被调用的用户
// $account = $this->processUserOrders();
// } catch (\Throwable $e) {
// $this->error = $e->getMessage();
// return false;
// }
// $company = CompanyModel::detail($account['company_id']);
// // 查询公司余额
// if ($data['amount'] > $company['balance']) {
// $this->error = '公司余额不足';
// return false;
// }
// // 对接平台接口
// $res = $SybOil->oilOilCardShare(['goodsNo'=>$goods['goods_no'],'amount'=>$data['amount'],'userNo'=>$account['userNo'],'mobile'=>$account['mobile'],'saleOrderNo'=>$this->model['order_no'],'oilCardType'=>$goods['oilCardType']], $company);
// //$res = json_decode('{"code":"00","message":"请求成功","errCode":null,"errMessage":null,"data":{"oilCardNo":null,"amount":100,"balance":null,"shareNo":"CDV2408021928160001"}}', true);
// if ($res['code'] !== '00') {
// $this->error = ($res['errMessage'] ?? $res['message']);
// return false;
// }
// $item['account_id'] = $account['account_id'];
// $item['userNo'] = $account['userNo'];
// $item['mobile'] = $account['mobile'];
// $item['company_id'] = $company['company_id'];
// $item['oilCardNo'] = $goods['oilCardType'] == 'zsy_ticket' ? $res['data']['shareNo'] : $res['data']['oilCardNo'];
// $item['shareNo'] = $res['data']['shareNo'] ?? '';
// $item['oil_time'] = time();
// $item['oil_status'] = 1;
// $goods->save($item);
// }
// }
// return true;
// }
/**
* @param $goodsNo
* @return string
*/
public function getCompany($goodsNo): string
{
switch ($goodsNo) {
case 'djgdface100':
case 'djgdface200':
case 'djgdface300':
return 'umQZhIHKofyA';
case 'jmgxyyface100':
case 'jmgxyyface200':
case 'jmgxyyface300':
case 'jmgzface100':
case 'jmgzface200':
case 'jmgzface300':
case 'jmfjface100':
case 'jmfjface200':
case 'jmfjface300':
return 'HpWqXIgYvTBg';
case 'face003':
return 'NKJBgaaRNdiL'; // 测试参数
default:
return '';
}
}
private function shareOil($order): bool
{
$IdingjuOil = new IdingjuOil();
foreach ($order->goods as $goods) {
/* @var GoodsModel $goods */
if($goods['oilCardType'] == 'zsy_ticket') {
$data['amount'] = $goods['total_price']; // 金额
$company = CompanyModel::detail(['orgNo' => $this->getCompany($goods['goods_no'])]);
if (!$company) {
$this->error = '没有可用参数';
return false;
}
try {
// 查找一个未被调用的用户
$account = $this->processUserOrders($company['company_id']);
} catch (\Throwable $e) {
$this->error = $e->getMessage();
return false;
}
// 查询公司余额
/*if ($data['amount'] > $company['balance']) {
$this->error = '公司余额不足';
return false;
}*/
// 对接平台接口
$res = $IdingjuOil->oilOilCardShare([
'goodsNo'=>$goods['goods_no'],
'amount'=>$data['amount'],
'userNo'=>$account['userNo'],
'mobile'=>$account['mobile'],
'saleOrderNo'=>$goods['oilCardNo'],
'oilCardType'=>$goods['oilCardType']
], $company);
//$res = json_decode('{"code":"00","message":"请求成功","errCode":null,"errMessage":null,"data":{"oilCardNo":null,"amount":100,"balance":null,"shareNo":"CDV2408021928160001"}}', true);
if ($res['code'] != 1) {
$this->error = ($res['errMessage'] ?? $res['message']);
return false;
}
$item['account_id'] = $account['account_id'];
$item['userNo'] = $account['userNo'];
$item['mobile'] = $account['mobile'];
$item['company_id'] = $company['company_id'];
$item['shareNo'] = $res['data']['trade_no'] ?? '';
$item['qrCode'] = $res['data']['useUrl'] ?? '';
$item['oil_status_zsy'] = $res['data']['state'] ?? 0;
$item['oil_time'] = time();
$item['oil_status'] = $item['oil_status_zsy'] == 2 ? 1 : 0; // 已发券 为1
$goods->save($item);
} elseif($goods['oilCardType'] == 'coupon'){
// 发放优惠券
$coupons = GoodsCouponModel::getCouponList($goods['goods_id'])->toArray();
if($coupons && is_array($coupons)) {
foreach ($coupons as $item) {
$coupon = CouponModel::detail($item['coupon_id']);
for ($i=0;$i<$item['send_num'];$i++){
$userCouponModel = new UserCouponModel();
$userCouponModel->add($goods['user_id'], $coupon);
}
}
}
}
}
return true;
}
/**
* 更新订单记录
* @param int $payType
* @param array $payData
* @return false|int
* @throws \Exception
*/
private function updateOrderInfo(int $payType, array $payData)
{
// 更新商品库存、销量
StockFactory::getFactory($this->model['order_source'])->updateStockSales($this->model['goods']);
// 整理订单信息
$order = [
'pay_type' => $payType,
'pay_status' => PayStatusEnum::SUCCESS,
'pay_time' => time()
];
if ($payType == OrderPayTypeEnum::WECHAT) {
$order['transaction_id'] = $payData['transaction_id'];
}
// 更新订单状态
return $this->model->save($order);
}
/**
* 记录订单支付信息
* @param int $payType
*/
private function updatePayInfo(int $payType)
{
// 余额支付
if ($payType == OrderPayTypeEnum::BALANCE) {
// 更新用户余额
UserModel::setDecBalance((int)$this->user['user_id'], (float)$this->model['pay_price']);
// 新增余额变动记录
BalanceLogModel::add(SceneEnum::CONSUME, [
'user_id' => (int)$this->user['user_id'],
'money' => -$this->model['pay_price'],
], ['order_no' => $this->model['order_no']]);
}
// 微信支付
if ($payType == OrderPayTypeEnum::WECHAT) {
}
}
}
@@ -0,0 +1,54 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source;
use app\common\service\BaseService;
use app\common\enum\order\OrderStatus as OrderStatusEnum;
use app\common\enum\order\PayStatus as OrderPayStatusEnum;
abstract class Basics extends BaseService
{
/**
* 判断订单是否允许付款
* @param $order
* @return mixed
*/
abstract public function checkOrderStatusOnPay($order);
/**
* 判断商品状态、库存 (未付款订单)
* @param $goodsList
* @return mixed
*/
abstract protected function checkGoodsStatusOnPay($goodsList);
/**
* 判断订单状态(公共)
* @param $order
* @return bool
*/
protected function checkOrderStatusOnPayCommon($order)
{
// 判断订单状态
if (
$order['order_status'] != OrderStatusEnum::NORMAL
|| $order['pay_status'] != OrderPayStatusEnum::PENDING
) {
$this->error = '很抱歉,当前订单不合法,无法支付';
return false;
}
return true;
}
}
@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source;
use app\common\service\BaseService;
use app\common\enum\order\OrderSource as OrderSourceEnum;
/**
* 商品库存工厂类
* Class Factory
* @package app\common\service\stock
*/
class Factory extends BaseService
{
// 订单来源的结算台服务类
private static $class = [
OrderSourceEnum::MAIN => 'Main',
];
/**
* 根据订单来源获取商品库存类
* @param int $orderSource
* @return mixed
*/
public static function getFactory($orderSource = OrderSourceEnum::MAIN)
{
static $classObj = [];
if (!isset($classObj[$orderSource])) {
$className = __NAMESPACE__ . '\\' . static::$class[$orderSource];
$classObj[$orderSource] = new $className();
}
return $classObj[$orderSource];
}
}
@@ -0,0 +1,85 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source;
use app\api\model\GoodsSku as GoodsSkuModel;
/**
* 订单来源-普通订单扩展类
* Class Main
* @package app\api\service\order\source
*/
class Main extends Basics
{
/**
* 判断订单是否允许付款
* @param $order
* @return bool
*/
public function checkOrderStatusOnPay($order)
{
// 判断订单状态
if (!$this->checkOrderStatusOnPayCommon($order)) {
return false;
}
// 判断商品状态、库存
if (!$this->checkGoodsStatusOnPay($order['goods'])) {
return false;
}
return true;
}
/**
* 判断商品状态、库存 (未付款订单)
* @param $goodsList
* @return bool
*/
protected function checkGoodsStatusOnPay($goodsList)
{
foreach ($goodsList as $goods) {
// 判断商品是否下架
if (
empty($goods['goods'])
|| $goods['goods']['status'] != 10
) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] 已下架";
return false;
}
// 获取商品的sku信息
$goodsSku = $this->getOrderGoodsSku($goods['goods_id'], $goods['goods_sku_id']);
// sku已不存在
if (empty($goodsSku)) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] sku已不存在,请重新下单";
return false;
}
// 付款减库存
if ($goods['deduct_stock_type'] == 20 && $goods['total_num'] > $goodsSku['stock_num']) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] 库存不足";
return false;
}
}
return true;
}
/**
* 获取指定的商品sku信息
* @param $goodsId
* @param $goodsSkuId
* @return GoodsSkuModel|array|null
*/
private function getOrderGoodsSku($goodsId, $goodsSkuId)
{
return GoodsSkuModel::detail($goodsId, $goodsSkuId);
}
}
@@ -0,0 +1,55 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source\checkout;
use app\common\service\BaseService;
use app\api\model\User as UserModel;
/**
* 订单结算台扩展基类
* Class Basics
* @package app\api\service\order\source\checkout
*/
abstract class Basics extends BaseService
{
/* @var UserModel $user 当前用户信息 */
protected $user;
// 订单结算商品列表
protected $goodsList = [];
// 订单结算主数据
protected $orderData = [];
/**
* 构造方法
* Checkout constructor.
* @param UserModel $user
* @param array $goodsList
* @param array $orderData
*/
public function __construct($user, $goodsList, $orderData)
{
parent::__construct();
$this->user = $user;
$this->goodsList = $goodsList;
$this->orderData = $orderData;
}
/**
* 验证商品列表
* @return mixed
*/
abstract public function validateGoodsList();
}
@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source\checkout;
use app\common\service\BaseService;
use app\common\enum\order\OrderSource as OrderSourceEnum;
/**
* 订单结算台扩展工厂类
* Class Factory
* @package app\common\service\stock
*/
class Factory extends BaseService
{
// 订单来源的结算台服务类
private static $class = [
OrderSourceEnum::MAIN => Main::class,
];
/**
* 根据订单来源获取商品库存类
* @param $user
* @param $goodsList
* @param int $orderSource
* @param array $orderData
* @return mixed
*/
public static function getFactory($user, $goodsList, $orderSource = OrderSourceEnum::MAIN, $orderData = [])
{
return new static::$class[$orderSource]($user, $goodsList, $orderData);
}
}
@@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\api\service\order\source\checkout;
use app\common\enum\order\PayType as OrderPayTypeEnum;
/**
* 订单结算台-普通商品扩展类
* Class Main
* @package app\api\service\order\source\checkout
*/
class Main extends Basics
{
/**
* 验证商品列表
* @return bool
*/
public function validateGoodsList()
{
$order = $this->orderData;
foreach ($this->goodsList as $goods) {
// 判断商品是否下架
if ($goods['status'] != 10) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] 已下架";
return false;
}
// 判断商品库存
if ($goods['total_num'] > $goods['skuInfo']['stock_num']) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] 库存不足";
return false;
}
// 判断购买优惠券不能使用 余额支付
if (isset($order['payType']) && $order['payType'] == OrderPayTypeEnum::BALANCE && $goods['oilCardType'] == 'coupon'){
$this->error = "本商品不可使用余额支付";
return false;
}
}
return true;
}
}