You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.9 KiB

  1. <?php
  2. namespace api\logic;
  3. use backend\modules\goods\models\ars\Goods;
  4. use backend\modules\shop\models\ars\ExpressArea;
  5. use backend\modules\shop\models\ars\ExpressTemplate;
  6. use backend\modules\shop\models\ars\Order;
  7. use backend\modules\shop\models\ars\OrderGoods;
  8. use Yii;
  9. use yii\base\BaseObject;
  10. use yii\web\NotFoundHttpException;
  11. /**
  12. * @author iron
  13. * @email weiriron@gmail.com
  14. * @package api\logic
  15. */
  16. class ExpressLogic extends BaseObject
  17. {
  18. public $viewAction = 'view';
  19. /**
  20. * @var Order
  21. * 订单
  22. */
  23. public $order;
  24. /**
  25. * @param $order
  26. * @return float|int
  27. * @throws NotFoundHttpException
  28. * 计算运费
  29. */
  30. public function countShippingAmount($order)
  31. {
  32. if ($order->shipping_type == Order::SHIPPING_TYPE_PICKED_UP) {
  33. return 0;
  34. }
  35. $this->order = $order;
  36. $allGoods = $this->findDifferentExpressTypeGoods($order);/*获取不同运费计算模式的商品*/
  37. $uniformPostage = $this->countGoodsExpress($allGoods['uniformPostageGoods'], Goods::EXPRESS_TYPE_UNIFORM_POSTAGE);/*计算统一运费模式下所有商品运费*/
  38. $expressTemplate = $this->countGoodsExpress($allGoods['uniformPostageGoods'], Goods::EXPRESS_TYPE_EXPRESS_TEMPLATE);/*计算运费模板模式下所有商品的运费*/
  39. return $uniformPostage > $expressTemplate ? $uniformPostage : $expressTemplate;/*比较两种不同运费计算模式下,取金额大的值为最终收取运费*/
  40. }
  41. /*--------------------------------------------------------------------------------------*/
  42. /**
  43. * @param $order
  44. * @return array
  45. * @throws NotFoundHttpException
  46. * 获取不同运费计算模式的商品
  47. */
  48. private function findDifferentExpressTypeGoods($order)
  49. {
  50. $uniformPostage = $useTemplate = [];
  51. $allGoods = OrderGoods::findAll(['order_id' => $order->id, 'user_id' => Yii::$app->user->getId()]);
  52. foreach ($allGoods as $orderGoods) {
  53. $goods = Goods::findOne(['id' => $orderGoods->goods_id, 'is_sale' => Goods::IS_SALE_YES, 'is_delete' => Goods::IS_DELETE_NO]);
  54. if (!$goods) {
  55. throw new NotFoundHttpException('商品未找到');
  56. }
  57. $goodsArr['object'] = $goods;
  58. $goodsArr['count'] = $orderGoods->goods_count;
  59. $goodsArr['weight'] = $orderGoods->weight;
  60. if ($goods->is_express && $goods->express_type == Goods::EXPRESS_TYPE_UNIFORM_POSTAGE) {
  61. $uniformPostage[] = $goodsArr;
  62. }
  63. if ($goods->is_express && $goods->express_type == Goods::EXPRESS_TYPE_EXPRESS_TEMPLATE) {
  64. $useTemplate[] = $goodsArr;
  65. }
  66. }
  67. return ['uniformPostageGoods' => $uniformPostage, 'useTemplateGoods' => $useTemplate];
  68. }
  69. /**
  70. * @param $allGoods
  71. * @param $type
  72. * @return float|int
  73. * @throws NotFoundHttpException
  74. * 根据不同计费模式计算商品运费
  75. */
  76. private function countGoodsExpress($allGoods, $type)
  77. {
  78. if (!$type == Goods::EXPRESS_TYPE_UNIFORM_POSTAGE) {
  79. $amount = 0;
  80. foreach ($allGoods['object'] as $goods) {
  81. $amount = $goods->uniform_postage > $amount ? $goods->uniform_postage : $amount;
  82. }
  83. return $amount;
  84. } else {
  85. $extraPrice = 0;
  86. $areasIds = [];
  87. foreach ($allGoods['object'] as $k => $goods) {
  88. /*计算增重运费*/
  89. $extraPrice += $this->countExtraAmount($allGoods['count'][$k], $allGoods['weight'][$k], $goods->express_template);
  90. $areasIds[] = $this->getAreaId($goods->express_template);
  91. }
  92. $basic = $this->getBasicPriceAndAreaId($areasIds);/*获取首重运费和对应的计费规则id*/
  93. /*返回所有按运费模板计费的商品运费(基础运费 + 所有商品增重运费 - 多余的增重运费)*/
  94. return $basic['price'] + $extraPrice - $this->countSurplusPrice($basic['id']);
  95. }
  96. }
  97. /**
  98. * @param $areaId
  99. * @return float|int
  100. * @throws NotFoundHttpException
  101. * 计算多余(多算的)运费
  102. * 选定作为基础运费的计费规则对应商品基础数量内的增重费用
  103. */
  104. private function countSurplusPrice($areaId)
  105. {
  106. $area = $this->findArea($areaId);
  107. return $area->extra_price * ceil($area->basic_count / $area->extra_count);
  108. }
  109. /**
  110. * @param $areaIds
  111. * @return array
  112. * @throws NotFoundHttpException
  113. * 获取基础运费
  114. */
  115. private function getBasicPriceAndAreaId($areaIds)
  116. {
  117. $basePrice = $id = 0;
  118. foreach ($areaIds as $areasId) {
  119. $area = $this->findArea($areasId);
  120. if (!$area->basic_price > $basePrice) {
  121. continue;
  122. }
  123. $basePrice = $area->basic_price;
  124. $id = $areasId;
  125. }
  126. return ['price' => $basePrice, 'id' => $id];
  127. }
  128. /**
  129. * @param $count
  130. * @param $weight
  131. * @param $templateId
  132. * @return float|int
  133. * @throws NotFoundHttpException
  134. * 计算增重运费
  135. */
  136. private function countExtraAmount($count, $weight, $templateId)
  137. {
  138. $area = $this->findArea($this->getAreaId($templateId));
  139. $template = $this->findTemplate($templateId);
  140. if ($template->calculation_type == ExpressTemplate::CALCULATION_TYPE_WEIGHT) {
  141. $amount = $area->extra_price * ceil($weight / $area->extra_count);
  142. } else {
  143. $amount = $area->extra_price * ceil($count / $area->extra_count);
  144. }
  145. return $amount;
  146. }
  147. /**
  148. * @param $templateId
  149. * @return int
  150. * @throws NotFoundHttpException
  151. * 根据运费模板和收货地址获取区域
  152. */
  153. private function getAreaId($templateId)
  154. {
  155. $areas = ExpressArea::findALl(['express_template' => $templateId]);
  156. $city = $this->order->city;
  157. foreach ($areas as $area) {
  158. $allCity = explode(',', $area->city);
  159. if (in_array($city, $allCity)) {
  160. return $area->id;
  161. }
  162. }
  163. throw new NotFoundHttpException('超出配送范围(无对应地区运费计算规则)');
  164. }
  165. /**
  166. * @param $areaId
  167. * @return ExpressArea|null
  168. * @throws NotFoundHttpException
  169. * 获取对应区域
  170. */
  171. private function findArea($areaId)
  172. {
  173. $area = ExpressArea::findOne($areaId);
  174. if (!$area) {
  175. throw new NotFoundHttpException('模板地区未找到');
  176. }
  177. return $area;
  178. }
  179. /**
  180. * @param $templateId
  181. * @return ExpressTemplate|null
  182. * @throws NotFoundHttpException
  183. * 获取运费模板
  184. */
  185. private function findTemplate($templateId)
  186. {
  187. $template = ExpressTemplate::findOne($templateId);
  188. if (!$template) {
  189. throw new NotFoundHttpException('运费模板未找到');
  190. }
  191. return $template;
  192. }
  193. }