diff --git a/app/Amqp/Consumer/couponRebateConsumer.php b/app/Amqp/Consumer/couponRebateConsumer.php index a76f046..3417e2a 100644 --- a/app/Amqp/Consumer/couponRebateConsumer.php +++ b/app/Amqp/Consumer/couponRebateConsumer.php @@ -37,6 +37,9 @@ class couponRebateConsumer extends ConsumerMessage public function isEnable(): bool { + if(env('APP_ENV') == 'local') { + return false; + } return parent::isEnable(); } } diff --git a/app/Constants/ErrorCode.php b/app/Constants/ErrorCode.php index 205e0b8..fdb920a 100644 --- a/app/Constants/ErrorCode.php +++ b/app/Constants/ErrorCode.php @@ -55,6 +55,11 @@ class ErrorCode extends AbstractConstants const PAY_FAILURE = 400; /** + * @Message("Separate Accounts Error!") + */ + const SEPARATE_ACCOUNTS_ERROR = 700; + +/** * @Message("Goods failure!") */ const GOODS_FAILURE = 700; diff --git a/app/Constants/LogLabel.php b/app/Constants/LogLabel.php index edcb57c..072a6f7 100644 --- a/app/Constants/LogLabel.php +++ b/app/Constants/LogLabel.php @@ -33,4 +33,25 @@ class LogLabel extends AbstractConstants * @Message("Order Log Label") */ const ORDER_LOG = 'order_log'; + + /** + * @Message("Separate Accounts Log Label") + */ + const SEPARATE_ACCOUNTS_LOG = 'separate_accounts_log'; + + /** + * @Message("Online Order Complete Log Label") + */ + const ONLINE_COMPLETE_LOG = 'online_complete_log'; + + /** + * @Message("Online Paid Complete Log Label") + */ + const ONLINE_PAID_LOG = 'online_paid_log'; + + /** + * @Message("Offline Paid Complete Log Label") + */ + const OFFLINE_PAID_LOG = 'offline_paid_log'; + } diff --git a/app/Controller/CommunityController.php b/app/Controller/CommunityController.php new file mode 100644 index 0000000..0caa660 --- /dev/null +++ b/app/Controller/CommunityController.php @@ -0,0 +1,28 @@ +validated(); + $res = $this->userCommunityService->bindLimitByUser(UserRelationBind::BIND_TYPE_COMMUNITY, $data['source_id'], $data['user_id'], $data['json_data']); + return $this->success(['id' => $res->id]); + } + +} diff --git a/app/Controller/NotifyController.php b/app/Controller/NotifyController.php index 955db3f..1ddfb11 100644 --- a/app/Controller/NotifyController.php +++ b/app/Controller/NotifyController.php @@ -18,6 +18,8 @@ use App\Service\DeviceServiceInterface; use App\Service\FeiePrintServiceInterface; use App\Service\MiniprogramServiceInterface; use App\Service\MqttServiceInterface; +use App\Service\OrderServiceInterface; +use App\Service\SeparateAccountsServiceInterface; use App\Service\UserServiceInterface; use EasyWeChat\Factory; use Hyperf\DbConnection\Db; @@ -68,6 +70,18 @@ class NotifyController extends BaseController */ protected $couponRebateService; + /** + * @Inject + * @var OrderServiceInterface + */ + protected $orderService; + + /** + * @Inject + * @var SeparateAccountsServiceInterface + */ + protected $separateAccountsService; + public function wxminiOnline() { @@ -122,92 +136,82 @@ class NotifyController extends BaseController return true; } - // 修改订单、子订单状态 - $currentTime = time(); - $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; - $orderMain->time_pay = $currentTime; - $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); - $orderMain->save(); - - $upOrder = Order::query() - ->where(['order_main_id' => $orderMain->id]) - ->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]); - - // 更新商户销量 - $upStoreScore = Store::query() - ->whereIn('id', explode(',', $orderMain->store_ids)) - ->update(['score' => Db::raw('score+1')]); - - // 更新商品库存和销量 - $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) - ->where(['order_main_id' => $orderMain->id]) - ->get() - ->toArray(); - $orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id']) - ->whereIn('order_id', array_values(array_column($orders, 'id'))) - ->get() - ->toArray(); - foreach ($orderGoods as $key => &$goodsItem) { - - $goods = Goods::find($goodsItem['id']); - - // 库存处理,有规格 - if ($goodsItem['combination_id']) { - $combination = SpecCombination::find($goodsItem['combination_id']); - $combination->number = $combination->number - $goodsItem['number']; - $combination->save(); - } else { - $goods->inventory = $goods->inventory - $goodsItem['number']; - } - - $goods->sales = $goods->sales - $goodsItem['number']; - $goods->save(); - - } - - // 月销流水 - $statistics = []; - foreach ($orders as $key => &$order) { - $statistics[] = [ - 'money' => $order['money'], - 'user_id' => $order['user_id'], - 'store_id' => $order['store_id'], - 'market_id' => $orderMain->market_id, - 'order_id' => $order['id'], - 'createtime' => strtotime($order['pay_time']), - ]; - } - - if (is_array($statistics) && !empty($statistics)) { - $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics); - } + $this->orderService->onlinePaid($message['out_trade_no']); + $this->separateAccountsService->orderOnlinePaid($message['out_trade_no']); + + // // 修改订单、子订单状态 + // $currentTime = time(); + // $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; + // $orderMain->time_pay = $currentTime; + // $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); + // $orderMain->save(); + // + // $upOrder = Order::query() + // ->where(['order_main_id' => $orderMain->id]) + // ->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]); + // + // // 更新商户销量 + // $upStoreScore = Store::query() + // ->whereIn('id', explode(',', $orderMain->store_ids)) + // ->update(['score' => Db::raw('score+1')]); + // + // // 更新商品库存和销量 + // $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) + // ->where(['order_main_id' => $orderMain->id]) + // ->get() + // ->toArray(); + // $orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id']) + // ->whereIn('order_id', array_values(array_column($orders, 'id'))) + // ->get() + // ->toArray(); + // foreach ($orderGoods as $key => &$goodsItem) { + // + // $goods = Goods::find($goodsItem['id']); + // + // // 库存处理,有规格 + // if ($goodsItem['combination_id']) { + // $combination = SpecCombination::find($goodsItem['combination_id']); + // $combination->number = $combination->number - $goodsItem['number']; + // $combination->save(); + // } else { + // $goods->inventory = $goods->inventory - $goodsItem['number']; + // } + // + // $goods->sales = $goods->sales - $goodsItem['number']; + // $goods->save(); + // + // } + // + // // 月销流水 + // $statistics = []; + // foreach ($orders as $key => &$order) { + // $statistics[] = [ + // 'money' => $order['money'], + // 'user_id' => $order['user_id'], + // 'store_id' => $order['store_id'], + // 'market_id' => $orderMain->market_id, + // 'order_id' => $order['id'], + // 'createtime' => strtotime($order['pay_time']), + // ]; + // } + // + // if (is_array($statistics) && !empty($statistics)) { + // $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics); + // } // 优惠券返券 $this->couponRebateService->couponRebateInTask($orderMain->id); // 喇叭通知,兼容旧音响,MQTT+IOT $res = $this->mqttSpeakerService->speakToStore($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_mqtt' => json_encode($res)] - ); $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_device' => json_encode($res)] - ); + // 公众号模板消息 $res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_mini' => json_encode($res)] - ); - // 打印订单,自动打印 TODO 后续优化调用逻辑 + + // 打印订单,自动打印 $res = $this->feiePrintService->feiePrint($orderMain->global_order_id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_feie' => json_encode($res)] - ); + Db::commit(); return true; @@ -284,112 +288,105 @@ class NotifyController extends BaseController return true; } - // 修改订单、子订单状态 - $currentTime = time(); - $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; - $orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE; - $orderMain->time_pay = $currentTime; - $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); - $orderMain->save(); - - $upOrder = Order::query() - ->where(['order_main_id' => $orderMain->id]) - ->update([ - 'state' => OrderMain::ORDER_STATE_UNTAKE, - 'dm_state' => OrderMain::ORDER_STATE_UNTAKE, - 'pay_time' => date('Y-m-d H:i:s', $currentTime) - ]); - - // 查询子订单,当面付目前实际上只有一个子订单 - $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) - ->where(['order_main_id' => $orderMain->id]) - ->get() - ->toArray(); - - // 商户钱包、流水资金、奖励、发布模板消息处理 - foreach ($orders as $key => $orderItem) { - - $recordBase = [ - 'user_id' => $orderItem['user_id'], - 'order_id' => $orderItem['id'], - 'store_id' => $orderItem['store_id'], - 'type' => 1, - 'time' => date('Y-m-d H:i:s', $currentTime), - 'add_time' => $currentTime, - ]; - - // 钱包 - $store = Store::find($orderItem['store_id']); - $store->store_wallet = bcadd($store->store_wallet, $orderItem['money'], 2); - $store->save(); - - // 流水 - $record = [ - 'money' => $orderItem['money'], - 'note' => '当面付订单收入', - 'category' => 2, - ]; - StoreAccount::query()->insert(array_merge($recordBase, $record)); - - // 平台新用户奖励给商户 - $isStageNewUser = $this->userService->isStageNewUser($orderItem['user_id'], $orderMain->id); - $needAward = false; - $awardAmount = 0; - if ($isStageNewUser) { - $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_new_user'])->value('value'); - // 流水 - $record = [ - 'money' => $awardAmount, - 'note' => '新用户下单成功,平台奖励', - 'category' => 3, - ]; - $needAward = true; - } else { - $isStoreFirstOrderToday = $this->userService->isStoreFirstOrderToday($orderItem['user_id'],$orderItem['store_id'],$orderItem['id'], self::AWARD_LIMIT_AMOUNT); - if ($isStoreFirstOrderToday && $orderItem['money'] >= self::AWARD_LIMIT_AMOUNT) { - $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_each_order'])->value('value'); - // 流水 - $record = [ - 'money' => $awardAmount, - 'note' => '用户下单成功,平台奖励', - 'category' => 4, - ]; - $needAward = true; - } - } - - if ($needAward && $awardAmount) { - // 奖励钱包 - $store->refresh(); - $store->award_money = bcadd($store->award_money, $awardAmount, 2); - $store->save(); - - // 流水 - StoreAccount::query()->insert(array_merge($recordBase, $record)); - - // 发布公众号消息 - $openid = Users::query()->where(['id' => $store['user_id']])->value('openid'); - $res = $this->miniprogramService->sendTemMsgForAward($record['money'], $record['note'], $openid, $recordBase['time']); - } - } + $orderPaid = $this->orderService->offlinePaid($message['out_trade_no']); + $separate = $this->separateAccountsService->orderOfflinePaid($message['out_trade_no']); + + // // 修改订单、子订单状态 + // $currentTime = time(); + // $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; + // $orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE; + // $orderMain->time_pay = $currentTime; + // $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); + // $orderMain->save(); + // + // $upOrder = Order::query() + // ->where(['order_main_id' => $orderMain->id]) + // ->update([ + // 'state' => OrderMain::ORDER_STATE_UNTAKE, + // 'dm_state' => OrderMain::ORDER_STATE_UNTAKE, + // 'pay_time' => date('Y-m-d H:i:s', $currentTime) + // ]); + + // // 查询子订单,当面付目前实际上只有一个子订单 + // $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) + // ->where(['order_main_id' => $orderMain->id]) + // ->get() + // ->toArray(); + // + // // 商户钱包、流水资金、奖励、发布模板消息处理 + // foreach ($orders as $key => $orderItem) { + // + // $recordBase = [ + // 'user_id' => $orderItem['user_id'], + // 'order_id' => $orderItem['id'], + // 'store_id' => $orderItem['store_id'], + // 'type' => 1, + // 'time' => date('Y-m-d H:i:s', $currentTime), + // 'add_time' => $currentTime, + // ]; + // + // // 钱包 + // $store = Store::find($orderItem['store_id']); + // $store->store_wallet = bcadd($store->store_wallet, $orderItem['money'], 2); + // $store->save(); + // + // // 流水 + // $record = [ + // 'money' => $orderItem['money'], + // 'note' => '当面付订单收入', + // 'category' => 2, + // ]; + // StoreAccount::query()->insert(array_merge($recordBase, $record)); + // + // // 平台新用户奖励给商户 + // $isStageNewUser = $this->userService->isPlatformNewUser($orderItem['user_id'], $orderMain->id); + // $needAward = false; + // $awardAmount = 0; + // if ($isStageNewUser) { + // $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_new_user'])->value('value'); + // // 流水 + // $record = [ + // 'money' => $awardAmount, + // 'note' => '新用户下单成功,平台奖励', + // 'category' => 3, + // ]; + // $needAward = true; + // } else { + // $isStoreFirstOrderToday = $this->userService->isStoreFirstOrderToday($orderItem['user_id'],$orderItem['store_id'],$orderItem['id'], self::AWARD_LIMIT_AMOUNT); + // if ($isStoreFirstOrderToday && $orderItem['money'] >= self::AWARD_LIMIT_AMOUNT) { + // $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_each_order'])->value('value'); + // // 流水 + // $record = [ + // 'money' => $awardAmount, + // 'note' => '用户下单成功,平台奖励', + // 'category' => 4, + // ]; + // $needAward = true; + // } + // } + // + // if ($needAward && $awardAmount) { + // // 奖励钱包 + // $store->refresh(); + // $store->award_money = bcadd($store->award_money, $awardAmount, 2); + // $store->save(); + // + // // 流水 + // StoreAccount::query()->insert(array_merge($recordBase, $record)); + // + // // 发布公众号消息 + // $openid = Users::query()->where(['id' => $store['user_id']])->value('openid'); + // $res = $this->miniprogramService->sendTemMsgForAward($record['money'], $record['note'], $openid, $recordBase['time']); + // } + // } // 喇叭通知,兼容旧音响,MQTT+IOT $res = $this->mqttSpeakerService->speakToStore($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_mqtt' => json_encode($res)] - ); $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_device' => json_encode($res)] - ); + // 公众号模板消息 $res = $this->miniprogramService->sendTemMsgForOfflineOrder($orderMain->id); - $this->log->event( - LogLabel::PAY_NOTIFY_WXMINI, - ['fail_mini' => json_encode($res)] - ); + Db::commit(); return true; diff --git a/app/Controller/OrderController.php b/app/Controller/OrderController.php index f26045d..fb2ed20 100644 --- a/app/Controller/OrderController.php +++ b/app/Controller/OrderController.php @@ -3,11 +3,16 @@ namespace App\Controller; use App\Constants\ErrorCode; +use App\Constants\LogLabel; +use App\Model\OrderMain; use App\Request\OrderOfflineRequest; use App\Request\OrderOnlineRequest; +use App\Service\SeparateAccountsServiceInterface; +use Hyperf\DbConnection\Db; use Hyperf\Di\Annotation\Inject; use App\Service\OrderServiceInterface; use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\Validation\ValidationException; class OrderController extends BaseController { @@ -18,6 +23,12 @@ class OrderController extends BaseController */ protected $orderService; + /** + * @Inject + * @var SeparateAccountsServiceInterface + */ + protected $separateAccountsService; + public function addOnlineOrder(OrderOnlineRequest $request) { $orderMainId = $this->orderService->addOnlineOrder($request->validated()); @@ -35,4 +46,64 @@ class OrderController extends BaseController } return $this->success(['order_id' => $orderMainId]); } + + /** + * 用户完成订单-确认收货 + */ + public function userComp() + { + + $validator = $this->validationFactory->make( + $this->request->all(), + [ + 'user_id' => 'required|nonempty|integer', + 'order_id' => 'required|nonempty|numeric', + ], + [ + '*.*' => ':attribute 参数不正确', + ] + ); + + if ($validator->fails()) { + // Handle exception + throw new ValidationException($validator); + return; + } + + $userId = $this->request->input('user_id'); + $orderId = $this->request->input('order_id'); // TODO 等新订单列表接口处理完毕后全面转换成global_order_id + $orderMain = OrderMain::query() + ->where(['id' => $orderId, 'state' => OrderMain::ORDER_STATE_DELIVERY, 'user_id' => $userId]) + ->first(); + + if (empty($orderMain)) { + $this->log->event(LogLabel::ONLINE_COMPLETE_LOG, ['order_not_found' => 'order_not_found']); + return $this->result(ErrorCode::SEPARATE_ACCOUNTS_ERROR, '', '操作失败,订单异常或不存在'); + } + + Db::beginTransaction(); + try { + + $this->orderService->onlineCompleted($orderMain->global_order_id); + $this->separateAccountsService->orderOnlineCompleted($orderMain->global_order_id); + + Db::commit(); + return $this->success(''); + } catch (\Exception $e) { + + Db::rollBack(); + $this->log->event(LogLabel::ONLINE_COMPLETE_LOG, ['exception' => $e->getMessage()]); + return $this->result(ErrorCode::SEPARATE_ACCOUNTS_ERROR, '', '操作失败,请稍后重试'); + } + + } + + /** + * 用户取消订单 + */ + public function onlineCancel(){ + $OrderId = $this->request->input('order_id'); + return $this->success($this->orderService->onlineCancel($OrderId)); + } + } \ No newline at end of file diff --git a/app/Controller/PaymentController.php b/app/Controller/PaymentController.php index b2c6fba..9fc92ae 100644 --- a/app/Controller/PaymentController.php +++ b/app/Controller/PaymentController.php @@ -33,7 +33,8 @@ class PaymentController extends BaseController $result = $app->order->unify([ 'body' => '懒族生活 - 外卖下单', 'out_trade_no' => $orderMain->global_order_id, - 'total_fee' => bcmul(floatval($orderMain->money), 100, 0), + // 'total_fee' => bcmul(floatval($orderMain->money), 100, 0), + 'total_fee' => 1, 'notify_url' => config('site_host') . '/wechat/notify/wxminionline', 'trade_type' => 'JSAPI', 'openid' => $data['openid'], diff --git a/app/JsonRpc/OrderService.php b/app/JsonRpc/OrderService.php new file mode 100644 index 0000000..43abb2e --- /dev/null +++ b/app/JsonRpc/OrderService.php @@ -0,0 +1,92 @@ +orderService->onlineCompleted($global_order_id); + $this->separateAccountsService->orderOnlineCompleted($global_order_id); + + Db::commit(); + return [ + "status" => 200, + "code" => 0, + "result" => [], + "message" => '调用成功' + ]; + } catch (\Exception $e) { + + Db::rollBack(); + $this->log->event(LogLabel::ONLINE_COMPLETE_LOG, ['exception' => $e->getMessage()]); + return [ + "status" => 200, + "code" =>ErrorCode::SEPARATE_ACCOUNTS_ERROR, + "result" => [], + "message" => ErrorCode::getMessage(ErrorCode::SEPARATE_ACCOUNTS_ERROR) + ]; + } + + } + + /** + * 线上订单退款 + * 申请退款 state = 8 + * 退款成功 state = 9 + */ + public function onlineRefund($global_order_id){ + Db::beginTransaction(); + try{ + + return [ + "status" => 200, + "code" => 0, + "result" => $this->orderService->onlineRefund($global_order_id), + // 'result' => $global_order_id, + "message" => '退款成功' + ]; + } catch (\Exception $e){ + Db::rollBack(); + return [ + "status" => 200, + "code" => ErrorCode::ORDER_FAILURE, + "result" => [], + "message" => $e->getMessage() + ]; + } + } +} \ No newline at end of file diff --git a/app/JsonRpc/OrderServiceInterface.php b/app/JsonRpc/OrderServiceInterface.php new file mode 100644 index 0000000..6292ffe --- /dev/null +++ b/app/JsonRpc/OrderServiceInterface.php @@ -0,0 +1,8 @@ +extend('exists_enable', function ($attribute, $value, $parameters, $validator) { + + // 查询 + $builder = Db::table($parameters[0])->where($parameters[1], '=', $value); + + $whereArr = array_slice($parameters,2); + if (!empty($whereArr)) { + foreach ($whereArr as $key => $where) { + $builder->whereRaw($where); + } + } + + return $builder->exists(); + }); + + // 注册了 not_equal 验证器规则,参数是anotherfield,table,primary_field,foreign_field + // 要排除对比的字段请求参数名、表名、本参数对应表id、比较字段 + $validatorFactory->extend('not_equal', function ($attribute, $value, $parameters, $validator) { + + // 获取比较字段参数值 + $foreignValue = $validator->getData()[$parameters[0]]; + + // 查询 + $builder = Db::table($parameters[1]) + ->where($parameters[2], '=', $value) + ->where($parameters[3], '!=', $foreignValue) + ; + + return $builder->exists(); + }); + // 注册了 base64 验证器规则 $validatorFactory->extend('base64', function ($attribute, $value, $parameters, $validator) { @@ -78,36 +111,40 @@ class ValidatorFactoryResolvedListener implements ListenerInterface }); - // 注册了 exists_enable 验证器规则,参数是table,field,where1,where2... - $validatorFactory->extend('exists_enable', function ($attribute, $value, $parameters, $validator) { - - // 查询 - $builder = Db::table($parameters[0])->where($parameters[1], '=', $value); + // 注册了 file_different_if_file 验证器规则 + // file_different_if_file:field 两文件字段不能是同一个文件 + $validatorFactory->extend('file_different_if_file', function ($attribute, $value, $parameters, $validator) { - $whereArr = array_slice($parameters,2); - if (!empty($whereArr)) { - foreach ($whereArr as $key => $where) { - $builder->whereRaw($where); - } + // 获取比较字段参数值 + $anotherFile = $validator->getData()[$parameters[0]]; + if (!($value instanceof UploadedFile && $anotherFile instanceof UploadedFile)) { + return true; } + return md5_file($value->getRealPath()) !== md5_file($anotherFile->getRealPath()); - return $builder->exists(); }); - // 注册了 not_equal 验证器规则,参数是anotherfield,table,primary_field,foreign_field - // 要排除对比的字段请求参数名、表名、本参数对应表id、比较字段 - $validatorFactory->extend('not_equal', function ($attribute, $value, $parameters, $validator) { + // 注册了 tel 验证器规则 + // 手机号码验证器 + $validatorFactory->extend('tel', function ($attribute, $value, $parameters, $validator) { + return boolval(preg_match('/^1[3-9]\d{9}$/', $value)); + }); - // 获取比较字段参数值 - $foreignValue = $validator->getData()[$parameters[0]]; + // 注册了 image_if_file 验证器规则 + // 如果是文件就必须是图片类型的 + $validatorFactory->extend('image_if_file', function ($attribute, $value, $parameters, $validator) { - // 查询 - $builder = Db::table($parameters[1]) - ->where($parameters[2], '=', $value) - ->where($parameters[3], '!=', $foreignValue) - ; + if (!($value instanceof UploadedFile)) { + return true; + } + + $rules = $validator->getRules(); + $rules[$attribute] = ['image']; + $validator->setRules($rules); + + return $validator->passes(); - return $builder->exists(); }); + } } \ No newline at end of file diff --git a/app/Model/CouponUserRec.php b/app/Model/CouponUserRec.php index c5c2608..25afd2f 100644 --- a/app/Model/CouponUserRec.php +++ b/app/Model/CouponUserRec.php @@ -6,5 +6,13 @@ namespace App\Model; class CouponUserRec extends Model { + /* 状态 */ + // 未使用 + const STATE_UNUSED = 0; + // 使用部分 + const STATE_SOME = 1; + // 已用完 + const STATE_FINISH = 2; + protected $table = 'ims_system_coupon_user_receive'; } \ No newline at end of file diff --git a/app/Model/CouponUserUse.php b/app/Model/CouponUserUse.php index a8cfcf3..0d53a14 100644 --- a/app/Model/CouponUserUse.php +++ b/app/Model/CouponUserUse.php @@ -6,5 +6,12 @@ namespace App\Model; class CouponUserUse extends Model { + // 正常使用 + const COUPON_USE_STATE_USED = 1; + // 退回用户 + const COUPON_USE_STATE_CANCEL = 2; + + public $timestamps = false; + protected $table = 'ims_system_coupon_user_use'; } \ No newline at end of file diff --git a/app/Model/FinancialRecord.php b/app/Model/FinancialRecord.php new file mode 100644 index 0000000..b56adbe --- /dev/null +++ b/app/Model/FinancialRecord.php @@ -0,0 +1,91 @@ +=100是提现消费等支出项 + */ + const MONEY_TYPE_PLAT_NEW_USER = 1; // 社区服务点新用户奖励(线上订单完成) + const MONEY_TYPE_FIRST_ORDER = 2; // 社区服务点新用户线上首单奖励(线上订单完成) + const MONEY_TYPE_OL_ORDER = 3; // 社区服务点用户线上订单分账(线上订单完成) + const MONEY_TYPE_STORE_PLAT_NEW_USER = 4; // 商户平台新用户奖励 + const MONEY_TYPE_STORE_FIRST_ORDER = 5; // 商户当日首单奖励 + const MONEY_TYPE_STORE_OL_ORDER_COMP = 6; // 商户线上订单完成收入 + const MONEY_TYPE_STORE_OFL_ORDER_COMP = 7; // 商户线下订单完成收入 + const MONEY_TYPE_USER_OFL_ORDER = 100; // 用户线下支付订单 + const MONEY_TYPE_USER_OL_ORDER = 101; // 用户线上支付订单 + + /** + * 状态 + */ + const STATUS_NORMAL = 1; + const STATUS_ABNORMAL = 2; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'lanzu_financial_record'; + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'user_id', + 'user_type', + 'money', + 'money_type', + 'source_id', + 'source_type', + 'desc', + 'comment', + 'status', + ]; + /** + * The attributes that should be cast to native types. + * + * @var array + */ + protected $casts = []; +} \ No newline at end of file diff --git a/app/Model/Model.php b/app/Model/Model.php index f606652..fa03395 100644 --- a/app/Model/Model.php +++ b/app/Model/Model.php @@ -19,4 +19,16 @@ abstract class Model extends BaseModel implements CacheableInterface { use Cacheable; protected $dateFormat = 'U'; + + /** + * 设置表后缀 + * @param string $suffix + * @return $this + */ + public function suffix($suffix = ''): Model + { + $tableName = $this->getTable(); + $this->setTable($tableName.'_'.$suffix); + return $this; + } } diff --git a/app/Model/OrderMain.php b/app/Model/OrderMain.php index 92213ad..dfb6d0d 100644 --- a/app/Model/OrderMain.php +++ b/app/Model/OrderMain.php @@ -32,6 +32,8 @@ class OrderMain extends Model const ORDER_STATE_REFUNDED = 9; // 拒绝退款 const ORDER_STATE_UNREFUND = 10; + // 完成状态组合 + const ORDER_STATE_FINISH = [self::ORDER_STATE_COMPLETE, self::ORDER_STATE_EVALUATED, self::ORDER_STATE_UNREFUND]; // 订单支付方式 // 微信支付 diff --git a/app/Model/ServiceReward.php b/app/Model/ServiceReward.php new file mode 100644 index 0000000..583ad0a --- /dev/null +++ b/app/Model/ServiceReward.php @@ -0,0 +1,33 @@ + 'array' + ]; +} \ No newline at end of file diff --git a/app/Model/UserBalance.php b/app/Model/UserBalance.php new file mode 100644 index 0000000..3883747 --- /dev/null +++ b/app/Model/UserBalance.php @@ -0,0 +1,36 @@ +attributes['json_data'] = $value ? json_encode(json_decode($value, true)) : ''; + } + +} \ No newline at end of file diff --git a/app/Request/CommunityBindRequest.php b/app/Request/CommunityBindRequest.php new file mode 100644 index 0000000..6fe4841 --- /dev/null +++ b/app/Request/CommunityBindRequest.php @@ -0,0 +1,45 @@ + 'required|nonempty', + 'user_id' => 'required|nonempty|exists_enable:ims_cjdc_user,id', + 'json_data' => 'json', + ]; + } + + public function messages(): array + { + return [ + '*.nonempty' => ':attribute参数异常', + 'user_id.exists_enable' => '用户不存在', + ]; + } + + public function attributes(): array + { + return [ + + ]; + } +} diff --git a/app/Request/OrderOnlineRequest.php b/app/Request/OrderOnlineRequest.php index 019cc99..b02144f 100644 --- a/app/Request/OrderOnlineRequest.php +++ b/app/Request/OrderOnlineRequest.php @@ -20,7 +20,6 @@ class OrderOnlineRequest extends BaseFormRequest public function rules(): array { return [ - 'order_num' => 'nonempty', 'delivery_no' => '', 'dada_fee' => 'nonempty', 'market_id' => 'required|nonempty|integer', diff --git a/app/Service/CouponService.php b/app/Service/CouponService.php index eb726f0..c5cb7bd 100644 --- a/app/Service/CouponService.php +++ b/app/Service/CouponService.php @@ -7,6 +7,7 @@ use Hyperf\DbConnection\Db; use App\Model\CouponUserRecType; use App\Model\Coupon; use App\Model\CouponRec; +use App\Model\CouponUserUse; use Hyperf\Utils\ApplicationContext; use App\TaskWorker\SSDBTask; use App\Constants\SsdbKeysPrefix; @@ -220,4 +221,56 @@ class CouponService implements CouponServiceInterface return $setRes&&$expireRes; } + /** + * 取消订单返券 + * @param $order_id + * @return bool + */ + public function refundOrderCoupons($order_id,$user_id){ + $coupon = CouponUserUse::where([ + ['order_main_id','=',$order_id], + ['status','=',CouponUserUse::COUPON_USE_STATE_USED], + ]) + ->select('id','user_receive_id','number') + ->first(); + // 返回用户优惠券数量并更新状态 + $res = Db::update("UPDATE ims_system_coupon_user_receive SET number_remain=number_remain+{$coupon->number}, status=IF(number=number_remain,0,1), update_time=".time()."" + ." WHERE id={$coupon->user_receive_id} AND number>=(number_remain+{$coupon->number})"); + + // 更新使用记录状态为已退回 + CouponUserUse::where([ + ['id','=',$coupon->id], + ['status','=',CouponUserUse::COUPON_USE_STATE_USED], + ]) + ->update([ + 'status' => CouponUserUse::COUPON_USE_STATE_CANCEL, + 'return_time' => time(), + 'update_time' => time(), + ]); + + //删除当日 redis 使用记录缓存 + $redis = ApplicationContext::getContainer()->get(Redis::class); + $remRes = $redis->sRem( + 'coupon_'.date('Ymd').'_used_'.$user_id, + $coupon->system_coupon_id + ); + return $res; + } + + /* 删除-优惠券今日使用的缓存 + * @param $userId + * @param $couponId + * @param $couponRecId + * @return bool + */ + function clearTodayCouponUsed($userId, $couponId) + { + + $redis = ApplicationContext::getContainer()->get(Redis::class); + + $res = $redis->sRem( + 'coupon_'.date('Ymd').'_used_'.$userId, + $couponId + ); + } } \ No newline at end of file diff --git a/app/Service/CouponServiceInterface.php b/app/Service/CouponServiceInterface.php index bdd60c5..e4155d7 100644 --- a/app/Service/CouponServiceInterface.php +++ b/app/Service/CouponServiceInterface.php @@ -27,4 +27,6 @@ interface CouponServiceInterface */ public function getOrderCanUseCoupons($orderAmount, $marketId, $userId, $fields=[], $type=1, $storeTypeIds=[0]); + public function refundOrderCoupons($order_id,$user_id); + public function clearTodayCouponUsed($userId, $couponId); } diff --git a/app/Service/FeiePrintService.php b/app/Service/FeiePrintService.php index 9f8f31d..114510b 100644 --- a/app/Service/FeiePrintService.php +++ b/app/Service/FeiePrintService.php @@ -37,6 +37,9 @@ class FeiePrintService implements FeiePrintServiceInterface ->orderBy('s.id') ->get() ->toArray(); + if (empty($data)) { + return ; + } foreach ($data as $key => &$item) { $item = (array)$item; } diff --git a/app/Service/FinancialRecordService.php b/app/Service/FinancialRecordService.php new file mode 100644 index 0000000..574de5c --- /dev/null +++ b/app/Service/FinancialRecordService.php @@ -0,0 +1,182 @@ +record( + FinancialRecord::ACCOUNT_LEDGER, + [ + 'user_id' => FinancialRecord::ACCOUNT_LEDGER, + 'user_type' => FinancialRecord::USER_TYPE_LEDGER, + 'money' => $money, + 'money_type' => $money_type, + 'source_id' => $source_id, + 'source_type' => $source_type, + 'desc' => $desc, + 'comment' => $comment, + 'status' => FinancialRecord::STATUS_NORMAL, + ], + true + ); + } + + public function record($user_id, $record, $isLedger=false) + { + $financialRecord = new FinancialRecord(); + + if (!$isLedger) { + $mod = bcmod((string)$user_id, '5', 0); + $financialRecord->suffix($mod); + } + + return $financialRecord->fill( + [ + 'user_id' => $user_id, + 'user_type' => $record['user_type'], + 'money' => $record['money'], + 'money_type' => $record['money_type'], + 'source_id' => $record['source_id'], + 'source_type' => $record['source_type'], + 'desc' => $record['desc'], + 'comment' => $record['comment'], + 'status' => $record['status'], + ] + )->save(); + + } + + /** + * @inheritDoc + */ + public function communityAwardByPlatNewUser($user_id, $source_id, $money, $user_type=2, $source_type=1, $money_type=1, $desc='新用户奖励', $comment='社区服务点') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 维护社区服务点余额 + $balance = UserBalance::firstOrNew([ + 'user_type' => UserBalance::USER_TYPE_CS, + 'source_id' => $user_id + ]); + $balance->balance = bcadd($balance->balance, $money); + $balance->save(); + } + + /** + * @inheritDoc + */ + public function communityAwardByPlatNewUserFirstOLOrder($user_id, $source_id, $money, $user_type=2, $source_type=1, $money_type=2, $desc='新用户首单奖励', $comment='社区服务点') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 维护社区服务点余额 + $balance = UserBalance::firstOrNew([ + 'user_type' => UserBalance::USER_TYPE_CS, + 'source_id' => $user_id + ]); + $balance->balance = bcadd($balance->balance, $money); + $balance->save(); + } + + /** + * @inheritDoc + */ + public function communitySeparateAccountsByOrderComp($user_id, $source_id, $money, $user_type=2, $source_type=1, $money_type=3, $desc='用户订单分成', $comment='社区服务点') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 维护社区服务点余额 + $balance = UserBalance::firstOrNew([ + 'user_type' => UserBalance::USER_TYPE_CS, + 'source_id' => $user_id + ]); + $balance->balance = bcadd($balance->balance, $money); + $balance->save(); + } + + + /** + * @inheritDoc + */ + public function storeAwardByPlatNewUserOFLOrder($user_id, $source_id, $money, $user_type=1, $source_type=1, $money_type=4, $desc='新用户下单奖励', $comment='用户当面付商户奖励') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 同时维护钱包 + $store = Store::query()->where(['user_id' => $user_id])->first(); + $store->award_money = bcadd($store->award_money, $money, 2); + $store->save(); + } + + /** + * @inheritDoc + */ + public function storeAwardByTodayFirstOFLOrder($user_id, $source_id, $money, $user_type=1, $source_type=1, $money_type=5, $desc='用户店铺首单奖励', $comment='用户当面付商户奖励') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 同时维护钱包 + $store = Store::query()->where(['user_id' => $user_id])->first(); + $store->award_money = bcadd($store->award_money, $money, 2); + $store->save(); + } + + public function recordAll($user_id, $source_id, $money, $user_type=1, $source_type=0, $money_type=0, $desc='', $comment='') { + $this->record( + $user_id, + [ + 'user_id' => $user_id, + 'user_type' => $user_type, + 'money' => $money, + 'money_type' => $money_type, + 'source_id' => $source_id, + 'source_type' => $source_type, + 'desc' => $desc, + 'comment' => $comment, + 'status' => FinancialRecord::STATUS_NORMAL, + ] + ); + + $this->ledgerAccounts($source_id, $money, $source_type, $money_type, $desc, $comment); + } + + /** + * @inheritDoc + */ + public function userByOFLOrderPaid($user_id, $source_id, $money, $user_type=1, $source_type=1, $money_type=100, $desc='用户下单(线下)', $comment='用户下单') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + } + + /** + * @inheritDoc + */ + public function userByOLOrderPaid($user_id, $source_id, $money, $user_type=1, $source_type=1, $money_type=101, $desc='用户下单(线上)', $comment='用户下单') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + } + + /** + * @inheritDoc + */ + public function storeByOLOrderComp($user_id, $source_id, $money, $user_type = 1, $source_type = 1, $money_type = 6, $desc = '线上外卖订单收入', $comment = '用户订单完成') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + // 同时维护钱包 + $store = Store::query()->where(['user_id' => $user_id])->first(); + $store->store_wallet = bcadd($store->store_wallet, $money, 2); + $store->save(); + } + + /** + * @inheritDoc + */ + public function storeByOFLOrderComp($user_id, $source_id, $money, $user_type = 1, $source_type = 1, $money_type = 7, $desc = '线下当面付订单收入', $comment = '用户订单完成') + { + $this->recordAll($user_id, $source_id, $money, $user_type, $source_type, $money_type, $desc, $comment); + } +} \ No newline at end of file diff --git a/app/Service/FinancialRecordServiceInterface.php b/app/Service/FinancialRecordServiceInterface.php new file mode 100644 index 0000000..8a53628 --- /dev/null +++ b/app/Service/FinancialRecordServiceInterface.php @@ -0,0 +1,146 @@ +existsByOrderNum($data['order_num'])) { - return $orderMainId; - } - Db::beginTransaction(); try { + // TODO 这个字段后续可能不用了,之前由达达订单号从前端传上来 + $dataMain['order_num'] = 'o'.date('YmdHis').mt_rand(1000,9999); + // 计算当前订单可用红包优惠金额 $couponMoney = 0; $receiveCouponIds = []; @@ -92,16 +90,17 @@ class OrderService implements OrderServiceInterface // 统计订单中所有店铺当日订单数,做店铺订单序号 $countsArr = Order::query() - ->selectRaw('id, COUNT(*) AS count') + ->selectRaw('store_id, COUNT(*) AS count') ->whereIn('store_id', explode(',', $dataMain['store_ids'])) ->where(['type' => OrderMain::ORDER_TYPE_ONLINE]) ->whereBetween('time', [date('Y-m-d 00:00:00'), date('Y-m-d 23:59:59')]) + ->groupBy('store_id') ->get() ->toArray(); $storeOrderCounts = []; foreach ($countsArr as $key => &$row) { - $storeOrderCounts[$row['id']] = $row['count']; + $storeOrderCounts[$row['store_id']] = $row['count']; } // 循环处理订单总额、子订单总额、商品、商户订单等信息 @@ -403,7 +402,7 @@ class OrderService implements OrderServiceInterface 'code' => $globalRrderId, 'jj_note' => '', 'uniacid' => 2, - 'order_num' => 'dm'.date('YmdHis', time()) . rand(1111, 9999), + 'order_num' => 'dm'.date('YmdHis') . mt_rand(1000, 9999), 'money' => $data['money'], 'user_id' => $data['user_id'], 'store_ids' => $data['store_id'], @@ -417,7 +416,7 @@ class OrderService implements OrderServiceInterface // 子订单模型保存 $dataChild = [ 'uniacid' => 1, - 'order_num' => 's'.date('YmdHis', time()) . rand(1111, 9999), + 'order_num' => 's'.date('YmdHis') . mt_rand(1000, 9999), 'user_id' => $orderMain->user_id, 'store_id' => $data['store_id'], 'order_main_id' => $orderMainId, @@ -465,14 +464,13 @@ class OrderService implements OrderServiceInterface } } - - /** * 计算和校验当前订单可用红包及金额 * @param $couponIds * @param $orderAmount * @param $userId * @param $marketId + * @return int|string * @throws Exception */ protected function getCouponAmount($couponIds, $orderAmount, $userId, $marketId) @@ -525,12 +523,261 @@ class OrderService implements OrderServiceInterface } /** - * 订单是否存在 - * @param $orderNum - * @return \Hyperf\Utils\HigherOrderTapProxy|mixed|void|null + * @inheritDoc + */ + public function existsByGlobalOrderId($global_order_id) + { + return OrderMain::query()->where(['order_num' => $global_order_id])->value('id'); + } + + /** + * @inheritDoc + */ + public function onlineCompleted($global_order_id) + { + Db::beginTransaction(); + try { + + // 主订单状态更新 + $orderMain = OrderMain::query() + ->where(['global_order_id' => $global_order_id, 'state' => OrderMain::ORDER_STATE_DELIVERY]) + ->first(); + + if (empty($orderMain)) { + Db::rollBack(); + return false; + } + + $orderMain->state = OrderMain::ORDER_STATE_COMPLETE; + $orderMain->save(); + + // 子订单状态更新 + $upChild = Order::query() + ->where(['order_main_id' => $orderMain->id]) + ->update(['state' => OrderMain::ORDER_STATE_COMPLETE]); + + Db::commit(); + return true; + } catch (Exception $e) { + + $this->log->event(LogLabel::ONLINE_COMPLETE_LOG, ['exception' => $e->getMessage()]); + Db::rollBack(); + return false; + } + + } + + /** + * @inheritDoc + */ + public function onlinePaid($global_order_id) + { + Db::beginTransaction(); + try { + // 查询订单 + $orderMain = OrderMain::query() + ->where([ + 'global_order_id' => $global_order_id, + 'type' => OrderMain::ORDER_TYPE_ONLINE + ]) + ->first(); + + // 修改订单、子订单状态 + $currentTime = time(); + $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; + $orderMain->time_pay = $currentTime; + $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); + $orderMain->save(); + + $upOrder = Order::query() + ->where(['order_main_id' => $orderMain->id]) + ->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]); + + // 更新商户销量 + $upStoreScore = Store::query() + ->whereIn('id', explode(',', $orderMain->store_ids)) + ->update(['score' => Db::raw('score+1')]); + + // 更新商品库存和销量 + $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) + ->where(['order_main_id' => $orderMain->id]) + ->get() + ->toArray(); + $orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id']) + ->whereIn('order_id', array_values(array_column($orders, 'id'))) + ->get() + ->toArray(); + foreach ($orderGoods as $key => &$goodsItem) { + + $goods = Goods::find($goodsItem['id']); + + // 库存处理,有规格 + if ($goodsItem['combination_id']) { + $combination = SpecCombination::find($goodsItem['combination_id']); + $combination->number = $combination->number - $goodsItem['number']; + $combination->save(); + } else { + $goods->inventory = $goods->inventory - $goodsItem['number']; + } + + $goods->sales = $goods->sales - $goodsItem['number']; + $goods->save(); + + } + + // 月销流水 + $statistics = []; + foreach ($orders as $key => &$order) { + $statistics[] = [ + 'money' => $order['money'], + 'user_id' => $order['user_id'], + 'store_id' => $order['store_id'], + 'market_id' => $orderMain->market_id, + 'order_id' => $order['id'], + 'createtime' => strtotime($order['pay_time']), + ]; + } + + if (is_array($statistics) && !empty($statistics)) { + $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics); + } + + Db::commit(); + return true; + } catch (Exception $e) { + + $this->log->event(LogLabel::ONLINE_PAID_LOG, ['exception' => $e->getMessage()]); + Db::rollBack(); + return false; + } + } + + /** + * @inheritDoc */ - public function existsByOrderNum($orderNum) + public function offlinePaid($global_order_id) { - return OrderMain::query()->where(['order_num' => $orderNum])->value('id'); + Db::beginTransaction(); + try { + + // 主订单状态更新 + $orderMain = OrderMain::query() + ->where(['global_order_id' => $global_order_id, 'type' => OrderMain::ORDER_TYPE_OFFLINE]) + ->first(); + + if (empty($orderMain)) { + + $this->log->event( + LogLabel::PAY_NOTIFY_WXMINI, + ['order_not_found' => $global_order_id] + ); + Db::rollBack(); + return false; + } + + $currentTime = time(); + $orderMain->state = OrderMain::ORDER_STATE_UNTAKE; + $orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE; + $orderMain->time_pay = $currentTime; + $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime); + $orderMain->save(); + + // 子订单状态更新 + $upOrder = Order::query() + ->where(['order_main_id' => $orderMain->id]) + ->update([ + 'state' => OrderMain::ORDER_STATE_UNTAKE, + 'dm_state' => OrderMain::ORDER_STATE_UNTAKE, + 'pay_time' => date('Y-m-d H:i:s', $currentTime) + ]); + + Db::commit(); + return true; + } catch (Exception $e) { + + $this->log->event(LogLabel::OFFLINE_PAID_LOG, ['exception' => $e->getMessage()]); + Db::rollBack(); + return false; + } + } + + /** + * @inheritDoc + */ + public function onlineCancel($order_id){ + $order_main = OrderMain::where('id',$order_id) + ->select('global_order_id','user_id') + ->first(); + OrderMain::where('id',$order_id) + ->update(['state' => OrderMain::ORDER_STATE_CANCEL]); + $res = $this->couponService->refundOrderCoupons($order_id,$order_main->user_id); + return $res; + } + /** + * @inheritDoc + */ + public function onlineRefund($global_order_id){ + Db::beginTransaction(); + try { + + $time = time(); + // 主订单状态更新 + $orderMain = OrderMain::query() + ->where(['global_order_id' => $global_order_id, 'state' => OrderMain::ORDER_STATE_DELIVERY]) + ->first(); + + if (empty($orderMain)) { + Db::rollBack(); + return false; + } + + $orderMain->state = OrderMain::ORDER_STATE_REFUNDED; + $upOrderMain = $orderMain->save(); + + // 子订单状态更新 + $upChild = Order::query() + ->where(['order_main_id' => $orderMain->id]) + ->update(['state' => OrderMain::ORDER_STATE_REFUNDED]); + + /* 退还优惠券 */ + // 先查询是否正常使用优惠券 + // 修改状态,退还领取记录库存,删除ssdb缓存 + $couponUses = CouponUserUse::query() + ->select('id','system_coupon_id','user_id','number','user_receive_id') + ->where('order_main_id',$orderMain->id) + ->where('status',CouponUserUse::COUPON_USE_STATE_USED) + ->select(); + if(!empty($couponUse)){ + foreach($couponUses as $use){ + $use->status = CouponUserUse::COUPON_USE_STATE_USED; + $use->return_time = $time; + $use->update_time = $time; + $use->save(); + + $couponReceive = CouponUserRec::query() + ->where('id',$use->user_receive_id) + ->whereRaw('number >= number_remain+'.$use->number) + ->update([ + 'number_remain' => Db::raw('number_remain+'.$use->number), + 'status' => Db::raw('IF(number=number_remain,' . CouponUserRec::STATE_UNUSED . ',' . CouponUserRec::STATE_SOME . ')'), + 'update_time' => $time + ]); + + $clearUseRedis = $this->couponService->clearTodayCouponUsed($use->user_id,$use->system_coupon_id); + } + } + + // 退还订单金额到用户微信余额 + + + Db::commit(); + return true; + } catch (Exception $e) { + + $this->log->event(LogLabel::ORDER_LOG, ['msg'=> '订单退款','exception' => $e->getMessage()]); + Db::rollBack(); + return false; + } } + } \ No newline at end of file diff --git a/app/Service/OrderServiceInterface.php b/app/Service/OrderServiceInterface.php index 0d5e0a2..4834c91 100644 --- a/app/Service/OrderServiceInterface.php +++ b/app/Service/OrderServiceInterface.php @@ -15,15 +15,50 @@ interface OrderServiceInterface /** * 线下订单下单 * 扫码支付 + * @param $data * @return mixed */ public function addOfflineOrder($data); /** * 订单是否已经存在 - * @param $orderNum + * @param $global_order_id + * @return mixed + */ + public function existsByGlobalOrderId($global_order_id); + + /** + * 订单完成 + * @param $global_order_id * @return mixed */ - public function existsByOrderNum($orderNum); + public function onlineCompleted($global_order_id); + /** + * 线上订单支付完成 + * @param $global_order_id + * @return mixed + */ + public function onlinePaid($global_order_id); + + /** + * 线下订单支付完成 + * @param $global_order_id + * @return mixed + */ + public function offlinePaid($global_order_id); + + /** + * 线上订单取消 + * @param $global_order_id + * @return mixed + */ + public function onlineCancel($order_id); + + /** + * 线上订单退款 + * @param $global_order_id + * @return mixed + */ + public function onlineRefund($global_order_id); } \ No newline at end of file diff --git a/app/Service/PayRefundService.php b/app/Service/PayRefundService.php new file mode 100644 index 0000000..27bd0d4 --- /dev/null +++ b/app/Service/PayRefundService.php @@ -0,0 +1,47 @@ + 0, + 'msg' => '退款成功' + ]; + + // 查询订单 + $orderMain = OrderMain::query() + ->select('id','code','order_num','money','state') + ->where('global_order_id',$global_order_id) + ->where('pay_type',OrderMain::ORDER_PAY_WX) + ->where(Db::raw('refund_time is null')) + ->first(); + if(empty($orderMain)){ + return ['status'=>1, 'msg'=>'订单不存在或已退款']; + } + $optional = []; + $result = $app->refund->byOutTradeNumber( + $orderMain->code, + $orderMain->code, + $orderMain->money * 100, + $orderMain->money * 100, + $optional + ); + return $result; + } + +} \ No newline at end of file diff --git a/app/Service/PayRefundServiceInterface.php b/app/Service/PayRefundServiceInterface.php new file mode 100644 index 0000000..7ca1de1 --- /dev/null +++ b/app/Service/PayRefundServiceInterface.php @@ -0,0 +1,8 @@ +where(['global_order_id' => $global_order_id]) + ->first(); + + if (empty($orderMain)) { + return false; + } + + // =======用户支付流水 / Start======= + $this->financialRecordService->userByOLOrderPaid($orderMain->user_id, $global_order_id, $orderMain->money); + // =======用户支付流水 / End======= + } + + /** + * @inheritDoc + */ + public function orderOnlineCompleted($global_order_id) + { + // 线上订单完成(用户点击确认收货完成/管理后台点击完成/配送员点击完成/自动收货等),进行相关分账 + // 订单 + $orderMain = OrderMain::query() + ->where(['global_order_id' => $global_order_id]) + ->whereIn('state', [OrderMain::ORDER_STATE_COMPLETE,OrderMain::ORDER_STATE_EVALUATED,OrderMain::ORDER_STATE_UNREFUND]) + ->first(); + + if (empty($orderMain)) { + return false; + } + + $currentTime = time(); + Db::beginTransaction(); + try { + + // =======商户订单收入流水 / Start======= + // 查询子订单 + $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) + ->where(['order_main_id' => $orderMain->id]) + ->get()->toArray(); + + foreach ($orders as $key => &$order) { + + // 商户 + $store = Store::find($order['store_id']); + + // 旧商户流水基础数据 TODO 直接移除或后续考虑移除 + $storeAccountBase = [ + 'user_id' => $order['user_id'], + 'order_id' => $order['id'], + 'store_id' => $order['store_id'], + 'type' => 1, + 'time' => date('Y-m-d H:i:s', $currentTime), + 'add_time' => $currentTime, + ]; + + // 旧商户流水 TODO 直接移除或后续考虑移除 + $storeAccount = [ + 'money' => $order['money'], + 'note' => '线上订单', + 'category' => 1, + ]; + StoreAccount::query()->insert(array_merge($storeAccountBase, $storeAccount)); + + // 新商户流水 + $this->financialRecordService->storeByOLOrderComp($store->user_id, $global_order_id ,$order['money']); + } + // =======商户订单收入流水 / End======= + + // =======社区服务点分账 / Start======= + // 前提:用户线上下单并且订单完成 + // 奖励规则A:用户是平台新用户,奖励社区服务点平台新用户奖励x元+平台新用户首单奖励y元+订单商品金额z%的分成 + // 奖励规则B:用户是非新用户,奖励社区服务点订单实际支付金额z%的分成 + // =======社区服务点分账 / Start======= + + // 当前用户的社区服务点绑定关系 + $communityBind = UserRelationBind::query() + ->where(['bind_type' => UserRelationBind::BIND_TYPE_COMMUNITY, 'user_id' => $orderMain->user_id]) + ->first(); + + if ($communityBind) { + + // 奖励/分账金额 + $award = ServiceReward::query()->where(['type' => ServiceReward::TYPE_COMMUNITY])->first(); + if (empty($award)) { + Db::rollBack(); + return false; + } + + $award = $award->set_reward; + + // 平台新用户 + if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->id)) { + $this->financialRecordService->communityAwardByPlatNewUser($communityBind->source_id, $global_order_id, $award['new_user_reward']); + $this->financialRecordService->communityAwardByPlatNewUserFirstOLOrder($communityBind->source_id, $global_order_id, $award['first_reward']); + } + + // 账单分成 + $money = bcmul($orderMain->money, bcdiv($award['flow_reward'], 100, 6), 2); + $this->financialRecordService->communitySeparateAccountsByOrderComp($communityBind->source_id, $global_order_id, $money); + } + + // =======社区服务点分账 / End======= + + Db::commit(); + return true; + + } catch (\Exception $e) { + + $this->log->event(LogLabel::SEPARATE_ACCOUNTS_LOG, ['exception' => $e->getMessage(), 'order_main' => json_encode($orderMain)]); + Db::rollBack(); + return false; + } + + } + + /** + * @inheritDoc + */ + public function orderOfflinePaid($global_order_id) + { + // 线下订单支付完成 + // 订单 + $orderMain = OrderMain::query() + ->where(['global_order_id' => $global_order_id]) + ->first(); + + if (empty($orderMain)) { + return false; + } + + // 查询子订单,当面付目前实际上只有一个子订单 + $order = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time']) + ->where(['order_main_id' => $orderMain->id]) + ->first(); + + if (empty($order)) { + return false; + } + + $currentTime = time(); + Db::beginTransaction(); + try { + + // =======用户支付流水 / Start======= + $this->financialRecordService->userByOFLOrderPaid($orderMain->user_id, $global_order_id, $orderMain->money); + // =======用户支付流水 / End======= + + // =======线下订单支付完成商户分账 / Start======= + // 前提:用户线上下单并且支付完成 + // 奖励规则A:用户是平台新用户,奖励商户2元 + // 奖励规则B:用户是非新用户,但是是商户当日首单,奖励商户0.05元 + // =======线下订单支付完成商户分账 / Start======= + + // 旧商户订单流水基础数据 TODO 直接移除或后续考虑移除 + $storeAccountBase = [ + 'user_id' => $order->user_id, + 'order_id' => $order->id, + 'store_id' => $order->store_id, + 'type' => 1, + 'time' => date('Y-m-d H:i:s', $currentTime), + 'add_time' => $currentTime, + ]; + + // 旧商户订单流水 TODO 直接移除或后续考虑移除 + $storeAccount = [ + 'money' => $order->money, + 'note' => '当面付订单收入', + 'category' => 2, + ]; + StoreAccount::query()->insert(array_merge($storeAccountBase, $storeAccount)); + + // 商户 + $store = Store::find($order->store_id); + + // 新商户订单流水 + $this->financialRecordService->storeByOFLOrderComp($store->user_id, $global_order_id, $order->money); + + $needAward = false; + $awardAmount = 0; + // 新用户商户奖励 + if ($this->userService->isPlatformNewUser($orderMain->user_id, $orderMain->id)) { + + $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_new_user'])->value('value'); + // 旧商户流水 TODO 直接移除或后续考虑移除 + $storeAccount = [ + 'money' => $awardAmount, + 'note' => '新用户下单成功,平台奖励', + 'category' => 3, + ]; + // 新商户流水 + $this->financialRecordService->storeAwardByPlatNewUserOFLOrder($store->user_id, $global_order_id, $awardAmount); + $needAward = true; + + } else { + // 商户当日首单奖励 + if ( + $this->userService->isStoreFirstOrderToday( + $order->user_id, + $order->store_id, + $order->id, + FinancialRecord::OFL_FIRST_AWARD_LIMIT_AMOUNT + ) + ) { + + $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_each_order'])->value('value'); + // 旧商户流水 TODO 直接移除或后续考虑移除 + $storeAccount = [ + 'money' => $awardAmount, + 'note' => '用户下单成功,平台奖励', + 'category' => 4, + ]; + // 新商户流水 + $this->financialRecordService->storeAwardByTodayFirstOFLOrder($store->user_id, $global_order_id, $awardAmount); + $needAward = true; + + } + } + + if ($needAward && $awardAmount) { + + // 旧商户流水 TODO 直接移除或后续考虑移除 + StoreAccount::query()->insert(array_merge($storeAccountBase, $storeAccount)); + + // 发模板消息 + $openid = Users::query()->where(['id' => $store['user_id']])->value('openid'); + $res = $this->miniprogramService->sendTemMsgForAward($storeAccount['money'], $storeAccount['note'], $openid, $storeAccountBase['time']); + } + + // =======线下订单支付完成商户分账 / End======= + + Db::commit(); + return true; + } catch (\Exception $e) { + + $this->log->event(LogLabel::SEPARATE_ACCOUNTS_LOG, ['exception' => $e->getMessage(), 'order_main' => json_encode($orderMain)]); + Db::rollBack(); + return false; + } + } +} \ No newline at end of file diff --git a/app/Service/SeparateAccountsServiceInterface.php b/app/Service/SeparateAccountsServiceInterface.php new file mode 100644 index 0000000..c574735 --- /dev/null +++ b/app/Service/SeparateAccountsServiceInterface.php @@ -0,0 +1,28 @@ +updateOrCreate( + ['bind_type' => $bind_type, 'user_id' => $user_id], + ['source_id' => $source_id, 'json_data' => $extra_data] + ); + } + + public function bindLimitBySource($bind_type, $source_id, $user_id, $extra_data) + { + // TODO: Implement bindLimitBySource() method. + } + + public function bind($bind_type, $source_id, $user_id, $extra_data) + { + // TODO: Implement bind() method. + } + + public function isBinded($bind_type, $source_id, $user_id) + { + // TODO: Implement isBinded() method. + } +} \ No newline at end of file diff --git a/app/Service/UserRelationBindServiceInterface.php b/app/Service/UserRelationBindServiceInterface.php new file mode 100644 index 0000000..33eccc3 --- /dev/null +++ b/app/Service/UserRelationBindServiceInterface.php @@ -0,0 +1,48 @@ +where(['user_id' => $user_id]) diff --git a/app/Service/UserServiceInterface.php b/app/Service/UserServiceInterface.php index 2920d53..1e8f0fb 100644 --- a/app/Service/UserServiceInterface.php +++ b/app/Service/UserServiceInterface.php @@ -12,7 +12,7 @@ interface UserServiceInterface * @param $order_main_id * @return mixed */ - public function isStageNewUser($user_id, $order_main_id): bool; + public function isPlatformNewUser($user_id, $order_main_id): bool; public function saveUserUnionid($openid,$unionid); diff --git a/composer.json b/composer.json index 284593c..4cfe0dd 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,11 @@ "alibabacloud/iot": "^1.8", "hyperf/snowflake": "^2.0", "ext-bcmath": "*", - "overtrue/wechat": "~4.0" + "overtrue/wechat": "~4.0", + "hyperf/json-rpc": "^2.0", + "hyperf/rpc-server": "^2.0", + "hyperf/rpc-client": "^2.0", + "hyperf/consul": "^2.0" }, "require-dev": { "swoole/ide-helper": "^4.5", diff --git a/config/autoload/dependencies.php b/config/autoload/dependencies.php index 893f000..0d7d6c1 100644 --- a/config/autoload/dependencies.php +++ b/config/autoload/dependencies.php @@ -26,4 +26,9 @@ return [ \App\Service\FeiePrintServiceInterface::class => \App\Service\FeiePrintService::class, \App\Service\MiniprogramServiceInterface::class => \App\Service\MiniprogramService::class, \App\Service\PurchaseLimitServiceInterface::class => \App\Service\PurchaseLimitService::class, + \App\Service\UserRelationBindServiceInterface::class => \App\Service\UserCommunityBindService::class, + \Hyperf\JsonRpc\JsonRpcTransporter::class => \Hyperf\JsonRpc\JsonRpcPoolTransporter::class, + \App\JsonRpc\OrderServiceInterface::class => \App\JsonRpc\OrderService::class, + \App\Service\FinancialRecordServiceInterface::class => \App\Service\FinancialRecordService::class, + \App\Service\SeparateAccountsServiceInterface::class => \App\Service\SeparateAccountsService::class, ]; diff --git a/config/autoload/server.php b/config/autoload/server.php index f44b083..1418f3a 100644 --- a/config/autoload/server.php +++ b/config/autoload/server.php @@ -25,6 +25,16 @@ return [ SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'], ], ], + [ + 'name' => 'jsonrpc-http', + 'type' => Server::SERVER_HTTP, + 'host' => '0.0.0.0', + 'port' => 9505, + 'sock_type' => SWOOLE_SOCK_TCP, + 'callbacks' => [ + SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'], + ], + ], ], 'settings' => [ 'enable_coroutine' => true, diff --git a/config/routes.php b/config/routes.php index 6f9ebdd..6ddd543 100644 --- a/config/routes.php +++ b/config/routes.php @@ -50,11 +50,12 @@ Router::addGroup('/v1/',function (){ //订单相关 Router::post('Order/addOnline', 'App\Controller\OrderController@addOnlineOrder'); Router::post('Order/addOffline', 'App\Controller\OrderController@addOfflineOrder'); + Router::post('Order/onlineCancel', 'App\Controller\OrderController@onlineCancel'); //小程序支付相关 Router::post('wxminipay/online', 'App\Controller\PaymentController@wxminiPayOnline'); Router::post('wxminipay/offline', 'App\Controller\PaymentController@wxminiPayOffline'); - + Router::post('Order/userComp', 'App\Controller\OrderController@userComp'); //加入购物车 Router::post('PurchaseLimit/addShopCar', 'App\Controller\PurchaseLimitController@addShopCar'); Router::post('PurchaseLimit/updateShopCar', 'App\Controller\PurchaseLimitController@updateShopCar');