This repository has been archived on 2024-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
yoshop/source/application/api/model/sharing/Order.php
2020-04-25 22:20:29 +08:00

478 lines
15 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
namespace app\api\model\sharing;
use app\api\model\User as UserModel;
use app\api\model\Setting as SettingModel;
use app\api\model\UserCoupon as UserCouponModel;
use app\api\model\sharing\Goods as GoodsModel;
use app\api\model\sharing\GoodsSku as GoodsSkuModel;
use app\common\model\sharing\Order as OrderModel;
use app\api\model\sharing\OrderGoods as OrderGoodsModel;
use app\api\service\User as UserService;
use app\api\service\sharing\order\PaySuccess;
use app\api\service\Payment as PaymentService;
use app\common\enum\OrderType as OrderTypeEnum;
use app\common\enum\order\Status as OrderStatusEnum;
use app\common\enum\DeliveryType as DeliveryTypeEnum;
use app\common\enum\order\PayType as PayTypeEnum;
use app\common\enum\order\PayStatus as PayStatusEnum;
use app\common\service\order\Complete as OrderCompleteService;
use app\common\library\helper;
use app\common\exception\BaseException;
/**
* 拼团订单模型
* Class Order
* @package app\api\model
*/
class Order extends OrderModel
{
/**
* 隐藏字段
* @var array
*/
protected $hidden = [
'wxapp_id',
'update_time'
];
/**
* 订单结算api参数
* @var array
*/
private $checkoutParam = [
'active_id' => 0, // 参与的拼单id
'delivery' => null, // 配送方式
'shop_id' => 0, // 自提门店id
'linkman' => '', // 自提联系人
'phone' => '', // 自提联系电话
'coupon_id' => 0, // 优惠券id
'remark' => '', // 买家留言
'pay_type' => PayTypeEnum::WECHAT, // 支付方式
];
/**
* 待支付订单详情
* @param $orderNo
* @return null|static
* @throws \think\exception\DbException
*/
public static function getPayDetail($orderNo)
{
return self::get(['order_no' => $orderNo, 'pay_status' => 10, 'is_delete' => 0], ['goods', 'user']);
}
/**
* 获取订单商品列表
* @param $params
* @return array
*/
public function getOrderGoodsListByNow($params)
{
// 商品详情
/* @var GoodsModel $goods */
$goods = GoodsModel::detail($params['goods_id']);
// 商品sku信息
$goods['goods_sku'] = GoodsModel::getGoodsSku($goods, $params['goods_sku_id']);
// 商品列表
$goodsList = [$goods->hidden(['category', 'content', 'image', 'sku'])];
foreach ($goodsList as &$item) {
// 商品单价(根据order_type判断单买还是拼单)
// order_type下单类型 10 => 单独购买20 => 拼团
$item['goods_price'] = $params['order_type'] == 10 ? $item['goods_sku']['goods_price']
: $item['goods_sku']['sharing_price'];
// 商品购买数量
$item['total_num'] = $params['goods_num'];
$item['spec_sku_id'] = $item['goods_sku']['spec_sku_id'];
// 商品购买总金额
$item['total_price'] = helper::bcmul($item['goods_price'], $params['goods_num']);
}
return $goodsList;
}
/**
* 订单支付事件
* @param int $payType
* @return bool
* @throws \think\exception\DbException
*/
public function onPay($payType = PayTypeEnum::WECHAT)
{
// 判断商品状态、库存
if (!$this->checkGoodsStatusFromOrder($this['goods'])) {
return false;
}
// 余额支付
if ($payType == PayTypeEnum::BALANCE) {
return $this->onPaymentByBalance($this['order_no']);
}
return true;
}
/**
* 构建支付请求的参数
* @param $user
* @param $order
* @param $payType
* @return array
* @throws BaseException
* @throws \think\exception\DbException
*/
public function onOrderPayment($user, $order, $payType)
{
if ($payType == PayTypeEnum::WECHAT) {
return $this->onPaymentByWechat($user, $order);
}
return [];
}
/**
* 构建微信支付请求
* @param $user
* @param $order
* @return array
* @throws BaseException
* @throws \think\exception\DbException
*/
private function onPaymentByWechat($user, $order)
{
return PaymentService::wechat(
$user,
$order['order_id'],
$order['order_no'],
$order['pay_price'],
OrderTypeEnum::SHARING
);
}
/**
* 余额支付标记订单已支付
* @param $orderNo
* @return bool
* @throws \think\exception\DbException
*/
public function onPaymentByBalance($orderNo)
{
// 获取订单详情
$PaySuccess = new PaySuccess($orderNo);
// 发起余额支付
$status = $PaySuccess->onPaySuccess(PayTypeEnum::BALANCE);
if (!$status) {
$this->error = $PaySuccess->getError();
}
return $status;
}
/**
* 验证拼单是否允许加入
* @param $active_id
* @return bool
* @throws BaseException
* @throws \think\exception\DbException
*/
public function checkActiveIsAllowJoin($active_id)
{
// 拼单详情
$detail = Active::detail($active_id);
if (!$detail) {
throw new BaseException('很抱歉,拼单不存在');
}
// 验证当前拼单是否允许加入新成员
return $detail->checkAllowJoin();
}
/**
* 保存上门自提联系人
* @param $linkman
* @param $phone
* @return false|\think\Model
*/
public function saveOrderExtract($linkman, $phone)
{
// 记忆上门自提联系人(缓存),用于下次自动填写
UserService::setLastExtract($this['user_id'], trim($linkman), trim($phone));
// 保存上门自提联系人(数据库)
return $this->extract()->save([
'linkman' => trim($linkman),
'phone' => trim($phone),
'user_id' => $this['user_id'],
'wxapp_id' => self::$wxapp_id,
]);
}
/**
* 用户拼团订单列表
* @param $user_id
* @param string $type
* @return \think\Paginator
* @throws \think\exception\DbException
*/
public function getList($user_id, $type = 'all')
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
// 全部
break;
case 'payment';
// 待支付
$filter['pay_status'] = PayStatusEnum::PENDING;
break;
case 'sharing';
// 拼团中
$filter['active.status'] = 10;
break;
case 'delivery';
// 待发货
$this->where('IF ( (`order`.`order_type` = 20), (`active`.`status` = 20), TRUE)');
$filter['pay_status'] = 20;
$filter['delivery_status'] = 10;
break;
case 'received';
// 待收货
$filter['pay_status'] = 20;
$filter['delivery_status'] = 20;
$filter['receipt_status'] = 10;
break;
case 'comment';
$filter['order_status'] = 30;
$filter['is_comment'] = 0;
break;
}
return $this->with(['goods.image', 'active'])
->alias('order')
->field('order.*, active.status as active_status')
->join('sharing_active active', 'order.active_id = active.active_id', 'LEFT')
->where('user_id', '=', $user_id)
->where($filter)
->where('order.is_delete', '=', 0)
->order(['create_time' => 'desc'])
->paginate(15, false, [
'query' => \request()->request()
]);
}
/**
* 取消订单
* @param UserModel $user
* @return bool|false|int
*/
public function cancel($user)
{
// 订单是否已支付
$isPay = $this['pay_status']['value'] == PayStatusEnum::SUCCESS;
// 已发货订单不可取消
if ($this['delivery_status']['value'] == 20) {
$this->error = '已发货订单不可取消';
return false;
}
// 已付款的拼团订单不允许取消
if ($isPay && $this['order_type']['value'] == 20) {
$this->error = '已付款的拼团订单不允许取消';
return false;
}
// 订单取消事件
$this->transaction(function () use ($user, $isPay) {
// 未付款的订单
if ($isPay == false) {
// 回退商品库存
(new OrderGoodsModel)->backGoodsStock($this['goods'], $isPay);
// 回退用户优惠券
$this['coupon_id'] > 0 && UserCouponModel::setIsUse($this['coupon_id'], false);
// 回退用户积分
$describe = "订单取消:{$this['order_no']}";
$this['points_num'] > 0 && $user->setIncPoints($this['points_num'], $describe);
}
// 更新订单状态
return $this->save(['order_status' => $isPay ? OrderStatusEnum::APPLY_CANCEL : OrderStatusEnum::CANCELLED]);
});
return true;
}
/**
* 确认收货
* @return bool|mixed
*/
public function receipt()
{
// 验证订单是否合法
// 条件1: 订单必须已发货
// 条件2: 订单必须未收货
if ($this['delivery_status']['value'] != 20 || $this['receipt_status']['value'] != 10) {
$this->error = '该订单不合法';
return false;
}
return $this->transaction(function () {
// 更新订单状态
$status = $this->save([
'receipt_status' => 20,
'receipt_time' => time(),
'order_status' => 30
]);
// 执行订单完成后的操作
$OrderCompleteService = new OrderCompleteService(OrderTypeEnum::SHARING);
$OrderCompleteService->complete([$this], static::$wxapp_id);
return $status;
});
}
/**
* 获取订单总数
* @param $user_id
* @param string $type
* @return int|string
* @throws \think\Exception
*/
public function getCount($user_id, $type = 'all')
{
// 筛选条件
$filter = [];
// 订单数据类型
switch ($type) {
case 'all':
break;
case 'payment';
$filter['pay_status'] = PayStatusEnum::PENDING;
break;
case 'received';
$filter['pay_status'] = PayStatusEnum::SUCCESS;
$filter['delivery_status'] = 20;
$filter['receipt_status'] = 10;
break;
case 'comment';
$filter['order_status'] = 30;
$filter['is_comment'] = 0;
break;
}
return $this->where('user_id', '=', $user_id)
->where('order_status', '<>', 20)
->where($filter)
->where('is_delete', '=', 0)
->count();
}
/**
* 订单详情
* @param $order_id
* @param $user_id
* @return array|false|\PDOStatement|string|\think\Model|static
* @throws BaseException
*/
public static function getUserOrderDetail($order_id, $user_id)
{
$order = (new static)->with(['goods' => ['image', 'refund'], 'address', 'express', 'extract_shop'])
->alias('order')
->field('order.*, active.status as active_status')
->join('sharing_active active', 'order.active_id = active.active_id', 'LEFT')
->where([
'order_id' => $order_id,
'user_id' => $user_id,
])->find();
if (!$order) {
throw new BaseException(['msg' => '订单不存在']);
}
return $order;
}
/**
* 判断商品库存不足 (未付款订单)
* @param $goodsList
* @return bool
* @throws \think\exception\DbException
*/
private function checkGoodsStatusFromOrder($goodsList)
{
foreach ($goodsList as $goods) {
// 判断商品是否下架
if (
empty($goods['goods'])
|| $goods['goods']['goods_status']['value'] != 10
) {
$this->error = "很抱歉,商品 [{$goods['goods_name']}] 已下架";
return false;
}
// 获取商品的sku信息
$goodsSku = GoodsSkuModel::detail($goods['goods_id'], $goods['spec_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;
}
/**
* 当前订单是否允许申请售后
* @return bool
*/
public function isAllowRefund()
{
// 必须是已发货的订单
if ($this['delivery_status']['value'] != 20) {
return false;
}
// 允许申请售后期限(天)
$refundDays = SettingModel::getItem('trade')['order']['refund_days'];
// 不允许售后
if ($refundDays == 0) {
return false;
}
// 当前时间超出允许申请售后期限
if (
$this['receipt_status'] == 20
&& time() > ($this['receipt_time'] + ((int)$refundDays * 86400))
) {
return false;
}
return true;
}
/**
* 判断当前订单是否允许核销
* @param static $order
* @return bool
*/
public function checkExtractOrder(&$order)
{
if (
$order['pay_status']['value'] == PayStatusEnum::SUCCESS
&& $order['delivery_type']['value'] == DeliveryTypeEnum::EXTRACT
&& $order['delivery_status']['value'] == 10
// 拼团订单验证拼单状态
&& ($order['order_type']['value'] == 20 ? $order['active']['status']['value'] == 20 : true)
) {
return true;
}
$this->setError('该订单不能被核销');
return false;
}
/**
* 设置错误信息
* @param $error
*/
private function setError($error)
{
empty($this->error) && $this->error = $error;
}
/**
* 是否存在错误
* @return bool
*/
public function hasError()
{
return !empty($this->error);
}
}