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. //申请退款状态
  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. return $ext;
  153. }
  154. public function getPlatformTextAttr($value, $data)
  155. {
  156. $value = $value ?: ($data['platform'] ?? null);
  157. $list = $this->platformList();
  158. return isset($list[$value]) ? $list[$value] : '';
  159. }
  160. /**
  161. * 微信小程序发货信息管理所需参数
  162. *
  163. * @param string|null $value
  164. * @param array $data
  165. * @return array
  166. */
  167. public function getWechatExtraDataAttr($value, $data)
  168. {
  169. $extraData = [];
  170. if (strpos(request()->url(), 'addons/shopro') !== false && $data['platform'] == 'WechatMiniProgram') {
  171. // 前端接口,并且是 微信小程序订单,才返这个参数
  172. $pays = $this->pays;
  173. foreach ($pays as $pay) {
  174. if ($pay->status != PayModel::PAY_STATUS_UNPAID && $pay->pay_type == 'wechat') {
  175. $extraData['merchant_trade_no'] = $pay->pay_sn;
  176. $extraData['transaction_id'] = $pay->transaction_id;
  177. }
  178. }
  179. }
  180. return $extraData;
  181. }
  182. /**
  183. * 申请退款状态
  184. *
  185. * @param string $value
  186. * @param array $data
  187. * @return string
  188. */
  189. public function getApplyRefundStatusTextAttr($value, $data)
  190. {
  191. $value = $value ?: ($data['apply_refund_status'] ?? null);
  192. $list = $this->applyRefundStatusList();
  193. return isset($list[$value]) ? $list[$value] : '';
  194. }
  195. public function getActivityTypeTextAttr($value, $data)
  196. {
  197. $value = $value ?: ($data['activity_type'] ?? null);
  198. $ext = $this->ext;
  199. $list = (new Activity)->typeList();
  200. $text = isset($list[$value]) ? $list[$value] : '';
  201. if (in_array($value, ['groupon', 'groupon_ladder'])) {
  202. // 订单已支付的,或者线下支付(货到付款)的
  203. if ((in_array($data['status'], [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data))
  204. && (!isset($ext['groupon_id']) || !$ext['groupon_id']))
  205. {
  206. // 已支付,并且没有团 id,就是单独购买
  207. $text .= '-单独购买';
  208. }
  209. }
  210. return $text;
  211. }
  212. public function getPromoTypesTextAttr($value, $data)
  213. {
  214. $value = $value ?: ($data['promo_types'] ?? null);
  215. $promoTypes = array_filter(explode(',', $value));
  216. $texts = [];
  217. $list = (new Activity)->typeList();
  218. foreach ($promoTypes as $type) {
  219. $text = isset($list[$type]) ? $list[$type] : '';
  220. if ($text) {
  221. $texts[] = $text;
  222. }
  223. }
  224. return $texts;
  225. }
  226. /**
  227. * 已支付订单,支付类型
  228. *
  229. * @param string $value
  230. * @param array $data
  231. * @return void
  232. */
  233. public function getPayTypesAttr($value, $data)
  234. {
  235. $status = $data['status'] ?? '';
  236. $payTypes = [];
  237. // 订单已支付的,或者线下支付(货到付款)的
  238. if (in_array($status, [self::STATUS_PAID, self::STATUS_COMPLETED]) || $this->isOffline($data)) {
  239. $payTypes = PayModel::typeOrder()->where('order_id', $data['id'])->where('status', '<>', PayModel::PAY_STATUS_UNPAID)->group('pay_type')->column('pay_type');
  240. }
  241. return $payTypes;
  242. }
  243. /**
  244. * 已支付订单,支付类型文字
  245. *
  246. * @param string $value
  247. * @param array $data
  248. * @return void
  249. */
  250. public function getPayTypesTextAttr($value, $data)
  251. {
  252. $payTypes = $this->pay_types;
  253. $list = (new PayModel)->payTypeList();
  254. $texts = [];
  255. foreach ($payTypes as $pay_type) {
  256. $text = isset($list[$pay_type]) ? $list[$pay_type] : '';
  257. if ($text) {
  258. $texts[] = $text;
  259. }
  260. }
  261. return $texts;
  262. }
  263. public function getExpressAttr($value, $data)
  264. {
  265. return Express::with(['items', 'logs'])->where('order_id', $data['id'])->select();
  266. }
  267. public function items()
  268. {
  269. return $this->hasMany(OrderItem::class, 'order_id', 'id');
  270. }
  271. public function user()
  272. {
  273. return $this->belongsTo(User::class, 'user_id', 'id');
  274. }
  275. public function aftersales()
  276. {
  277. return $this->hasMany(Aftersale::class, 'order_id')->order('id', 'desc');
  278. }
  279. public function address()
  280. {
  281. return $this->hasOne(Address::class, 'order_id', 'id');
  282. }
  283. public function invoice()
  284. {
  285. return $this->hasOne(Invoice::class, 'order_id', 'id');
  286. }
  287. public function pays()
  288. {
  289. return $this->hasMany(PayModel::class, 'order_id', 'id')->typeOrder()->order('id', 'desc');
  290. }
  291. public function activityOrders()
  292. {
  293. return $this->hasMany(ActivityOrder::class, 'order_id');
  294. }
  295. }