| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- <?php
- namespace addons\StarChain\common\services;
- use addons\StarChain\common\enums\OrderRefundEnum;
- use addons\StarChain\common\enums\RefundStatusEnum;
- use addons\StarChain\common\enums\RefundTypeEnum;
- use addons\StarChain\common\enums\StarChainEnum;
- use addons\StarChain\common\models\Goods;
- use addons\StarChain\common\models\MallOrder;
- use addons\StarChain\common\models\Order;
- use addons\StarChain\common\models\OrderItem;
- use addons\StarChain\common\models\OrderRefund;
- use addons\StarChain\common\models\Setting;
- use common\enums\EventNameEnum;
- use common\enums\OrderStatusEnum;
- use common\enums\RabbitMqEnum;
- use common\enums\RefundTypeEnum as EnumsRefundTypeEnum;
- use common\enums\ShippingStatusEnum;
- use common\globals\GlobalInvoke;
- use common\logic\order\OrderRefundLogic;
- use common\logic\statistics\StatisticsHandle;
- use common\models\order\OrderDetail;
- use common\models\order\OrderRefund as MallOrderRefund;
- use common\models\order\OrderRefundStep;
- use Exception;
- use Yii;
- use yii\data\Pagination;
- use yii\helpers\Json;
- /**
- * 售后服务类
- */
- class RefundService extends BaseService
- {
- /**
- * 获取售后订单列表
- *
- * @param array $params
- * @return array
- */
- public function getRefundList($params = [])
- {
- $limit = $params['limit'] ?? 10;
- $model = OrderRefund::find();
- $model->where(['mall_id' => $this->mall_id]);
- $model->with([
- 'goods' => function ($query) {
- $query->select('id, name, spu_id, carousel_img_list, status');
- },
- 'detail' => function ($query) {
- $query->select('id, order_id, goods_attr_name, price, goods_price');
- },
- 'order' => function ($query) {
- $query->select('id, region_name, address, receiver_name, shipping_money, goods_price, mobile');
- },
- 'refund' => function ($query) {
- $query->select('id, order_no, reason, refund_price, pic_list, type, remark');
- },
- ]);
- // 查询
- if (!empty($params['name'])) {
- $model->andWhere([
- 'spu_id' => Goods::find()->where(['like', 'name', $params['name']])->select('spu_id'),
- ]);
- }
- if (!empty($params['order_no'])) {
- $model->andWhere([
- 'order_refund_id' => MallOrderRefund::find()->where(['like', 'order_no', $params['order_no']])->select('id')->column(),
- ]);
- }
- if (!empty($params['data'])) {
- list($start, $end) = $params['data'];
- $start = strtotime($start);
- $end = strtotime($end);
- $model->andFilterWhere(['between', 'created_at', $start, $end]);
- }
-
- $pagination = new Pagination(['totalCount' => $model->count(), 'pageSize' => $limit]);
- $model->limit($pagination->limit)->offset($pagination->offset);
- $list = $model->orderBy('id desc')
- ->asArray()
- ->all();
- foreach ($list as $k => $v) {
- $list[$k]['goods']['carousel_img_list'] = Json::decode($v['goods']['carousel_img_list']);
- $list[$k]['data'] = Json::decode($v['data']);
- $list[$k]['refund']['pic_list'] = Json::decode($v['refund']['pic_list']);
- $list[$k]['refund']['type_text'] = RefundTypeEnum::getValue($v['refund']['type']);
- $list[$k]['refund_status_text'] = RefundStatusEnum::getValue($v['refund_status']);
- $list[$k]['status_text'] = OrderRefundEnum::getValue($v['status']);
- }
- $data['list'] = $list;
- $data['status_arr'] = OrderRefundEnum::getMap();
- $data['refund_status_arr'] = RefundStatusEnum::getMap();
- $data['page_count'] = $pagination->pageCount;
- return $data;
- }
- /**
- * 添加售后
- *
- * @param array $params
- * @return MallOrderRefund
- */
- public function doRefund($params)
- {
- $params2 = $params;
- $db = Yii::$app->db->beginTransaction();
- try {
- //订单详情表
- $order_detail = OrderDetail::findOne(['id' => $params['order_detail_id'], 'user_id' => $params['user_id']]);
- if (empty($order_detail)) throw new Exception('订单不存在');
- if ($order_detail->order_status == OrderStatusEnum::ACCOMPLISH) throw new Exception('订单已过售后时间,无法申请售后');
- if (!in_array($order_detail->order_status, [OrderStatusEnum::PAY, OrderStatusEnum::SHIPMENTS, OrderStatusEnum::SING])) {
- throw new Exception('该订单状态下,无法申请售后');
- }
- // 订单是否聚合
- $order = MallOrder::find()->where(['id' => $order_detail['order_id']])->select('id, order_no, mall_id, shipping_money, order_source')->one();
- if ($order->order_source != StarChainEnum::PLUGIN_SIGN) throw new Exception('该订单不是聚合供应链订单');
- // 供应链订单信息
- $chain_order = OrderItem::find()->where(['mall_order_id' => $order_detail['order_id']])->select('sku_id, spu_id, num')->one();
- if (empty($chain_order)) throw new Exception('该订单不是聚合供应链订单');
- // 公共调用
- $order_detail = GlobalInvoke::exec(GlobalInvoke::ORDER_REFUND_SUBMIT, $this->mall_id, [
- 'order_detail' => $order_detail,
- 'mall_id' => $this->mall_id,
- ]) ?: $order_detail;
- // 一共可以退款
- $refund_total_money = bcadd($order_detail->goods_price, $order_detail->adjust_money, 2);
- // 未发货添加邮费
- if ($order_detail['shipping_status'] == ShippingStatusEnum::UN_SHIPPED) {
- $refund_total_money = bcadd($refund_total_money, $order->shipping_money, 2);
- }
- if ($params['refund_price'] > $refund_total_money) {
- throw new Exception('最多可退款金额¥' . $refund_total_money);
- }
- // 替换成商城状态
- $params['type'] = RefundTypeEnum::typeChange($params['type']);
- if (empty($params['type'])) {
- throw new Exception('选择退款状态有误');
- }
- $order_detail->is_feedback = OrderStatusEnum::FEEDBACKING;
- if(!$order_detail->save()) throw new Exception(OrderDetail::getStaticError());
- // 处理售后步骤
- !empty($params['pic_list']) && $params['pic_list'] = Json::decode($params['pic_list']);
- MallOrderRefund::stepHandle($params);
- // 退款主表
- $params2['is_feedback'] = $params['is_feedback'] = OrderStatusEnum::FEEDBACKING;
- $params2['order_id'] = $params['order_id'] = $order_detail->order_id;
- $params2['order_no'] = $params['order_no'] = MallOrder::generateOrderNo('r');
- $order_refund_model = MallOrderRefund::setData($params);
- if(!$order_refund_model) throw new Exception(MallOrderRefund::getStaticError());
- $params2['order_refund_id'] = $params['order_refund_id'] = $order_refund_model->id;
- $res = OrderRefundStep::setData($params);
- if(!$res) throw new Exception(OrderRefundStep::getStaticError());
- //自动维护订单主表
- $order = MallOrder::findOne($params['order_id']);
- $res = MallOrder::autoUpdateStatus($order);
- // 供应链订单详情
- $order_item = OrderItem::getOrderItemByDetailId($order_detail->id);
- if (empty($order_item)) throw new Exception('售后订单详情不存在');
- // 添加聚合售后
- $refund = OrderRefund::add([
- 'user_id' => $params['user_id'],
- 'mall_id' => $order->mall_id,
- 'order_id' => $order_detail['order_id'],
- 'order_detail_id' => $order_detail['id'],
- 'order_refund_id' => $order_refund_model->id,
- 'spu_id' => $order_item->spu_id,
- 'sku_id' => $order_item->sku_id,
- 'num' => $order_item->num,
- 'data' => $params2,
- ]);
-
- $db->commit();
- // 触发售后统计
- $refund_event = ['id' => $order_refund_model->id, 'type' => EnumsRefundTypeEnum::EVENT_APPLY];
- Yii::$app->services->rabbitMq->push(
- RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
- 'type' => EventNameEnum::ORDER_REFUND,
- 'params' => $refund_event,
- ], StatisticsHandle::class, 'handleSync'
- );
- // 自动推送售后
- Yii::$app->services->rabbitMq->push(
- RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, [
- 'mall_id' => $refund->mall_id,
- 'id' => $refund->id,
- ],
- self::class, 'autoPush'
- );
- return $order_refund_model;
- } catch (Exception $e) {
- $db->rollback();
- return $this->error($e->getMessage());
- }
- }
- /**
- * 驳回申请
- *
- * @param array $ids
- * @return integer
- */
- public function reject($ids)
- {
- $list = OrderRefund::find()->where(['id' => $ids, 'status' => OrderRefundEnum::NOT_PUSHED])->all();
- $num = 0;
- foreach ($list as $v) {
-
- $db = Yii::$app->db->beginTransaction();
- try {
- self::refuse($v);
- $db->commit();
- $num++;
- } catch (Exception $e) {
- $db->rollback();
- $v->error_msg = $e->getMessage();
- $v->save();
- }
- }
- return $num;
- }
- /**
- * 同意申请
- *
- * @param array $ids [1,2,3]
- * @return void
- */
- public function agree($ids)
- {
- $list = OrderRefund::find()->where(['id' => $ids, 'status' => OrderRefundEnum::NOT_PUSHED])->all();
- $num = 0;
- /**
- * @var OrderRefund
- */
- foreach ($list as $v) {
- $db = Yii::$app->db->beginTransaction();
- try {
- $res = $this->push($v);
- $v->pushOk($res);
- $num++;
- $db->commit();
- } catch (Exception $e) {
- $db->rollback();
- $v->error_msg = $e->getMessage();
- $v->save();
- }
- }
- return $num;
- }
- /**
- * 推送申请
- *
- * @param OrderRefund $model
- * @return void
- */
- public function push(OrderRefund $model)
- {
- // 聚合订单
- $chain_order = OrderItem::find()
- ->where(['mall_order_id' => $model->order_id, 'sku_id' => $model->sku_id])
- ->one();
- // 商城退款订单
- $mall_refund_order = MallOrderRefund::find()->where(['id' => $model->order_refund_id])->one();
- // 提交到聚合供应链
- $params = $this->getParams($model, $chain_order, $mall_refund_order);
- \Yii::error('-------- 推送售后订单 --------');
- \Yii::error(Json::encode($params));
- return $this->api->applyRefund($params);
- }
- /**
- * 获取供应链售后参数
- *
- * @param OrderRefund $model
- * @param OrderItem $chain_order
- * @param MallOrderRefund $mall_refund_order
- * @return array
- */
- private function getParams($model, $chain_order, $mall_refund_order)
- {
- $data = Json::decode($model->data);
- $params = [
- 'reason' => $mall_refund_order->reason,
- 'orderSn' => $chain_order->chain_order_sn,
- 'refundReasonId' => $data['reason_id'],
- 'goodsList' => [
- [
- 'goodsQuantity' => $model->num,
- 'goodsSpecId' => $model->sku_id,
- ]
- ],
- 'returnType' => /* RefundTypeEnum::typeChange */($data['type']),
- ];
- $mall_refund_order->remark && $params['memo'] = $mall_refund_order->remark;
- Json::decode($mall_refund_order->pic_list) && $params['pictureurlList'] = Json::decode($mall_refund_order->pic_list);
- return $params;
- }
-
- /**
- * 驳回
- *
- * @param OrderRefund $model
- * @return void
- */
- public static function refuse(OrderRefund $model)
- {
- $model->status = OrderRefundEnum::REFUSE;
- $res = $model->save();
- if ($res === false) throw new Exception($model->getError());
- $res = OrderRefundLogic::refuseRefundForChain($model->mall_id, $model->order_refund_id);
- if ($res === false) throw new Exception(MallOrderRefund::$static_error);
- }
- /**
- * 售后状态变更
- *
- * @param string $return_sn
- * @param integer $status
- * @return boolean
- */
- public function statusChange($return_sn, $status)
- {
- try {
- /**
- * @var OrderRefund|null
- */
- $refund_order = OrderRefund::getOrderByReturnSn($this->mall_id, $return_sn);
- if (empty($refund_order)) {
- throw new Exception("售后订单{$return_sn}不存在");
- }
- switch ($status) {
- // 审核中
- case '1':
- $refund_order->review();
- break;
- // 卖家拒绝退款
- case '2':
- $refund_order->refuseMoney();
- break;
- // 退款成功
- case '3':
- $refund_order->success();
- break;
- // 卖家拒绝退货退款
- case '4':
- $refund_order->refuseMoneyAndProduct();
- break;
- // 待买家退货
- case '5':
- $refund_detail = $this->api->orderReturnGoodsDetail($return_sn);
- $refund_order->waitBuyerSend($refund_detail);
- break;
- // 买家已退货,待卖家收货
- case '6':
- $refund_order->waitSellerReceive();
- break;
- // 买家已退货,卖家拒绝收货
- case '7':
- $refund_order->sellerRefuseReceive();
- break;
- // 卖家已收货,待确认退款
- case '8':
- $refund_order->sellerReceiveOfWait();
- break;
- // 退货退款成功
- case '9':
- $refund_order->successMoneyAndProduct();
- break;
- // 卖家拒绝换货
- case '10':
- $refund_order->refuseExchange();
- break;
- // 买家已退货,待卖家换货
- case '11':
- $refund_order->waitSellerSend();
- break;
- // 卖家已换货,待买家收货
- case '12':
- $refund_detail = $this->api->orderReturnGoodsDetail($return_sn);
- $refund_order->waitBuyerReceive($refund_detail);
- break;
- // 换货成功
- case '13':
- $refund_order->successExchange();
- break;
- // 已关闭
- case '14':
- $refund_order->close();
- break;
- // 卖家同意退款
- case '15':
- $refund_order->adoptMoney();
- break;
- // 卖家同意仅退款
- case '16':
- $refund_order->adoptOnlyMoney();
- break;
- // 卖家拒绝仅退款
- case '17':
- $refund_order->refuseOnlyMoney();
- break;
- // 仅退款成功
- case '18':
- $refund_order->successOnlyMoney();
- break;
- default:
- break;
- }
- } catch (Exception $e) {
- return $this->error("售后订单{$return_sn}, 售后失败, 状态为{$status}, 失败原因:" . $e->getMessage());
- }
- return true;
- }
- /**
- * 售后处理
- *
- * @param integer $refund_id
- * @return void
- */
- public function buyerDelivery($refund_id)
- {
- $chain_refund_sn = OrderRefund::find()->where(['order_refund_id' => $refund_id])->select('chain_refund_sn')->scalar();
- if ($chain_refund_sn) {
- $refund_order = MallOrderRefund::find()->where(['id' => $refund_id])->select('id, express, express_no')->one();
- try {
- // 都不为空的时候调用
- !empty($refund_order)
- && $refund_order->express_no
- && $refund_order->express
- && $this->api->sendReturnGoods(
- $chain_refund_sn,
- $refund_order->express_no,
- $refund_order->express
- );
- } catch (Exception $e) {
- Yii::error("");
- }
- }
- }
- /**
- * 取消订单
- *
- * @param integer $id
- * @return boolean
- */
- public function cancel($id)
- {
- $model = OrderRefund::find()->where(['order_refund_id' => $id, 'status' => OrderRefundEnum::NOT_PUSHED])->one();
- return self::refuse($model);
- }
- /**
- * 售后订单收货完成
- *
- * @param integer $id
- * @return boolean
- */
- public function finish($id)
- {
- $model = OrderRefund::find()->where(['order_refund_id' => $id])->one();
- if (empty($model)) return false;
- $this->api->receiptRefund($model->chain_refund_sn);
- }
- /**
- * 自动推送售后
- *
- * @param array $params
- * @return boolean
- */
- public static function autoPush($params = [])
- {
- if (empty($mall_id = $params['mall_id']) || empty($id = $params['id'])) return true;
- // 获取设置
- $setting = Setting::getSetting($mall_id);
- if (empty($setting) || empty($setting['refund_auto_push'])) return true;
- try {
- /**
- * @var OrderRefund
- */
- $model = OrderRefund::find()->where(['id' => $id])->one();
- $res = (new static(['mall_id' => $mall_id]))->push($model);
- $model->pushOk($res);
- } catch (Exception $e) {
- echo '文件: ' . $e->getFile() . ', 错误行数: ' . $e->getLine() . ', 错误信息: ' . $e->getMessage();
- }
- return true;
- }
- }
|