527 lines
15 KiB
PHP
527 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* The file was created by Assimon.
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
|
|
namespace App\Service;
|
|
|
|
use App\Exceptions\RuleValidationException;
|
|
use App\Jobs\ApiHook;
|
|
use App\Jobs\MailSend;
|
|
use App\Jobs\OrderExpired;
|
|
use App\Jobs\ServerJiang;
|
|
use App\Jobs\TelegramPush;
|
|
use App\Jobs\BarkPush;
|
|
use App\Jobs\WorkWeiXinPush;
|
|
use App\Models\BaseModel;
|
|
use App\Models\Coupon;
|
|
use App\Models\Goods;
|
|
use App\Models\Order;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* 订单处理层
|
|
*
|
|
* Class OrderProcessService
|
|
* @package App\Service
|
|
* @author: Assimon
|
|
* @email: Ashang@utf8.hk
|
|
* @blog: https://utf8.hk
|
|
* Date: 2021/5/30
|
|
*/
|
|
class OrderProcessService
|
|
{
|
|
|
|
const PENDING_CACHE_KEY = 'PENDING_ORDERS_LIST';
|
|
|
|
/**
|
|
* 优惠码服务层
|
|
* @var \App\Service\CouponService
|
|
*/
|
|
private $couponService;
|
|
|
|
/**
|
|
* 订单服务层
|
|
* @var \App\Service\OrderService
|
|
*/
|
|
private $orderService;
|
|
|
|
/**
|
|
* 卡密服务层
|
|
* @var \App\Service\CarmisService
|
|
*/
|
|
private $carmisService;
|
|
|
|
/**
|
|
* 邮件服务层
|
|
* @var \App\Service\EmailtplService
|
|
*/
|
|
private $emailtplService;
|
|
|
|
/**
|
|
* 商品服务层.
|
|
* @var \App\Service\GoodsService
|
|
*/
|
|
private $goodsService;
|
|
|
|
/**
|
|
* 商品
|
|
* @var Goods
|
|
*/
|
|
private $goods;
|
|
|
|
/**
|
|
* 优惠码
|
|
* @var Coupon;
|
|
*/
|
|
private $coupon;
|
|
|
|
/**
|
|
* 其他输入框
|
|
* @var string
|
|
*/
|
|
private $otherIpt;
|
|
|
|
/**
|
|
* 购买数量
|
|
* @var int
|
|
*/
|
|
private $buyAmount;
|
|
|
|
/**
|
|
* 购买邮箱
|
|
* @var string
|
|
*/
|
|
private $email;
|
|
|
|
/**
|
|
* 查询密码
|
|
* @var string
|
|
*/
|
|
private $searchPwd;
|
|
|
|
/**
|
|
* 下单id
|
|
* @var string
|
|
*/
|
|
private $buyIP;
|
|
|
|
/**
|
|
* 支付方式
|
|
* @var int
|
|
*/
|
|
private $payID;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->couponService = app('Service\CouponService');
|
|
$this->orderService = app('Service\OrderService');
|
|
$this->carmisService = app('Service\CarmisService');
|
|
$this->emailtplService = app('Service\EmailtplService');
|
|
$this->goodsService = app('Service\GoodsService');
|
|
|
|
}
|
|
|
|
/**
|
|
* 设置支付方式
|
|
* @param int $payID
|
|
*/
|
|
public function setPayID(int $payID): void
|
|
{
|
|
$this->payID = $payID;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 下单ip
|
|
* @param mixed $buyIP
|
|
*/
|
|
public function setBuyIP($buyIP): void
|
|
{
|
|
$this->buyIP = $buyIP;
|
|
}
|
|
|
|
/**
|
|
* 设置查询密码
|
|
* @param mixed $searchPwd
|
|
*/
|
|
public function setSearchPwd($searchPwd): void
|
|
{
|
|
$this->searchPwd = $searchPwd;
|
|
}
|
|
|
|
/**
|
|
* 设置购买数量
|
|
* @param mixed $buyAmount
|
|
*/
|
|
public function setBuyAmount($buyAmount): void
|
|
{
|
|
$this->buyAmount = $buyAmount;
|
|
}
|
|
|
|
/**
|
|
* 设置下单邮箱
|
|
* @param mixed $email
|
|
*/
|
|
public function setEmail($email): void
|
|
{
|
|
$this->email = $email;
|
|
}
|
|
|
|
/**
|
|
* 设置商品
|
|
*
|
|
* @param Goods $goods
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function setGoods(Goods $goods)
|
|
{
|
|
$this->goods = $goods;
|
|
}
|
|
|
|
/**
|
|
* 设置优惠码.
|
|
*
|
|
* @param ?Coupon $coupon
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function setCoupon(?Coupon $coupon)
|
|
{
|
|
$this->coupon = $coupon;
|
|
}
|
|
|
|
/**
|
|
* 其他输入框设置.
|
|
*
|
|
* @param ?string $otherIpt
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function setOtherIpt(?string $otherIpt)
|
|
{
|
|
$this->otherIpt = $otherIpt;
|
|
}
|
|
|
|
/**
|
|
* 计算优惠码价格
|
|
*
|
|
* @return float
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
private function calculateTheCouponPrice(): float
|
|
{
|
|
$couponPrice = 0;
|
|
// 优惠码优惠价格
|
|
if ($this->coupon) {
|
|
$couponPrice = $this->coupon->discount;
|
|
}
|
|
return $couponPrice;
|
|
}
|
|
|
|
/**
|
|
* 计算批发优惠
|
|
* @return float
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
private function calculateTheWholesalePrice(): float
|
|
{
|
|
$wholesalePrice = 0; // 优惠单价
|
|
$wholesaleTotalPrice = 0; // 优惠总价
|
|
if ($this->goods->wholesale_price_cnf) {
|
|
$formatWholesalePrice = format_wholesale_price($this->goods->wholesale_price_cnf);
|
|
foreach ($formatWholesalePrice as $item) {
|
|
if ($this->buyAmount >= $item['number']) {
|
|
$wholesalePrice = $item['price'];
|
|
}
|
|
}
|
|
}
|
|
if ($wholesalePrice > 0 ) {
|
|
$totalPrice = $this->calculateTheTotalPrice(); // 实际原总价
|
|
$newTotalPrice = bcmul($wholesalePrice, $this->buyAmount, 2); // 批发价优惠后的总价
|
|
$wholesaleTotalPrice = bcsub($totalPrice, $newTotalPrice, 2); // 批发总优惠
|
|
}
|
|
return $wholesaleTotalPrice;
|
|
}
|
|
|
|
/**
|
|
* 订单总价
|
|
* @return float
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
private function calculateTheTotalPrice(): float
|
|
{
|
|
$price = $this->goods->actual_price;
|
|
return bcmul($price, $this->buyAmount, 2);
|
|
}
|
|
|
|
/**
|
|
* 计算实际需要支付的价格
|
|
*
|
|
* @param float $totalPrice 总价
|
|
* @param float $couponPrice 优惠码优惠价
|
|
* @param float $wholesalePrice 批发优惠
|
|
* @return float
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
private function calculateTheActualPrice(float $totalPrice, float $couponPrice, float $wholesalePrice): float
|
|
{
|
|
$actualPrice = bcsub($totalPrice, $couponPrice, 2);
|
|
$actualPrice = bcsub($actualPrice, $wholesalePrice, 2);
|
|
if ($actualPrice <= 0) {
|
|
$actualPrice = 0;
|
|
}
|
|
return $actualPrice;
|
|
}
|
|
|
|
/**
|
|
* 创建订单.
|
|
* @return Order
|
|
* @throws RuleValidationException
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function createOrder(): Order
|
|
{
|
|
try {
|
|
$order = new Order();
|
|
// 生成订单号
|
|
$order->order_sn = strtoupper(Str::random(16));
|
|
// 设置商品
|
|
$order->goods_id = $this->goods->id;
|
|
// 标题
|
|
$order->title = $this->goods->gd_name . ' x ' . $this->buyAmount;
|
|
// 订单类型
|
|
$order->type = $this->goods->type;
|
|
// 查询密码
|
|
$order->search_pwd = $this->searchPwd;
|
|
// 邮箱
|
|
$order->email = $this->email;
|
|
// 支付方式.
|
|
$order->pay_id = $this->payID;
|
|
// 商品单价
|
|
$order->goods_price = $this->goods->actual_price;
|
|
// 购买数量
|
|
$order->buy_amount = $this->buyAmount;
|
|
// 订单详情
|
|
$order->info = $this->otherIpt;
|
|
// ip地址
|
|
$order->buy_ip = $this->buyIP;
|
|
// 优惠码优惠价格
|
|
$order->coupon_discount_price = $this->calculateTheCouponPrice();
|
|
if ($this->coupon) {
|
|
$order->coupon_id = $this->coupon->id;
|
|
}
|
|
// 批发价
|
|
$order->wholesale_discount_price = $this->calculateTheWholesalePrice();
|
|
// 订单总价
|
|
$order->total_price = $this->calculateTheTotalPrice();
|
|
// 订单实际需要支付价格
|
|
$order->actual_price = $this->calculateTheActualPrice(
|
|
$this->calculateTheTotalPrice(),
|
|
$this->calculateTheCouponPrice(),
|
|
$this->calculateTheWholesalePrice()
|
|
);
|
|
// 保存订单
|
|
$order->save();
|
|
// 如果有用到优惠券
|
|
if ($this->coupon) {
|
|
// 设置优惠码已经使用
|
|
$this->couponService->used($this->coupon->coupon);
|
|
// 使用次数-1
|
|
$this->couponService->retDecr($this->coupon->coupon);
|
|
}
|
|
// 将订单加入队列 x分钟后过期
|
|
$expiredOrderDate = dujiaoka_config_get('order_expire_time', 5);
|
|
OrderExpired::dispatch($order->order_sn)->delay(Carbon::now()->addMinutes($expiredOrderDate));
|
|
return $order;
|
|
} catch (\Exception $exception) {
|
|
throw new RuleValidationException($exception->getMessage());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* 订单成功方法
|
|
*
|
|
* @param string $orderSN 订单号
|
|
* @param float $actualPrice 实际支付金额
|
|
* @param string $tradeNo 第三方订单号
|
|
* @return Order
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function completedOrder(string $orderSN, float $actualPrice, string $tradeNo = '')
|
|
{
|
|
DB::beginTransaction();
|
|
try {
|
|
// 得到订单详情
|
|
$order = $this->orderService->detailOrderSN($orderSN);
|
|
if (!$order) {
|
|
throw new \Exception(__('dujiaoka.prompt.order_does_not_exist'));
|
|
}
|
|
// 订单已经处理
|
|
if ($order->status == Order::STATUS_COMPLETED) {
|
|
throw new \Exception(__('dujiaoka.prompt.order_status_completed'));
|
|
}
|
|
$bccomp = bccomp($order->actual_price, $actualPrice, 2);
|
|
// 金额不一致
|
|
if ($bccomp != 0) {
|
|
throw new \Exception(__('dujiaoka.prompt.order_inconsistent_amounts'));
|
|
}
|
|
$order->actual_price = $actualPrice;
|
|
$order->trade_no = $tradeNo;
|
|
// 区分订单类型
|
|
// 自动发货
|
|
if ($order->type == Order::AUTOMATIC_DELIVERY) {
|
|
$completedOrder = $this->processAuto($order);
|
|
} else {
|
|
$completedOrder = $this->processManual($order);
|
|
}
|
|
// 销量加上
|
|
$this->goodsService->salesVolumeIncr($order->goods_id, $order->buy_amount);
|
|
DB::commit();
|
|
// 如果开启了server酱
|
|
if (dujiaoka_config_get('is_open_server_jiang', 0) == BaseModel::STATUS_OPEN) {
|
|
ServerJiang::dispatch($order);
|
|
}
|
|
// 如果开启了TG推送
|
|
if (dujiaoka_config_get('is_open_telegram_push', 0) == BaseModel::STATUS_OPEN) {
|
|
TelegramPush::dispatch($order);
|
|
}
|
|
// 如果开启了Bark推送
|
|
if (dujiaoka_config_get('is_open_bark_push', 0) == BaseModel::STATUS_OPEN) {
|
|
BarkPush::dispatch($order);
|
|
}
|
|
// 如果开启了企业微信Bot推送
|
|
if (dujiaoka_config_get('is_open_qywxbot_push', 0) == BaseModel::STATUS_OPEN) {
|
|
WorkWeiXinPush::dispatch($order);
|
|
}
|
|
// 回调事件
|
|
ApiHook::dispatch($order);
|
|
return $completedOrder;
|
|
} catch (\Exception $exception) {
|
|
DB::rollBack();
|
|
throw new RuleValidationException($exception->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 手动处理的订单.
|
|
*
|
|
* @param Order $order 订单
|
|
* @return Order 订单
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function processManual(Order $order)
|
|
{
|
|
// 设置订单为待处理
|
|
$order->status = Order::STATUS_PENDING;
|
|
// 保存订单
|
|
$order->save();
|
|
// 商品库存减去
|
|
$this->goodsService->inStockDecr($order->goods_id, $order->buy_amount);
|
|
// 邮件数据
|
|
$mailData = [
|
|
'created_at' => $order->create_at,
|
|
'product_name' => $order->goods->gd_name,
|
|
'webname' => dujiaoka_config_get('text_logo', '云泽数卡'),
|
|
'weburl' => config('app.url') ?? 'http://dujiaoka.com',
|
|
'ord_info' => str_replace(PHP_EOL, '<br/>', $order->info),
|
|
'ord_title' => $order->title,
|
|
'order_id' => $order->order_sn,
|
|
'buy_amount' => $order->buy_amount,
|
|
'ord_price' => $order->actual_price,
|
|
'created_at' => $order->created_at,
|
|
];
|
|
$tpl = $this->emailtplService->detailByToken('manual_send_manage_mail');
|
|
$mailBody = replace_mail_tpl($tpl, $mailData);
|
|
$manageMail = dujiaoka_config_get('manage_email', '');
|
|
// 邮件发送
|
|
MailSend::dispatch($manageMail, $mailBody['tpl_name'], $mailBody['tpl_content']);
|
|
return $order;
|
|
}
|
|
|
|
/**
|
|
* 处理自动发货.
|
|
*
|
|
* @param Order $order 订单
|
|
* @return Order 订单
|
|
*
|
|
* @author assimon<ashang@utf8.hk>
|
|
* @copyright assimon<ashang@utf8.hk>
|
|
* @link http://utf8.hk/
|
|
*/
|
|
public function processAuto(Order $order): Order
|
|
{
|
|
// 获得卡密
|
|
$carmis = $this->carmisService->withGoodsByAmountAndStatusUnsold($order->goods_id, $order->buy_amount);
|
|
// 实际可使用的库存已经少于购买数量了
|
|
if (count($carmis) != $order->buy_amount) {
|
|
$order->info = __('dujiaoka.prompt.order_carmis_insufficient_quantity_available');
|
|
$order->status = Order::STATUS_ABNORMAL;
|
|
$order->save();
|
|
return $order;
|
|
}
|
|
$carmisInfo = array_column($carmis, 'carmi');
|
|
$ids = array_column($carmis, 'id');
|
|
$order->info = implode(PHP_EOL, $carmisInfo);
|
|
$order->status = Order::STATUS_COMPLETED;
|
|
$order->save();
|
|
// 将卡密设置为已售出
|
|
$this->carmisService->soldByIDS($ids);
|
|
// 邮件数据
|
|
$mailData = [
|
|
'created_at' => $order->create_at,
|
|
'product_name' => $order->goods->gd_name,
|
|
'webname' => dujiaoka_config_get('text_logo', '云泽数卡'),
|
|
'weburl' => config('app.url') ?? 'http://dujiaoka.com',
|
|
'ord_info' => implode('<br/>', $carmisInfo),
|
|
'ord_title' => $order->title,
|
|
'order_id' => $order->order_sn,
|
|
'buy_amount' => $order->buy_amount,
|
|
'ord_price' => $order->actual_price,
|
|
];
|
|
$tpl = $this->emailtplService->detailByToken('card_send_user_email');
|
|
$mailBody = replace_mail_tpl($tpl, $mailData);
|
|
// 邮件发送
|
|
MailSend::dispatch($order->email, $mailBody['tpl_name'], $mailBody['tpl_content']);
|
|
return $order;
|
|
}
|
|
|
|
}
|