DepositPresaleOrder.php 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322
  1. <?php
  2. namespace addons\DepositPresale\common\models;
  3. use addons\Coupon\common\models\AddonsCouponUserRelate;
  4. use addons\DepositPresale\common\enums\DepositPresaleEnum;
  5. use addons\DepositPresale\common\events\order\OrderCreateEvent as DepositOrderCreateEvent;
  6. use common\enums\GoodsTypeEnum;
  7. use common\enums\RedisKeyEnum;
  8. use common\enums\OrderStatusEnum;
  9. use common\enums\StatusEnum;
  10. use addons\DepositPresale\common\events\order\OrderPaidEvent;
  11. use addons\DepositPresale\common\helpers\sms\Sms;
  12. use addons\DepositPresale\common\helpers\wechat\WechatTemplate;
  13. use common\enums\UserWalletEnum;
  14. use common\events\order\OrderCloseEvent;
  15. use common\events\order\OrderCreateEvent;
  16. use common\helpers\FormatHelper;
  17. use common\helpers\LockHelper;
  18. use common\helpers\StringHelper;
  19. use common\models\base\BaseActiveRecord;
  20. use common\models\cart\Cart;
  21. use common\models\common\PaymentTrade;
  22. use common\models\common\PaymentTradeOrder;
  23. use common\models\common\PaymentTransfer;
  24. use common\models\goods\Goods;
  25. use common\models\goods\GoodsAttr;
  26. use common\models\order\Order;
  27. use common\models\order\OrderAction;
  28. use common\models\order\OrderDetail;
  29. use common\models\order\OrderMarketing;
  30. use common\models\user\User;
  31. use services\common\UserWalletService;
  32. use Yii;
  33. use yii\helpers\Json;
  34. use Exception;
  35. /**
  36. * This is the model class for table "qimall_addons_deposit_presale_order".
  37. *
  38. * @property int $id id
  39. * @property int $mall_id 商城ID
  40. * @property int $mch_id 商户ID
  41. * @property int $user_id 用户ID
  42. * @property int $order_id 主订单表id
  43. * @property string $order_no 订单编号
  44. * @property string $out_trade_no 外部交易号
  45. * @property string $final_out_trade_no 外部交易号(尾款)
  46. * @property int $deposit_presale_active_id 定金预售活动id
  47. * @property int $open_group_id 开团id
  48. * @property int $commander_id 定金预售长id
  49. * @property int $is_commander 是否团长 0:否:1:是
  50. * @property int $goods_id 商品id
  51. * @property int $goods_name 商品名称
  52. * @property int $goods_attr_name 商品规格名称
  53. * @property string $pic_url 商品图片
  54. * @property int $goods_attr_id 商品规格id
  55. * @property int $order_status 定金预售状态 0待支付 1参团中 2定金预售成功 3定金预售失败
  56. * @property int $shipping_type 快递方式
  57. * @property float $shipping_money 运费
  58. * @property float $price 商品原销售价格
  59. * @property float $deposit_presale_price 定金预售商品价格
  60. * @property int $num 购买数量
  61. * @property int $win_time 拼中时间
  62. * @property int $payment_type 支付方式:1.在线支付 2.货到付款 3.余额支付
  63. * @property int $pay_time 支付时间
  64. * @property int $final_payment_time 尾款支付时间
  65. * @property float $deposit_price 应付定金(活动创建时设定的)
  66. * @property float $actual_deposit_paid 实际支付的定金
  67. * @property float $total_pay_price 实际支付总费用(含运费)
  68. * @property string $remark 用户订单备注
  69. * @property int $is_pay 是否支付:0.未支付|1.已支付
  70. * @property int $status 状态[-1:删除;0:禁用;1启用]
  71. * @property int $created_at 创建时间
  72. * @property int $updated_at 更新时间
  73. * @property string|null $mobile 收货人的手机号码
  74. * @property string|null $receiver_name 收货人姓名
  75. * @property int|null $province 收货人所在省
  76. * @property int|null $city 收货人所在城市
  77. * @property int|null $area 收货人所在街道
  78. * @property string|null $zip 收货人邮编
  79. * @property string|null $address 详细地址
  80. * @property string|null $region_name 地区名称(省市区[乡/镇])
  81. */
  82. class DepositPresaleOrder extends BaseActiveRecord
  83. {
  84. /**
  85. * {@inheritdoc}
  86. */
  87. public static function tableName()
  88. {
  89. return '{{%addons_deposit_presale_order}}';
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function rules()
  95. {
  96. return [
  97. [['mch_id', 'mall_id', 'user_id', 'order_id', 'deposit_presale_active_id', 'open_group_id', 'commander_id', 'is_commander', 'goods_id', 'goods_attr_id', 'order_status', 'num', 'win_time', 'payment_type', 'pay_time', 'shipping_type', 'is_pay', 'status', 'created_at', 'updated_at', 'province', 'city', 'area', 'final_payment_time'], 'integer'],
  98. [['order_no'], 'required'],
  99. [['shipping_money', 'price', 'deposit_presale_price', 'total_pay_price', 'actual_deposit_paid', 'deposit_price'], 'number'],
  100. [['order_no', 'out_trade_no', 'final_out_trade_no'], 'string', 'max' => 50],
  101. [['remark', 'goods_name', 'goods_attr_name', 'pic_url'], 'string', 'max' => 255],
  102. [['mobile'], 'string', 'max' => 11],
  103. [['receiver_name'], 'string', 'max' => 50],
  104. [['zip'], 'string', 'max' => 20],
  105. [['address', 'region_name'], 'string', 'max' => 200],
  106. ];
  107. }
  108. /**
  109. * {@inheritdoc}
  110. */
  111. public function attributeLabels()
  112. {
  113. return [
  114. 'id' => 'id',
  115. 'mall_id' => '商城ID',
  116. 'mch_id' => '商户id',
  117. 'user_id' => '用户ID',
  118. 'order_id' => '主订单表id',
  119. 'order_no' => '订单编号',
  120. 'out_trade_no' => '外部交易号',
  121. 'final_out_trade_no' => '外部交易号(尾款)',
  122. 'deposit_presale_active_id' => '定金预售活动id',
  123. 'open_group_id' => '开团id',
  124. 'commander_id' => '定金预售长id',
  125. 'is_commander' => '是否团长 0:否:1:是',
  126. 'goods_id' => '商品id',
  127. 'goods_attr_id' => '商品规格id',
  128. 'pic_url' => '商品图片',
  129. 'order_status' => '定金预售状态 0待支付 1参团中 2定金预售成功 3定金预售失败',
  130. 'price' => '商品原销售价格',
  131. 'deposit_presale_price' => '定金预售商品价格',
  132. 'actual_deposit_paid' => '实际支付的定金',
  133. 'deposit_payable' => '应付定金(活动创建设定的)',
  134. 'num' => '购买数量',
  135. 'win_time' => '拼中时间',
  136. 'payment_type' => '支付方式:1.在线支付 2.货到付款 3.余额支付',
  137. 'pay_time' => '支付时间',
  138. 'final_payment_time' => '尾款支付时间',
  139. 'total_pay_price' => '实际支付总费用(含运费)',
  140. 'remark' => '用户订单备注',
  141. 'is_pay' => '是否支付:0.未支付|1.已支付',
  142. 'status' => '状态[-1:删除;0:禁用;1启用]',
  143. 'created_at' => '创建时间',
  144. 'updated_at' => '更新时间',
  145. 'mobile' => '收货人的手机号码',
  146. 'receiver_name' => '收货人姓名',
  147. 'province' => '收货人所在省',
  148. 'city' => '收货人所在城市',
  149. 'area' => '收货人所在街道',
  150. 'zip' => '收货人邮编',
  151. 'address' => '详细地址',
  152. 'region_name' => '地区名称(省市区[乡/镇])',
  153. ];
  154. }
  155. // 关联模型
  156. public function getUser()
  157. {
  158. return $this->hasOne(User::class, ['id' => 'user_id']);
  159. }
  160. public function getDepositPresaleActive()
  161. {
  162. return $this->hasOne(DepositPresaleActive::class, ['id' => 'deposit_presale_active_id']);
  163. }
  164. public function getMainOrder()
  165. {
  166. return $this->hasOne(Order::class, ['id' => 'order_id']);
  167. }
  168. /**
  169. * @desc:生成订单
  170. * @Author: hua
  171. * @Date: 2021/12/15
  172. * @Time: 15:14
  173. * @Copyright: copyright (c) 2021 广东七件事集团
  174. * @param $form
  175. * @return array|false
  176. */
  177. public static function createOrder($form)
  178. {
  179. $stock_locks = [];
  180. try {
  181. $group_order_goods = $form['group_order_goods'];
  182. $data = is_array($form->data) ? $form->data : Json::decode($form->data, true);
  183. $trans = Yii::$app->db->beginTransaction();
  184. // 生成主商城订单
  185. $order_ids = self::generateMainOrder($group_order_goods, $form, $data);
  186. $order_trade_info = [];
  187. $goods_stock_arr = [];
  188. $open_group_id = 0;
  189. //只有一个订单
  190. $order_id_arr = [];
  191. // 生成活动订单
  192. foreach ($group_order_goods as $mch_order) {
  193. $mch_order_info = $mch_order['mch_order_info'];
  194. $order = new DepositPresaleOrder();
  195. $order->loadDefaultValues();
  196. $order->load($mch_order_info, '');
  197. $order->remark = $data['remark'];
  198. $order->order_status = OrderStatusEnum::NOT_PAY;
  199. $order->total_pay_price = $mch_order_info['pay_money'];
  200. $order->actual_deposit_paid = $mch_order_info['pay_money'];
  201. $order->order_no = StringHelper::generateOrderNo('dp');
  202. $order->order_id = $order_ids[0];
  203. $res = $order->save();
  204. if ($res === false) throw new \Exception($order->getErrorMessage());
  205. $order_id_arr[] = $order->id;
  206. if (empty($mch_order_info['open_group_id'])) {
  207. $order->open_group_id = $order->id;
  208. $order->save();
  209. }
  210. $open_group_id = $order->open_group_id;
  211. // 总商品库存维护
  212. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR, $mch_order_info['goods_attr_id']);
  213. $identification = uniqid();
  214. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多');
  215. $stock_locks[$lock_key] = $identification;
  216. //操作商品库存-减
  217. DepositPresaleActiveGoodsAttr::handleStock($form['mall_id'], $mch_order_info['deposit_presale_active_id'], $mch_order_info['goods_attr_id'], $mch_order_info['num'] * -1);
  218. if (!isset($goods_stock_arr[$mch_order_info['goods_id']])) {
  219. $goods_stock_arr[$mch_order_info['goods_id']] = $mch_order_info['num'];
  220. } else {
  221. $goods_stock_arr[$mch_order_info['goods_id']] += $mch_order_info['num'];
  222. }
  223. $order_trade_info[] = [
  224. 'order_no' => $order->order_no,
  225. 'amount' => $order->total_pay_price,
  226. 'title' => mb_strlen($mch_order_info['goods_name']) > 32 ? mb_substr($mch_order_info['goods_name'], 0, 32) : $mch_order_info['goods_name'],
  227. 'notify_class' => DepositPresaleEnum::NOTIFY_CLASS,
  228. 'order_type' => DepositPresaleEnum::ADDONS_NAME,
  229. ];
  230. foreach ($goods_stock_arr as $goods_id => $num) {
  231. $active_model = DepositPresaleActive::findOne(['mall_id' => $form['mall_id'], 'id' => $data['active_id'], 'goods_id' => $goods_id]);
  232. $active_model->goods_stock -= $num;
  233. $active_model->save();
  234. }
  235. }
  236. // if($order){
  237. // OrderAction::create("手机号为:{$order->mobile}用户订单创建成功", $order_ids[0], 0, $order->user_id, $order->receiver_name);
  238. // }
  239. $trans->commit();
  240. LockHelper::batchUlock($stock_locks);
  241. //生成支付流水
  242. $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info);
  243. if ($res == false) throw new \Exception('生成支付流水失败');
  244. DepositPresaleOrder::updateAll(['out_trade_no' => $res['trade_no']], ['id' => $order_id_arr]);
  245. $deposit_event = new DepositOrderCreateEvent($form['mall_id']);
  246. Yii::$app->services->events->dispatch($deposit_event, ['id' => $order_id_arr[0]], $deposit_event->listeners);
  247. Order::updateAll(['out_trade_no' => $res['trade_no']], ['id' => $order_ids]);
  248. // 触发订单添加事件,事务提交完成后触发
  249. $event = new OrderCreateEvent($form['mall_id']);
  250. Yii::$app->services->events->dispatch($event, ['order_ids' => $order_ids], $event->listeners);
  251. $arr['transaction'] = $res;
  252. $arr['open_group_id'] = $open_group_id;
  253. $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link'); // 支付成功后跳转的地址
  254. return $arr;
  255. } catch (\Exception $e) {
  256. LockHelper::batchUlock($stock_locks);
  257. if (isset($trans)) $trans->rollback();
  258. self::$static_error = $e->getMessage();
  259. return false;
  260. }
  261. }
  262. /**
  263. * @Description: 生成主商城订单
  264. * @Author: observer3
  265. * @DateTime 2022-05-23 21:22:24
  266. * @param [type] $group_order_goods
  267. * @param [type] $form
  268. * @return array
  269. */
  270. public static function generateMainOrder($group_order_goods, $form, $data)
  271. {
  272. $order_ids = [];
  273. $activity_model = null;
  274. foreach ($group_order_goods as $mch_order) {
  275. $mch_order_info = $mch_order['mch_order_info'];
  276. $main_order = new Order();
  277. $main_order->loadDefaultValues();
  278. $main_order->load($mch_order_info, '');
  279. $main_order->order_status = OrderStatusEnum::NOT_PAY;
  280. $main_order->marketing_type = DepositPresaleEnum::ADDONS_NAME;
  281. $main_order->remark = $data['remark'] ?? '';
  282. empty($main_order->order_no) && $main_order->order_no = Order::generateOrderNo('s');
  283. $res = $main_order->save();
  284. if ($res === false) throw new Exception($main_order->getErrorMessage());
  285. if (!$activity_model) {
  286. $activity_model = DepositPresaleActive::findOne(['mall_id' => $form['mall_id'], 'id' => $mch_order_info['deposit_presale_active_id']]);
  287. }
  288. // 设置为支付尾款的结束时间,防止主商城自动关闭订单
  289. if ($activity_model) {
  290. $main_order->created_at = $activity_model->final_payment_end_at;
  291. $res = $main_order->save();
  292. if ($res === false) throw new Exception($main_order->getErrorMessage());
  293. }
  294. $order_id = $main_order->id;
  295. $order_ids[] = $main_order->id;
  296. //$region_statistics[] = ['mall_id' => $order->mall_id, 'province_id' => $order->province, 'city_id' => $order->city, 'order' => $order->pay_money];
  297. // 总商品库存维护
  298. $goods_stock_arr = [];
  299. // 遍历商户商品
  300. // $goods_ids = array_keys($mch_order['goods']);
  301. foreach ($mch_order['goods'] as $goods_id => $goods) {
  302. !isset($goods_name) && $goods_name = $goods['goods_name'];
  303. foreach ($goods['goods_details'] as $goods_detail) {
  304. // $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR, $goods_detail['goods_attr_id']);
  305. // $identification = uniqid();
  306. // if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
  307. // $stock_locks[$lock_key] = $identification;
  308. //操作商品库存-减
  309. // GoodsAttr::handleStock($goods_detail['goods_attr_id'], $goods_detail['num'] * -1);
  310. if (!isset($goods_stock_arr[$goods_id])) {
  311. $goods_stock_arr[$goods_id] = $goods_detail['num'];
  312. } else {
  313. $goods_stock_arr[$goods_id] += $goods_detail['num'];
  314. }
  315. // 订单详情
  316. $order_detail = new OrderDetail();
  317. $order_detail->loadDefaultValues();
  318. $order_detail->load($goods_detail, '');
  319. $order_detail->order_id = $order_id;
  320. // $goods_statistics[] = ['goods_id' => $goods_detail['goods_id'], 'order_num' => 1, 'sales_num' => $goods_detail['num']];
  321. $res = $order_detail->save();
  322. if ($res === false) throw new Exception($order_detail->getErrorMessage());
  323. $attr[$goods_detail['goods_attr_id']] = $goods_detail['num'];
  324. // 订单营销
  325. if (!empty($goods_detail['marketing'])) {
  326. $order_marketing = new OrderMarketing();
  327. $order_marketing->loadDefaultValues();
  328. $order_marketing->load($goods_detail['marketing'], '');
  329. $order_marketing->order_detail_id = $order_detail->id;
  330. $res = $order_marketing->save();
  331. if ($res === false) throw new Exception($order_marketing->getErrorMessage());
  332. }
  333. }
  334. }
  335. $data = is_array($form->data) ? $form->data : Json::decode($form->data, true);
  336. if (!empty($data['user_coupon_ids'])) {
  337. $user_coupon_id = $data['user_coupon_ids'];
  338. $res = AddonsCouponUserRelate::updateAll(['is_use' => 1], ['id' => $user_coupon_id]);
  339. if ($res === false) throw new Exception($main_order->getErrorMessage());
  340. }
  341. }
  342. return $order_ids;
  343. }
  344. /**
  345. * @Description: 生成支付尾款的交易号
  346. * @Author: code farmer 3
  347. * @DateTime 2022-04-23 18:15:06
  348. * @param array $form
  349. * @return bool|array
  350. */
  351. public static function generateFinalPaymentTradeNo($form)
  352. {
  353. try {
  354. /** @var DepositPresaleOrder $order */
  355. $order = $form['deposit_presale_order'];
  356. $order_trade_info = [];
  357. $total_pay_price = bcsub($order->deposit_presale_price, $order->deposit_price, 2);
  358. $order_trade_info[] = [
  359. 'order_no' => $order->order_no,
  360. 'amount' => $total_pay_price,
  361. 'title' => mb_strlen($order->goods_name) > 32 ? mb_substr($order->goods_name, 0, 32) : $order->goods_name,
  362. 'notify_class' => DepositPresaleEnum::FINAL_NOTIFY_CLASS,
  363. 'order_type' => DepositPresaleEnum::ADDONS_NAME,
  364. ];
  365. $trans = Yii::$app->db->beginTransaction();
  366. if (!$order->final_out_trade_no) {
  367. //生成支付流水
  368. $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info);
  369. if ($res == false) throw new \Exception('生成支付流水失败');
  370. } else {
  371. $trade_model = \Yii::$app->services->pay->getByTradeNo($order->final_out_trade_no);
  372. if (!$trade_model) throw new \Exception('支付流水号异常');
  373. $res = [];
  374. $res['trade_id'] = $trade_model->id;
  375. $res['trade_no'] = $trade_model->out_trade_no;
  376. }
  377. if (!$order->final_out_trade_no) {
  378. $update_res = DepositPresaleOrder::updateAll(['final_out_trade_no' => $res['trade_no']], ['id' => $order->id]);
  379. if ($update_res == false) throw new \Exception('保存支付流水号失败');
  380. }
  381. $trans->commit();
  382. $arr = [];
  383. $arr['transaction'] = $res;
  384. $arr['open_group_id'] = $order->id;
  385. $arr['total_pay_money'] = $total_pay_price;
  386. $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link'); // 支付成功后跳转的地址
  387. return $arr;
  388. } catch (\Exception $e) {
  389. if (isset($trans)) $trans->rollback();
  390. self::$static_error = $e->getMessage();
  391. return false;
  392. }
  393. }
  394. /**
  395. * @desc:取消定金预售订单
  396. * @Author: hua
  397. * @Date: 2021/12/15
  398. * @Time: 17:19
  399. * @Copyright: copyright (c) 2021 广东七件事集团
  400. * @param $params
  401. * @param false $force
  402. * @return DepositPresaleOrder|false
  403. * @throws \yii\db\Exception
  404. */
  405. public static function close($params, $force = false)
  406. {
  407. $trans = Yii::$app->db->beginTransaction();
  408. $stock_locks = [];
  409. try {
  410. $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  411. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  412. $model = self::findOne($cond);
  413. if (empty($model)) throw new \Exception('订单不存在或已删除');
  414. // 判断订单是否已经被关闭
  415. if ($model->order_status == DepositPresaleEnum::GROUP_CLOSE) throw new Exception('订单已经关闭');
  416. // 判断是否是未支付的订单
  417. if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理');
  418. $model->order_status = DepositPresaleEnum::GROUP_CLOSE;
  419. if (!$model->save()) throw new Exception($model->getErrorMessage());
  420. self::rollBackStock($model, $stock_locks); //回退库存
  421. $params['id'] = $model->order_id;
  422. $params['created_at'] = $model->created_at;
  423. $res = self::mainOrderClose($params);
  424. if ($res === false) throw new Exception(self::getStaticError());
  425. $trans->commit();
  426. LockHelper::batchUlock($stock_locks);
  427. $event = new OrderCloseEvent($params['mall_id']);
  428. $order_data['id'] = $params['id'];
  429. $order_data['operator_id'] = $params['operator_id'] ?? 0;
  430. $order_data['operator_name'] = $params['operator_name'] ?? '系统';
  431. Yii::$app->services->events->dispatch($event, $order_data, $event->listeners);
  432. return $model;
  433. } catch (Exception $e) {
  434. $trans->rollback();
  435. LockHelper::batchUlock($stock_locks);
  436. self::$static_error = $e->getMessage();
  437. return false;
  438. }
  439. }
  440. /**
  441. * 取消订单
  442. * @Author bing
  443. * @DateTime 2021-09-14 15:43:18
  444. * @copyright: Copyright (c) 2020 广东七件事集团
  445. * @param [type] $params
  446. * @return order
  447. */
  448. public static function mainOrderClose($params, $force = false)
  449. {
  450. // $trans = Yii::$app->db->beginTransaction();
  451. $stock_locks = [];
  452. $close_lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS, $params['id']);
  453. try {
  454. // 加锁
  455. $close_identification = uniqid();
  456. $stock_locks[$close_lock_key] = $close_identification;
  457. if (!LockHelper::lock($close_lock_key, $close_identification, 30, 60)) throw new \Exception('正在关闭订单');
  458. $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  459. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  460. $model = Order::findOne($cond);
  461. if (empty($model)) throw new Exception('订单不存在或已删除');
  462. // 判断订单是否已经被关闭
  463. if ($model->order_status == OrderStatusEnum::REPEAL) throw new Exception('订单已经关闭');
  464. // 判断是否是未支付的订单
  465. if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理');
  466. $model->close_time = time();
  467. $model->order_status = OrderStatusEnum::REPEAL;
  468. if (!empty($params['created_at']) && $params['created_at'] != $model->created_at) {
  469. $model->created_at = $params['created_at'];
  470. }
  471. if (!$model->save()) throw new Exception($model->getErrorMessage());
  472. // $goods_attr_arr = array_column($model->detail,'num','goods_attr_id');
  473. //操作规格库存-回退
  474. // foreach ($goods_attr_arr as $goods_attr_id=>$num){
  475. // $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR , $goods_attr_id);
  476. // $identification = uniqid();
  477. // if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
  478. // $stock_locks[$lock_key] = $identification;
  479. // //操作商品库存-回退
  480. // GoodsAttr::handleStock($goods_attr_id,$num);
  481. // }
  482. // 订单营销扣减返还
  483. $order_detail_id_arr = array_column($model->detail, 'id');
  484. $res = OrderMarketing::deductBack($model->id, $order_detail_id_arr, $order_detail_id_arr, $model->mall_id, $model->user_id, '交易关闭返还');
  485. if ($res == false) throw new Exception(OrderMarketing::getStaticError());
  486. // $trans->commit();
  487. // 解锁
  488. LockHelper::batchUlock($stock_locks);
  489. return $model;
  490. } catch (Exception $e) {
  491. // $trans->rollback();
  492. // 解锁
  493. LockHelper::batchUlock($stock_locks);
  494. self::$static_error = $e->getMessage();
  495. return false;
  496. }
  497. }
  498. /**
  499. * @desc:回退库存
  500. * @Author: hua
  501. * @Date: 2021/12/15
  502. * @Time: 17:34
  503. * @Copyright: copyright (c) 2021 广东七件事集团
  504. * @param $model
  505. * @param $stock_locks
  506. * @throws Exception
  507. */
  508. public static function rollBackStock($model, &$stock_locks)
  509. {
  510. $goods_attr_arr[$model->goods_attr_id] = $model->num;
  511. //操作规格库存-回退
  512. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR, $model->goods_attr_id);
  513. $identification = uniqid();
  514. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
  515. $stock_locks[$lock_key] = $identification;
  516. //操作商品库存-回退
  517. DepositPresaleActiveGoodsAttr::handleStock($model->mall_id, $model->deposit_presale_active_id, $model->goods_attr_id, $model->num);
  518. $stock = DepositPresaleActiveGoodsAttr::find()->where(['mall_id' => $model->mall_id, 'deposit_presale_active_id' => $model->deposit_presale_active_id, 'goods_id' => $model->goods_id])->sum('stock');
  519. $stock = $stock ?? 0;
  520. $res = DepositPresaleActive::updateAll(['goods_stock' => $stock], ['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id, 'goods_id' => $model->goods_id]);
  521. if (!$res) throw new \Exception(Goods::getStaticError());
  522. }
  523. /**
  524. * @desc:结束定金预售
  525. * @Author: hua
  526. * @Date: 2021/12/15
  527. * @Time: 11:43
  528. * @Copyright: copyright (c) 2021 广东七件事集团
  529. * @param $mall_id
  530. * @param $open_group_id
  531. * @return bool
  532. */
  533. public static function finishDepositPresaleOrder($mall_id, $open_group_id)
  534. {
  535. Yii::$app->db->close();
  536. $t = Yii::$app->db->beginTransaction();
  537. $stock_locks = [];
  538. try {
  539. $deposit_presale_order = self::findOne(['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => DepositPresaleEnum::JOINING]);
  540. $order_id = 0;
  541. $user_id = 0;
  542. $config = Yii::$app->services->setting->addons->get($mall_id, DepositPresaleEnum::ADDONS_NAME, 'basic.general_settings');
  543. if (!empty($config)) {
  544. $config = json_decode($config, true);
  545. }
  546. $is_refund = isset($config['is_refund_deposit']) ? (!empty($config['is_refund_deposit']['value']) ? 1 : 0) : 0;
  547. $created_at = 0;
  548. $order_id = $deposit_presale_order->order_id;
  549. $user_id = $deposit_presale_order->user_id;
  550. //归还库存
  551. self::rollBackStock($deposit_presale_order, $stock_locks);
  552. if (!$created_at) $created_at = $deposit_presale_order->created_at;
  553. //拼团失败
  554. $res = self::updateAll(['order_status' => DepositPresaleEnum::GROUP_FAILURE], ['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => DepositPresaleEnum::JOINING]);
  555. if ($res == false) {
  556. throw new \Exception(self::getStaticError());
  557. }
  558. $params = [
  559. 'mall_id' => $mall_id, 'user_id' => $user_id, 'id' => $order_id, 'created_at' => $created_at,
  560. ];
  561. $res = self::mainOrderClose($params);
  562. if ($res === false) {
  563. throw new Exception(self::getStaticError());
  564. }
  565. if ($is_refund) {
  566. //退款逻辑
  567. $payment_order = PaymentTradeOrder::findOne(['order_no' => $deposit_presale_order->order_no, 'is_pay' => StatusEnum::ENABLED]);
  568. $payment_trade = PaymentTrade::findOne(['id' => $payment_order->trade_id]);
  569. $desc = '用户(' . $deposit_presale_order->user_id . '),预定失败,订单(' . $deposit_presale_order->id . ')退款:,金额:' . $payment_trade->pay_fee;
  570. $res = Yii::$app->services->pay->refund($payment_trade->pay_fee, $payment_trade->pay_fee, $payment_trade->out_trade_no, $deposit_presale_order, $desc, DepositPresaleEnum::ADDONS_NAME, UserWalletEnum::REFUND_ORDER);
  571. if ($res == false) throw new \Exception('退款失败');
  572. }
  573. LockHelper::batchUlock($stock_locks);
  574. $t->commit();
  575. // 触发订单取消事件
  576. $event = new OrderCloseEvent($mall_id);
  577. $order_data['id'] = $params['id'];
  578. $order_data['operator_id'] = $params['operator_id'] ?? 0;
  579. $order_data['operator_name'] = $params['operator_name'] ?? '系统';
  580. Yii::$app->services->events->dispatch($event, $order_data, $event->listeners);
  581. return true;
  582. } catch (Exception $e) {
  583. $t->rollback();
  584. LockHelper::batchUlock($stock_locks);
  585. self::$static_error = $e->getMessage();
  586. return false;
  587. }
  588. }
  589. public static function finishDepositPresaleOrderSync($data)
  590. {
  591. self::finishDepositPresaleOrder($data['mall_id'], $data['open_group_id']);
  592. }
  593. /**
  594. * @desc:支付
  595. * @Author: hua
  596. * @Date: 2021/12/15
  597. * @Time: 15:15
  598. * @Copyright: copyright (c) 2021 广东七件事集团
  599. * @param $params
  600. * @param $peyment_type
  601. * @return DepositPresaleOrder|false
  602. */
  603. public static function pay($params, $peyment_type)
  604. {
  605. $trans = Yii::$app->db->beginTransaction();
  606. try {
  607. $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  608. if (empty($model)) throw new \Exception('订单不存在或已删除');
  609. if ($model->is_pay != OrderStatusEnum::NOT_PAY) throw new \Exception('订单已经被处理,无法进行支付');
  610. if ($model->is_pay == StatusEnum::ENABLED) throw new \Exception('订单已支付,请不要重复支付');
  611. $model->is_pay = OrderStatusEnum::PAY;
  612. $model->order_status = DepositPresaleEnum::JOINING;
  613. $model->payment_type = $peyment_type;
  614. $model->pay_time = time();
  615. $active_model = DepositPresaleActive::findOne($model->deposit_presale_active_id);
  616. if (empty($active_model)) throw new \Exception('预售活动不存在或已删除');
  617. $num = 1;
  618. $order_detail = OrderDetail::findOne(['mall_id' => $model->mall_id, 'order_id' => $model->order_id]);
  619. if ($order_detail) $num = $order_detail->num;
  620. $active_model->presale_total = $active_model->presale_total + $num;
  621. $active_res = $active_model->save();
  622. if ($active_res === false) throw new \Exception('更新预定人数失败:' . $active_model->getErrorMessage());
  623. // $result = DepositPresaleActive::updateDiyGoods(['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id, 'presale_total' => $active_model->presale_total]);
  624. // if($result === false) throw new \Exception('更新装修页预定人数失败:'. DepositPresaleActive::getStaticError());
  625. $res = $model->save();
  626. if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage());
  627. OrderAction::create("手机号为:{$order_detail->order->mobile}用户订单支付定金成功", $model->order_id, 0, $model->user_id, $order_detail->order->receiver_name);
  628. $trans->commit();
  629. // 触发订单支付事件,事务提交完成后触发
  630. // $event = new OrderPaidEvent($model->mall_id);
  631. // $order['id'] = $model['id'];
  632. // $order['operator_id'] = $params['operator_id'] ?? '';
  633. // $order['operator_name'] = $params['operator_name'] ?? '';
  634. // Yii::$app->services->events->dispatch($event, $order, $event->listeners);
  635. if ($model->mainOrder) {
  636. $sms = new Sms($model->mall_id);
  637. $sms->createOrder($model->mobile, ['order_no' => $model->mainOrder->order_no, 'date' => date('Y-m-d H:i:s', $active_model->final_payment_start_at)]);
  638. self::sendTemplateMessage(1, $model->mainOrder, $active_model->final_payment_start_at);
  639. }
  640. return $model;
  641. } catch (\Exception $e) {
  642. if (isset($trans)) $trans->rollback();
  643. self::$static_error = $e->getMessage();
  644. return false;
  645. }
  646. }
  647. /**
  648. * @Description: 支付尾款
  649. * @Author: code farmer 3
  650. * @DateTime 2022-04-23 17:28:50
  651. * @param array $params
  652. * @param int $peyment_type
  653. * @return bool|DepositPresaleOrder
  654. */
  655. public static function payFinalPayment($params, $peyment_type)
  656. {
  657. $trans = Yii::$app->db->beginTransaction();
  658. try {
  659. $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  660. if (empty($model)) throw new \Exception('订单不存在或已删除');
  661. if ($model->is_pay != OrderStatusEnum::PAY) throw new \Exception('订单没有支付定金,无法进行尾款支付');
  662. if ($model->order_status == DepositPresaleEnum::GROUP_SUCCESS) throw new \Exception('订单已支付尾款,请不要重复支付');
  663. $model->order_status = DepositPresaleEnum::GROUP_SUCCESS;
  664. $model->payment_type = $peyment_type;
  665. $model->final_payment_time = time();
  666. $trade_payment = PaymentTrade::find()->where(['out_trade_no' => $model->final_out_trade_no])->select(['pay_fee'])->one();
  667. $model->total_pay_price = bcadd($model->total_pay_price, $trade_payment->pay_fee ?? 0, 2);
  668. $res = $model->save();
  669. if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage());
  670. $active_model = DepositPresaleActive::findOne(['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id]);
  671. $num = 1;
  672. $order_detail = OrderDetail::findOne(['mall_id' => $model->mall_id, 'order_id' => $model->order_id]);
  673. if ($order_detail) $num = $order_detail->num;
  674. $active_model->sales_num = $active_model->sales_num + $num;
  675. $result = $active_model->save();
  676. if ($result === false) throw new \Exception('销量更新失败:' . $active_model->getErrorMessage());
  677. OrderAction::create("手机号为:{$order_detail->order->mobile}用户订单支付尾款成功", $model->order_id, 1, $model->user_id, $order_detail->order->receiver_name);
  678. $trans->commit();
  679. if ($model->depositPresaleActive) {
  680. if ($model->depositPresaleActive->delivery_time_way == 0) {
  681. $send_goods_start_at = $model->depositPresaleActive->send_goods_start_at;
  682. } else {
  683. $send_goods_start_at = $model->depositPresaleActive->final_payment_end_at + $model->depositPresaleActive->shipping_days * 86400;
  684. }
  685. }
  686. if ($model->mainOrder) {
  687. $sms = new Sms($model->mall_id);
  688. $sms->shipOrder($model->mobile, ['order_no' => $model->mainOrder->order_no, 'date' => date('Y-m-d H:i:s', $send_goods_start_at)]);
  689. self::sendTemplateMessage(2, $model->mainOrder, $send_goods_start_at);
  690. }
  691. return $model;
  692. } catch (\Exception $e) {
  693. if (isset($trans)) $trans->rollback();
  694. self::$static_error = $e->getMessage();
  695. return false;
  696. }
  697. }
  698. /**
  699. * @desc:延时队列,执行自动关闭拼团订单
  700. * @Author: hua
  701. * @Date: 2022/1/4
  702. * @Time: 10:38
  703. * @Copyright: copyright (c) 2021 广东七件事集团
  704. * @param $data
  705. */
  706. public static function autoFinish($data)
  707. {
  708. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_OPEN_GROUP_ID, $data['open_group_id']);
  709. $identification = uniqid();
  710. try {
  711. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多:order_id:' . $data['id']);
  712. $deposit_presale_order = self::findOne(['id' => $data['order_id'], 'open_group_id' => $data['open_group_id'], 'is_pay' => 1, 'order_status' => DepositPresaleEnum::JOINING]);
  713. if (empty($deposit_presale_order)) throw new Exception('该订单不存在');
  714. $active = DepositPresaleActive::findOne(['mall_id' => $deposit_presale_order->mall_id, 'id' => $deposit_presale_order->deposit_presale_active_id]);
  715. $where = [
  716. ['mall_id' => $deposit_presale_order->mall_id],
  717. ['deposit_presale_active_id' => $deposit_presale_order->deposit_presale_active_id],
  718. ['open_group_id' => $deposit_presale_order->open_group_id],
  719. ['is_pay' => 1],
  720. ['order_status' => DepositPresaleEnum::JOINING],
  721. ];
  722. $limit = $active->gt_group_size ? $active->gt_group_size : $active->group_size;
  723. $list = DepositPresaleOrder::lists(['where' => $where, 'order' => 'pay_time asc,id asc', 'limit' => $limit], false);
  724. $counts = count($list);
  725. if ($counts >= $active->group_size) {
  726. //拼团成功(虚拟和非虚拟)
  727. $res = DepositPresaleOrder::addMainOrder($deposit_presale_order, $list, $active, $counts);
  728. if ($res == false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['id']);
  729. } else {
  730. if ($active->is_virtual && $active->virtual_group_type == 2 && $counts >= $active->gt_group_size) {
  731. //虚拟拼团成功
  732. $res = DepositPresaleOrder::addMainOrder($deposit_presale_order, $list, $active, $counts);
  733. if ($res == false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['id']);
  734. } else {
  735. foreach ($list as $item) {
  736. $res = self::finishDepositPresaleOrder($item->mall_id, $item->open_group_id);
  737. if ($res == false) {
  738. throw new Exception(' 拼团订单[ID:' . $item->id . ']过期,执行拼团结束失败, errmsg: ' . DepositPresaleOrder::getStaticError() . PHP_EOL);
  739. }
  740. }
  741. }
  742. }
  743. LockHelper::uLock($lock_key, $identification);
  744. } catch (Exception $e) {
  745. LockHelper::uLock($lock_key, $identification);
  746. }
  747. }
  748. /**
  749. * @desc:生成主订单
  750. * @Author: hua
  751. * @Date: 2022/1/4
  752. * @Time: 10:33
  753. * @Copyright: copyright (c) 2021 广东七件事集团
  754. * @param $last_order
  755. * @param $list
  756. * @param $active
  757. * @param $counts
  758. */
  759. public static function addMainOrder($last_order, $list, $active, $counts)
  760. {
  761. $t = Yii::$app->db->beginTransaction();
  762. try {
  763. $goods = Goods::findOne(['id' => $last_order->goods_id]);
  764. $goods_attr = GoodsAttr::findOne(['id' => $last_order->goods_attr_id]);
  765. $marketing_type = DepositPresaleEnum::ADDONS_NAME;
  766. $total_num = $total_orders_price = 0;
  767. //成功开团,往主订单写入数据
  768. $main_order_id_arr = [];
  769. foreach ($list as $deposit_presale_order) {
  770. $order_id = self::createMallOrder($deposit_presale_order, $marketing_type, $goods, $goods_attr);
  771. $deposit_presale_order->order_id = $order_id;
  772. $main_order_id_arr[$deposit_presale_order->user_id] = $order_id;
  773. $deposit_presale_order->order_status = DepositPresaleEnum::GROUP_SUCCESS;
  774. $deposit_presale_order->win_time = $last_order->created_at;
  775. $res = $deposit_presale_order->save();
  776. if ($res == false) throw new \Exception('开团成功回写主订id失败');
  777. $total_num += $deposit_presale_order['num'];
  778. $total_orders_price += $deposit_presale_order['deposit_presale_price'] * $deposit_presale_order['num'];
  779. }
  780. $active->total_num += $total_num + ($active->group_size - $counts);
  781. $active->total_orders += $counts;
  782. $active->total_orders_price += $total_orders_price;
  783. $res = $active->save();
  784. if ($res == false) throw new \Exception('更新拼团活动失败');
  785. $t->commit();
  786. self::giveReward($last_order->commander_id, DepositPresaleOrder::tableName(), $last_order->open_group_id, $active);
  787. // 触发订单支付事件,事务提交完成后触发
  788. $user_id_arr = array_keys($main_order_id_arr);
  789. $user_list = User::lists(['where' => [['id' => $user_id_arr]], 'index' => 'id']);
  790. foreach ($main_order_id_arr as $user_id => $order_id) {
  791. $event = new \common\events\order\OrderPaidEvent($last_order->mall_id);
  792. $order['id'] = $order_id;
  793. $order['operator_id'] = $user_id;
  794. $order['operator_name'] = $user_list[$user_id]['nickname'] ?? '';
  795. Yii::$app->services->events->dispatch($event, $order, $event->listeners);
  796. }
  797. return true;
  798. } catch (Exception $e) {
  799. $t->rollBack();
  800. $exception = FormatHelper::exception($e, "订单支付触发拼团事件");
  801. echo $exception;
  802. Yii::error($exception);
  803. return false;
  804. }
  805. }
  806. /**
  807. * @desc:生成主订单
  808. * @Author: hua
  809. * @Date: 2021/12/16
  810. * @Time: 14:32
  811. * @Copyright: copyright (c) 2021 广东七件事集团
  812. * @param $deposit_presale_order
  813. * @param $marketing_type
  814. * @param $goods
  815. * @param $goods_attr
  816. * @return int
  817. * @throws Exception
  818. */
  819. public static function createMallOrder($deposit_presale_order, $marketing_type, $goods, $goods_attr)
  820. {
  821. $order = new Order();
  822. $order->loadDefaultValues();
  823. $order->load($deposit_presale_order->toArray(), '');
  824. $order->order_status = OrderStatusEnum::PAY;
  825. $order->marketing_id = $deposit_presale_order->deposit_presale_active_id;
  826. $order->marketing_type = $marketing_type;
  827. $order->goods_price = $deposit_presale_order->deposit_presale_price;
  828. $order->pay_money = $deposit_presale_order->total_pay_price;
  829. $order->shipping_money = $deposit_presale_order->shipping_money;
  830. $order->shipping_type = $deposit_presale_order->shipping_type;
  831. $order->original_goods_price = $goods_attr->original_price;
  832. $order->pay_status = 1;
  833. $res = $order->save();
  834. if ($res == false) throw new \Exception('开团成功生成主订单失败');
  835. self::createMallOrderDetail($deposit_presale_order, $order->id, $goods, $goods_attr, $marketing_type);
  836. return $order->id;
  837. }
  838. /**
  839. * @desc:生成主订单详情
  840. * @Author: hua
  841. * @Date: 2021/12/16
  842. * @Time: 14:32
  843. * @Copyright: copyright (c) 2021 广东七件事集团
  844. * @param $deposit_presale_order
  845. * @param $order_id
  846. * @param $goods
  847. * @param $goods_attr
  848. * @param $marketing_type
  849. * @throws Exception
  850. */
  851. public static function createMallOrderDetail($deposit_presale_order, $order_id, $goods, $goods_attr, $marketing_type)
  852. {
  853. // 订单详情
  854. $order_detail = new OrderDetail();
  855. $order_detail->loadDefaultValues();
  856. $order_detail->user_id = $deposit_presale_order->user_id;
  857. $order_detail->mall_id = $deposit_presale_order->mall_id;
  858. $order_detail->mch_id = $deposit_presale_order->mch_id;
  859. $order_detail->order_id = $order_id;
  860. $order_detail->goods_id = $deposit_presale_order->goods_id;
  861. $order_detail->goods_attr_id = $deposit_presale_order->goods_attr_id;
  862. $order_detail->goods_name = $deposit_presale_order->goods_name;
  863. $order_detail->goods_attr_name = $deposit_presale_order->goods_attr_name;
  864. $order_detail->price = $deposit_presale_order->price;
  865. $order_detail->cost_price = $goods_attr->cost_price;
  866. $order_detail->original_goods_price = $goods_attr->original_price;
  867. $order_detail->goods_price = $deposit_presale_order->deposit_presale_price;
  868. $order_detail->num = $deposit_presale_order->num;
  869. $order_detail->pic_url = $deposit_presale_order->pic_url;
  870. $order_detail->marketing_id = $deposit_presale_order->deposit_presale_active_id;
  871. $order_detail->marketing_type = $marketing_type;
  872. $order_detail->order_status = OrderStatusEnum::PAY;
  873. $order_detail->remark = $deposit_presale_order->remark;
  874. //$order_detail->is_virtual = $goods->goods_type;
  875. $order_detail->is_virtual = $goods->goods_type == GoodsTypeEnum::GoodsTypeVirtual ? 1 : 0;
  876. $res = $order_detail->save();
  877. if ($res == false) throw new \Exception('开团成功生成订单详情失败');
  878. }
  879. /**
  880. * @desc:拼团奖励
  881. * @Author: hua
  882. * @Date: 2022/1/4
  883. * @Time: 10:35
  884. * @Copyright: copyright (c) 2021 广东七件事集团
  885. * @param $user_id
  886. * @param $source_table
  887. * @param $open_group_id
  888. * @param $active
  889. * @throws Exception
  890. */
  891. public static function giveReward($user_id, $source_table, $open_group_id, $active)
  892. {
  893. $insert_wallet = [];
  894. $give_arr = ['balance' => ['numbers' => $active->give_balance, 'name' => '余额'], 'score' => ['numbers' => $active->give_score, 'name' => '积分']];
  895. foreach ($give_arr as $code => $item) {
  896. if ($item['numbers']) {
  897. $desc = '用户(' . $user_id . '),获得开团(' . $open_group_id . ')奖励,奖励类型:' . $item['name'] . ',数量:' . $item['numbers'];
  898. $insert_wallet[] = [
  899. 'mall_id' => $active->mall_id, 'user_id' => $user_id,
  900. 'is_frozen' => false, 'wallet_type' => $code, 'money' => $item['numbers'],
  901. 'desc' => $desc,
  902. 'source_table' => $source_table,
  903. 'source_table_id' => $open_group_id,
  904. 'from_type' => UserWalletEnum::FROM_GROUP_BUY,
  905. 'capital_type' => UserWalletEnum::GIVE,
  906. ];
  907. }
  908. }
  909. if (!empty($insert_wallet)) {
  910. UserWalletService::batchHandleByQueue($insert_wallet);
  911. }
  912. }
  913. /**
  914. * @Description: 订单收货
  915. * @Author: code farmer 3
  916. * @DateTime 2022-04-28 18:42:50
  917. * @param array $data
  918. * @return bool
  919. */
  920. public static function orderReceipt($data)
  921. {
  922. try {
  923. $order = self::findOne($data['id']);
  924. if (!$order) throw new Exception('订单不存在');
  925. if (!$order->is_pay) throw new Exception('订单尚未支付定金');
  926. if (!$order->final_payment_time) throw new Exception('订单尚未支付尾款');
  927. // 活动订单收货
  928. $order->order_status = DepositPresaleEnum::ORDER_RECEIPT;
  929. $res = $order->save();
  930. if (!$res) throw new Exception($order->getErrorMessage());
  931. $params = [
  932. 'id' => $order->order_id, 'mall_id' => $order->mall_id, 'user_id' => $order->user_id,
  933. 'operator_id' => $data['operator_id'], 'operator_name' => $data['operator_name']
  934. ];
  935. // 主订单收货
  936. $result = Order::takeDelivery($params);
  937. if ($result === false) throw new Exception(Order::getStaticError());
  938. return true;
  939. } catch (Exception $e) {
  940. self::$static_error = $e->getMessage();
  941. return false;
  942. }
  943. }
  944. public static function check($params): bool
  945. {
  946. $order_no_arr = $params['order_no_arr'];
  947. $payment_order_list = $params['payment_order_list'];
  948. $counts = DepositPresaleOrder::find()->where([
  949. 'order_no' => $order_no_arr,
  950. // 'is_pay'=>0
  951. ])->count();
  952. if ($counts != count($payment_order_list)) {
  953. self::$static_error = '预售订单不一致';
  954. return false;
  955. }
  956. return true;
  957. }
  958. public function appendFieldsToDetail($params)
  959. {
  960. if (!isset($params['order']) || !isset($params['order']['id'])) {
  961. return $params['order'];
  962. }
  963. // 追加预售订单信息部分
  964. $data = $params['order'];
  965. $presale_order = DepositPresaleOrder::find()->where(['order_id' => $params['order']['id']])->select(['id', 'order_id', 'created_at', 'pay_time', 'final_payment_time'])->one();
  966. if ($presale_order) {
  967. $data['created_at'] = $presale_order->created_at;
  968. $data['deposite_pay_time'] = $presale_order->pay_time ?: 0;
  969. $data['final_payment_time'] = $presale_order->final_payment_time ?: 0;
  970. isset($params['order']['pay_time']) && empty($params['order']['pay_time']) && $data['pay_time'] = -1;
  971. }
  972. $data['presale_info'] = [
  973. 'is_presale' => $presale_order ? 1 : 0,
  974. 'presale_order_id' => $presale_order ? $presale_order->id : 0,
  975. 'created_at' => $presale_order ? $presale_order->created_at : 0,
  976. ];
  977. return $data;
  978. }
  979. /**
  980. * @Description: 向主商城订单列表接口返回数据中追加字段
  981. * @Author: Observer3
  982. * @DateTime 2022-05-07 10:07:49
  983. * @param array $params
  984. * @return array
  985. */
  986. public function appendFieldsToList($params)
  987. {
  988. if (!isset($params['order']) || !is_array($params['order'])) return [];
  989. foreach ($params['order'] as &$item) {
  990. // 追加预售订单信息部分
  991. $item['presale_info'] = [
  992. 'is_presale' => 0,
  993. 'presale_order_id' => 0,
  994. 'is_pay_final_payment' => 0
  995. ];
  996. $presale_order = DepositPresaleOrder::find()->where([
  997. 'and',
  998. ['order_id' => $item['id']],
  999. ['mall_id' => $item['mall_id']]
  1000. ])
  1001. ->select(['id', 'order_id', 'is_pay', 'deposit_price', 'deposit_presale_price'])
  1002. ->limit(1)
  1003. ->one();
  1004. if ($presale_order) {
  1005. // 是否为预售订单
  1006. $item['presale_info']['is_presale'] = 1;
  1007. $item['presale_info']['presale_order_id'] = $presale_order->id;
  1008. $item['presale_info']['is_pay_final_payment'] = $presale_order->is_pay ? 1 : 0;
  1009. $item['presale_info']['deposit_price'] = $presale_order->deposit_price;
  1010. $item['presale_info']['final_payment'] = bcsub($presale_order->deposit_presale_price, $presale_order->deposit_price, 2);
  1011. }
  1012. }
  1013. return $params['order'];
  1014. }
  1015. /**
  1016. * @Description: 修改预售订单对应的主商城订单创建时间
  1017. * @DateTime 2022-09-20 17:11:06
  1018. * @param array $params
  1019. * @return array
  1020. */
  1021. public function modifiedFieldsOfBackendList($params)
  1022. {
  1023. if (!isset($params['order']) || !is_array($params['order'])) return [];
  1024. foreach ($params['order'] as &$item) {
  1025. if (!isset($item['marketing_type']) || $item['marketing_type'] != DepositPresaleEnum::ADDONS_NAME) {
  1026. continue;
  1027. }
  1028. $presale_order = DepositPresaleOrder::find()->where([
  1029. 'and',
  1030. ['order_id' => $item['id']],
  1031. ['mall_id' => $item['mall_id']]
  1032. ])
  1033. ->select(['id', 'created_at'])
  1034. ->limit(1)
  1035. ->one();
  1036. if ($presale_order) {
  1037. $item['created_at'] = $presale_order->created_at;
  1038. }
  1039. }
  1040. return $params['order'];
  1041. }
  1042. /**
  1043. * @Description: 执行控制台具体订单调用
  1044. * @Author: observer3
  1045. * @DateTime 2022-06-10 20:04:14
  1046. * @param [type] $params
  1047. * @return array
  1048. */
  1049. public function getAddonExpected($params)
  1050. {
  1051. if (!isset($params['order'])) return [];
  1052. if (!isset($params['action'])) return [];
  1053. $action_arr = ['close' => false];
  1054. $action_keys = array_keys($action_arr);
  1055. $addons = [
  1056. DepositPresaleEnum::ADDONS_NAME => [
  1057. $params['action'] => in_array($params['action'], $action_keys) ? $action_arr[$params['action']] : 0
  1058. ]
  1059. ];
  1060. return $addons;
  1061. }
  1062. /**
  1063. * @Description:
  1064. * @Author: observer3
  1065. * @DateTime 2022-05-13 19:33:30
  1066. * @param [type] $type
  1067. * @param Order $order
  1068. * @param [type] $time
  1069. * @return void
  1070. */
  1071. public static function sendTemplateMessage($type, $order, $time)
  1072. {
  1073. $order_detail = OrderDetail::findOne(['order_id' => $order->id]);
  1074. $data = [
  1075. 'mall_id' => $order->mall_id,
  1076. 'user_id' => $order->user_id,
  1077. 'order_id' => $order->id,
  1078. 'order_no' => $order->order_no,
  1079. 'goods_name' => $order_detail ? $order_detail->goods_name : '',
  1080. 'time' => $time,
  1081. ];
  1082. switch ($type) {
  1083. case 1: //支付定金后
  1084. self::sendDepositWechatTemplate($data);
  1085. break;
  1086. case 2: //支付尾款后
  1087. self::sendFinalWechatTemplate($data);
  1088. break;
  1089. }
  1090. }
  1091. /**
  1092. * @Description: 支付定金发送模板消息
  1093. * @Author: observer3
  1094. * @DateTime 2022-05-13 17:25:36
  1095. * @param array $param
  1096. * @return void|null
  1097. */
  1098. public static function sendDepositWechatTemplate($param)
  1099. {
  1100. $wechat = new WechatTemplate($param['mall_id']);
  1101. //插件是否开启推送模板消息
  1102. if ($wechat->is_logging() === false) {
  1103. return;
  1104. }
  1105. //是否公众号用户
  1106. if ($wechat->is_platform_wechat($param['user_id']) === false) {
  1107. return;
  1108. }
  1109. $platform = $wechat->getPlatForm();
  1110. $url = "/pages/order/detail?order_id=" . $param['order_id'];
  1111. $h5_url = \Yii::$app->params['web_url'] . "/h5/#" . $url;
  1112. $send_data = [
  1113. 'first' => '您好,您的订单已支付定金',
  1114. 'keyword1' => date("Y-m-d H:i:s", time()),
  1115. 'keyword2' => $param['goods_name'],
  1116. 'keyword3' => $param['order_no'],
  1117. 'remark' => '请留意在' . date("Y-m-d H:i:s", $param['time']) . '开始支付尾款'
  1118. ];
  1119. $temp_key = WechatTemplate::ORDER_DEPOSIT;
  1120. $wechat->sendTemplate($param['user_id'], $temp_key, $h5_url, $send_data, $platform, $url);
  1121. }
  1122. /**
  1123. * @Description: 支付尾款发送模板消息
  1124. * @Author: observer3
  1125. * @DateTime 2022-05-13 17:26:20
  1126. * @param array $param
  1127. * @return void|null
  1128. */
  1129. public static function sendFinalWechatTemplate($param)
  1130. {
  1131. $wechat = new WechatTemplate($param['mall_id']);
  1132. //插件是否开启推送模板消息
  1133. if ($wechat->is_logging() === false) {
  1134. return;
  1135. }
  1136. //是否公众号用户
  1137. if ($wechat->is_platform_wechat($param['user_id']) === false) {
  1138. return;
  1139. }
  1140. $platform = $wechat->getPlatForm();
  1141. $url = "/pages/order/detail?order_id=" . $param['order_id'];
  1142. $h5_url = \Yii::$app->params['web_url'] . "/h5/#" . $url;
  1143. $send_data = [
  1144. 'first' => '您好,您的订单已支付尾款',
  1145. 'keyword1' => date("Y-m-d H:i:s", time()),
  1146. 'keyword2' => $param['goods_name'],
  1147. 'keyword3' => $param['order_no'],
  1148. 'remark' => '将在' . date("Y-m-d H:i:s", $param['time']) . '开始发货'
  1149. ];
  1150. $temp_key = WechatTemplate::ORDER_FINAL_PAYMENT;
  1151. $wechat->sendTemplate($param['user_id'], $temp_key, $h5_url, $send_data, $platform, $url);
  1152. }
  1153. /**
  1154. * 预售订单状态统计
  1155. */
  1156. public static function getOrderStatistics($mall_id)
  1157. {
  1158. $all_order_number = 0;
  1159. $not_pay_order = 0;
  1160. $just_pay_deposit = 0;
  1161. $order_success = 0;
  1162. $order_fail = 0;
  1163. $data = self::find()->where([
  1164. 'and', ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED]
  1165. ])->select('id, order_status, status')
  1166. ->asArray()
  1167. ->all();
  1168. foreach ($data as $item) {
  1169. $all_order_number += 1;
  1170. if ($item['order_status'] == 0) {
  1171. $not_pay_order += 1;
  1172. }
  1173. if ($item['order_status'] == 1) {
  1174. $just_pay_deposit += 1;
  1175. }
  1176. if ($item['order_status'] == 2) {
  1177. $order_success += 1;
  1178. }
  1179. if ($item['order_status'] == 3) {
  1180. $order_fail += 1;
  1181. }
  1182. }
  1183. return compact('order_success', 'order_fail', 'just_pay_deposit', 'not_pay_order', 'all_order_number');
  1184. }
  1185. /**
  1186. * 获取订单详情订单状态
  1187. */
  1188. public static function getOrderStatus($main_order_detail, $order)
  1189. {
  1190. $status_text = '';
  1191. if (!$main_order_detail || !$order) {
  1192. return $status_text;
  1193. }
  1194. switch ($order->order_status) {
  1195. case DepositPresaleEnum::NOT_PAY:
  1196. $status_text = '待付定金';
  1197. break;
  1198. case DepositPresaleEnum::JOINING:
  1199. $status_text = '待付尾款';
  1200. break;
  1201. // case DepositPresaleEnum::GROUP_SUCCESS:
  1202. // $status_text = '待发货';
  1203. // break;
  1204. case DepositPresaleEnum::GROUP_FAILURE:
  1205. $status_text = '预售失败';
  1206. break;
  1207. case DepositPresaleEnum::GROUP_CLOSE:
  1208. $status_text = '订单关闭';
  1209. break;
  1210. }
  1211. if (!$status_text) {
  1212. $main_order_status_map = DepositPresaleEnum::getMainOrderStatusMap();
  1213. if (!isset($main_order_detail['detail'][0])) {
  1214. return $status_text;
  1215. }
  1216. $status_text = $main_order_status_map[$main_order_detail['detail'][0]['order_status']] ?? $status_text;
  1217. }
  1218. return $status_text;
  1219. }
  1220. /**
  1221. * @param array $order_ids
  1222. * @return array
  1223. */
  1224. public static function getMallOrderByOrderIds(array $order_ids)
  1225. {
  1226. return static::find()
  1227. ->where(['order_id' => $order_ids])
  1228. ->select('id, order_id')
  1229. ->asArray()
  1230. ->all();
  1231. }
  1232. }