Order.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. <?php
  2. namespace app\admin\model\shopro\order;
  3. use app\admin\model\shopro\Common;
  4. use traits\model\SoftDelete;
  5. use app\admin\model\shopro\user\User;
  6. use app\admin\model\shopro\Pay as PayModel;
  7. use app\admin\model\shopro\activity\Activity;
  8. use app\admin\model\shopro\order\traits\OrderScope;
  9. use app\admin\model\shopro\order\traits\OrderStatus;
  10. use app\admin\model\shopro\activity\Order as ActivityOrder;
  11. class Order extends Common
  12. {
  13. use SoftDelete, OrderScope, OrderStatus;
  14. protected $name = 'shopro_order';
  15. protected $deleteTime = 'deletetime';
  16. protected $type = [
  17. 'ext' => 'json',
  18. 'paid_time' => 'timestamp',
  19. ];
  20. // 追加属性
  21. protected $append = [
  22. 'type_text',
  23. 'status_code',
  24. 'status_text',
  25. 'status_desc',
  26. 'apply_refund_status_text',
  27. 'btns',
  28. 'platform_text',
  29. 'activity_type_text',
  30. 'promo_types_text',
  31. 'wechat_extra_data'
  32. ];
  33. // 订单状态
  34. const STATUS_CLOSED = 'closed';
  35. const STATUS_CANCEL = 'cancel';
  36. const STATUS_UNPAID = 'unpaid';
  37. const STATUS_PAID = 'paid';
  38. const STATUS_COMPLETED = 'completed';
  39. const STATUS_PENDING = 'pending'; // 待定 后付款
  40. const APPLY_REFUND_STATUS_NOAPPLY = 0;
  41. const APPLY_REFUND_STATUS_APPLY = 1;
  42. const APPLY_REFUND_STATUS_FINISH = 2;
  43. const APPLY_REFUND_STATUS_REFUSE = -1;
  44. public function statusList()
  45. {
  46. return [
  47. 'closed' => '交易关闭',
  48. 'cancel' => '已取消',
  49. 'unpaid' => '未支付',
  50. 'pending' => '待定', // 货到付款未付款状态
  51. 'paid' => '已支付',
  52. 'completed' => '已完成'
  53. ];
  54. }
  55. public function applyRefundStatusList()
  56. {
  57. return [
  58. self::APPLY_REFUND_STATUS_NOAPPLY => '未申请',
  59. self::APPLY_REFUND_STATUS_APPLY => '申请退款',
  60. self::APPLY_REFUND_STATUS_FINISH => '退款完成',
  61. self::APPLY_REFUND_STATUS_REFUSE => '拒绝申请'
  62. ];
  63. }
  64. /**
  65. * 订单列表状态搜索
  66. */
  67. public function searchStatusList()
  68. {
  69. return [
  70. 'unpaid' => '待付款',
  71. 'paid' => '已支付', // 包括刚支付的,发货中,和已退款的,以及已完成的所有付过款的订单,不包含货到付款还未真实付款的订单
  72. 'nosend' => '待发货',
  73. 'noget' => '待收货',
  74. 'refuse' => '已拒收',
  75. 'nocomment' => '待评价',
  76. 'completed' => '已完成',
  77. 'aftersale' => '售后',
  78. 'applyRefundIng' => '申请退款',
  79. 'refund' => '已退款',
  80. 'cancel' => '已取消',
  81. 'closed' => '交易关闭', // 包含货到付款,拒收的商品
  82. ];
  83. }
  84. public function typeList()
  85. {
  86. return [
  87. 'goods' => '商城订单',
  88. 'score' => '积分订单'
  89. ];
  90. }
  91. public function platformList()
  92. {
  93. return [
  94. 'H5' => 'H5',
  95. 'WechatOfficialAccount' => '微信公众号',
  96. 'WechatMiniProgram' => '微信小程序',
  97. 'App' => 'App',
  98. ];
  99. }
  100. public function getExtAttr($value, $data)
  101. {
  102. $ext = (isset($data['ext']) && $data['ext']) ? json_decode($data['ext'], true) : [];
  103. // 每类活动优惠金额聚合(可能订单购买多个商品,然后同时参与了两种满减,金额累加)
  104. $ext['promo_discounts'] = [
  105. 'full_reduce' => 0,
  106. 'full_discount' => 0,
  107. 'free_shipping' => 0,
  108. 'full_gift' => 0
  109. ];
  110. if ($ext && isset($ext['promo_infos']) && $ext['promo_infos']) {
  111. foreach ($ext['promo_infos'] as $key => $info) {
  112. if ($info['activity_type'] == 'full_gift') {
  113. $ext['promo_discounts']['full_gift'] = 1;
  114. continue;
  115. }
  116. $ext['promo_discounts'][$info['activity_type']] = bcadd((string)$ext['promo_discounts'][$info['activity_type']], (string)$info['promo_discount_money'], 2);
  117. }
  118. }
  119. // 格式化
  120. $ext['promo_discounts'] = array_map(function ($value) {
  121. return number_format(floatval($value), 2, '.', '');
  122. }, $ext['promo_discounts']);
  123. // 处理时间
  124. if (isset($ext['closed_time']) && $ext['closed_time']) {
  125. $ext['closed_date'] = date('Y-m-d H:i:s', $ext['closed_time']);
  126. }
  127. if (isset($ext['cancel_time']) && $ext['cancel_time']) {
  128. $ext['cancel_date'] = date('Y-m-d H:i:s', $ext['cancel_time']);
  129. }
  130. if (isset($ext['pending_time']) && $ext['pending_time']) {
  131. $ext['pending_date'] = date('Y-m-d H:i:s', $ext['pending_time']);
  132. }
  133. if (isset($ext['apply_refund_time']) && $ext['apply_refund_time']) {
  134. $ext['apply_refund_date'] = date('Y-m-d H:i:s', $ext['apply_refund_time']);
  135. }
  136. if (isset($ext['send_time']) && $ext['send_time']) {
  137. $ext['send_date'] = date('Y-m-d H:i:s', $ext['send_time']);
  138. }
  139. if (isset($ext['confirm_time']) && $ext['confirm_time']) {
  140. $ext['confirm_date'] = date('Y-m-d H:i:s', $ext['confirm_time']);
  141. }
  142. if (isset($ext['comment_time']) && $ext['comment_time']) {
  143. $ext['comment_date'] = date('Y-m-d H:i:s', $ext['comment_time']);
  144. }
  145. if (isset($ext['completed_time']) && $ext['completed_time']) {
  146. $ext['completed_date'] = date('Y-m-d H:i:s', $ext['completed_time']);
  147. }
  148. if (isset($ext['refund_time']) && $ext['refund_time']) {
  149. $ext['refund_date'] = date('Y-m-d H:i:s', $ext['refund_time']);
  150. }
  151. return $ext;
  152. }
  153. public function getPlatformTextAttr($value, $data)
  154. {
  155. $value = $value ?: ($data['platform'] ?? null);
  156. $list = $this->platformList();
  157. return isset($list[$value]) ? $list[$value] : '';
  158. }
  159. /**
  160. * 微信小程序发货信息管理所需参数
  161. *
  162. * @param string|null $value
  163. * @param array $data
  164. * @return array
  165. */
  166. public function getWechatExtraDataAttr($value, $data)
  167. {
  168. $extraData = [];
  169. if (strpos(request()->url(), 'addons/shopro') !== false && $data['platform'] == 'WechatMiniProgram') {
  170. // 前端接口,并且是 微信小程序订单,才返这个参数
  171. $pays = $this->pays;
  172. foreach ($pays as $pay) {
  173. if ($pay->status != PayModel::PAY_STATUS_UNPAID && $pay->pay_type == 'wechat') {
  174. $extraData['merchant_trade_no'] = $pay->pay_sn;
  175. $extraData['transaction_id'] = $pay->transaction_id;
  176. }
  177. }
  178. }
  179. return $extraData;
  180. }
  181. /**
  182. * 申请退款状态
  183. *
  184. * @param string $value
  185. * @param array $data
  186. * @return string
  187. */
  188. public function getApplyRefundStatusTextAttr($value, $data)
  189. {
  190. $value = $value ?: ($data['apply_refund_status'] ?? null);
  191. $list = $this->applyRefundStatusList();
  192. return isset($list[$value]) ? $list[$value] : '';
  193. }
  194. public function getActivityTypeTextAttr($value, $data)
  195. {
  196. $value = $value ?: ($data['activity_type'] ?? null);
  197. $ext = $this->ext;
  198. $list = (new Activity)->typeList();
  199. $text = isset($list[$value]) ? $list[$value] : '';
  200. if (in_array($value, ['groupon', 'groupon_ladder'])) {
  201. // 订单已支付的,或者线下支付(货到付款)的
  202. if ((in_array($data['status'], [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data))
  203. && (!isset($ext['groupon_id']) || !$ext['groupon_id']))
  204. {
  205. // 已支付,并且没有团 id,就是单独购买
  206. $text .= '-单独购买';
  207. }
  208. }
  209. return $text;
  210. }
  211. public function getPromoTypesTextAttr($value, $data)
  212. {
  213. $value = $value ?: ($data['promo_types'] ?? null);
  214. $promoTypes = array_filter(explode(',', $value));
  215. $texts = [];
  216. $list = (new Activity)->typeList();
  217. foreach ($promoTypes as $type) {
  218. $text = isset($list[$type]) ? $list[$type] : '';
  219. if ($text) {
  220. $texts[] = $text;
  221. }
  222. }
  223. return $texts;
  224. }
  225. /**
  226. * 已支付订单,支付类型
  227. *
  228. * @param string $value
  229. * @param array $data
  230. * @return void
  231. */
  232. public function getPayTypesAttr($value, $data)
  233. {
  234. $status = $data['status'] ?? '';
  235. $payTypes = [];
  236. // 订单已支付的,或者线下支付(货到付款)的
  237. if (in_array($status, [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data)) {
  238. $payTypes = PayModel::typeOrder()->where('order_id', $data['id'])->where('status', '<>', PayModel::PAY_STATUS_UNPAID)->group('pay_type')->column('pay_type');
  239. }
  240. return $payTypes;
  241. }
  242. /**
  243. * 已支付订单,支付类型文字
  244. *
  245. * @param string $value
  246. * @param array $data
  247. * @return void
  248. */
  249. public function getPayTypesTextAttr($value, $data)
  250. {
  251. $payTypes = $this->pay_types;
  252. $list = (new PayModel)->payTypeList();
  253. $texts = [];
  254. foreach ($payTypes as $pay_type) {
  255. $text = isset($list[$pay_type]) ? $list[$pay_type] : '';
  256. if ($text) {
  257. $texts[] = $text;
  258. }
  259. }
  260. return $texts;
  261. }
  262. public function getExpressAttr($value, $data)
  263. {
  264. return Express::with(['items', 'logs'])->where('order_id', $data['id'])->select();
  265. }
  266. public function items()
  267. {
  268. return $this->hasMany(OrderItem::class, 'order_id', 'id');
  269. }
  270. public function user()
  271. {
  272. return $this->belongsTo(User::class, 'user_id', 'id');
  273. }
  274. public function aftersales()
  275. {
  276. return $this->hasMany(Aftersale::class, 'order_id')->order('id', 'desc');
  277. }
  278. public function address()
  279. {
  280. return $this->hasOne(Address::class, 'order_id', 'id');
  281. }
  282. public function invoice()
  283. {
  284. return $this->hasOne(Invoice::class, 'order_id', 'id');
  285. }
  286. public function pays()
  287. {
  288. return $this->hasMany(PayModel::class, 'order_id', 'id')->typeOrder()->order('id', 'desc');
  289. }
  290. public function activityOrders()
  291. {
  292. return $this->hasMany(ActivityOrder::class, 'order_id');
  293. }
  294. }