Orders.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <?php
  2. namespace app\common\model;
  3. use app\admin\model\AdminMoneyLog;
  4. use app\common\service\UserSvc;
  5. use think\db\Query;
  6. use think\Model;
  7. use Yansongda\Supports\Arr;
  8. /**
  9. * @property OrderInfo[] info
  10. * @property OrderAddress address
  11. * @property OrderLogistics logistics
  12. * @property User user
  13. * @property bool is_wait_pay
  14. * @property bool is_wait_send
  15. * @property Payment payment
  16. * @property int user_id
  17. * @property int id
  18. * @property int status
  19. * @property int admin_id
  20. * @property string order_no
  21. * @property float amount_cmn
  22. * @property float amount_pay
  23. * @method static static payed()
  24. * @method static static statusPay()
  25. * @method Query hasGoods($goods_id)
  26. */
  27. class Orders extends Model
  28. {
  29. protected $type=[
  30. 'tax'=>'json',
  31. ];
  32. #未支付过期时间
  33. const EXP_PAY=1800;
  34. #线下付款超时
  35. const EXP_PAY_OFFLINE=3*86400;
  36. #代付超时
  37. const EXP_PAY_DF=3*86400;
  38. #待收货过期时间
  39. const EXP_REC=30*86400;
  40. #已完成可售后时间
  41. const EXP_OVER=7*86400;
  42. const PT_QYWY=1;
  43. const PT_WX=2;
  44. const PT_ZFB=3;
  45. const PT_YL=4;
  46. const PT_DF=5;
  47. const PT_OFF=6;
  48. public static $pay_types=[
  49. self::PT_QYWY=>'企业网银',
  50. self::PT_WX=>'微信',
  51. self::PT_ZFB=>'支付宝',
  52. self::PT_YL=>'银联',
  53. self::PT_DF=>'代付',
  54. self::PT_OFF=>'线下支付',
  55. ];
  56. const S_WAIT_PAY=0;
  57. const S_WAIT_SEND=5;
  58. const S_WAIT_REC=10;
  59. const S_OVER=20;
  60. const S_CANCEL=30;
  61. //const S_REFUND=40;
  62. public static $status=[
  63. self::S_WAIT_PAY=>'待支付',
  64. self::S_WAIT_SEND=>'待发货',
  65. self::S_WAIT_REC=>'待收货',
  66. self::S_OVER=>'已完成',
  67. self::S_CANCEL=>'已取消',
  68. //self::S_REFUND=>'退款退货',
  69. ];
  70. /**
  71. * @return string[]
  72. */
  73. public static function getStatus(): array
  74. {
  75. return self::$status;
  76. }
  77. protected $autoWriteTimestamp=true;
  78. public function info(){
  79. return $this->hasMany(OrderInfo::class,'order_id');
  80. }
  81. public function user(){
  82. return $this->belongsTo(User::class);
  83. }
  84. public function payment(){
  85. return $this->belongsTo(Payment::class);
  86. }
  87. public function address(){
  88. return $this->hasOne(OrderAddress::class,'order_id');
  89. }
  90. public function logistics(){
  91. return $this->hasOne(OrderLogistics::class,'order_id');
  92. }
  93. public function voucher(){
  94. return $this->hasOne(OrderVoucher::class,'order_id');
  95. }
  96. /*public function getGoodsAttr(){
  97. $info=$this->info()->with(['goodsBak'])->find();
  98. $goods=$info['goodsBak'];
  99. return [
  100. 'goods'=>$goods['goods'],
  101. 'sku'=>$goods['sku'],
  102. ];
  103. }*/
  104. public function getIsWaitPayAttr($_,$model){
  105. return $model['status']==self::S_WAIT_PAY;
  106. }
  107. public function getIsWaitSendAttr($_,$model){
  108. return $model['status']==self::S_WAIT_SEND;
  109. }
  110. public function getIsEvaledAttr($_,$model){
  111. $goodsIds=array_unique(OrderInfo::where('order_id',$model['id'])->column('goods_id'));
  112. $has=GoodsEval::where('order_id',$model['id'])->whereIn('goods_id',$goodsIds)->count();
  113. return $has==count($goodsIds);
  114. }
  115. public function getPayTypeTextAttr($_,$model){
  116. if(empty($model['pay_type'])){
  117. return null;
  118. }
  119. return self::getPayTypes()[$model['pay_type']];
  120. }
  121. /**
  122. * @return string[]
  123. */
  124. public static function getPayTypes(): array
  125. {
  126. return self::$pay_types;
  127. }
  128. public static function continue($status){
  129. $now=time();
  130. return self::where('status',$status)->limit(20)->where('continue_expire_time','<',$now);
  131. }
  132. #未支付过期
  133. public function makeCancel(){
  134. $this['status']=self::S_CANCEL;
  135. $this['cancel_time']=time();
  136. foreach ($this->info as $orderInfo){
  137. $stock=$orderInfo['is_kill']?'num_stock_kill':'num_stock';
  138. try {
  139. Goods::where('id',$orderInfo['goods_id'])->setDec('num_sell',$orderInfo['num']);
  140. }catch (\Exception $e){
  141. user_log('orders/cancel',"订单{$this['id']}减已售失败");
  142. }
  143. try {
  144. GoodsSku::where('id',$orderInfo['goods_sku_id'])->setDec('num_sell',$orderInfo['num']);
  145. }catch (\Exception $e){
  146. user_log('orders/cancel',"订单{$this['id']}减sku已售失败");
  147. }
  148. try {
  149. GoodsSku::where('id',$orderInfo['goods_sku_id'])->setInc($stock,$orderInfo['num']);
  150. }catch (\Exception $e){
  151. user_log('orders/cancel',"订单{$this['id']}增库存【{$stock}】失败");
  152. }
  153. }
  154. #返还优惠券
  155. $hasCoupon=$this->info()->where('coupon_id','>',0)->value('coupon_id');
  156. if($hasCoupon){
  157. UserCoupon::makeUse($hasCoupon,0);
  158. }
  159. $this->save();
  160. }
  161. #待收货过期
  162. public function makeRec(){
  163. $this->makeOver();
  164. }
  165. #支付
  166. public function makePayInfo($pay_type){
  167. $user=$this->user;
  168. if($pay_type==self::PT_OFF){
  169. $this['continue_expire_time']=strtotime(date('Y-m-d 00:00:00'))+self::EXP_PAY_OFFLINE+86400-1;
  170. $this->save();
  171. return [
  172. 'account_name'=>config('site.account_name'),
  173. 'bank_no'=>config('site.account_bank_no'),
  174. 'bank_name'=>config('site.accout_bank_name'),
  175. ];
  176. }elseif($pay_type==self::PT_DF){
  177. $this['continue_expire_time']=strtotime(date('Y-m-d 00:00:00'))+self::EXP_PAY_DF+86400-1;
  178. $this->save();
  179. return [
  180. 'expire'=>$this['continue_expire_time'],
  181. ];
  182. }else{
  183. $this['continue_expire_time']=time()+self::EXP_PAY;
  184. $this->save();
  185. }
  186. if($pay_type==self::PT_OFF){
  187. return [
  188. 'account_name'=>config('site.account_name'),
  189. 'bank_no'=>config('site.account_bank_no'),
  190. 'bank_name'=>config('site.accout_bank_name'),
  191. ];
  192. }
  193. return Payment::pay(
  194. $user,
  195. $pay_type,
  196. $this['amount_pay'],
  197. $this['id'],
  198. "订单【{$this['order_no']}】付款",
  199. $this->getTable()
  200. );
  201. }
  202. #支付后
  203. public static function makePayed(Payment $payment){
  204. $order=Orders::find($payment['payment_id']);
  205. if(!$order){
  206. return false;
  207. }
  208. if(!$order->isNotPay()){
  209. return false;
  210. }
  211. $order['payment_id']=$payment['id'];
  212. #代付
  213. if($order['user_id']!=$payment->user_id){
  214. }
  215. $order->save();
  216. $order->makePay($payment['pay_type']);
  217. return true;
  218. }
  219. public function makePay($payType=self::PT_OFF){
  220. $order=$this;
  221. $order['status']=self::S_WAIT_SEND;
  222. $order['pay_time']=time();
  223. $order['pay_type']=$payType;
  224. $order->save();
  225. }
  226. #发货
  227. public function makeSend($logistics,$data){
  228. $newData=Arr::only($data,['com_id','trans_no','remark']);
  229. if(!$logistics) {
  230. $this->logistics()->save($newData);
  231. $this['status']=self::S_WAIT_REC;
  232. $this['send_time']=time();
  233. $this->save();
  234. }else{
  235. $logistics->save($newData);
  236. }
  237. }
  238. #确认收货
  239. public function makeOver(){
  240. $this['status']=self::S_OVER;
  241. $this->save();
  242. }
  243. #发放提成
  244. public function makeSendCommission(){
  245. if($this->admin_id){
  246. AdminMoneyLog::money($this->admin_id,$this->amount_cmn,AdminMoneyLog::T_COMMISSION,$this['user_id'],$this['id']);
  247. }
  248. }
  249. /*
  250. * 是否未支付
  251. */
  252. public function isNotPay(){
  253. return $this['status']===self::S_WAIT_PAY;
  254. }
  255. /**
  256. * 是否允许退款
  257. */
  258. public function allowRefund(){
  259. if(in_array($this['status'],[
  260. self::S_WAIT_PAY,
  261. self::S_CANCEL,
  262. ])){
  263. throw_user('订单状态不允许售后');
  264. }
  265. /*if($this['status']==self::S_OVER && time()>$this['rec_time']+self::EXP_REC){
  266. throw_user('已过售后期');
  267. }*/
  268. }
  269. /**
  270. * 是否允许取消
  271. */
  272. public function allowCancel(){
  273. return in_array($this['status'],[
  274. self::S_WAIT_PAY,
  275. ]);
  276. }
  277. /**
  278. * 是否允许确认收货
  279. */
  280. public function allowOver(){
  281. return in_array($this['status'],[
  282. self::S_WAIT_REC,
  283. ]);
  284. }
  285. public function scopePayed(Query $query){
  286. $query->whereNotIn('status',[self::S_CANCEL,self::S_WAIT_PAY]);
  287. }
  288. public function scopeStatusPay(Query $query){
  289. $query->where('status',self::S_WAIT_SEND);
  290. }
  291. public function scopeHasGoods(Query $query,$goods_id){
  292. $query->whereExists(
  293. OrderInfo::whereRaw("orders.id=order_info.order_id and order_info.goods_id={$goods_id}")->buildSql()
  294. );
  295. }
  296. protected static function init()
  297. {
  298. self::beforeInsert(function (self $orders){
  299. #优惠总金额
  300. //$orders['amount_discount']=bcAddAll($orders['amount_coupon']??0,$orders['amount_coupon_kill']);
  301. #过期时间
  302. $orders['continue_expire_time']=time()+self::EXP_PAY;
  303. #去除无发票的
  304. if(empty($orders['tax']) || !in_array($orders['tax']['paper_type']??0,[1,2])){
  305. $orders['tax']=null;
  306. }
  307. #属于哪个销售员
  308. $orders['admin_id']=UserSvc::getSellerId($orders->user_id);
  309. });
  310. self::afterInsert(function (self $orders){
  311. #添加发票
  312. UserTax::fromOrder($orders);
  313. #合同链接
  314. $contract_link=request()->root(true)."/contract/view/show/{$orders['id']}";
  315. $orders->where('id',$orders['id'])->update([
  316. 'contract_link'=>$contract_link,
  317. ]);
  318. });
  319. self::beforeUpdate(function (self $order){
  320. $data=$order->getChangedData();
  321. if(!empty($data['status'])){
  322. #待发货
  323. if($data['status']==self::S_WAIT_SEND){
  324. $order['continue_expire_time']=null;
  325. }
  326. #已完成
  327. elseif($data['status']==self::S_OVER){
  328. $order['rec_time']=time();
  329. $order['continue_expire_time']=null;
  330. }
  331. #待收货过期时间
  332. elseif ($data['status']==self::S_WAIT_REC){
  333. $order['continue_expire_time']=time()+self::EXP_REC;
  334. }
  335. $order['status_pre']=$order->origin['status'];
  336. }
  337. if(isset($order['amount_profit']) && $order['amount_profit']<0){
  338. $order['amount_profit']=0;
  339. }
  340. if(isset($order['amount_profit_per']) && $order['amount_profit_per']<0){
  341. $order['amount_profit_per']=0;
  342. }
  343. if(isset($order['amount_cmn']) && $order['amount_cmn']<0){
  344. $order['amount_cmn']=0;
  345. }
  346. });
  347. self::afterUpdate(function (self $orders){
  348. if(!empty($orders->status) && $orders->status==self::S_WAIT_SEND){
  349. Transaction::addTransaction($orders);
  350. }
  351. #如果已完成发放提成
  352. if(!empty($orders->status) && $orders->status==self::S_OVER){
  353. $orders->makeSendCommission();
  354. }
  355. });
  356. }
  357. }