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.

201 lines
6.6 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. $this->order = $order;
  33. $allGoods = $this->findDifferentExpressTypeGoods();/*获取不同运费计算模式的商品*/
  34. $uniformPostage = $this->countGoodsExpress($allGoods['uniformPostageGoods'], Goods::EXPRESS_TYPE_UNIFORM_POSTAGE);/*计算统一运费模式下所有商品运费*/
  35. $expressTemplate = $this->countGoodsExpress($allGoods['useTemplateGoods'], Goods::EXPRESS_TYPE_EXPRESS_TEMPLATE);/*计算运费模板模式下所有商品的运费*/
  36. $amount = $uniformPostage > $expressTemplate ? $uniformPostage : $expressTemplate;/*比较两种不同运费计算模式下,取金额大的值为最终收取运费*/
  37. return $amount / 100; /*将金额单位[分]转化为[元]*/
  38. }
  39. /*--------------------------------------------------------------------------------------*/
  40. /**
  41. * @return array
  42. * @throws NotFoundHttpException
  43. * 获取不同运费计算模式的商品
  44. */
  45. private function findDifferentExpressTypeGoods()
  46. {
  47. $uniformPostage = $useTemplate = [];
  48. $allGoods = OrderGoods::findAll(['order_id' => $this->order->id]);
  49. foreach ($allGoods as $orderGoods) {
  50. $goods = Goods::findOne(['id' => $orderGoods->goods_id, 'is_sale' => Goods::IS_SALE_YES, 'is_delete' => Goods::IS_DELETE_NO]);
  51. if (!$goods) {
  52. throw new NotFoundHttpException('商品未找到');
  53. }
  54. $goodsArr['object'] = $goods;
  55. $goodsArr['count'] = $orderGoods->goods_count;
  56. $goodsArr['weight'] = $orderGoods->weight;
  57. if ($goods->is_express && $goods->express_type == Goods::EXPRESS_TYPE_UNIFORM_POSTAGE) {
  58. $uniformPostage[] = $goodsArr;
  59. }
  60. if ($goods->is_express && $goods->express_type == Goods::EXPRESS_TYPE_EXPRESS_TEMPLATE) {
  61. $useTemplate[] = $goodsArr;
  62. }
  63. }
  64. return ['uniformPostageGoods' => $uniformPostage, 'useTemplateGoods' => $useTemplate];
  65. }
  66. /**
  67. * @param $allGoods
  68. * @param $type
  69. * @return float|int
  70. * @throws NotFoundHttpException
  71. * 根据不同计费模式计算商品运费
  72. */
  73. private function countGoodsExpress($allGoods, $type)
  74. {
  75. if ($type == Goods::EXPRESS_TYPE_UNIFORM_POSTAGE) {
  76. $amount = 0;
  77. foreach ($allGoods as $goods) {
  78. $amount = $goods['object']->uniform_postage > $amount ? $goods['object']->uniform_postage : $amount;
  79. }
  80. return $amount;
  81. } else {
  82. $extraPrice = 0;
  83. $areasIds = [];
  84. foreach ($allGoods as $goods) {
  85. $areasIds[] = $this->getAreaId($goods['object']->express_template);
  86. }
  87. /*获取首重运费和对应的计费规则id*/
  88. $basic = $this->getBasicPriceAndAreaId($areasIds);
  89. foreach ($allGoods as $goods) {
  90. /*计算增重运费*/
  91. $extraPrice += $this->countExtraAmount($goods['count'], $goods['weight'], $goods['object']->express_template, $basic['id']);
  92. }
  93. return ($basic['price'] + $extraPrice);
  94. }
  95. }
  96. /**
  97. * @param $areaIds
  98. * @return array
  99. * @throws NotFoundHttpException
  100. * 获取基础运费
  101. */
  102. private function getBasicPriceAndAreaId($areaIds)
  103. {
  104. $basePrice = $id = 0;
  105. foreach ($areaIds as $areasId) {
  106. $area = $this->findArea($areasId);
  107. if (!$area->basic_price > $basePrice) {
  108. continue;
  109. }
  110. $basePrice = $area->basic_price;
  111. $id = $areasId;
  112. }
  113. return ['price' => $basePrice, 'id' => $id];
  114. }
  115. /**
  116. * @param $count
  117. * @param $weight
  118. * @param $templateId
  119. * @param $areaId
  120. * @return float|int
  121. * @throws NotFoundHttpException
  122. * 计算增重运费
  123. */
  124. private function countExtraAmount($count, $weight, $templateId, $areaId)
  125. {
  126. $area = $this->findArea($this->getAreaId($templateId));
  127. $template = $this->findTemplate($templateId);
  128. if ($template->calculation_type == ExpressTemplate::CALCULATION_TYPE_WEIGHT) {
  129. if ($area->id == $areaId) {
  130. $amount = $weight - $area->basic_count > 0 ? $weight - $area->basic_count : 0;
  131. } else {
  132. $amount = $weight;
  133. }
  134. } else {
  135. if ($area->id == $areaId) {
  136. $amount = $count - $area->basic_count > 0 ? $count - $area->basic_count : 0;
  137. } else {
  138. $amount = $count;
  139. }
  140. }
  141. return $area->extra_price * ceil($amount / $area->extra_count);
  142. }
  143. /**
  144. * @param $templateId
  145. * @return int
  146. * @throws NotFoundHttpException
  147. * 根据运费模板和收货地址获取区域
  148. */
  149. private function getAreaId($templateId)
  150. {
  151. $areas = ExpressArea::findALl(['express_template' => $templateId]);
  152. $city = $this->order->city;
  153. foreach ($areas as $area) {
  154. $allCity = explode(',', $area->city);
  155. if (in_array($city, $allCity)) {
  156. return $area->id;
  157. }
  158. }
  159. throw new NotFoundHttpException('超出配送范围(未找到对应地区运费计算规则)');
  160. }
  161. /**
  162. * @param $areaId
  163. * @return ExpressArea|null
  164. * @throws NotFoundHttpException
  165. * 获取对应区域
  166. */
  167. private function findArea($areaId)
  168. {
  169. $area = ExpressArea::findOne($areaId);
  170. if (!$area) {
  171. throw new NotFoundHttpException('模板地区未找到');
  172. }
  173. return $area;
  174. }
  175. /**
  176. * @param $templateId
  177. * @return ExpressTemplate|null
  178. * @throws NotFoundHttpException
  179. * 获取运费模板
  180. */
  181. private function findTemplate($templateId)
  182. {
  183. $template = ExpressTemplate::findOne($templateId);
  184. if (!$template) {
  185. throw new NotFoundHttpException('运费模板未找到');
  186. }
  187. return $template;
  188. }
  189. }