OrderService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <?php
  2. namespace addons\QiDingDong\common\service;
  3. use addons\QiDingDong\common\enums\QiDingDongEnums;
  4. use addons\QiDingDong\common\expand\sdk\qidingdong\src\model\CreateOrderModel;
  5. use addons\QiDingDong\common\expand\sdk\qidingdong\src\model\OrderGoodsItemModel;
  6. use addons\QiDingDong\common\expand\sdk\qidingdong\src\model\ShippingFeeModel;
  7. use addons\QiDingDong\common\expand\sdk\qidingdong\src\request\CreateOrderRequest;
  8. use addons\QiDingDong\common\expand\sdk\qidingdong\src\request\ShippingFeeRequest;
  9. use addons\QiDingDong\common\helper\RequestHelper;
  10. use addons\QiDingDong\common\models\QiDingDongEvent;
  11. use addons\QiDingDong\common\models\QiDingDongGoods;
  12. use addons\QiDingDong\common\models\QiDingDongGoodsAttr;
  13. use addons\QiDingDong\common\models\QiDingDongOrder;
  14. use addons\QiDingDong\common\models\QiDingDongRegion;
  15. use common\enums\AddonsEnum;
  16. use common\enums\ShippingTypeEnum;
  17. use common\enums\StatusEnum;
  18. use common\helpers\FormatHelper;
  19. use common\models\common\Express;
  20. use common\models\mall\Mall;
  21. use common\models\order\Order;
  22. use common\models\order\OrderExpress;
  23. use common\models\user\User;
  24. use yii\helpers\Json;
  25. class OrderService
  26. {
  27. public function page(int $mall_id, array $params)
  28. {
  29. $where = [
  30. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]
  31. ];
  32. if (!empty($params['order_no'])) {
  33. $where[] = ['like', 'order_no', $params['order_no']];
  34. }
  35. if (!empty($params['third_order_no'])) {
  36. $where[] = ['like', 'third_order_no', $params['third_order_no']];
  37. }
  38. $is_master = SettingService::isMasterMall($mall_id);
  39. if (!$is_master) {
  40. $where[] = ['mall_id' => $mall_id];
  41. } elseif (!empty($params['keyword'])) {
  42. $mIds = Mall::find()->where(['or', ['like', 'id', $params['keyword']], ['like', 'name', $params['keyword']]])
  43. ->select('id')->column();
  44. if (empty($mIds)) return [];
  45. $where[] = ['mall_id' => $mIds];
  46. }
  47. if (!empty($params['member'])) {
  48. $query = User::find();
  49. if (!$is_master) $query->where(['mall_id' => $mall_id]);
  50. $uids = $query->andWhere(['or', ['like', 'id', $params['member']], ['like', 'mobile', $params['member']], ['like', 'nickname', $params['member']]])
  51. ->andWhere(['status' => StatusEnum::ENABLED])
  52. ->select('id')->column();
  53. if (empty($uids)) return [];
  54. $where[] = ['user_id' => $uids];
  55. }
  56. $ret = QiDingDongOrder::listPage([
  57. 'where' => $where,
  58. 'order' => 'id desc',
  59. 'limit' => $params['limit'] ?? '',
  60. 'with' => ['order' => function($query) {
  61. $query->with(['detail']);
  62. }, 'mall']
  63. ]);
  64. if (!empty(QiDingDongOrder::getStaticError())) return QiDingDongOrder::getStaticError();
  65. if (!empty($ret['list'])) {
  66. foreach ($ret['list'] as &$item) {
  67. $item['mall']['logo'] = MallService::getLogo($item['mall_id']);
  68. }
  69. }
  70. return $ret;
  71. }
  72. /**
  73. * @param array $order
  74. * @param int $a_order_id
  75. * @return bool
  76. */
  77. public function create(array $order, int $a_order_id = 0)
  78. {
  79. try {
  80. $goods_ids = array_column($order['detail'], 'goods_id');
  81. $list = QiDingDongGoods::lists([
  82. 'where' => [
  83. ['goods_id' => $goods_ids],
  84. ['mall_id' => $order['mall_id']]
  85. ],
  86. 'index' => 'goods_id',
  87. 'select'=> 'goods_id, third_goods_id'
  88. ]);
  89. $order_detail_ids = [];
  90. if (!empty($list)) {
  91. $goods = [];
  92. if (!empty($a_order_id)) {
  93. $orderModel = QiDingDongOrder::findOne(['id' => $a_order_id]);
  94. } else {
  95. $orderModel = QiDingDongOrder::findOne(['order_id' => $order['id']]);
  96. if (empty($orderModel)) $orderModel = new QiDingDongOrder();
  97. }
  98. $is_d = true;
  99. $region = QiDingDongRegion::findOne(['local_id' => $order['area']]);
  100. if (empty($region)) {
  101. $is_d = false;
  102. $region = QiDingDongRegion::findOne(['local_id' => $order['city']]);
  103. }
  104. $consumer_amount = 0;
  105. $consumer_ship_amount = 0;
  106. foreach ($order['detail'] as $item) {
  107. if (!empty($list[$item['goods_id']])) {
  108. $specItem = QiDingDongGoodsAttr::findOne(['goods_attr_id' => $item['goods_attr_id']]);
  109. // 取运费
  110. $shipContentModel = RequestHelper::contentModelInstance($order['mall_id']);
  111. $shipContentModel->content->data = new ShippingFeeModel();
  112. $shipContentModel->content->data->goods_id = $list[$item['goods_id']]['third_goods_id'];
  113. $shipContentModel->content->data->spec_id = $specItem->third_spec_id;
  114. $shipContentModel->content->data->province = $region->province_id;
  115. $shipContentModel->content->data->city = $region->city_id;
  116. $shipContentModel->content->data->area = $is_d ? $region->id : $region->district_id;
  117. $shipContentModel->content->data->num = $item['num'];
  118. $shipContentModel->content->data->yf_mode = StatusEnum::ENABLED;
  119. $shipContentModel->content->data->device = QiDingDongEnums::REQUEST_PARAMS_DEVICE;
  120. $req = new ShippingFeeRequest();
  121. $res = RequestHelper::send($req, RequestHelper::enCrypto($shipContentModel, $order['mall_id']), $order['mall_id']);
  122. if (is_array($res)) {
  123. $tGoods = new OrderGoodsItemModel();
  124. $tGoods->goods_id = $list[$item['goods_id']]['third_goods_id'];
  125. $tGoods->spec_id = $specItem->third_spec_id; // 商品规格ID
  126. $tGoods->num = $item['num'];
  127. $tGoods->yf_mode = StatusEnum::ENABLED; // 运输方式 2.4接口获取的code
  128. $tGoods->ship_price = $res['ship_price']; // 运费-- 运费计算接口获取 单位:分
  129. $tGoods->total_ship_price = $res['total_ship_price']; // 总运费-- 运费计算接口获取 单位:分
  130. $tGoods->basic_ship_price = $res['basic_ship_price']; // 基础运费-- 运费计算接口获取 单位:分
  131. $tGoods->goods_price = (int) bcmul($specItem->third_price, 100, 0); // 商品单价 (单位:分)
  132. $tGoods->ent_id = $res['ent_id'] ?? '';
  133. $order_detail_ids[] = $item['id'];
  134. $goods[] = $tGoods;
  135. $orderModel->req_success = 100;
  136. $consumer_amount += (int) bcmul($tGoods->goods_price, $item['num']);
  137. $consumer_ship_amount += $tGoods->ship_price;
  138. } else {
  139. $orderModel->req_success = StatusEnum::ENABLED;
  140. }
  141. $orderModel->last_resp = var_export($res, true);
  142. }
  143. }
  144. if (!empty($goods)) {
  145. // 如果失败了 这一行需要去掉
  146. $goods_price = round(bcmul(bcmul($consumer_amount, MallService::rate($order['mall_id']), 2), 0.01, 3), 2);
  147. $consumer_ship_amount = bcmul($consumer_ship_amount, 0.01, 2);
  148. $total_price = bcadd($goods_price, $consumer_ship_amount, 2);
  149. $balanceLogModel = (new FundService())->create([
  150. 'mall_id' => $order['mall_id'],
  151. 'amount' => $total_price,
  152. 'remark' => "来自订单号为[{$order['order_no']}]的购物消费,其中商品金额为[$goods_price],运费金额为[$consumer_ship_amount]",
  153. 'type' => QiDingDongEnums::BALANCE_LOG_TYPE_CONSUMER,
  154. 'direction' => QiDingDongEnums::BALANCE_DIRECTION_OUT,
  155. 'order_no' => $order['order_no'],
  156. 'addons' => AddonsEnum::ADDONS_NAME_QI_DING_DONG,
  157. ]);
  158. if (!is_string($balanceLogModel)) {
  159. $contentModel = RequestHelper::contentModelInstance($order['mall_id']);
  160. $contentModel->content->data = new CreateOrderModel();
  161. $contentModel->content->data->phone = $order['mobile'];
  162. $contentModel->content->data->consignee = "{$order['region_name']}{$order['address']}";
  163. $contentModel->content->data->province = $region->province_id; // ID要相通
  164. $contentModel->content->data->city = $region->city_id;
  165. $contentModel->content->data->area = $region->district_id;
  166. $contentModel->content->data->buyer_name = $order['receiver_name'];
  167. $contentModel->content->data->trade_no = $order['order_no'];
  168. $contentModel->content->data->goods = $goods;
  169. $contentModel->content->data->device = QiDingDongEnums::REQUEST_PARAMS_DEVICE;
  170. // 商品信息
  171. $req = new CreateOrderRequest();
  172. $res = RequestHelper::send($req, RequestHelper::enCrypto($contentModel, $order['mall_id']), $order['mall_id']);
  173. $orderModel->req_success = 100;
  174. if (!is_array($res)) {
  175. $orderModel->req_success = StatusEnum::ENABLED;
  176. // throw new \Exception($res);
  177. }
  178. } else {
  179. $res = $balanceLogModel;
  180. $orderModel->req_success = StatusEnum::ENABLED;
  181. }
  182. $orderModel->last_resp = var_export($res, true);
  183. }
  184. // 创建订单
  185. $orderModel->content = ['create' => !empty($res) ? $res : []];
  186. $orderModel->post = ['create' => !empty($contentModel) ? $contentModel->toArray() : (!empty($shipContentModel) ? $shipContentModel->toArray() : [])];
  187. if (empty($a_order_id)) {
  188. $orderModel->order_no = $order['order_no'];
  189. $orderModel->order_id = $order['id'];
  190. $orderModel->mall_id = $order['mall_id'];
  191. $orderModel->user_id = $order['user_id'];
  192. $orderModel->order_detail_ids = $order_detail_ids;
  193. }
  194. $orderModel->third_order_no = $res['order_sn'] ?? '';
  195. $orderModel->req_success = !empty($orderModel->req_success) ? $orderModel->req_success : 100;
  196. $orderModel->last_req = 'create';
  197. if (!$orderModel->save()) throw new \Exception($orderModel->getErrorMessage());
  198. if ($orderModel->req_success != 100 && !empty($balanceLogModel) && !is_string($balanceLogModel)) {
  199. FundService::asyncRefund($balanceLogModel->id);
  200. }
  201. }
  202. } catch (\Exception $e) {
  203. \Yii::error(FormatHelper::exception($e, __METHOD__));
  204. var_dump($e->getMessage(), $e->getFile(), $e->getLine());
  205. return false;
  206. }
  207. return true;
  208. }
  209. /**
  210. * 订单更新
  211. * @param QiDingDongEvent $event
  212. * @return void
  213. * @throws \Exception
  214. */
  215. public function eventUpdate(QiDingDongEvent &$event)
  216. {
  217. // foreach (Mall::getAllMallIds() as $mallId) {
  218. // $config = (new SettingService())->get($mallId);
  219. // if ($config['app_key'] == $event->post['app_key'] && $config['token'] == $event->post['base']['token']) {
  220. // break;
  221. // }
  222. // $config = null;
  223. // }
  224. // if (empty($config)) throw new \Exception("未找到插件信息");
  225. $aOrder = QiDingDongOrder::findOne(['third_order_no' => $event->content['content']['data']['order_sn']]);
  226. if (empty($aOrder)) throw new \Exception("订单不存在!");
  227. $event->mall_id = $aOrder->mall_id;
  228. // 做处理
  229. $order = Order::getOne([
  230. ['id' => $aOrder->order_id]
  231. ], true, 'detail');
  232. if (empty($order)) throw new \Exception("订单不存在");
  233. $t = \Yii::$app->db->beginTransaction();
  234. try {
  235. switch ($event->content['content']['data']['fahuo_status']) {
  236. case 0:
  237. // 已支付
  238. break;
  239. case 3:
  240. // 配货中
  241. break;
  242. case 1:
  243. // 已发货
  244. // 执行发货
  245. // 查快递
  246. /**
  247. * @var $express Express
  248. */
  249. $express = Express::getOne([
  250. ['like', 'name', $event->content['content']['data']['ship_name']]
  251. ]);
  252. if (empty($express)) {
  253. $express = Express::getOne([
  254. ['id' => Express::EXPRESS_OTHER]
  255. ]);
  256. }
  257. $form['mall_id'] = $event->mall_id;
  258. $form['shipping_type'] = ShippingTypeEnum::LOGISTICS;
  259. $form['order_detail_ids'] = $aOrder->order_detail_ids;
  260. $form['express_id'] = $express->id;
  261. $form['express_no'] = $event->content['content']['data']['ship_sn'][0];
  262. $ships = Json::encode($event->content['content']['data']['ship_sn']);
  263. $form['memo'] = "{$event->content['content']['data']['ship_name']}, {$ships}, {$event->content['content']['data']['ship_time']}";
  264. $form['express_name'] = $express->name;
  265. $form['id'] = $aOrder->order_id;
  266. $form['mch_id'] = 0;
  267. $form['operator_id'] = 0;
  268. $form['operator_name'] = "企叮咚供应链发货";
  269. $res = OrderExpress::delivery($form); // 发货
  270. if ($res === false) throw new \Exception(OrderExpress::getStaticError());
  271. break;
  272. case 4:
  273. // 已完成
  274. break;
  275. case 9:
  276. // 已关闭
  277. break;
  278. }
  279. $event->mall_id = $aOrder->mall_id;
  280. $aOrder->content = array_merge($aOrder->content, [
  281. 'event' => [
  282. $event->content['fahuo_status'] => $event->content
  283. ]
  284. ]);
  285. if (!$aOrder->save()) throw new \Exception($aOrder->getErrorMessage());
  286. $t->commit();
  287. } catch (\Exception $e) {
  288. $t->rollBack();
  289. \Yii::error(FormatHelper::exception($e, __METHOD__));
  290. throw new \Exception($e->getMessage());
  291. }
  292. }
  293. /**
  294. * 补偿
  295. * @param int $mall_id
  296. * @param $id
  297. * @return bool|string
  298. */
  299. public function compensate(int $mall_id, $id)
  300. {
  301. $aOrder = QiDingDongOrder::findOne(['mall_id' => $mall_id, 'id' => $id]);
  302. if (empty($aOrder)) return '记录不存在';
  303. if ($aOrder->req_success == 100) return '当前状态无效补偿';
  304. try {
  305. switch ($aOrder->last_req) {
  306. case 'create':
  307. $order = Order::getOne([['id' => $aOrder->order_id]],true, ['detail']);
  308. return $this->create($order, $id);
  309. }
  310. } catch (\Exception $e) {
  311. return $e->getMessage();
  312. }
  313. return '当前订单非补偿状态';
  314. }
  315. /**
  316. * @param int $order_id
  317. * @return bool
  318. */
  319. public static function existOrder(int $order_id)
  320. {
  321. return !empty(QiDingDongOrder::findOne(['order_id' => $order_id]));
  322. }
  323. }