Browse Source

Merge branch 'zhongqi-recommend'

shish 4 months ago
parent
commit
b6496653ce

+ 67 - 0
app-ghs/controllers/PartController.php

@@ -7,6 +7,7 @@ use bizGhs\part\classes\PartItemClass;
 use bizGhs\product\classes\ProductClass;
 use common\components\dict;
 use common\components\imgUtil;
+use common\components\printUtil;
 use common\components\util;
 use Yii;
 
@@ -110,4 +111,70 @@ class PartController extends BaseController
         }
     }
 
+    //打印拆散订单
+    public function actionPrintOrder()
+    {
+        $get = Yii::$app->request->get();
+        $orderSn = $get['orderSn'] ?? '';
+        if (empty($orderSn)) {
+            util::fail('参数错误');
+        }
+
+        $info = PartClass::getByCondition(['orderSn' => $orderSn], true);
+        if (empty($info)) {
+            util::fail('没有找到拆散单');
+        }
+        if ($info->mainId != $this->mainId) {
+            util::fail('没有权限');
+        }
+
+        $itemList = PartItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*');
+        if (empty($itemList)) {
+            util::fail('没有花材需要打印');
+        }
+
+        $ext = $this->shopExt;
+        $printSn = is_array($ext) ? ($ext['printSn'] ?? '') : ($ext->printSn ?? '');
+        $printKey = is_array($ext) ? ($ext['printKey'] ?? '') : ($ext->printKey ?? '');
+        if (empty($printSn) || empty($printKey)) {
+            util::success(['hasNoPrint' => 1]);
+        }
+
+        $shop = $this->shop;
+        $sj = $this->sj;
+        $sjName = $sj->name ?? '';
+        $shopName = $shop->shopName ?? '';
+        $currentName = $shopName == '首店' ? $sjName : $sjName . ' ' . $shopName;
+
+        $kindNum = 0;
+        $totalNum = 0;
+        $content = "<CB>{$currentName}</CB><BR>";
+        $content .= "<CB>拆散单</CB><BR>";
+        $content .= '商品             数量 <BR>';
+        $content .= '--------------------------------<BR>';
+        foreach ($itemList as $current) {
+            $name = $current['name'] ?? '';
+            $num = $current['itemNum'] ?? 0;
+            $content .= '<B>' . $name . '    ' . floatval($num) . '扎' . "</B><BR>";
+            $content .= '--------------------------------<BR>';
+            $kindNum = bcadd($kindNum, 1);
+            $totalNum = bcadd($totalNum, $current['itemNum']);
+        }
+        if (!empty($info->remark)) {
+            $content .= '备注:' . $info->remark . '<BR>';
+        }
+        $content .= '<BR>';
+        $content .= '********************************<BR>';
+        $content .= "<CB>共{$kindNum}种,{$totalNum}扎";
+        $content .= "</CB>";
+        $content .= '********************************<BR>';
+        $content .= '<BR>';
+        $content .= "订单编号:{$orderSn}<BR>";
+        $content .= '拆散人员:' . ($info->shopAdminName ?? '') . '<BR>';
+
+        $p = new printUtil($printSn);
+        $p->printMsg($content, $shop, $orderSn);
+
+        util::complete('打印成功');
+    }
 }

+ 30 - 1
app-hd/controllers/GhsController.php

@@ -3,7 +3,6 @@
 namespace hd\controllers;
 
 use biz\ghs\classes\GhsClass;
-use biz\recharge\classes\RechargeHbClass;
 use biz\shop\classes\ShopClass;
 use bizGhs\custom\classes\CustomClass;
 use bizGhs\custom\classes\CustomLevelClass;
@@ -13,6 +12,7 @@ use bizHd\shop\classes\ShopExtClass;
 use bizGhs\stat\classes\StatVisitClass;
 use common\components\dict;
 use common\components\imgUtil;
+use common\components\mapUtil;
 use common\components\qrCodeUtil;
 use common\components\stringUtil;
 use common\components\util;
@@ -442,4 +442,33 @@ class GhsController extends BaseController
         util::complete('载入成功');
     }
 
+    //寻找附近批发店
+    public function actionSearchNearbyGhs()
+    {
+        $get = Yii::$app->request->get();
+        $locationType = $get['locationType'];
+        $toLat = $get['lat'] ?? '';
+        $toLnt = $get['long'] ?? '';
+        if ($toLat == '' || $toLnt == '') {
+            util::fail('未获取到定位数据');
+        }
+
+        if ($locationType == 'wgs84') {
+            // WGS84 → GCJ-02 转换
+            $re = mapUtil::wgs84ToGcj02($toLnt, $toLat);
+            $toLat = $re['lat'];
+            $toLnt = $re['lng'];
+        }
+
+        $gs = GhsClass::getByCondition(['ownShopId' => $this->shopId], true);
+        if (!empty($gs)) {
+            util::fail('已有批发商了');
+        }
+
+        // 找出附近批发店,之后自动给建立关系,然后补充二个店之间的距离
+        GhsClass::buildNearbyGhsRelations($this->shop['id'], $this->shop->pfShopId, $toLat, $toLnt);
+
+        util::complete();
+    }
+
 }

+ 69 - 0
app-hd/controllers/PartController.php

@@ -2,11 +2,13 @@
 
 namespace hd\controllers;
 
+use biz\shop\classes\ShopExtClass;
 use bizGhs\product\classes\ProductClass;
 use bizHd\part\classes\PartClass;
 use bizHd\part\classes\PartItemClass;
 use common\components\dict;
 use common\components\imgUtil;
+use common\components\printUtil;
 use common\components\util;
 use Yii;
 
@@ -114,4 +116,71 @@ class PartController extends BaseController
         }
     }
 
+    //打印拆散订单
+    public function actionPrintOrder()
+    {
+        $get = Yii::$app->request->get();
+        $orderSn = $get['orderSn'] ?? '';
+        if (empty($orderSn)) {
+            util::fail('参数错误');
+        }
+
+        $info = PartClass::getByCondition(['orderSn' => $orderSn], true);
+        if (empty($info)) {
+            util::fail('没有找到拆散单');
+        }
+        if ($info->mainId != $this->mainId) {
+            util::fail('没有权限');
+        }
+
+        $itemList = PartItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*');
+        if (empty($itemList)) {
+            util::fail('没有花材需要打印');
+        }
+
+        $currentShopId = $this->admin->currentGhsShopId;
+        $ext = ShopExtClass::getByCondition(['shopId' => $currentShopId], true);
+        $printSn = is_array($ext) ? ($ext['printSn'] ?? '') : ($ext->printSn ?? '');
+        $printKey = is_array($ext) ? ($ext['printKey'] ?? '') : ($ext->printKey ?? '');
+        if (!empty($printSn) || empty($printKey)) {
+            util::success(['hasNoPrint' => 1]);
+        }
+
+        $shop = $this->shop;
+        $sj = $this->sj;
+        $sjName = $sj->name ?? '';
+        $shopName = $shop->shopName ?? '';
+        $currentName = $shopName == '首店' ? $sjName : $sjName . ' ' . $shopName;
+
+        $kindNum = 0;
+        $totalNum = 0;
+        $content = "<CB>{$currentName}</CB><BR>";
+        $content .= "<CB>拆散单</CB><BR>";
+        $content .= '商品             数量 <BR>';
+        $content .= '--------------------------------<BR>';
+        foreach ($itemList as $current) {
+            $name = $current['name'] ?? '';
+            $num = $current['itemNum'] ?? 0;
+            $content .= '<B>' . $name . '    ' . floatval($num) . '扎' . "</B><BR>";
+            $content .= '--------------------------------<BR>';
+            $kindNum = bcadd($kindNum, 1);
+            $totalNum = bcadd($totalNum, $current['itemNum']);
+        }
+        if (!empty($info->remark)) {
+            $content .= '备注:' . $info->remark . '<BR>';
+        }
+        $content .= '<BR>';
+        $content .= '********************************<BR>';
+        $content .= "<CB>共{$kindNum}种,{$totalNum}扎";
+        $content .= "</CB>";
+        $content .= '********************************<BR>';
+        $content .= '<BR>';
+        $content .= "订单编号:{$orderSn}<BR>";
+        $content .= '拆散人员:' . ($info->shopAdminName ?? '') . '<BR>';
+
+        $p = new printUtil($printSn);
+        $p->printMsg($content, $shop, $orderSn);
+
+        util::complete('打印成功');
+    }
 }

+ 20 - 2
app-hd/controllers/ShopController.php

@@ -155,8 +155,26 @@ class ShopController extends BaseController
         $mobile = $data['mobile'];
         //手机号具有唯一性,暂时不允许修改 --- 同批发端 app-ghs/controllers/ShopController.php 保持一致
         unset($data['mobile']);
-        ShopClass::updateShop($shop, $data);
-        util::complete();
+
+        // 添加事务处理
+        $connection = Yii::$app->db;
+        $transaction = $connection->beginTransaction();
+        try {
+            ShopClass::updateShop($shop, $data);
+
+            // 找出附近批发店,之后自动给建立关系,然后补充二个店之间的距离(计算距离使用高德接口)
+            // if(isset($data['openLocation']) && $data['openLocation'] == 1){
+            //     $toLat = $data['lat'] ?? null;
+            //     $toLnt = $data['long'] ?? null;
+            //     \biz\ghs\classes\GhsClass::buildNearbyGhsRelations($id, $this->shop->pfShopId, $toLat, $toLnt);
+            // }
+            $transaction->commit();
+            util::complete();
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+            Yii::error("更新门店失败:" . $exception->getMessage());
+            util::fail('更新门店失败');
+        }
     }
 
     public function actionAdd()

+ 4 - 2
biz-ghs/order/classes/OrderClass.php

@@ -461,7 +461,8 @@ class OrderClass extends BaseClass
         if ($order->status == 2) {
             $staffId = $params['staffId'] ?? 0;
             $staffName = $params['staffName'] ?? '';
-            $element = ['staffId' => $staffId, 'staffName' => $staffName];
+            $notice = $params['notice'] ?? true;
+            $element = ['staffId' => $staffId, 'staffName' => $staffName, 'notice' => $notice];
             self::orderSend($order, $element, true);
             $cg = PurchaseClass::getById($cgId, true);
         }
@@ -492,7 +493,8 @@ class OrderClass extends BaseClass
         if (empty($cgInfo)) {
             util::fail('没有找到采购信息');
         }
-        PurchaseClass::orderFh($cgInfo, $params, $allowRepeat, true);
+        $notice = isset($params['notice']) ? $params['notice'] : true; // 兼容处理,实现控制是否发发货通知
+        PurchaseClass::orderFh($cgInfo, $params, $allowRepeat, $notice);
     }
 
     //取消发货 ssh 20250917

+ 0 - 1
biz-ghs/part/classes/PartClass.php

@@ -10,7 +10,6 @@ use bizGhs\stock\classes\StockRecordClass;
 use common\components\dict;
 use common\components\orderSn;
 use common\components\util;
-use Yii;
 
 class PartClass extends BaseClass
 {

+ 72 - 1
biz/ghs/classes/GhsClass.php

@@ -8,6 +8,7 @@ use biz\sj\classes\SjClass;
 use biz\wx\classes\WxMessageClass;
 use bizGhs\custom\classes\CustomClass;
 use common\components\imgUtil;
+use common\components\noticeUtil;
 use common\components\stringUtil;
 use common\components\util;
 use biz\base\classes\BaseClass;
@@ -328,4 +329,74 @@ class GhsClass extends BaseClass
         util::fail('找不到供货商');
     }
 
-}
+    // 建立附近批发店关系
+    public static function buildNearbyGhsRelations($shopId, $pfShopId, $toLat, $toLnt)
+    {
+        if (empty($toLat) || empty($toLnt)) {
+            util::fail('门店未定位');
+        }
+
+        // 获取除虚拟外的所有批发店
+        $nearbyShops = ShopClass::getAllByCondition(['ptStyle'=>2, 'live'=>1, 'actTime>=' => strtotime('yesterday')], null, 'id, merchantName, lat, long');
+        if (empty($nearbyShops)) {
+            return;
+        }
+
+        $origins = [];
+        $validNearbyShops = [];
+        foreach ($nearbyShops as $nearbyShop) {
+            if ($nearbyShop['id'] == $pfShopId) {
+                continue;
+            }
+            if ($nearbyShop['lat'] && $nearbyShop['long']) {
+                $origins[] = [
+                    'lat' => $nearbyShop['lat'],
+                    'lng' => $nearbyShop['long'],
+                ];
+                $validNearbyShops[] = $nearbyShop;
+            } else {
+                // 发送钉钉通知
+                noticeUtil::push('批发商:' . $nearbyShop['merchantName'] . '(' . $nearbyShop['id'] . ')未设置经纬度');
+            }
+        }
+
+        if (empty($origins)) {
+            return;
+        }
+
+        // 高德批量测距接口最多支持 100 个起点,需分批处理
+        $chunkOrigins = array_chunk($origins, 100);
+        $allDistances = [];
+
+        foreach ($chunkOrigins as $chunk) {
+            $distances = \common\components\mapUtil::calculateBatchDistance($chunk, $toLnt, $toLat);
+            $allDistances = array_merge($allDistances, $distances);
+        }
+
+        // 建立关系前要先执照距离从小到大排序
+        // 注意:array_multisort($allDistances, SORT_ASC, $validNearbyShops) 能保证 $allDistances 与 $validNearbyShops 保持索引同步,
+        // 即排序后 $validNearbyShops[$i] 就是排序后第 $i 小距离的门店信息,$allDistances[$i] 为其对应距离。
+        array_multisort($allDistances, SORT_ASC, $validNearbyShops);
+
+        // 取前6个
+        $allDistances = array_slice($allDistances, 0, 6);
+        $validNearbyShops = array_slice($validNearbyShops, 0, 6);
+
+        // 建立关系并保存距离
+        foreach ($validNearbyShops as $index => $nearbyShop) {
+            $ghsShopId = $nearbyShop['id'];
+            $distance = $allDistances[$index] ?? 0;
+            // 距离大于60公里不建立关系
+            if ($distance > 60*1000) {
+                continue;
+            }
+
+            // 调用 GhsClass::build 建立关系 (返回的 $ghs 包含 id 和 customId)
+            $ghs = self::build($ghsShopId, $shopId);
+            if (!empty($ghs) && $distance > 0) {
+                $ghsId = $ghs['id'];
+                self::updateById($ghsId, ['distance' => $distance]);
+            }
+        }
+    }
+}

+ 97 - 0
common/components/mapUtil.php

@@ -47,6 +47,46 @@ class mapUtil
         return $distance;
     }
 
+    /**
+     * 批量计算多个起点到一个终点的距离 (高德 V3 距离测量接口)
+     * @param array $origins 起点坐标数组,例如:[['lng' => '116.481028', 'lat' => '39.989643'], ...]
+     * @param string $toLnt 终点经度
+     * @param string $toLat 终点纬度
+     * @param int $type 路径计算的方式和方法 (0:直线距离, 1:驾车, 3:步行)
+     * @return array
+     */
+    public static function calculateBatchDistance($origins, $toLnt, $toLat, $type = 1)
+    {
+        if (empty($origins)) {
+            return [];
+        }
+
+        // 将起点数组拼接成高德要求的格式: lng1,lat1|lng2,lat2
+        $originStrs = [];
+        foreach ($origins as $origin) {
+            $originStrs[] = $origin['lng'] . ',' . $origin['lat'];
+        }
+        $originsParam = implode('|', $originStrs);
+        $destinationParam = $toLnt . ',' . $toLat;
+
+        $domain = getenv('YII_ENV') == 'production' ? 'https://restapi.amap.com' : 'http://restapi.amap.com';
+        $url = $domain . "/v3/distance?key=" . self::$thirdMapKey . "&origins={$originsParam}&destination={$destinationParam}&type={$type}";
+
+        $curl = new curl\Curl();
+        $result = $curl->get($url);
+        $result = \yii\helpers\Json::decode($result);
+
+        $distances = [];
+        if (!empty($result['status']) && $result['status'] == 1 && !empty($result['results'])) {
+            foreach ($result['results'] as $index => $res) {
+                // 返回的结果顺序与传入的 origins 顺序一致
+                $distances[$index] = $res['distance'] ?? 0; 
+            }
+        }
+        
+        return $distances;
+    }
+
     //逆地址解析,根据经纬度解析出中文地址 ssh
     public static function resolveLocation($lat, $long)
     {
@@ -56,4 +96,61 @@ class mapUtil
         $result = Json::decode($result);
         return $result;
     }
+
+    /**
+     * 坐标系转换:从 WGS84 转换为 GCJ-02
+     * @param $lng
+     * @param $lat
+     * @return array
+     */
+    public static function wgs84ToGcj02($lng, $lat)
+    {
+        $lng = (float)$lng;
+        $lat = (float)$lat;
+        if (self::outOfChina($lng, $lat)) {
+            return ['lng' => $lng, 'lat' => $lat];
+        }
+
+        $a = 6378245.0;
+        $ee = 0.00669342162296594323;
+        $dLat = self::transformLat($lng - 105.0, $lat - 35.0);
+        $dLng = self::transformLng($lng - 105.0, $lat - 35.0);
+        $radLat = $lat / 180.0 * M_PI;
+        $magic = sin($radLat);
+        $magic = 1 - $ee * $magic * $magic;
+        $sqrtMagic = sqrt($magic);
+        $dLat = ($dLat * 180.0) / (($a * (1 - $ee)) / ($magic * $sqrtMagic) * M_PI);
+        $dLng = ($dLng * 180.0) / ($a / $sqrtMagic * cos($radLat) * M_PI);
+
+        return ['lng' => $lng + $dLng, 'lat' => $lat + $dLat];
+    }
+
+    private static function transformLat($lng, $lat)
+    {
+        $ret = -100.0 + 2.0 * $lng + 3.0 * $lat + 0.2 * $lat * $lat + 0.1 * $lng * $lat + 0.2 * sqrt(abs($lng));
+        $ret += (20.0 * sin(6.0 * $lng * M_PI) + 20.0 * sin(2.0 * $lng * M_PI)) * 2.0 / 3.0;
+        $ret += (20.0 * sin($lat * M_PI) + 40.0 * sin($lat / 3.0 * M_PI)) * 2.0 / 3.0;
+        $ret += (160.0 * sin($lat / 12.0 * M_PI) + 320.0 * sin($lat * M_PI / 30.0)) * 2.0 / 3.0;
+        return $ret;
+    }
+
+    private static function transformLng($lng, $lat)
+    {
+        $ret = 300.0 + $lng + 2.0 * $lat + 0.1 * $lng * $lng + 0.1 * $lng * $lat + 0.1 * sqrt(abs($lng));
+        $ret += (20.0 * sin(6.0 * $lng * M_PI) + 20.0 * sin(2.0 * $lng * M_PI)) * 2.0 / 3.0;
+        $ret += (20.0 * sin($lng * M_PI) + 40.0 * sin($lng / 3.0 * M_PI)) * 2.0 / 3.0;
+        $ret += (150.0 * sin($lng / 12.0 * M_PI) + 300.0 * sin($lng / 30.0 * M_PI)) * 2.0 / 3.0;
+        return $ret;
+    }
+
+    private static function outOfChina($lng, $lat)
+    {
+        if ($lng < 72.004 || $lng > 137.8347) {
+            return true;
+        }
+        if ($lat < 0.8293 || $lat > 55.8271) {
+            return true;
+        }
+        return false;
+    }
 }

+ 6 - 0
common/components/rabbitmq/notifyConsumer.php

@@ -128,6 +128,12 @@ class notifyConsumer implements ConsumerInterface
         if (empty($shop)) {
             return false;
         }
+        if ($shop->actTime != strtotime(date('Y-m-d'))) {
+            // actTime 活跃时间,只记录以天为单位的时候戳,用于花店注册时推荐批发店
+            $shop->actTime = strtotime(date('Y-m-d'));
+            $shop->save();
+        }
+
         WxMessageClass::ghsHasNewOrderInform($shop, $order);
 
         // 向供货商App发通知

+ 62 - 2
console/controllers/GhsOrderController.php

@@ -4,15 +4,14 @@ namespace console\controllers;
 
 use biz\shop\classes\ShopClass;
 use bizGhs\order\classes\OrderClass;
-use yii\console\Controller;
 use Yii;
+use yii\console\Controller;
 
 class GhsOrderController extends Controller
 {
 
     public function actionBcId()
     {
-
         ini_set('memory_limit', '2045M');
         set_time_limit(0);
 
@@ -30,4 +29,65 @@ class GhsOrderController extends Controller
         }
     }
 
+    // 脚本一:每天 03:20 执行,处理付款时间 7~10 天前订单
+    public function actionAutoSetOrderToFinish()
+    {
+        $minPayTime = date('Y-m-d H:i:s', strtotime('-10 day'));
+        $maxPayTime = date('Y-m-d H:i:s', strtotime('-7 day'));
+        $condition = [
+            'payStatus' => 1,
+            'status' => ['in', [2, 3]],
+            'payTime' => ['between', [$minPayTime, $maxPayTime]],
+        ];
+        $this->batchConfirmReachByMainId($condition);
+        Yii::info('批发订单自动完结脚本成功执行');
+    }
+
+    // 脚本二:历史补偿,处理付款超过 10 天未完结订单
+    public function actionSetOldOrderToFinish()
+    {
+        $maxPayTime = date('Y-m-d H:i:s', strtotime('-10 day'));
+        $condition = [
+            'payStatus' => 1,
+            'status' => ['in', [2, 3]],
+            'payTime <' => $maxPayTime,
+        ];
+        $this->batchConfirmReachByMainId($condition);
+        Yii::info('批发订单自动完结历史补偿脚本成功执行');
+    }
+
+    /**
+     * 按批发店 mainId 分批处理订单自动收货完结
+     * @param array $extraCondition
+     */
+    private function batchConfirmReachByMainId($extraCondition)
+    {
+        $ghsShops = ShopClass::getAllByCondition(['ptStyle' => 2, 'live' => 1], null, 'mainId');
+        if (empty($ghsShops)) {
+            return;
+        }
+        $mainIds = array_unique(array_filter(array_column($ghsShops, 'mainId')));
+        if (empty($mainIds)) {
+            return;
+        }
+        $params = ['staffId' => 0, 'staffName' => '系统', 'notice' => false]; // notice设置为 false,实现不发送发货通知
+        foreach ($mainIds as $mainId) {
+            $condition = array_merge(['mainId' => $mainId], $extraCondition);
+            $orders = OrderClass::getAllByCondition($condition, 'id asc', '*', null, true);
+            if (empty($orders)) {
+                continue;
+            }
+            foreach ($orders as $order) {
+                try {
+                    OrderClass::confirmReach($order, $params);
+                } catch (\Exception $e) {
+                    $orderId = $order->id ?? 0;
+                    Yii::error(
+                        "批发订单自动完结失败 mainId={$mainId}, orderId={$orderId}, message={$e->getMessage()}",
+                        'ghsOrderAutoFinish'
+                    );
+                }
+            }
+        }
+    }
 }

+ 0 - 1
console/controllers/OrderController.php

@@ -2,7 +2,6 @@
 
 namespace console\controllers;
 
-use bizHd\hb\classes\HbClass;
 use bizHd\order\classes\OrderClass;
 use bizHd\order\models\Order;
 use bizHd\purchase\classes\PurchaseClass;