<?php
namespace app\api\service;
use app\api\model\OrderProduct;
use app\api\model\Product;
use app\api\model\UserAddress;
use app\lib\exception\OrderException;
use app\lib\exception\UserException;
use think\Exception;
class Order
{
// 订单的商品列表,客户端传递来的下单商品参数--二维数组
protected $oProducts;
// 根据product_id从数据库中查询出的真实商品信息--库存量
protected $products;
protected $uid;
// 下单方法,参数$uid--用户,$oProducts
public function place($uid, $oProducts)
{
// 将传进来的$uid和$oProducts赋值给成员变量$uid和$oProducts
$this->uid = $uid;
$this->oProducts = $oProducts;
// 从数据库中获取$products的信息,调用方法getProductsByOrder
$this->products = $this->getProductsByOrder($oProducts);
// 获取getOrderStatus方法的返回结果
$status = $this->getOrderStatus();
// 查看库存量是否通过,未通过则:
if (!$status['pass']) {
//在$status数组中增加订单编号为-1,表示订单创建失败值,作为标记
$status['order_id'] = -1;
//返回结果到客户端,
return $status;
}
// 库存量通过,则创建订单.第一步,创建订单快照
$orderSnap = $this->snapOrder($status);
$order = $this->createOrder($orderSnap);
$order['pass'] = true;
return $order;
}
// 10-12
// 第二步,创建订单
private function createOrder($snap)
{
try {
// 订单号
$orderNo = $this->makeOrderNo();
// 实例化order模型
$order = new \app\api\model\Order();
// 数据库的order表中插入数据
$order->user_id = $this->uid;
$order->order_no = $orderNo;
$order->total_price = $snap['orderPrice'];
$order->total_count = $snap['totalCount'];
$order->snap_img = $snap['snapImg'];
$order->snap_name = $snap['snapNme'];
$order->snap_address = $snap['snapAddress'];
$order->snap_items = json_encode($snap['pStatus']);
$order->save();
// order表的id 插入 到order_product的order_id赋值
// 获取order表的id和create_time
$orderID = $order->id;
$create_time = $order->create_time;
// 为订单中的每一个商品添加$orderID
// &引用符号,才能够在数组中增加字段
foreach ($this->oProducts as &$p) {
$p['order_id'] = $orderID;
}
//调用模型orderproduct,将数据保存到数据库order_product表
$orderProduct = new OrderProduct();
// 保存数组需要调用saveAll方法
$orderProduct->saveAll($this->oProducts);
return [
'order_no' => $orderNo,
'order_id' => $orderID,
'create_time' => $create_time
];
} catch (Exception $ex) {
throw $ex;
}
}
// 生成订单号
public static function makeOrderNo()
{
$yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
$orderSn =
$yCode[intval(date('Y')) - 2019] . strtoupper(dechex(date('m'))) . date(
'd') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf(
'%02d', rand(0, 99));
return $orderSn;
}
// 10-11
// 生成订单快照
private function snapOrder($status)
{
//快照信息的关联数组
$snap = [
//商品总价
'orderPrice' => 0,
//所有商品的数量和
'totalCount' => 0,
//单类商品的详细信息
'pStatus' => [],
//快照地址,快照商品名,快照商品图
'snapAddress' => null,
//订单中第一个商品的名字和图片作为快照
'snapName' => '',
'snapImg' => ''
];
$snap['orderPrice'] = $status['orderPrice'];
$snap['totalCount'] = $status['totalCount'];
$snap['pStatus'] = $status['pStatusArray'];
//将$userAddress数组序列化为json字符串,方便存入数据库中,但不太好.
$snap['snapAddress'] = json_encode($this->getUserAddress());
$snap['snapName'] = $this->products[0]['name'];
$snap['snapImg'] = $this->products[0]['main_img_url'];
if (count($this->products) > 1) {
$snap['snapName'] .= '等';
}
// print_r($snap);
}
// 获取快照地址
private function getUserAddress()
{
//获取$userAddress对象
$userAddress = UserAddress::where('user_id', '=', $this->uid)->find();
if (!$userAddress) {
throw new UserException([
'msg' => '用户收货地址不存在,下单失败',
'errorCode' => 60001
]);
}
//返回$userAddress数组
return $userAddress->toArray();
}
// 10-9 下单接口业务模型二
// 定义方法:获取订单状态.对比$oProducts和$products,检验库存量
// 此处不需要传递参数$oProducts和$products,是因为本类中已经定了赋值好了.
// 定义订单状态相关属性,用于返回结果
// pass--库存量检测是否通过,默认值设为true
// orderPrice--所有商品价格总和,默认值设为0
// pStatusArray--数组,通过order的product_id获取并保存订单中所有商品的详细信息
// 用于历史订单,默认值设为空数组
//获取订单状态,返回值为数组,包含库存量是否充足,所有商品总价,和所有订单商品的详细信息.
private function getOrderStatus()
{
$status = [
'pass' => true,
'orderPrice' => 0,
'totalCount' => 0,
'pStatusArray' => []
];
// 使用循环对比进行库存量检测
foreach ($this->oProducts as $oProduct) {
$pStatus = $this->getProductStatus(
$oProduct['product_id'], $oProduct['count'], $this->products
);
if (!$pStatus['haveStock']) {
$status['pass'] = false;
}
$status['orderPrice'] += $pStatus['totalPrice'];
$status['totalCount'] += $pStatus['count'];
array_push($status['pStatusArray'], $pStatus);
}
return $status;
}
// 定义方法getProductStatus
// 根据$oPIDs中的product_id获取$products数组中对应的商品库存量
// $oPIDs数组中只有product_id
// 定义$pStatus的数据结构
// $pStatus的作用,将本次订单信息保存至历史订单
// $pIndex指定product_id在$products中id对应数组的下标序号
// totalPrice--订单中某个商品的总价格
private function getProductStatus($oPIDs, $oCount, $products)
{
$pIndex = -1;
$pStatus = [
'id' => null,
'haveStock' => false,
//订单中某个商品的数量
'count' => 0,
'name' => '',
'totalPrice' => 0
];
//使用循环找出$pIndex
for ($i = 0; $i < count($products); $i++) {
if ($oPIDs == $products[$i]['id']) {
$pIndex = $i;
}
}
if ($pIndex == -1) {
//以防用户下单的商品客户端传递的productid有可能根本不存在,在服务器中已经下架了或丢失了,即$pIndex = -1,需要抛出异常
throw new OrderException([
'msg' => 'id为' . $oPIDs . '的商品不存在,订单创建失败'
]);
} else {
$products = $products[$pIndex];
$pStatus['id'] = $products['id'];
$pStatus['count'] = $oCount;
$pStatus['name'] = $products['name'];
$pStatus['totalPrice'] = $products['price'] * $oCount;
if ($products['stock'] - $oCount >= 0) {
$pStatus['haveStock'] = true;
}
}
return $pStatus;
}
// 根据订单信息$oProducts查找真实的商品信息$products
private function getProductsByOrder($oProducts)
{
// 通过循环将product_id读取出来并存放在$oPIDs数组中,$oPIDs是一个只有product_id的以为数组.
$oPIDs = [];
foreach ($oProducts as $item) {
array_push($oPIDs, $item['product_id']);
}
// 通过新构造的数组$oPIDs,调用Product模型的all方法到数据库中进行硬查询
// 并使用->visible方法获取指定部分数据
// 之前在全局配置中数组返回形式是collection数据集,
// 此处使用数据集的toArray方法将数据集转化为数组形式(方便与$oProducts数组作对比)
// 查询结构$products是一个二维数组
$products = Product::all($oPIDs)
->visible(['id', 'price', 'stock', 'name', 'main_img_url'])
->toArray();
return $products;
}
}
目前暂无任何回答
添加回答
举报
0/150
提交
取消