Zory 10 hodín pred
rodič
commit
ea18f1a5ab

+ 24 - 0
app/command/OrderDelay.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace app\command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class OrderDelay extends Command
+{
+
+
+    protected static string $defaultName = 'order:delay';
+
+    protected static string $defaultDescription = '超出核销时段订单第二天定时进行核销';
+
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+
+        return self::SUCCESS;
+    }
+
+}

+ 66 - 0
app/controller/api/Complaint.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace app\controller\api;
+
+
+use app\extra\basic\Base;
+use app\middleware\AuthMiddleware;
+use app\model\saas\SaasComplaint;
+use app\service\saas\ComplaintService;
+use DI\Attribute\Inject;
+use LinFly\Annotation\Attributes\Route\Controller;
+use LinFly\Annotation\Attributes\Route\GetMapping;
+use LinFly\Annotation\Attributes\Route\Middleware;
+use support\Request;
+use support\Response;
+
+/**
+ * 投诉
+ */
+#[Controller("/dy/complaint"),Middleware(AuthMiddleware::class)]
+class Complaint extends Base
+{
+
+    #[Inject]
+    protected ComplaintService $service;
+
+    #[Inject]
+    protected SaasComplaint $model;
+
+    #[GetMapping('list')]
+    public function getDataList(Request $request): Response
+    {
+        try {
+            $param = $request->all();
+            if (!empty($param['size'])) {
+                $param['pageSize'] = $param['size'];
+            }
+            $param['openid'] = $request->user['openid'];
+            $data = $this->service->setModel()->getList($param);
+            return successTrans("success.data",pageFormat($data));
+        } catch (\Throwable $th) {
+            return error($th->getMessage());
+        }
+    }
+
+    #[GetMapping('detail')]
+    public function getDataDetail(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "id.require"    => trans("empty.require")
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $data = $this->model->where("id",$param["id"])->with(['store' => function($query){
+                $query->field("poi_id,poi_name,poi_address,poi_city");
+            }])->findOrEmpty();
+            if ($data->isEmpty()) return errorTrans("empty.data");
+            if ($data['openid'] <> $request->user['openid']) return error("非法操作");
+            $data['mobile'] = hide_mobile($data['mobile']);
+            return successTrans("success.data",$data->toArray());
+        } catch (\Throwable $th) {
+            return error($th->getMessage());
+        }
+    }
+
+}

+ 2 - 3
app/controller/api/Order.php

@@ -269,7 +269,6 @@ class Order extends Base
                 "mobile.default"    => "",
                 "order.require"     => trans("empty.require"),
                 "text.require"      => trans("empty.require"),
-                "poi_id.require"    => trans("empty.require"),
             ],$request->method());
             if (!is_array($param)) return error($param);
             $order = (new SaasOrder)->where("out_order_no",$param['order'])->findOrEmpty();
@@ -277,10 +276,10 @@ class Order extends Base
             if ($order['openid'] <> $request->user['openid']) return error("非法操作");
             $state = (new SaasComplaint)->insertGetId([
                 "openid"    => $request->user['openid'],
-                "poi_id"    => $param['poi_id'],
+                "poi_id"    => $order['poi_id'],
                 "content"   => $param['content'],
                 "question"  => $param['text'],
-                "order_sn"  => $order['order'],
+                "order_sn"  => $param['order'],
                 "mobile"    => $param['mobile']??$order['mobile'],
             ]);
             if (!$state) return error("提交失败");

+ 48 - 3
app/controller/api/Service.php

@@ -7,6 +7,9 @@ use app\extra\tools\UploadExtend;
 use app\middleware\AuthMiddleware;
 use app\model\saas\SaasChatMsg;
 use app\model\saas\SaasChatStore;
+use app\model\saas\SaasOrder;
+use app\model\saas\SaasOrderAddress;
+use app\model\saas\SaasOrderDelay;
 use app\model\saas\SaasStore;
 use app\model\system\SystemUser;
 use app\service\saas\ChatStoreService;
@@ -18,6 +21,7 @@ use LinFly\Annotation\Attributes\Route\PostMapping;
 use support\Request;
 use support\Response;
 use Webman\Push\Api;
+use Webman\RedisQueue\Redis;
 use function DI\get;
 
 
@@ -269,9 +273,50 @@ class Service extends Base
     public function setOrderAddress(Request $request): Response
     {
         try {
-            $param = $request->all();
-            print_r($param);
-
+            $param = $this->_valid([
+                "city.require"      => trans("empty.require"),
+                "mobile.require"    => trans("empty.require"),
+                "mobile.mobile"     => trans("error.mobile"),
+                "address.require"   => trans("empty.require"),
+                "nickname.require"  => trans("empty.require"),
+                "order.require"     => trans("empty.require"),
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $cityJson = json_decode($param['city'],true);
+            $cityCode = [];
+            foreach ($cityJson as $k => $v){
+                $cityCode[$k] = $v['value'];
+                $param['city_text'] .= $v['text'];
+            }
+            $param['city_code'] = json_encode($cityCode);
+            $orderData = json_decode($param['order'],true);
+            $order = (new SaasOrder)->where("out_trade_no",$orderData["order"])->with(['poi'])->findOrEmpty();
+            if ($order->isEmpty()) return error("关联订单错误");
+            if ($order['openid'] <> $request->user['openid']) return error("关联订单错误");
+            if ($order['status'] <> 1) return error("关联订单错误");
+            $startTime = $order['poi']['order_start']??'09:00';
+            $endTime = $order['poi']['order_end']??'22:30';
+            $startTimeStamp = strtotime("Y-m-d {$startTime}:00");
+            $endTimeStamp = strtotime("Y-m-d {$endTime}:00");
+            $address = (new SaasOrderAddress)->where(['openid' => $request->user['openid'],'order_sn' => $orderData['order']])->findOrEmpty();
+            if (!$address->isEmpty()) return error("请勿重复提交");
+            $address->insertGetId([
+                "openid"    => $request->user['openid'],
+                "order_sn"  => $orderData['order'],
+                "city_code" => $param['city_code'],
+                "city_text" => $param['city_text'],
+                "mobile"    => $param['mobile'],
+                "address"   => $param['address'],
+                "nickname"  => $param['nickname'],
+            ]);
+            // 判断是否在核销范围
+            if (time() > $startTimeStamp && time() < $endTimeStamp) { // 自动核销,订单状态改成待发货
+                Redis::send("order-done",['order' => $orderData['order']]);
+            } else { // 写入待核销定时任务队列中
+                (new SaasOrderDelay)->insertGetId([
+                    "order_sn"  => $orderData['order'],
+                ]);
+            }
             return success("提交成功");
         } catch (\Throwable $throwable) {
             echo $throwable->getMessage()."\n";

+ 18 - 8
app/model/saas/SaasComplaint.php

@@ -3,17 +3,18 @@
 namespace app\model\saas;
 
 use app\extra\basic\Model;
+use think\model\relation\HasOne;
 
 
 /**
- * @property integer $id (主键)
- * @property mixed $openid 
- * @property mixed $poi_id 
- * @property mixed $mobile 
- * @property mixed $order_sn 
- * @property string $question 
- * @property string $content 
- * @property integer $status 
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property mixed $poi_id 
+ * @property mixed $mobile 
+ * @property mixed $order_sn 
+ * @property string $question 
+ * @property string $content 
+ * @property integer $status 
  * @property mixed $create_at
  */
 class SaasComplaint extends Model
@@ -46,5 +47,14 @@ class SaasComplaint extends Model
      */
     public bool $timestamps = false;
 
+    public function store(): HasOne
+    {
+        return $this->hasOne(SaasStore::class,"poi_id","poi_id");
+    }
+
+    public function orders(): HasOne
+    {
+        return $this->hasOne(SaasOrder::class,"out_order_no","order_sn");
+    }
 
 }

+ 50 - 0
app/model/saas/SaasOrderAddress.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\model\saas;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $order_sn 
+ * @property mixed $openid 
+ * @property string $city_text 
+ * @property mixed $city_code 
+ * @property string $nickname 
+ * @property string $mobile 
+ * @property string $address 
+ * @property mixed $create_at
+ */
+class SaasOrderAddress extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "saas_order_address";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 44 - 0
app/model/saas/SaasOrderDelay.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace app\model\saas;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $order_sn 
+ * @property mixed $create_at
+ */
+class SaasOrderDelay extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "saas_order_delay";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 47 - 0
app/model/saas/SaasStoreExpress.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace app\model\saas;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $poi_id 
+ * @property string $type 
+ * @property integer $status 0关闭1开通
+ * @property mixed $rule 权限信息
+ * @property mixed $create_at
+ */
+class SaasStoreExpress extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "saas_store_express";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 105 - 0
app/queue/redis/fast/OrderDone.php

@@ -0,0 +1,105 @@
+<?php
+
+namespace app\queue\redis\fast;
+
+use app\extra\dyLife\data\OrderData;
+use app\model\saas\SaasOrder;
+use app\model\saas\SaasOrderVerify;
+use Webman\RedisQueue\Consumer;
+
+class OrderDone implements Consumer
+{
+
+    /**
+     * 消费队列名
+     * 核销队列
+     * @var string
+     */
+    public string $queue = "order-done";
+
+    /**
+     * 连接配置
+     * @var string
+     */
+    public string $connection = "default";
+
+    public function consume($data): bool
+    {
+        try {
+            echo getDateFull()."==开始核销\n";
+            echo "订单数据===".json_encode($data)."\n";
+            $order = (new SaasOrder)->where("out_trade_no",$data["order"])->with(['poi'])->findOrEmpty();
+            if ($order['status'] <> 1)
+            {
+                echo getDateFull()."===订单状态不符合核销\n";
+                return true;
+            }
+            // 获取到订单encrypted_code
+            $orderCode = (new OrderData)->config([
+                "appid"     => sConf("wechat.appid"),
+                "secret"    => sConf("wechat.secret"),
+                "account"   => sConf("wechat.shop_id"),
+            ])->token()->getCertificate($order['order_sn'],$order['poi']['store_id']);
+            if (empty($orderCode['certificates']))
+            {
+                echo getDateFull()."===获取订单数据失败\n";
+                return true;
+            }
+            if (!isset($orderCode['certificates'][0]['encrypted_code']))
+            {
+                echo getDateFull()."===获取订单数据失败\n";
+                return true;
+            }
+            if ($orderCode['certificates'][0]['status'] <> 1)
+            {
+                echo getDateFull()."===该订单状态不支持核销\n";
+                return true;
+            }
+            // 核销订单
+            $orderDone = (new OrderData)->config([
+                "appid"     => sConf("wechat.appid"),
+                "secret"    => sConf("wechat.secret"),
+                "account"   => sConf("wechat.shop_id"),
+            ])->token()->verifyCertificate([
+                "account_id"    => $order['poi']['store_id'],
+                "pay_sn"        => $order['pay_sn'],
+                "encrypted_code"    => $orderCode['certificates'][0]['encrypted_code'],
+                "order_id"      => $order['order_sn'],
+                "poi_id"        => $order['poi_id']
+            ]);
+            if (empty($orderDone['verify_results']))
+            {
+                echo getDateFull()."===核销失败\n";
+                return true;
+            }
+            if (!isset($orderDone['verify_results'][0]['verify_id']))
+            {
+                echo getDateFull()."===核销失败\n";
+                return true;
+            }
+            if (!isset($orderDone['verify_results'][0]['certificate_id']))
+            {
+                echo getDateFull()."===核销失败\n";
+                return true;
+            }
+            $order->status = 2;
+            $order->express_status = 1;
+            $order->verify_id = $orderDone['verify_results'][0]['verify_id'];
+            $order->certificate_id = $orderDone['verify_results'][0]['certificate_id'];
+            $order->done_at = getDateFull();
+            $order->save();
+            (new SaasOrderVerify)->insertGetId([
+                "poi_id"            => $order['poi_id'],
+                "order_sn"          => $order['order_sn'],
+                "certificate_id"    => $orderDone['verify_results'][0]['certificate_id'],
+                "verify_id"         => $orderDone['verify_results'][0]['verify_id'],
+            ]);
+        } catch (\Throwable $throwable) {
+            echo getDateFull()."==核销队列报错\n";
+            echo $throwable->getMessage()."\n";
+            echo $throwable->getFile()."【".$throwable->getLine()."】\n";
+        }
+        return true;
+    }
+
+}

+ 1 - 1
app/queue/redis/SyncCategory.php → app/queue/redis/slow/SyncCategory.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace app\queue\redis;
+namespace app\queue\redis\slow;
 
 use app\extra\dyLife\data\BaseData;
 use app\model\saas\SaasCategory;

+ 1 - 1
app/queue/redis/SyncStore.php → app/queue/redis/slow/SyncStore.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace app\queue\redis;
+namespace app\queue\redis\slow;
 
 use app\extra\dyLife\data\BaseData;
 use app\model\saas\SaasStore;

+ 37 - 0
app/service/saas/ComplaintService.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace app\service\saas;
+
+use app\extra\basic\Service;
+use app\model\saas\SaasComplaint;
+
+class ComplaintService extends Service
+{
+
+    /**
+     *
+     * @return $this
+     */
+    public function setModel(): static
+    {
+        $this->mode = (new SaasComplaint);
+        return $this;
+    }
+
+
+    /**
+     *
+     * @param array $param
+     * @return array
+     */
+    public function searchFilter(array $param = []): array
+    {
+        $filter = [];
+        !empty($param['openid']) && $filter[] = ["openid", '=', $param['openid']];
+        !empty($param['poi_id']) && $filter[] = ["poi_id", '=', $param['poi_id']];
+        !empty($param['poi']) && $filter[] = ["poi_id", '=', $param['poi']];
+        !empty($param['status']) && $filter[] = ["status", '=', ($param['status']-1)];
+        return $filter;
+    }
+
+}

+ 11 - 3
config/plugin/webman/redis-queue/process.php

@@ -1,11 +1,19 @@
 <?php
 return [
-    'consumer'  => [
+    'redis_consumer_fast'  => [ // key是自定义的,没有格式限制,这里取名redis_consumer_fast
         'handler'     => Webman\RedisQueue\Process\Consumer::class,
-        'count'       => 8, // 可以设置多进程同时消费
+        'count'       => 8,
         'constructor' => [
             // 消费者类目录
-            'consumer_dir' => app_path() . '/queue/redis'
+            'consumer_dir' => app_path() . '/queue/redis/fast'
+        ]
+    ],
+    'redis_consumer_slow'  => [  // key是自定义的,没有格式限制,这里取名redis_consumer_slow
+        'handler'     => Webman\RedisQueue\Process\Consumer::class,
+        'count'       => 8,
+        'constructor' => [
+            // 消费者类目录
+            'consumer_dir' => app_path() . '/queue/redis/slow'
         ]
     ]
 ];