Order.php 12 KB

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