Order.php 11 KB

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