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.

227 lines
7.9 KiB

  1. <?php
  2. namespace backend\modules\shop\logic\delivery;
  3. use backend\modules\shop\models\ars\Delivery;
  4. use backend\modules\shop\models\ars\DeliveryGoods;
  5. use backend\modules\shop\models\ars\Order;
  6. use backend\modules\shop\models\ars\OrderGoods;
  7. use Yii;
  8. use yii\db\Exception;
  9. use yii\helpers\ArrayHelper;
  10. use yii\helpers\Json;
  11. use yii\web\NotFoundHttpException;
  12. class DeliveryManager
  13. {
  14. const LOGISTICS_URL = 'http://route.showapi.com/64-19';
  15. /**
  16. * @param Order $order
  17. * @param Delivery $delivery
  18. * @return array
  19. * 订单发货
  20. */
  21. public static function orderDelivery($order, $delivery)
  22. {
  23. $transaction = Yii::$app->db->beginTransaction();
  24. try {
  25. $data = Yii::$app->request->post();
  26. if (empty($data['deliveryGoods'])) {
  27. throw new Exception('缺少发货商品信息');
  28. }
  29. $delivery->load($data);
  30. $delivery->order_id = $order->id;
  31. if (!$delivery->save()) {
  32. throw new Exception('保存物流信息失败');
  33. }
  34. /*发货商品数据*/
  35. $orderStatus = self::saveDeliveryGoods($data['deliveryGoods'], $delivery->id);
  36. $order->status = $orderStatus;
  37. if (!$order->save()) {
  38. throw new Exception('order shipping_status update false');
  39. }
  40. if ($orderStatus == Order::STATUS_SHIPMENT_PORTION || Delivery::find()->where(['!=', 'id', $delivery->id])->andWhere(['order_id' => $delivery->order_id])->one()) {
  41. $delivery->type = Delivery::TYPE_SHIPMENT_PORTION;
  42. } else {
  43. $delivery->type = Delivery::TYPE_SHIPMENT_ALL;
  44. }
  45. if (!$delivery->save()) {
  46. throw new Exception('保存物流信息失败');
  47. }
  48. $transaction->commit();
  49. return ['status' => true];
  50. } catch (Exception $e) {
  51. $transaction->rollBack();
  52. return ['status' => false, 'info' => $e->getMessage()];
  53. }
  54. }
  55. /**
  56. * @param $deliveryGoods
  57. * @param $delivery_id
  58. * @return int
  59. * @throws Exception
  60. * 保存发货商品信息
  61. */
  62. private static function saveDeliveryGoods($deliveryGoods, $delivery_id)
  63. {
  64. $status = Order::STATUS_SHIPMENT_ALL;
  65. foreach ($deliveryGoods as $id => $goodsCount) {
  66. if ($goodsCount < 0) {
  67. throw new Exception('操作异常,发货数量不能小于0');
  68. } elseif ($goodsCount == 0) {
  69. continue;
  70. }
  71. $orderGoods = OrderGoods::findOne($id);
  72. /*如果是发货数量不是全部,订单状态为部分发货*/
  73. $deliveryGoodsCount = DeliveryGoods::find()->where(['order_goods_id' => $id])->sum('goods_count');
  74. if (($deliveryGoodsCount + $goodsCount) < $orderGoods->goods_count) { //如果已发货数量未达到order_goods里的数量
  75. $status = Order::STATUS_SHIPMENT_PORTION;
  76. } elseif (($deliveryGoodsCount + $goodsCount) > $orderGoods->goods_count) {
  77. throw new Exception('操作异常,现发货数量超过之前缺少的发货数量');
  78. }
  79. $model = new DeliveryGoods();
  80. $model->delivery_id = $delivery_id;
  81. $model->order_goods_id = $orderGoods->id;
  82. $model->goods_id = $orderGoods->goods_id;
  83. $model->goods_name = $orderGoods->goods_name;
  84. $model->goods_count = $goodsCount;
  85. if (!$model->save()) {
  86. throw new Exception('delivery_goods save false');
  87. }
  88. }
  89. return $status;
  90. }
  91. /**
  92. * @param $order_id
  93. * @return array
  94. * 查询订单发货商品信息
  95. */
  96. public static function deliveryGoodsInfo($order_id)
  97. {
  98. $delivery = Delivery::findAll(['order_id' => $order_id]);
  99. /*如果该订单是首次发货*/
  100. if ($delivery) {
  101. /*获取订单已发的商品和未发的商品*/
  102. return self::getDeliveryGoodsInfo($delivery);
  103. } else {
  104. $unShippedGoods = OrderGoods::find()->where(['order_id' => $order_id])->all();
  105. return ['unShipped' => $unShippedGoods];
  106. }
  107. }
  108. /**
  109. * @param $delivery
  110. * @return array
  111. * 获取订单已发的商品和未发的商品
  112. */
  113. public static function getDeliveryGoodsInfo($delivery)
  114. {
  115. $data = [];
  116. $deliveryIds = [];
  117. foreach ($delivery as $k => $value) {
  118. $deliveryIds[] = $value->id;
  119. $orderGoodsIds = DeliveryGoods::find()
  120. ->select('order_goods_id')
  121. ->where(['delivery_id' => $value->id])
  122. ->andWhere(['>', 'goods_count', 0])
  123. ->column();
  124. $value->deliveryGoods = OrderGoods::findAll($orderGoodsIds);
  125. }
  126. $data['shipped'] = $delivery;
  127. $deliveryGoodsData = [];
  128. $deliveryGoods = DeliveryGoods::find()
  129. ->select(['order_goods_id', 'goods_count'])
  130. ->where(['delivery_id' => $deliveryIds])
  131. ->andWhere(['>', 'goods_count', 0])
  132. ->all();
  133. foreach ($deliveryGoods as $k => $value) {
  134. $orderGoods = $value->order_goods_id;
  135. if (isset($deliveryGoodsData[$orderGoods])) {
  136. $deliveryGoodsData[$orderGoods] += $value->goods_count;
  137. } else {
  138. $deliveryGoodsData[$orderGoods] = $value->goods_count;
  139. }
  140. }
  141. foreach ($deliveryGoodsData as $k => $value) { //键名为order_goods_id,键值为对应的已发货数量
  142. $orderGoods = OrderGoods::findOne($k); //通过orderGoods_id找到订单商品
  143. if ($value < $orderGoods->goods_count) { //如果已发货数量未达到order_goods里的数量
  144. $orderGoods->lack_number = $orderGoods->goods_count - $value;
  145. $data['unShipped'][] = $orderGoods;
  146. }
  147. }
  148. return $data;
  149. }
  150. /**
  151. * @param $orderId
  152. * @return array|mixed
  153. * @throws NotFoundHttpException
  154. * 查询物流接口
  155. */
  156. public static function queryLogistics($orderId)
  157. {
  158. $delivery = Delivery::findOne(['order_id' => $orderId]);
  159. if (!$delivery) {
  160. throw new NotFoundHttpException('发货信息未找到');
  161. }
  162. $cache = Yii::$app->cache;
  163. if ($cache->exists($delivery->shipping_id)) {
  164. return $cache->get($delivery->shipping_id);
  165. }
  166. $logisticsParams = self::createLogisticsParam($delivery); //创建参数(包括签名的处理)
  167. $url = self::LOGISTICS_URL . '?' . $logisticsParams;
  168. $result = Json::decode(file_get_contents($url), false);
  169. if (isset($result->showapi_res_body)) {
  170. $cache->set($delivery->shipping_id, $result->showapi_res_body, 7200); //设置缓存2个小时
  171. return $result->showapi_res_body;
  172. } else {
  173. return [];
  174. }
  175. }
  176. /**
  177. * @param Delivery $delivery
  178. * @return string
  179. * 查询物流 创建参数(包括签名的处理)
  180. */
  181. private static function createLogisticsParam($delivery)
  182. {
  183. $params = [
  184. 'showapi_appid' => Yii::$app->params['logistics_config']['logistics_appid'],
  185. 'com' => $delivery->shipping_name , //物流单位
  186. 'nu' => $delivery->invoice_sn, //运单号
  187. //添加其他参数
  188. ];
  189. $paraStr = "";
  190. $signStr = "";
  191. ksort($params);
  192. foreach ($params as $key => $val) {
  193. if ($key != '' && $val != '') {
  194. $signStr .= $key.$val;
  195. $paraStr .= $key . '=' . urlencode($val) . '&';
  196. }
  197. }
  198. $signStr .= Yii::$app->params['logistics_config']['logistics_secret'];
  199. //排好序的参数加上secret,进行md5,将md5后的值作为参数,便于服务器的效验
  200. $sign = strtolower(md5($signStr));
  201. $paraStr .= 'showapi_sign=' . $sign;
  202. return $paraStr;
  203. }
  204. }