Order.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. namespace app\common\service\wechat\wow;
  3. use app\common\model\Wxapp as WxappModel;
  4. use app\common\model\wow\Order as OrderModel;
  5. use app\common\model\wow\Setting as SettingModel;
  6. use app\common\library\helper;
  7. use app\common\enum\OrderType as OrderTypeEnum;
  8. use app\common\enum\order\PayType as PayTypeEnum;
  9. use app\common\enum\DeliveryType as DeliveryTypeEnum;
  10. use app\common\library\wechat\wow\Order as WowOrder;
  11. /**
  12. * 好物圈-订单同步 服务类
  13. * Class Shoping
  14. * @package app\common\service\wechat\wow
  15. */
  16. class Order
  17. {
  18. /* @var int $wxapp_id 小程序商城id */
  19. private $wxappId;
  20. /* @var WowOrder $ApiDriver 微信api驱动 */
  21. private $ApiDriver;
  22. protected $error;
  23. /**
  24. * 构造方法
  25. * Shoping constructor.
  26. * @param $wxappId
  27. * @throws \app\common\exception\BaseException
  28. * @throws \think\exception\DbException
  29. */
  30. public function __construct($wxappId)
  31. {
  32. $this->wxappId = $wxappId;
  33. $this->initApiDriver();
  34. }
  35. /**
  36. * 导入好物圈订单信息
  37. * @param array|\think\Collection $orderList 订单列表
  38. * @param bool $isCheck 验证后台是否开启同步设置
  39. * @return bool
  40. * @throws \app\common\exception\BaseException
  41. * @throws \Exception
  42. */
  43. public function import($orderList, $isCheck = true)
  44. {
  45. // 判断是否开启同步设置
  46. $setting = SettingModel::getItem('basic', $this->wxappId);
  47. if ($isCheck && $setting['is_order'] == false) {
  48. return false;
  49. }
  50. // 整理订单列表
  51. $orderListParams = $this->getOrderList($orderList, true);
  52. // 执行api请求
  53. $status = $this->ApiDriver->import($orderListParams);
  54. if ($status == false) {
  55. $this->error = $this->ApiDriver->getError();
  56. return $status;
  57. }
  58. // 新增好物圈订单记录
  59. $this->model()->add($this->wxappId, $orderList);
  60. return $status;
  61. }
  62. /**
  63. * 更新好物圈订单信息
  64. * @param array|\think\Collection $orderList 订单列表
  65. * @return bool
  66. * @throws \app\common\exception\BaseException
  67. * @throws \Exception
  68. */
  69. public function update($orderList)
  70. {
  71. // 过滤不存在的订单列表
  72. $legalList = $this->getLegalOrderList($orderList);
  73. if (empty($legalList)) {
  74. return false;
  75. }
  76. // 整理订单列表
  77. $orderListParams = $this->getOrderList($legalList);
  78. // 执行api请求
  79. $status = $this->ApiDriver->update($orderListParams);
  80. if ($status == false) {
  81. $this->error = $this->ApiDriver->getError();
  82. return $status;
  83. }
  84. // 更新好物圈订单记录
  85. $this->model()->edit($legalList);
  86. return $status;
  87. }
  88. /**
  89. * 获取存在好物圈记录的订单列表
  90. * 用于过滤不存在好物圈同步记录的订单
  91. * @param array|\think\Collection $orderList 订单列表
  92. * @param int $orderType
  93. * @return array|\think\Collection
  94. * @throws \think\db\exception\DataNotFoundException
  95. * @throws \think\db\exception\ModelNotFoundException
  96. * @throws \think\exception\DbException
  97. */
  98. private function getLegalOrderList($orderList, $orderType = OrderTypeEnum::MASTER)
  99. {
  100. // 把order_id设置为key
  101. $orderList = helper::arrayColumn2Key($orderList, 'order_id');
  102. // 查询出合法的id集
  103. $legalOrderList = $this->model()->getListByOrderIds(array_keys($orderList), $orderType);
  104. // 遍历合法的订单信息
  105. $legalList = [];
  106. foreach ($legalOrderList as $item) {
  107. $legalList[$item['id']] = $orderList[$item['order_id']];
  108. }
  109. return $legalList;
  110. }
  111. /**
  112. * 删除好物圈订单记录
  113. * @param array $id 订单同步记录id
  114. * @return bool
  115. * @throws \app\common\exception\BaseException
  116. * @throws \think\exception\DbException
  117. */
  118. public function delete($id)
  119. {
  120. // 实例化模型
  121. $model = $this->model($id, ['user']);
  122. // 执行api请求
  123. $status = $this->ApiDriver->delete($model['user']['open_id'], $model['order_id']);
  124. if ($status == false) {
  125. $this->error = $this->ApiDriver->getError();
  126. }
  127. // 删除订单记录
  128. $model->setDelete();
  129. return true;
  130. }
  131. /**
  132. * 返回错误信息
  133. * @return mixed
  134. */
  135. public function getError()
  136. {
  137. return $this->error;
  138. }
  139. /**
  140. * 返回商城id
  141. * @return mixed
  142. */
  143. public function getWxappId()
  144. {
  145. return $this->wxappId;
  146. }
  147. /**
  148. * 实例化微信api驱动
  149. * @throws \app\common\exception\BaseException
  150. * @throws \think\exception\DbException
  151. */
  152. private function initApiDriver()
  153. {
  154. $config = WxappModel::getWxappCache($this->wxappId);
  155. $this->ApiDriver = new WowOrder($config['app_id'], $config['app_secret']);
  156. }
  157. /**
  158. * 获取好物圈订单记录模型
  159. * @param int|null $id
  160. * @param array $with
  161. * @return OrderModel|null
  162. * @throws \think\exception\DbException
  163. */
  164. private function model($id = null, $with = ['user'])
  165. {
  166. static $model;
  167. if (!$model instanceof OrderModel) {
  168. $model = $id > 0 ? OrderModel::detail($id, $with) : (new OrderModel);
  169. }
  170. return $model;
  171. }
  172. /**
  173. * 整理订单列表 (用于添加好物圈接口)
  174. * @param $orderList
  175. * @param bool $isCreate 是否为创建新订单
  176. * @return array
  177. */
  178. private function getOrderList($orderList, $isCreate = false)
  179. {
  180. // 整理api参数
  181. $data = [];
  182. foreach ($orderList as $order) {
  183. // 商品列表
  184. $goodsList = $this->getProductList($order['goods']);
  185. // 订单记录
  186. $item = [
  187. 'order_id' => $order['order_id'],
  188. 'trans_id' => $order['transaction_id'], // 微信支付交易单号
  189. 'status' => self::getStatusByOrder($order), // 订单状态,3:支付完成 4:已发货 5:已退款 100: 已完成
  190. 'ext_info' => [
  191. 'user_open_id' => $order['user']['open_id'],
  192. 'order_detail_page' => [
  193. 'path' => "pages/order/detail?order_id={$order['order_id']}"
  194. ],
  195. ],
  196. ];
  197. // 用于更新订单的参数
  198. if ($isCreate == false) {
  199. // 快递及包裹信息
  200. // 条件1:配送方式为快递配送
  201. // 条件2: 订单已发货
  202. if (
  203. $order['delivery_type']['value'] == DeliveryTypeEnum::EXPRESS
  204. && $order['delivery_status']['value'] == 20
  205. ) {
  206. $item['ext_info']['express_info']['express_package_info_list'] = [[
  207. 'express_company_id' => $order['express']['express_id'], // 快递公司id
  208. 'express_company_name' => $order['express']['express_name'], // 快递公司名
  209. 'express_code' => $order['express_no'], // 快递单号
  210. 'ship_time' => $order['delivery_time'], // 发货时间
  211. 'express_page' => [
  212. 'path' => "pages/order/detail?order_id={$order['order_id']}"
  213. ],
  214. 'express_goods_info_list' => helper::getArrayColumns($goodsList, ['item_code', 'sku_id'])
  215. ]];
  216. }
  217. }
  218. // 用于新增订单的参数
  219. if ($isCreate == true) {
  220. // 订单创建时间
  221. $item['create_time'] = $order['create_time'];
  222. // 支付完成时间
  223. $item['pay_finish_time'] = $order['pay_time'];
  224. // 订单金额,单位:分
  225. $item['fee'] = $order['pay_price'] * 100;
  226. // 订单支付方式,0:未知方式 1:微信支付 2:其他支付方式
  227. $item['ext_info']['payment_method'] = $order['pay_type']['value'] == PayTypeEnum::WECHAT ? 1 : 2;
  228. // 商品列表
  229. $item['ext_info']['product_info'] = ['item_list' => $goodsList];
  230. // 收件人信息
  231. $item['ext_info']['express_info'] = array_merge(
  232. $this->getAddressInfo($order['delivery_type']['value'], $order['address']),
  233. ['price' => $order['express_price'] * 100] // 运费
  234. );
  235. // todo: 商家信息
  236. $item['ext_info']['brand_info'] = [
  237. 'phone' => '020-666666', // 必填:联系电话
  238. 'contact_detail_page' => [
  239. 'kf_type' => 3,
  240. 'path' => 'pages/index/index',
  241. ],
  242. ];
  243. }
  244. $data[] = $item;
  245. }
  246. return $data;
  247. }
  248. /**
  249. * 整理订单状态码
  250. * 订单状态,3:支付完成 4:已发货 5:已退款 100: 已完成
  251. * @param array $order
  252. * @return bool|int
  253. */
  254. public static function getStatusByOrder($order)
  255. {
  256. // 未付款
  257. if ($order['pay_status']['value'] != 20) {
  258. return (int)false;
  259. }
  260. // 已退款
  261. if ($order['order_status']['value'] == 20) {
  262. return 5;
  263. }
  264. // 已完成
  265. if ($order['order_status']['value'] == 30) {
  266. return 100;
  267. }
  268. // 支付完成(未发货)
  269. if ($order['delivery_status']['value'] == 10) {
  270. return 3;
  271. }
  272. // 已发货
  273. if ($order['delivery_status']['value'] == 20) {
  274. return 4;
  275. }
  276. return (int)false;
  277. }
  278. /**
  279. * 订单状态,3:支付完成 4:已发货 5:已退款 100: 已完成
  280. * @return array
  281. */
  282. public static function status()
  283. {
  284. return [
  285. 0 => '未知',
  286. 3 => '支付完成',
  287. 4 => '已发货',
  288. 5 => '已退款',
  289. 100 => '已完成',
  290. ];
  291. }
  292. /**
  293. * 整理商品列表
  294. * @param array $goodsList
  295. * @return array
  296. */
  297. private function getProductList($goodsList)
  298. {
  299. $data = [];
  300. foreach ($goodsList as $goods) {
  301. $data[] = [
  302. 'item_code' => $goods['goods_id'], // 物品id,要求appid下全局唯一
  303. 'sku_id' => $goods['goods_id'],
  304. 'amount' => $goods['total_num'], // 物品数量
  305. 'total_fee' => $goods['total_price'] * 100, // 物品总价,单位:分
  306. 'thumb_url' => $goods['image']['file_path'],
  307. 'title' => $goods['goods_name'], // 商品名称
  308. 'unit_price' => $goods['goods_price'] * 100, // 物品单价(实际售价)
  309. 'original_price' => $goods['line_price'] * 100, // 物品原价
  310. 'category_list' => ['商品分类'], // todo: 商品分类
  311. 'item_detail_page' => ['path' => "pages/goods/index?goods_id={$goods['goods_id']}"],
  312. ];
  313. }
  314. return $data;
  315. }
  316. /**
  317. * 整理收件人信息
  318. * @param int $deliveryType
  319. * @param array $express
  320. * @return array
  321. */
  322. private function getAddressInfo($deliveryType, $express)
  323. {
  324. // 快递信息
  325. $data = [];
  326. if ($deliveryType == DeliveryTypeEnum::EXPRESS) {
  327. $data = [
  328. 'name' => $express['name'], // 收件人姓名
  329. 'phone' => $express['phone'], // 收件人联系电话
  330. 'province' => $express['region']['province'], // 省
  331. 'city' => $express['region']['city'], // 市
  332. 'district' => $express['region']['region'], // 区
  333. ];
  334. // 详细地址
  335. $data['address'] = "{$data['province']} {$data['city']} {$data['district']} {$express['detail']}";
  336. }
  337. return $data;
  338. }
  339. }