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.

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