Browse Source

feat: 订单运费计算,自动添加默认地址,库存判断

wechat_public_accounts
iron 5 years ago
parent
commit
395a3fb755
  1. 2
      api/controllers/AddressController.php
  2. 2
      api/controllers/SiteController.php
  3. 20
      api/logic/AddressLogic.php
  4. 86
      api/logic/ExpressLogic.php
  5. 29
      api/logic/Helper.php
  6. 79
      api/logic/OrderLogic.php
  7. 12
      backend/modules/shop/models/ars/Order.php

2
api/controllers/AddressController.php

@ -19,7 +19,7 @@ class AddressController extends CommonController
/**
* @return object
* @throws \yii\base\InvalidConfigException
* @throws yii\base\InvalidConfigException
*/
public function actionIndex()
{

2
api/controllers/SiteController.php

@ -18,7 +18,7 @@ class SiteController extends Controller
return ArrayHelper::merge(parent::behaviors(), [
'authenticatior' => [
'class' => HttpBearerAuth::className(),
'except' => [],
'except' => ['index'],
]
]);
}

20
api/logic/AddressLogic.php

@ -19,9 +19,17 @@ use yii\web\ServerErrorHttpException;
class AddressLogic extends BaseObject
{
const SET_DEFAULT_ADDRESS = 1;
public $viewAction = 'view';
/**
* @return Address|null
* 获取默认地址
*/
public function getDefault()
{
return $this->findDefault();
}
/**
* @return Address
* @throws BadRequestHttpException
@ -37,7 +45,7 @@ class AddressLogic extends BaseObject
if (!$address->save()) {
throw new ServerErrorHttpException('地址添加失败');
}
if (!$this->getDefaultAddress()) {
if (!$this->findDefault()) {
$this->setDefaultAddress($address);
}
Helper::createdResponse($address, $this->viewAction);
@ -76,7 +84,7 @@ class AddressLogic extends BaseObject
{
$tra = Yii::$app->db->beginTransaction();
try {
$oldDefault = $this->getDefaultAddress();
$oldDefault = $this->findDefault();
if ($oldDefault) {
$oldDefault->status = Address::STATUS_NOT_DEFAULT;
if (!$oldDefault->save()) {
@ -106,10 +114,10 @@ class AddressLogic extends BaseObject
$data['phone'] = Yii::$app->request->getBodyParam('phone');
$data['province'] = Yii::$app->request->getBodyParam('province');
$data['city'] = Yii::$app->request->getBodyParam('city');
$data['district'] = Yii::$app->request->getBodyParam('district');
$data['area'] = Yii::$app->request->getBodyParam('area');
$data['address'] = Yii::$app->request->getBodyParam('address');
if (empty($data['consignee']) || empty($data['phone']) || empty($data['province']) ||
empty($data['city']) || empty($data['district']) || empty($data['address'])) {
empty($data['city']) || empty($data['area']) || empty($data['address'])) {
throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
}
return $data;
@ -135,7 +143,7 @@ class AddressLogic extends BaseObject
/**
* @return array|Address|null
*/
private function getDefaultAddress()
private function findDefault()
{
return Address::find()
->where(['user_id' => Yii::$app->user->getId()])

86
api/logic/ExpressLogic.php

@ -8,7 +8,6 @@ use backend\modules\shop\models\ars\ExpressArea;
use backend\modules\shop\models\ars\ExpressTemplate;
use backend\modules\shop\models\ars\Order;
use backend\modules\shop\models\ars\OrderGoods;
use Yii;
use yii\base\BaseObject;
use yii\web\NotFoundHttpException;
@ -19,7 +18,6 @@ use yii\web\NotFoundHttpException;
*/
class ExpressLogic extends BaseObject
{
public $viewAction = 'view';
/**
* @var Order
* 订单
@ -87,67 +85,89 @@ class ExpressLogic extends BaseObject
return $amount;
} else {
$extraPrice = 0;
$areasIds = [];
$areasIds = $basicGoods = [];
foreach ($allGoods as $goods) {
$areasIds[] = $this->getAreaId($goods['object']->express_template);
$areasIds[] = $this->getAreaId($goods['object']->express_template);/*获取所有配送区域的id*/
}
/*获取首重运费和对应的计费规则id*/
$basic = $this->getBasicPriceAndAreaId($areasIds);
foreach ($allGoods as $goods) {
/*计算增重运费*/
$extraPrice += $this->countExtraAmount($goods['count'], $goods['weight'], $goods['object']->express_template, $basic['id']);
$basicId = $this->getBasicAreaId($areasIds);/*获取首重运费和对应的计费规则id*/
foreach ($allGoods as $k => $goods) {
$res = $this->countExtraAmount($goods, $basicId);/*判断商品绑定的是否为基础模板并计算非基础模板商品的增重运费*/
if (is_bool($res) && $res === true) {
$basicGoods[] = $allGoods[$k];
continue;
}
$extraPrice += $res;
}
return ($basic['price'] + $extraPrice);
$basicPrice = $this->countBasicPrice($basicGoods, $basicId);/*计算基础模板商品的运费*/
return $extraPrice + $basicPrice;
}
}
/**
* @param $allGoods
* @param $areaId
* @return float|int
* @throws NotFoundHttpException
* 计算基础模板商品的运费价格
*/
private function countBasicPrice($allGoods, $areaId)
{
$area = $this->findArea($areaId);
$count = $weight = 0;
$template = $this->findTemplate($area->express_template);
foreach ($allGoods as $goods) {
$count += $goods['count'];
$weight += $goods['weight'];
}
if ($template->calculation_type == ExpressTemplate::CALCULATION_TYPE_WEIGHT) {
$amount = $weight - $area->basic_count > 0 ? $weight - $area->basic_count : 0;
} else {
$amount = $weight - $area->basic_count > 0 ? $weight - $area->basic_count : 0;
}
return $area->basic_price + $area->extra_price * ceil($amount / $area->extra_count);
}
/**
* @param $areaIds
* @return array
* @return int
* @throws NotFoundHttpException
* 获取基础运费
* 获取基础运费的区域id
*/
private function getBasicPriceAndAreaId($areaIds)
private function getBasicAreaId($areaIds)
{
$basePrice = $id = 0;
foreach ($areaIds as $areasId) {
$area = $this->findArea($areasId);
if (!$area->basic_price > $basePrice) {
if ($area->basic_price < $basePrice) {
continue;
}
$basePrice = $area->basic_price;
$id = $areasId;
}
return ['price' => $basePrice, 'id' => $id];
return $id;
}
/**
* @param $count
* @param $weight
* @param $templateId
* @param $goods
* @param $areaId
* @return float|int
* @return bool|int
* @throws NotFoundHttpException
* 计算增重运费
* 计算非使用基础运费模板的商品按增重运费计算运费
*/
private function countExtraAmount($count, $weight, $templateId, $areaId)
private function countExtraAmount($goods, $areaId)
{
$area = $this->findArea($this->getAreaId($templateId));
$template = $this->findTemplate($templateId);
if ($template->calculation_type == ExpressTemplate::CALCULATION_TYPE_WEIGHT) {
$count = $goods['count'];
$weight = $goods['weight'];
$area = $this->findArea($this->getAreaId($goods['object']->express_template));
$template = $this->findTemplate($goods['object']->express_template);
if ($area->id == $areaId) {
$amount = $weight - $area->basic_count > 0 ? $weight - $area->basic_count : 0;
} else {
$amount = $weight;
return true;
}
} else {
if ($area->id == $areaId) {
$amount = $count - $area->basic_count > 0 ? $count - $area->basic_count : 0;
if ($template->calculation_type == ExpressTemplate::CALCULATION_TYPE_WEIGHT) {
$amount = $weight;
} else {
$amount = $count;
}
}
return $area->extra_price * ceil($amount / $area->extra_count);
}
@ -155,12 +175,12 @@ class ExpressLogic extends BaseObject
* @param $templateId
* @return int
* @throws NotFoundHttpException
* 根据运费模板和收货地址获取区域
* 根据收货地址获取配送区域id
*/
private function getAreaId($templateId)
{
$areas = ExpressArea::findALl(['express_template' => $templateId]);
$city = $this->order->city;
$areas = ExpressArea::findALl(['express_template' => $templateId]);
foreach ($areas as $area) {
$allCity = explode(',', $area->city);
if (in_array($city, $allCity)) {

29
api/logic/Helper.php

@ -8,7 +8,6 @@ use backend\modules\goods\models\ars\GoodsAttr;
use backend\modules\goods\models\ars\GoodsSku;
use backend\modules\shop\models\ars\Cart;
use yii\data\ActiveDataProvider;
use yii\di\Instance;
use yii\helpers\Url;
use yii\web\BadRequestHttpException;
use yii\web\NotFoundHttpException;
@ -25,6 +24,19 @@ class Helper
{
const REQUEST_BAD_PARAMS = '参数缺失或包含无效参数';
public static function timeRandomNum($digit, $Prefix = '')
{
$max = pow(10, $digit + 1);
return $Prefix . date('YmdHis', time()) . rand(0, $max - 1);
}
/**
* @param $data
* @param $oid
* @param $type
* @throws ServerErrorHttpException
*/
public static function saveFileMsg($data, $oid, $type)
{
$file = new File();
@ -104,26 +116,29 @@ class Helper
* @param $goodsId
* @param $count
* @param null $skuId
* @throws BadRequestHttpException
* @throws NotFoundHttpException
* @return bool true代表无限库存,false代表有限库存需要进行增删库存操作
* 判断库存
* @throws NotFoundHttpException
* @throws BadRequestHttpException
*/
public static function checkStock($goodsId, $count, $skuId = null)
{
$sku = GoodsSku::findOne($skuId);
$goods = Goods::findOne($goodsId);
if (!$goods) {
print_r($goodsId);exit;
throw new NotFoundHttpException('商品未找到');
}
if (!$sku && $goods->stock == Goods::UNLIMITED_STOCK) {
return;
if ($goods->stock == Goods::UNLIMITED_STOCK) {
return true;
}
if ($sku && $sku->stock == Goods::UNLIMITED_STOCK) {
return true;
}
$stock = $sku ? $sku->stock : $goods->stock;
if ($stock < $count) {
throw new BadRequestHttpException("{$goods->name}库存不足");
}
return;
return false;
}
/**

79
api/logic/OrderLogic.php

@ -59,6 +59,9 @@ class OrderLogic extends Component
$tra = Yii::$app->db->beginTransaction();
try {
$order = new Order();
$order->user_id = Yii::$app->user->getId();
$order->type = Order::TYPE_SHOPPING;
$order->order_sn = Helper::timeRandomNum(3, 'W');
if (!$order->save()) {
throw new ServerErrorHttpException('服务器创建订单失败');
}
@ -67,7 +70,11 @@ class OrderLogic extends Component
} else {
$this->addGoodsByCart($cartIds, $order->id);/*通过购物车添加订单商品*/
}
$this->getShippingType($order);
$this->saveGoodsInfo($order);/*保存订单商品信息*/
if (!$order->save()) {
throw new Exception('服务器创建订单失败');
}
$tra->commit();
Helper::createdResponse($order, $this->viewAction);
return $order;
@ -110,6 +117,8 @@ class OrderLogic extends Component
case self::TYPE_CHANGE_TAKING_SITE:
$this->changeTakingSite($order, $data);
break;
default:
throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
}
if (!$order->save()) {
throw new ServerErrorHttpException('服务器更新订单失败');
@ -123,6 +132,25 @@ class OrderLogic extends Component
}
/*----------------------------------------- 华丽的分割线 -----------------------------------------*/
/**
* @param $order
* @return int
* @throws BadRequestHttpException
* @throws NotFoundHttpException
*/
private function getShippingType($order)
{
$allOrderGoods = $this->findOrderGoods($order->id);
$goods = $this->findGoods($allOrderGoods[0]->goods_id);
if ($goods->is_express) {
return Order::SHIPPING_TYPE_EXPRESS;
}
if ($goods->is_taking) {
return Order::SHIPPING_TYPE_PICKED_UP;
}
throw new BadRequestHttpException('配送方式异常');
}
/**
* @param Order $order
* @param array $data
@ -138,6 +166,9 @@ class OrderLogic extends Component
if ($order->shipping_type !== Order::SHIPPING_TYPE_EXPRESS) {
throw new BadRequestHttpException('配送方式异常');
}
if ($order->status !== Order::STATUS_UNCONFIRMED) {
throw new BadRequestHttpException('该状态下不允许更改配送方式');
}
$address = Address::findOne(['id' => $data['address_id'], 'user_id' => Yii::$app->user->getId()]);
if (!$address) {
throw new NotFoundHttpException('收货地址未找到');
@ -165,6 +196,9 @@ class OrderLogic extends Component
if ($order->shipping_type !== Order::SHIPPING_TYPE_PICKED_UP) {
throw new BadRequestHttpException('配送方式异常');
}
if ($order->status !== Order::STATUS_UNCONFIRMED) {
throw new BadRequestHttpException('该状态下不允许更改提货地址方式');
}
$site = TakingSite::findOne($data['taking_site_id']);
if (!$site) {
throw new NotFoundHttpException('自提点未找到');
@ -181,12 +215,14 @@ class OrderLogic extends Component
*/
private function switchShippingType($order, $data)
{
if (!isset($data['shipping_type'])) {
if (!isset($data['shipping_type']) ||
!in_array($data['shipping_type'], [Order::SHIPPING_TYPE_PICKED_UP, Order::SHIPPING_TYPE_EXPRESS])) {
throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS);
}
if ($order->status !== Order::STATUS_UNCONFIRMED) {
throw new BadRequestHttpException('订单状态异常');
throw new BadRequestHttpException('该状态下不允许更改配送方式');
}
$order->shipping_type = $data['shipping_type'];
}
@ -251,7 +287,7 @@ class OrderLogic extends Component
private function cancel($order)
{
if ($order->status !== Order::STATUS_NONPAYMENT) {
throw new BadRequestHttpException('订单状态异常');
throw new BadRequestHttpException('该状态下无法取消订单');
}
$order->status = Order::STATUS_CANCEL;
$this->updateStock($order, self::TYPE_ADD_STOCK);/*更新库存*/
@ -265,7 +301,7 @@ class OrderLogic extends Component
private function take($order)
{
if ($order->status !== Order::STATUS_SHIPMENT_ALL) {
throw new BadRequestHttpException('订单状态异常');
throw new BadRequestHttpException('该状态下无法确认收货');
}
$order->status = Order::STATUS_FINISH;
}
@ -283,11 +319,13 @@ class OrderLogic extends Component
$allOrderGoods = $this->findOrderGoods($id);
foreach ($allOrderGoods as $orderGoods) {
/*检查库存*/
Helper::checkStock($orderGoods->goods_id, $orderGoods->goods_count, $orderGoods->sku_id);
if (Helper::checkStock($orderGoods->goods_id, $orderGoods->goods_count, $orderGoods->sku_id)) {
return;
}
if ($orderGoods->sku_id) {
$goods = GoodsSku::findOne($orderGoods->sku_id);
} else {
$goods = Goods::findOne($orderGoods->goods_id);
$goods = $this->findGoods($orderGoods->goods_id);
}
if ($type) {
$count = $orderGoods->goods_count;
@ -320,7 +358,6 @@ class OrderLogic extends Component
/**
* @param Order $order
* @throws Exception
* 保存商品总价格和总数量信息到
*/
private function saveGoodsInfo($order)
@ -330,9 +367,6 @@ class OrderLogic extends Component
$order->goods_amount += $goods->price;
$order->goods_count += $goods->goods_count;
}
if (!$order->save()) {
throw new Exception('服务器创建订单失败');
}
}
@ -347,7 +381,7 @@ class OrderLogic extends Component
*/
private function addGoods($id, $goodsId, $skuId, $count)
{
$goods = Goods::findOne($goodsId);
$goods = $this->findGoods($goodsId);
$orderGoods = new OrderGoods();
$orderGoods->order_id = $id;
$orderGoods->goods_id = $goodsId;
@ -364,6 +398,12 @@ class OrderLogic extends Component
}
}
/**
* @param $skuId
* @return int
* @throws NotFoundHttpException
* 获取sku重量
*/
private function skuWeight($skuId)
{
$sku = GoodsSku::findOne($skuId);
@ -398,5 +438,22 @@ class OrderLogic extends Component
->all();
}
/**
* @param int $goodsId
* @return Goods|null
* @throws NotFoundHttpException
*/
private function findGoods($goodsId)
{
$goods = Goods::find()
->where(['id' => $goodsId])
->andWhere(['is_delete' => Goods::IS_DELETE_NO])
->andWhere(['is_sale' => Goods::IS_SALE_YES])
->one();
if (!$goods) {
throw new NotFoundHttpException("商品[{$goodsId}]未找到");
}
return $goods;
}
}

12
backend/modules/shop/models/ars/Order.php

@ -125,12 +125,14 @@ class Order extends \yii\db\ActiveRecord
public function beforeSave($insert)
{
$address = Yii::createObject([
'class' => 'api\logic\AddressLogic',
]);
if ($insert) {
$this->user_id = Yii::$app->user->getId();
$this->type = Order::TYPE_SHOPPING;
//TODO 测试
$this->city = '445100';
$this->type = Order::TYPE_SHOPPING;
$default = $address->getDefault();
$this->province = $default['province'] ?? '';
$this->city = $default['city'] ?? '';
$this->area = $default['area'] ?? '';
}
if (!$insert && $this->status == self::STATUS_UNCONFIRMED && $this->type == self::TYPE_SHOPPING) {
$express = Yii::createObject([

Loading…
Cancel
Save