浏览代码

Merge branch 'master' into fix_260721

shish 1 周之前
父节点
当前提交
4e71953313

+ 3 - 0
app-ghs/controllers/CustomController.php

@@ -1096,6 +1096,7 @@ class CustomController extends BaseController
         $homeNum = $get['homeNum'] ?? 0;
         $homeUnMeet = $get['homeUnMeet'] ?? 2;
         $homeUnFee = $get['homeUnFee'] ?? 0;
+        $homeRule = $get['homeRule'] ?? 0;
         if (isset($get['homeType'])) {
             //早期系统有带这个参数,来判断
             util::fail('请升级系统');
@@ -1116,11 +1117,13 @@ class CustomController extends BaseController
         $custom->homeNum = $homeNum;
         $custom->homeUnMeet = $homeUnMeet;
         $custom->homeUnFee = $homeUnFee;
+        $custom->homeRule = $homeRule;
         $custom->save();
         $ghs->homeAmount = $homeAmount;
         $ghs->homeNum = $homeNum;
         $ghs->homeUnMeet = $homeUnMeet;
         $ghs->homeUnFee = $homeUnFee;
+        $ghs->homeRule = $homeRule;
         $ghs->save();
         util::complete('修改成功');
     }

+ 224 - 21
app-ghs/controllers/OrderController.php

@@ -611,19 +611,147 @@ class OrderController extends BaseController
         util::checkRepeatCommit($id, 3);
 
         $order = OrderClass::getById($id, true);
-        if (empty($order)) {
+        OrderClass::valid($order, $this->shopId);
+        if ($order->payStatus == 1) {
             util::success(['returnStatus' => 'SUCCESS']);
         }
-        if ($order->status == OrderClass::ORDER_STATUS_COMPLETE) {
-            util::complete('订单已付款');
+        if ($order->status == 5) {
+            util::success(['returnStatus' => 'CANCEL']);
         }
-        if ($order->status == OrderClass::ORDER_STATUS_CANCEL) {
-            util::complete('订单已取消');
+
+        $cgId = $order->purchaseId ?? 0;
+        $cg = PurchaseClass::getById($cgId, true);
+        $orderSn = $cg->orderSn ?? '';
+        $totalFee = $cg->actPrice ?? 0;
+        if (empty($orderSn)) {
+            util::complete('没有找到采购单');
+        }
+
+        $connection = Yii::$app->db;
+        $transaction = $connection->beginTransaction();
+        try {
+
+            $capitalType = dict::getDict('capitalType', 'xhPurchase', 'id');
+
+            $shop = $this->shop;
+
+            $merchantPrivateKeyPath = Yii::getAlias("@vendor/lakala") . '/production/api_private_key.pem';
+            $lklCertificatePath = Yii::getAlias("@vendor/lakala") . '/production/lkl-apigw-v1.cer';
+            $params = [
+                'appid' => 'OP00002119',
+                'serial_no' => '018b08cfddbd',
+                'merchant_no' => $shop->lklSjNo,
+                'term_no' => $shop->lklScanTermNo,
+                'merchantPrivateKeyPath' => $merchantPrivateKeyPath,
+                'lklCertificatePath' => $lklCertificatePath,
+            ];
+            $laResource = new Lakala($params);
+            $scanParams = ['orderSn' => $orderSn,];
+            $response = $laResource->query($scanParams);
+
+            if (isset($response['code']) && $response['code'] == 'BBS00000') {
+                if (isset($response['resp_data']['trade_state']) && $response['resp_data']['trade_state'] == 'SUCCESS') {
+                    //支付成功
+                    $transactionId = $response['resp_data']['trade_no'] ?? '';
+                    $openId = '';
+                    $aliUserId = '';
+
+                    $cg->onlinePay = dict::getDict('onlinePay', 'yes');
+                    $cg->codePay = 1;
+                    $cg->payOpenId = $openId;
+                    $cg->aliUserId = $aliUserId;
+                    //自取订单
+                    $cg->getType = PurchaseClass::GET_TYPE_SELF_GET;
+                    $cg->save();
+
+                    $order->onlinePay = dict::getDict('onlinePay', 'yes');
+                    $order->codePay = 1;
+                    //自取订单
+                    $order->sendType = OrderClass::SEND_TYPE_NO;
+                    $order->save();
+
+                    $payWayType = dict::getDict('payWay', 'wxPay');
+                    $account_type = $response['resp_data']['account_type'] ?? '';
+                    if ($account_type == 'WECHAT') {
+                        $payWayType = dict::getDict('payWay', 'wxPay');
+                    }
+                    if ($account_type == 'ALIPAY') {
+                        $payWayType = dict::getDict('payWay', 'alipay');
+                    }
+                    $order->payWay = $payWayType;
+                    $order->save();
+                    $cg->payWay = $payWayType;
+                    $cg->save();
+
+                    $attach = '';
+                    payUtil::thirdPay($payWayType, $capitalType, $orderSn, $totalFee, $attach, $transactionId);
+                    $transaction->commit();
+
+                    $saleId = $order->id ?? 0;
+                    $order = OrderClass::getById($saleId, true);
+                    if (!empty($order)) {
+
+                        //解决付款成功后重复通知打印问题
+                        $cacheKey = 'pay_success_notice_' . $orderSn;
+                        $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
+                        if (!empty($has)) {
+                            return false;
+                        }
+                        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 1, 'has']);
+
+                        //订单生成时唤起在线打印
+                        if (isset($order->needPrint) && $order->needPrint == dict::getDict('needPrint', 'need')) {
+                            if ($order->status != 1 && $order->status != 5) {
+                                OrderClass::onlinePrint($order);
+                                $ext = $this->shopExt;
+                                if (isset($ext->printSn) && !empty($ext->printSn)) {
+                                    $order->printNum += 1;
+                                    $order->save();
+                                }
+                            }
+                        }
+
+                        //付款成功之后呼叫跑腿,关键词 pay_after_call_pt,多处要同步修改
+                        GhsDeliveryOrderClass::payAfter($order);
+
+                        ShopExtClass::ghsGatheringReport($order);
+                    }
+                    util::success(['returnStatus' => 'SUCCESS']);
+                } else {
+                    util::complete('未知状态..');
+                }
+            } else {
+                util::complete('未知状态....');
+            }
+        } catch (\Exception $e) {
+            $transaction->rollBack();
+            noticeUtil::push('查询订单状态失败:' . $e->getMessage(), '15280215347');
+            util::fail('支付失败');
         }
-        if ($order->status != OrderClass::ORDER_STATUS_UN_PAY) {
-            util::complete('订单不是待付款状态');
+    }
+
+    //微信和支付宝付款码支付复查 ssh 20260716
+    public function actionCodePayVerify()
+    {
+        ini_set('date.timezone', 'Asia/Shanghai');
+        header("Content-type: text/html; charset=utf-8");
+        $get = Yii::$app->request->get();
+        $id = $get['id'] ?? 0;
+
+        util::checkRepeatCommit($id, 3);
+
+        $order = OrderClass::getById($id, true);
+        if (empty($order)) {
+            util::complete('没有找到订单呢');
         }
         OrderClass::valid($order, $this->shopId);
+        if ($order->payStatus == 1) {
+            util::success(['returnStatus' => 'SUCCESS']);
+        }
+        if ($order->status == 5) {
+            util::success(['returnStatus' => 'CANCEL']);
+        }
+
         $cgId = $order->purchaseId ?? 0;
         $cg = PurchaseClass::getById($cgId, true);
         $orderSn = $cg->orderSn ?? '';
@@ -696,8 +824,8 @@ class OrderController extends BaseController
                     $order = OrderClass::getById($saleId, true);
                     if (!empty($order)) {
 
-                        //解决扫码付重复打印问题
-                        $cacheKey = 'scan_pay_print_order_' . $orderSn;
+                        //解决付款成功后重复通知打印问题
+                        $cacheKey = 'pay_success_notice_' . $orderSn;
                         $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
                         if (!empty($has)) {
                             return false;
@@ -723,10 +851,10 @@ class OrderController extends BaseController
                     }
                     util::success(['returnStatus' => 'SUCCESS']);
                 } else {
-                    util::complete('未知状态..');
+                    util::success(['returnStatus' => 'PENDING'], '等待支付中...');
                 }
             } else {
-                util::complete('未知状态....');
+                util::success(['returnStatus' => 'PENDING'], '等待支付中...');
             }
         } catch (\Exception $e) {
             $transaction->rollBack();
@@ -898,8 +1026,8 @@ class OrderController extends BaseController
                 $order = OrderClass::getById($saleId, true);
                 if (!empty($order)) {
 
-                    //解决扫码付重复打印问题
-                    $cacheKey = 'scan_pay_print_order_' . $orderSn;
+                    //解决付款成功后重复通知打印问题
+                    $cacheKey = 'pay_success_notice_' . $orderSn;
                     $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
                     if (!empty($has)) {
                         return false;
@@ -977,18 +1105,24 @@ class OrderController extends BaseController
             $where['book'] = $book;
         }
         $searchTime = $get['searchTime'] ?? '';
+        //0搜索的addTime 1搜索的payTime
+        $searchTimeType = $get['searchTimeType'] ?? 0;
         if (!empty($searchTime)) {
             $startTime = $get['startTime'] ?? '';
             $endTime = $get['endTime'] ?? '';
             $period = dateUtil::formatTime($searchTime, $startTime, $endTime);
-            $where['payTime'] = ['between', [$period['startTime'], $period['endTime']]];
+            if ($searchTimeType == 0) {
+                $where['addTime'] = ['between', [$period['startTime'], $period['endTime']]];
+            } else {
+                $where['payTime'] = ['between', [$period['startTime'], $period['endTime']]];
+            }
         }
 
         if ($export == 1) {
             ini_set('memory_limit', '2045M');
             set_time_limit(0);
             if (!isset($where['payTime'])) {
-                util::fail('请选时间段');
+                util::fail('请选 账单日期 和 时间段');
             }
             $start = $where['payTime'][1][0];
             $end = $where['payTime'][1][1];
@@ -2643,19 +2777,88 @@ class OrderController extends BaseController
     public function actionCancel()
     {
         $shopAdmin = $this->shopAdmin;
-        if (isset($shopAdmin->super) == false || $shopAdmin->super != 1) {
+        if (!isset($shopAdmin->super) || $shopAdmin->super != 1) {
             util::fail('超管才能取消订单');
         }
-        $id = Yii::$app->request->get('id');
-        $order = OrderClass::getById($id, true);
+        //避免重复提交
+        $adminId = $this->adminId;
+        util::checkRepeatCommit($adminId, 3);
 
+        $get = Yii::$app->request->get();
+        $cashier = $get['cashier'] ?? 0;
+        //是否强制取消订单 0不要强制 1强制,没有关单成功也要取消
+        $forceCancel = $get['forceCancel'] ?? 0;
+        $id = $get['id'] ?? 0;
+        $order = OrderClass::getById($id, true);
+        OrderClass::valid($order, $this->shopId);
         if ($order->orderType == 2) {
             util::fail('客户下单,不能主动取消');
         }
+        //如果收银台的订单,取消时要关闭拉卡拉的订单
+        if ($cashier == 1) {
+            //已取消,不需要再走下面的流程
+            if ($order->status == 5) {
+                util::complete('已取消');
+            }
+            $cgId = $order->purchaseId ?? 0;
+            $cg = PurchaseClass::getById($cgId, true);
+            $orderSn = $cg->orderSn ?? '';
 
-        OrderClass::valid($order, $this->shopId);
-        OrderService::expire($order, true);
-        util::complete('已取消');
+            $shop = $this->shop;
+            $merchantPrivateKeyPath = Yii::getAlias("@vendor/lakala") . '/production/api_private_key.pem';
+            $lklCertificatePath = Yii::getAlias("@vendor/lakala") . '/production/lkl-apigw-v1.cer';
+            $params = [
+                'appid' => 'OP00002119',
+                'serial_no' => '018b08cfddbd',
+                'merchant_no' => $shop->lklSjNo,
+                'term_no' => $shop->lklScanTermNo,
+                'merchantPrivateKeyPath' => $merchantPrivateKeyPath,
+                'lklCertificatePath' => $lklCertificatePath,
+            ];
+            $laResource = new Lakala($params);
+
+            // 1. 先查询拉卡拉侧订单状态
+            $queryResponse = $laResource->query(['orderSn' => $orderSn]);
+            //响应CODE为BBS00000,仅表示查到了这笔交易。交易本身的成功与否状态,要查看响应报文中的trade_state这个值
+            if (isset($queryResponse['code']) && $queryResponse['code'] == 'BBS00000') {
+                $tradeState = $queryResponse['resp_data']['trade_state'] ?? '';
+
+                // 订单已支付,拦截取消操作
+                if ($tradeState == 'SUCCESS') {
+                    util::fail('已付款,不能取消');
+                }
+
+                // 根据拉卡拉聚合支付文档(id=116)及实际情况,判断是否为非终态
+                // INIT:初始化, CREATE:下单成功, DEAL:交易处理中, USERPAYING:支付中, NOTPAY:未支付
+                $pendingStates = ['INIT', 'CREATE', 'DEAL', 'USERPAYING', 'NOTPAY'];
+                if (in_array($tradeState, $pendingStates)) {
+                    $closeParams = ['orderSn' => $orderSn];
+                    $closeResponse = $laResource->close($closeParams);
+                    if (!isset($closeResponse['code']) || $closeResponse['code'] != 'BBS00000') {
+                        $msg = $closeResponse['msg'] ?? '关闭失败';
+                        noticeUtil::push("拉卡拉聚合支付关单失败:{$orderSn},原因:{$msg} 原单状态:{$tradeState}", '15280215347');
+                        if ($forceCancel == 0) {
+                            //返回禁止关单
+                            util::fail('取消失败,如必要请强制取消');
+                        }
+                    }else{
+                        noticeUtil::push("关单成功,订单号:{$orderSn} 原单状态:{$tradeState}", '15280215347');
+                    }
+                }
+                // 如果状态是 CLOSED 或 CANCELED,则视为已关单,直接继续本地流程
+            }
+        }
+        $connection = Yii::$app->db;
+        $transaction = $connection->beginTransaction();
+        try {
+            OrderService::expire($order);
+            $transaction->commit();
+            util::complete('已取消');
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+            Yii::info("取消原因:" . $exception->getMessage());
+            util::fail('取消失败');
+        }
     }
 
     //获取收款语音播报地址 ssh 20211231

+ 1 - 1
app-ghs/controllers/ShMethodController.php

@@ -33,7 +33,7 @@ class ShMethodController extends BaseController
      * 获取门店所有的5种配送方式配置
      * 如果数据库里没有,则取默认配置进行初始化
      */
-    public function actionGetAllConfig()
+    public function actionGetAllMethod()
     {
         try {
             $configs = ShMethodClass::getAllConfigs($this->shopId, $this->mainId);

+ 5 - 4
app-ghs/controllers/TestController.php

@@ -412,9 +412,6 @@ class TestController extends BaseController
 
     public function actionGet()
     {
-        ini_set('memory_limit', '2045M');
-        set_time_limit(0);
-
         GhsDeviceClass::updateByCondition(['adminId' => 4, 'status' => 1], ['status' => 0]);
         HdDeviceClass::updateByCondition(['adminId' => 4, 'status' => 1], ['status' => 0]);
 
@@ -507,7 +504,11 @@ class TestController extends BaseController
             //['name' => '张家口万花汇', 'merchantNo' => '82213805992008D', 'wx' => [901551070, 901551037], 'zfb' => '2088780253600870'],
             //['name' => '深圳每日鲜花批发', 'merchantNo' => '82258405992020E', 'wx' => [902309136, 902307468], 'zfb' => '2088780298610704'],
             //['name' => '滨州花镜鲜花', 'merchantNo' => '82246605992005U', 'wx' => [904373612, 904373338], 'zfb' => '2088780426621723'],
-            ['name' => '广州情意鲜花', 'merchantNo' => '8225810599201U2', 'wx' => [904871059, 904872401], 'zfb' => '2088780455410378'],
+            //['name' => '广州情意鲜花', 'merchantNo' => '8225810599201U2', 'wx' => [904871059, 904872401], 'zfb' => '2088780455410378'],
+            //['name' => '我要花义乌店', 'merchantNo' => '8223380599200A6', 'wx' => [2000005220, 907253683], 'zfb' => '2088780613953851'],
+            //['name' => '宣城花农鲜花批发', 'merchantNo' => '82237705992001J', 'wx' => [908946077, 908945971], 'zfb' => '2088780700979012'],
+            //['name' => '亳州花鲜谷', 'merchantNo' => '82238105992004A', 'wx' => [908947821, 908946480], 'zfb' => '2088780700742980'],
+            ['name' => '福建清流美朵花业', 'merchantNo' => '82239505992002F', 'wx' => [909185571, 2000017120], 'zfb' => '2088780716665741'],
             //['name' => '厦门纯彩花艺', 'merchantNo' => '8223930599200LD', 'wx' => [894984230, 894983290], 'zfb' => '2088680439152343'],
             //['name' => '东莞我要花鲜花', 'merchantNo' => '8226020599200R8', 'wx' => [894794554, 894794917], 'zfb' => '2088680405463378'],
             //['name' => '镇江花珩鲜花批发', 'merchantNo' => '82231405992003N', 'wx' => [894925711, 894925626], 'zfb' => '2088680426877183'],

+ 23 - 41
app-hd/controllers/GhsController.php

@@ -257,7 +257,7 @@ class GhsController extends BaseController
         $ghsInfo['packCost'] = $ghsShop->packCost ? floatval($ghsShop->packCost) : 0;
         $lackExpend = $ghsShop->lackExpend ? floatval($ghsShop->lackExpend) : 0;
         $customId = $ghsInfo['customId'] ?? 0;
-        $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShop, $customId);
+        $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShop, $customId, 4);
         //昆明批发,需要算打包费和运费
         $needAddPackFreight = 1;
         if (!$needAdd) {
@@ -273,6 +273,7 @@ class GhsController extends BaseController
         $ghsInfo['kiloFee'] = $ghsShop->kiloFee ?? 0;
         $ghsInfo['miniKilo'] = $ghsShop->miniKilo ?? 0;
 
+        //这个多处要补充的地方 add_pfLevel_many_place
         $ghsInfo['pfLevel'] = $ghsShop->pfLevel ?? 0;
         $ghsInfo['afterSale'] = $ghsShop->afterSale ?? 1;
         //联系电话
@@ -321,6 +322,10 @@ class GhsController extends BaseController
         }
         $ghsInfo['hcMap'] = $hcMap;
 
+        //是否使用新的配送方式,关键词 sh_method_area
+        $newShMethod = dict::getNewMethodShop();
+        $ghsInfo['useNewShMethod'] = in_array($ghsShopId, $newShMethod) ? 1 : 0;
+
         util::success($ghsInfo);
     }
 
@@ -378,6 +383,13 @@ class GhsController extends BaseController
 
             $ghs['transCost'] = dict::getDict('transCost', null, null, $ghsShop->mainId);
 
+            //这个多处要补充的地方 add_pfLevel_many_place
+            $ghs['pfLevel'] = $ghsShop->pfLevel ?? 0;
+
+            //是否使用新的配送方式,关键词 sh_method_area
+            $newShMethod = dict::getNewMethodShop();
+            $ghs['useNewShMethod'] = in_array($ghsShopId, $newShMethod) ? 1 : 0;
+
         } else {
             //没有开店也给显示供货商信息
             $shop = ShopClass::getShopInfo($shopId);
@@ -500,7 +512,16 @@ class GhsController extends BaseController
 
     public function actionCommonInfo()
     {
-        $mainId = $this->resolveGhsMainId();
+        $get = Yii::$app->request->get();
+        $ghsId = intval($get['ghsId'] ?? 0);
+        $ghs = GhsClass::getById($ghsId);
+        if (empty($ghs)) {
+            util::fail('没有找到批发店');
+        }
+        if ($ghs['ownMainId'] != $this->mainId) {
+            util::fail('不是你的批发店');
+        }
+        $mainId = $ghs['mainId'] ?? 0;
         // 通用接口返回全部有效公告,前端按 positions 字段筛选展示位置
         $ghsNoticeList = GhsNoticeClass::getClientNoticeList($mainId);
         util::success(['ghsNoticeList' => $ghsNoticeList]);
@@ -518,43 +539,4 @@ class GhsController extends BaseController
         util::success(GhsNoticeClass::getClientDetail($id));
     }
 
-    /**
-     * 根据批发商 ghsId 或 shopId 解析 mainId(列表接口用,勿与公告 id 混用)
-     */
-    protected function resolveGhsMainId(): int
-    {
-        $get = Yii::$app->request->get();
-        $ghsId = intval($get['ghsId'] ?? 0);
-        $shopId = intval($get['shopId'] ?? 0);
-        $ghsShopId = 0;
-
-        if ($ghsId > 0) {
-            $ghs = GhsClass::getById($ghsId);
-            if (empty($ghs)) {
-                util::fail('没有找到批发商');
-            }
-            if (!empty($this->shopId)) {
-                GhsClass::valid($ghs, $this->shopId);
-            }
-            $ghsShopId = intval($ghs['shopId'] ?? 0);
-        } elseif ($shopId > 0) {
-            $ghsShop = ShopClass::getById($shopId, true);
-            if (empty($ghsShop) || $ghsShop->ptStyle != dict::getDict('ptStyle', 'ghs')) {
-                util::fail('没有找到批发店');
-            }
-            $ghsShopId = $shopId;
-        } else {
-            util::fail('参数不对');
-        }
-
-        $ghsShop = ShopClass::getById($ghsShopId, true);
-        if (empty($ghsShop)) {
-            util::fail('没有找到批发商');
-        }
-        $mainId = intval($ghsShop->mainId ?? 0);
-        if ($mainId <= 0) {
-            util::fail('批发商信息不完整');
-        }
-        return $mainId;
-    }
 }

+ 40 - 22
app-hd/controllers/NoticeController.php

@@ -192,12 +192,16 @@ class NoticeController extends PublicController
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
                     }
                 } else {
-                    if (isset($cg->sendType) && $cg->sendType == 4) {
-                        //标记当天发快递方式已收一次包装费,岭南批发市场用的功能
-                        $customId = $cg->customId ?? 0;
-                        $current = date("Y_m_d");
-                        $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
+                    //标记当配送方式已收一次包装费/运费,岭南批发市场用的功能,关键词 sh_method_area,只要有成功单就标记,不再要求金额必须>0
+                    $customId = $cg->customId ?? 0;
+                    $current = date("Y_m_d");
+                    if (isset($cg->sendType) && in_array($cg->sendType, [0, 4])) {
+                        $key = 'ghs_custom_today_has_get_pack_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+
+                        // 兼容快递收运费的情况
+                        $sendKey = 'ghs_custom_today_has_get_send_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
+                        Yii::$app->redis->executeCommand('SETEX', [$sendKey, 86400, '1']);
                     }
                 }
 
@@ -222,7 +226,7 @@ class NoticeController extends PublicController
 
                                 if (getenv('YII_ENV') == 'production') {
                                     //福州我要花、花路鲜花批发、小齐鲜花、花镜打二次小票,有多处要修改搜索关键词tow_print
-                                    $needTwoPrint = [7538, 36707, 76796];
+                                    $needTwoPrint = [7538, 36707, 76796, 94589];
                                 } else {
                                     $needTwoPrint = [644];
                                 }
@@ -407,12 +411,16 @@ class NoticeController extends PublicController
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
                     }
                 } else {
-                    if (isset($cg->sendType) && $cg->sendType == 4) {
-                        //标记当天发快递方式已收一次包装费,岭南批发市场用的功能
-                        $customId = $cg->customId ?? 0;
-                        $current = date("Y_m_d");
-                        $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
+                    //标记当配送方式已收一次包装费/运费,岭南批发市场用的功能,关键词 sh_method_area,只要有成功单就标记,不再要求金额必须>0
+                    $customId = $cg->customId ?? 0;
+                    $current = date("Y_m_d");
+                    if (isset($cg->sendType) && in_array($cg->sendType, [0, 4])) {
+                        $key = 'ghs_custom_today_has_get_pack_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+
+                        // 兼容快递收运费的情况
+                        $sendKey = 'ghs_custom_today_has_get_send_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
+                        Yii::$app->redis->executeCommand('SETEX', [$sendKey, 86400, '1']);
                     }
                 }
 
@@ -443,7 +451,7 @@ class NoticeController extends PublicController
 
                                 if (getenv('YII_ENV') == 'production') {
                                     //福州我要花、花路鲜花批发、花镜打二次小票,有多处要修改搜索关键词tow_print
-                                    $needTwoPrint = [7538, 36707, 76796];
+                                    $needTwoPrint = [7538, 36707, 76796, 94589];
                                 } else {
                                     $needTwoPrint = [];
                                 }
@@ -570,13 +578,19 @@ class NoticeController extends PublicController
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
                     }
                 } else {
-                    if (isset($cg->sendType) && $cg->sendType == 4) {
-                        //标记当天发快递方式已收一次包装费,岭南批发市场用的功能
-                        $customId = $cg->customId ?? 0;
-                        $current = date("Y_m_d");
-                        $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
+
+                    //标记当配送方式已收一次包装费/运费,岭南批发市场用的功能,关键词 sh_method_area,只要有成功单就标记,不再要求金额必须>0
+                    $customId = $cg->customId ?? 0;
+                    $current = date("Y_m_d");
+                    if (isset($cg->sendType) && in_array($cg->sendType, [0, 4])) {
+                        $key = 'ghs_custom_today_has_get_pack_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
                         Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+
+                        // 兼容快递收运费的情况
+                        $sendKey = 'ghs_custom_today_has_get_send_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
+                        Yii::$app->redis->executeCommand('SETEX', [$sendKey, 86400, '1']);
                     }
+
                 }
 
                 if (!empty($cg) && $cg->payStatus == 1) {
@@ -822,14 +836,18 @@ class NoticeController extends PublicController
                                 Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
                             }
                         } else {
-                            if (isset($cg->sendType) && $cg->sendType == 4) {
-                                //标记当天发快递方式已收一次包装费,岭南批发市场用的功能
+                                //标记当配送方式已收一次包装费/运费,岭南批发市场用的功能,关键词 sh_method_area,只要有成功单就标记,不再要求金额必须>0
                                 $customId = $cg->customId ?? 0;
                                 $current = date("Y_m_d");
-                                $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
-                                Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+                                if (isset($cg->sendType) && in_array($cg->sendType, [0, 4])) {
+                                    $key = 'ghs_custom_today_has_get_pack_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
+                                    Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+
+                                    // 兼容快递收运费的情况
+                                    $sendKey = 'ghs_custom_today_has_get_send_cost_' . $cg->sendType . '_' . $current . '_' . $customId;
+                                    Yii::$app->redis->executeCommand('SETEX', [$sendKey, 86400, '1']);
+                                }
                             }
-                        }
 
                         //微信通知
                         $saleId = $cg->saleId ?? 0;

+ 162 - 15
app-hd/controllers/OrderController.php

@@ -94,25 +94,78 @@ class OrderController extends BaseController
     //取消订单 ssh 20221231
     public function actionCancel()
     {
+        $shopAdmin = $this->shopAdmin;
         //避免重复提交
         $adminId = $this->adminId;
-        util::checkRepeatCommit($adminId, 8);
+        util::checkRepeatCommit($adminId, 3);
 
         $get = Yii::$app->request->get();
+        $cashier = $get['cashier'] ?? 0;
+        //是否强制取消订单 0不要强制 1强制,没有关单成功也要取消
+        $forceCancel = $get['forceCancel'] ?? 0;
         $id = $get['id'] ?? 0;
         $order = OrderClass::getById($id, true);
         if ($order->mainId != $this->mainId) {
             util::fail('不是你的订单');
         }
+        //如果收银台的订单,取消时要关闭拉卡拉的订单
+        if ($cashier == 1) {
+            //已取消,不需要再走下面的流程
+            if ($order->status == 5) {
+                util::complete('已取消');
+            }
+            $orderSn = $order->orderSn ?? '';
+
+            $shop = $this->shop;
+            $merchantPrivateKeyPath = Yii::getAlias("@vendor/lakala") . '/production/api_private_key.pem';
+            $lklCertificatePath = Yii::getAlias("@vendor/lakala") . '/production/lkl-apigw-v1.cer';
+            $params = [
+                'appid' => 'OP00002119',
+                'serial_no' => '018b08cfddbd',
+                'merchant_no' => $shop->lklSjNo,
+                'term_no' => $shop->lklScanTermNo,
+                'merchantPrivateKeyPath' => $merchantPrivateKeyPath,
+                'lklCertificatePath' => $lklCertificatePath,
+            ];
+            $laResource = new Lakala($params);
+
+            // 1. 先查询拉卡拉侧订单状态
+            $queryResponse = $laResource->query(['orderSn' => $orderSn]);
+            //响应CODE为BBS00000,仅表示查到了这笔交易。交易本身的成功与否状态,要查看响应报文中的trade_state这个值
+            if (isset($queryResponse['code']) && $queryResponse['code'] == 'BBS00000') {
+                $tradeState = $queryResponse['resp_data']['trade_state'] ?? '';
 
-        $staff = $this->shopAdmin;
+                // 订单已支付,拦截取消操作
+                if ($tradeState == 'SUCCESS') {
+                    util::fail('已付款,不能取消');
+                }
+
+                // 根据拉卡拉聚合支付文档(id=116)及实际情况,判断是否为非终态
+                // INIT:初始化, CREATE:下单成功, DEAL:交易处理中, USERPAYING:支付中, NOTPAY:未支付
+                $pendingStates = ['INIT', 'CREATE', 'DEAL', 'USERPAYING', 'NOTPAY'];
+                if (in_array($tradeState, $pendingStates)) {
+                    $closeParams = ['orderSn' => $orderSn];
+                    $closeResponse = $laResource->close($closeParams);
+                    if (!isset($closeResponse['code']) || $closeResponse['code'] != 'BBS00000') {
+                        $msg = $closeResponse['msg'] ?? '关闭失败';
+                        noticeUtil::push("拉卡拉聚合支付关单失败:{$orderSn},原因:{$msg} 原单状态:{$tradeState}", '15280215347');
+                        if ($forceCancel == 0) {
+                            //返回禁止关单
+                            util::fail('取消失败,如必要请强制取消');
+                        }
+                    }else{
+                        noticeUtil::push("关单成功,订单号:{$orderSn} 原单状态:{$tradeState}", '15280215347');
+                    }
+                }
+            }
+        }
 
         $connection = Yii::$app->db;
         $transaction = $connection->beginTransaction();
         try {
-            OrderClass::setExpire($order, true, $staff);
+            OrderClass::setExpire($order, true, $shopAdmin);
             $transaction->commit();
-            util::complete();
+            util::complete('已取消');
         } catch (\Exception $exception) {
             $transaction->rollBack();
             Yii::info("取消原因:" . $exception->getMessage());
@@ -275,8 +328,8 @@ class OrderController extends BaseController
     public function actionBatchFetch()
     {
         $where = ["status" => 2, "sendType" => 1, "shopId" => $this->shopId];
-        $orderList = OrderService::getLimitList("id",$where,500,"id desc");
-        $ids = ArrayHelper::getColumn($orderList,"id");
+        $orderList = OrderService::getLimitList("id", $where, 500, "id desc");
+        $ids = ArrayHelper::getColumn($orderList, "id");
         OrderService::updateByIds($ids, ["status" => 4]);
         util::complete($ids);
     }
@@ -347,14 +400,11 @@ class OrderController extends BaseController
         OrderClass::valid($order, $this->mainId);
         $orderSn = $order->orderSn ?? '';
         $totalFee = $order->mainPay ?? 0;
-        if ($order->status == OrderClass::ORDER_STATUS_COMPLETE) {
+        if ($order->payStatus == 1) {
             util::success(['returnStatus' => 'SUCCESS']);
         }
-        if ($order->status == OrderClass::ORDER_STATUS_CANCEL) {
-            util::complete('订单已取消');
-        }
-        if ($order->status != OrderClass::ORDER_STATUS_UN_PAY) {
-            util::complete('订单不是待付款状态');
+        if ($order->status == 5) {
+            util::success(['returnStatus' => 'CANCEL']);
         }
 
         $connection = Yii::$app->db;
@@ -398,7 +448,7 @@ class OrderController extends BaseController
                     $transaction->commit();
 
                     //解决重复通知
-                    $cacheKey = 'hd_shop_order_pay_check_' . $orderSn;
+                    $cacheKey = 'pay_success_notice_' . $orderSn;
                     $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
                     if (empty($has)) {
                         Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 300, 'has']);
@@ -433,6 +483,103 @@ class OrderController extends BaseController
         }
     }
 
+    //微信和支付宝付款码支付复查 ssh 20260716
+    public function actionCodePayVerify()
+    {
+        ini_set('date.timezone', 'Asia/Shanghai');
+        header("Content-type: text/html; charset=utf-8");
+        $get = Yii::$app->request->get();
+        $id = $get['id'] ?? 0;
+
+        util::checkRepeatCommit($id, 3);
+
+        $order = OrderClass::getById($id, true);
+        OrderClass::valid($order, $this->mainId);
+        $orderSn = $order->orderSn ?? '';
+        $totalFee = $order->mainPay ?? 0;
+        if ($order->payStatus == 1) {
+            util::success(['returnStatus' => 'SUCCESS']);
+        }
+        if ($order->status == 5) {
+            util::success(['returnStatus' => 'CANCEL']);
+        }
+
+        $connection = Yii::$app->db;
+        $transaction = $connection->beginTransaction();
+        try {
+
+            $capitalType = dict::getDict('capitalType', 'xhOrder', 'id');
+
+            $shop = $this->shop;
+            $merchantPrivateKeyPath = Yii::getAlias("@vendor/lakala") . '/production/api_private_key.pem';
+            $lklCertificatePath = Yii::getAlias("@vendor/lakala") . '/production/lkl-apigw-v1.cer';
+            $params = [
+                'appid' => 'OP00002119',
+                'serial_no' => '018b08cfddbd',
+                'merchant_no' => $shop->lklSjNo,
+                'term_no' => $shop->lklScanTermNo,
+                'merchantPrivateKeyPath' => $merchantPrivateKeyPath,
+                'lklCertificatePath' => $lklCertificatePath,
+            ];
+            $laResource = new Lakala($params);
+            $scanParams = ['orderSn' => $orderSn,];
+            $response = $laResource->query($scanParams);
+
+            if (isset($response['code']) && $response['code'] == 'BBS00000') {
+                if (isset($response['resp_data']['trade_state']) && $response['resp_data']['trade_state'] == 'SUCCESS') {
+
+                    $payWayType = dict::getDict('payWay', 'wxPay');
+                    $account_type = $response['resp_data']['account_type'] ?? '';
+                    if ($account_type == 'WECHAT') {
+                        $payWayType = dict::getDict('payWay', 'wxPay');
+                    }
+                    if ($account_type == 'ALIPAY') {
+                        $payWayType = dict::getDict('payWay', 'alipay');
+                    }
+
+                    $transactionId = $response['resp_data']['trade_no'] ?? '';
+                    $order->onlinePay = dict::getDict('onlinePay', 'yes');
+                    $order->save();
+                    $attach = '';
+                    payUtil::thirdPay($payWayType, $capitalType, $orderSn, $totalFee, $attach, $transactionId);
+                    $transaction->commit();
+
+                    //解决重复通知
+                    $cacheKey = 'pay_success_notice_' . $orderSn;
+                    $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
+                    if (empty($has)) {
+                        Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 300, 'has']);
+
+                        //打印小票和语音播报
+                        $newOrder = OrderClass::getById($id, true);
+                        OrderClass::onlinePrint($newOrder);
+                        ShopExtClass::hdGatheringReport($newOrder);
+
+                        //到店自取订单,并且是待取货状态,则自动完成取货,多处要同步修改,关键词 reach_shop_fetch_goods
+                        if ($newOrder->getGoods == 1 && $newOrder->sendType == 1 && $newOrder->status == 2) {
+                            $newOrder->status = 4;
+                            $newOrder->save();
+                        }
+
+                        HdDeliveryOrderClass::payAfter($newOrder);
+
+                        $shopId = $newOrder->shopId ?? 0;
+                        $shop = ShopClass::getById($shopId, true);
+                        WxMessageClass::gatheringIncomeInform($shop, $newOrder);
+                    }
+
+                    util::success(['returnStatus' => 'SUCCESS']);
+                } else {
+                    util::success(['returnStatus' => 'PENDING'], '等待支付中...');
+                }
+            }
+            util::success(['returnStatus' => 'PENDING'], '等待支付中...');
+        } catch (\Exception $e) {
+            $transaction->rollBack();
+            util::complete('支付失败');
+        }
+    }
+
     /**
      * 微信和支付宝付款码支付
      * 职责:处理商户扫描客户付款码(被扫支付)的请求,调用拉卡拉支付接口并更新本地订单状态(零售端)
@@ -866,7 +1013,7 @@ class OrderController extends BaseController
                         if ($hasPay != dict::getDict('hasPay', 'balance')) {
                             util::fail('用红包要用余额支付');
                         } else {
-                            if($custom->balance < $post['modifyPrice']) {
+                            if ($custom->balance < $post['modifyPrice']) {
                                 util::fail('用红包要用余额支付(您的余额不足)');
                             }
                         }
@@ -1357,7 +1504,7 @@ class OrderController extends BaseController
         }
         $list = OrderService::getOrderList($where);
         $list['shop'] = $this->shop->attributes ?? [];
-        
+
         util::success($list);
     }
 

+ 216 - 178
app-hd/controllers/PurchaseController.php

@@ -11,6 +11,7 @@ use bizGhs\custom\classes\AccountMoneyClass;
 use bizGhs\custom\classes\CustomClass;
 use bizGhs\express\classes\GhsDeliveryOrderClass;
 use bizGhs\order\classes\OrderClass;
+use bizGhs\order\classes\ShMethodClass;
 use bizHd\cg\classes\CgMergeSnClass;
 use bizHd\purchase\classes\PurchaseClass;
 use bizHd\purchase\classes\PurchaseItemClass;
@@ -520,6 +521,9 @@ class PurchaseController extends BaseController
 
             $post['product'] = $productList;
 
+            // xhShMethod 门店下单前保留花材合计,供后续 packCost 计算(pfLevel==0 分支会 unset itemTotalAmount)
+            $shMethodItemAmount = $post['itemTotalAmount'] ?? 0;
+
             $sendType = $post['sendType'] ?? 0;
             $transType = $post['transType'] ?? 0;
             if ($sendType == dict::getDict('sendType', 'thirdSend')) {
@@ -568,7 +572,7 @@ class PurchaseController extends BaseController
                     }
                 }
                 //如果已经算过一次打包费和运费了,则不再费了
-                $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId);
+                $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId, $sendType);
                 if (!$needAdd) {
                     $packCost = 0;
                     if (isset($ghsInfo['mainId']) && $ghsInfo['mainId'] == 14499) {
@@ -618,7 +622,7 @@ class PurchaseController extends BaseController
                 }
 
                 //如果已经算过一次打包费和运费了,则不再费了
-                $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId);
+                $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId, $sendType);
                 if ($needAdd == false) {
                     $sendCost = 0;
                 }
@@ -627,218 +631,248 @@ class PurchaseController extends BaseController
                 //标记为昆明到地方订单
                 $post['localOrder'] = 1;
             } else {
-                //同城发货包装费和运费的计算
-                $sendCost = 0;
-                $sendDistance = 0;
-                //特别注意,这边取供货商的shop信息
-                $mapSet = ShopClass::hasIntraCity($ghsShopInfo);
-                $openIntraCity = $mapSet['openIntraCity'] ?? 0;
-                if ($sendType == dict::getDict('sendType', 'thirdSend')) {
-                    if ($openIntraCity == 2) {
-                        util::fail('不能使用跑腿');
+
+                // xhShMethod 门店:下单前按配置写入不满最低消费时的附加包装费/运费,关键词 sh_method_area
+                $newShMethod = dict::getNewMethodShop();
+                if (in_array($ghsShopId, $newShMethod)) {
+                    $shMethodBigNum = 0;
+                    foreach ($productList as $itemData) {
+                        $shMethodBigNum += floatval($itemData['bigNum'] ?? 0);
+                    }
+                    $additionalCosts = ShMethodClass::calcFee(
+                        $ghsShopId,
+                        $ghsMainId,
+                        $sendType,
+                        $shMethodItemAmount,
+                        $shMethodBigNum,
+                        $customId,
+                        $ghsInfo
+                    );
+
+                    // 如果产生了附加运费,与前面可能产生的 sendCost 进行累加或覆盖
+                    if ($additionalCosts['sendCost'] > 0) {
+                        $post['sendCost'] = bcadd($post['sendCost'] ?? 0, $additionalCosts['sendCost'], 2);
                     }
-                    if ($openIntraCity == 1) {
-                        // 生成随机订单号,不要跟原来的混起来,跑腿-销售单-
-                        $prefix = 'PT-XSD-' . $this->mainId . '-';
-                        $orderSn = $prefix . round(microtime(true) * 1000);
 
-                        // 使用 DeliveryQuoteUtil 获取配送报价
-                        try {
+                    // 如果产生了附加包装费,覆盖前面赋值的 packCost
+                    if ($additionalCosts['packCost'] > 0) {
+                        $post['packCost'] = $additionalCosts['packCost'];
+                    }
+                }else{
 
-                            if (empty($post['deliveryPlatform'])) {
-                                util::fail('请选择跑腿');
-                            }
+                    //同城发货包装费和运费的计算
+                    $sendCost = 0;
+                    $sendDistance = 0;
+                    //特别注意,这边取供货商的shop信息
+                    $mapSet = ShopClass::hasIntraCity($ghsShopInfo);
+                    $openIntraCity = $mapSet['openIntraCity'] ?? 0;
+                    if ($sendType == dict::getDict('sendType', 'thirdSend')) {
+                        if ($openIntraCity == 2) {
+                            util::fail('不能使用跑腿');
+                        }
+                        if ($openIntraCity == 1) {
+                            // 生成随机订单号,不要跟原来的混起来,跑腿-销售单-
+                            $prefix = 'PT-XSD-' . $this->mainId . '-';
+                            $orderSn = $prefix . round(microtime(true) * 1000);
+
+                            // 使用 DeliveryQuoteUtil 获取配送报价
+                            try {
+
+                                if (empty($post['deliveryPlatform'])) {
+                                    util::fail('请选择跑腿');
+                                }
 
-                            $quoteResult = DeliveryQuoteUtil::getDeliveryQuote([
-                                'productList' => $productList,
-                                'deliveryPlatform' => $post['deliveryPlatform'],
-                                'deliveryBracketContent' => $post['deliveryBracketContent'], // 平台多报价识别id
-                                'ghsInfo' => $ghsInfo,
-                                'custom' => $custom,
-                                'order' => [
-                                    'orderSn' => $orderSn,
-                                    'goodsType' => 1, //商品类型:0花束 1花材
-                                    'itemTotalAmount' => $post['itemTotalAmount'] ?? 0,
-                                    'remark' => $post['remark'] ?? '',
-                                ],
-                                'mainId' => $this->mainId,
-                                'productCount' => $productCount,
-                            ]);
-
-                            $sendCost = $quoteResult['sendCost'];
-                            $sendDistance = $quoteResult['sendDistance'];
-                        } catch (\Exception $e) {
-                            util::fail($e->getMessage());
+                                $quoteResult = DeliveryQuoteUtil::getDeliveryQuote([
+                                    'productList' => $productList,
+                                    'deliveryPlatform' => $post['deliveryPlatform'],
+                                    'deliveryBracketContent' => $post['deliveryBracketContent'], // 平台多报价识别id
+                                    'ghsInfo' => $ghsInfo,
+                                    'custom' => $custom,
+                                    'order' => [
+                                        'orderSn' => $orderSn,
+                                        'goodsType' => 1, //商品类型:0花束 1花材
+                                        'itemTotalAmount' => $post['itemTotalAmount'] ?? 0,
+                                        'remark' => $post['remark'] ?? '',
+                                    ],
+                                    'mainId' => $this->mainId,
+                                    'productCount' => $productCount,
+                                ]);
+
+                                $sendCost = $quoteResult['sendCost'];
+                                $sendDistance = $quoteResult['sendDistance'];
+                            } catch (\Exception $e) {
+                                util::fail($e->getMessage());
+                            }
                         }
                     }
-                }
 
-                $post['sendCost'] = $sendCost;
-                $post['sendDistance'] = $sendDistance;
+                    $post['sendCost'] = $sendCost;
+                    $post['sendDistance'] = $sendDistance;
 
-                //出车、发快递、发物流可以算包装费
-                $packCost = 0;
-                if (isset($ghsInfo['mainId']) && $ghsInfo['mainId'] == 14499) {
-                    noticeUtil::push("走的pfLevel=0", '15280215347');
-                }
-                $itemTotalAmount = $post['itemTotalAmount'] ?? 0;
-                unset($post['itemTotalAmount']);
-                if ($sendType == dict::getDict('sendType', 'express')) {
-                    $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId, $itemTotalAmount);
-                    if ($needAdd) {
-                        $packCost = $ghsShopInfo->packCost ?? 0;
+                    // 出车(0)、发快递(4)、发物流可以算包装费
+                    $packCost = 0;
+                    if (isset($ghsInfo['mainId']) && $ghsInfo['mainId'] == 14499) {
+                        noticeUtil::push("走的pfLevel=0", '15280215347');
                     }
-                }
-                $post['packCost'] = $packCost;
-            }
+                    $itemTotalAmount = $post['itemTotalAmount'] ?? 0;
+                    unset($post['itemTotalAmount']);
+
+                    // sendType == 0 或 4 都要收包装费
+                    if (in_array($sendType, [0, 4])) {
+                        $needAdd = \bizHd\shop\classes\ShopClass::needAddPackCost($ghsShopInfo, $customId, $sendType, $itemTotalAmount);
+                        if ($needAdd) {
+                            $packCost = $ghsShopInfo->packCost ?? 0;
+                        }
+                    }
+                    $post['packCost'] = $packCost;
 
-            if (isset($ghsInfo['mainId']) && $ghsInfo['mainId'] == 14499) {
-                noticeUtil::push("包装费:" . $packCost, '15280215347');
+                }
             }
 
             $respond = PurchaseService::createPurchase($post, $ghsInfo);
 
-            if ($sendType == 0) {
-                if (getenv('YII_ENV') == 'production') {
-                    //杭州斗南鲜花批发部,满500,10公里内免费配送,满1000,20公里免费配送
-                    if ($ghsShopId == 4608) {
-                        if ($respond->actPrice < 500) {
-                            $transaction->rollBack();
-                            util::fail('满500元支持免费配送');
-                        }
-                    }
-                    //叶上花,满500元市区免费配送
-                    if ($ghsShopId == 4804) {
-                        if ($respond->actPrice < 500) {
-                            $transaction->rollBack();
-                            util::fail('满500元支持免费配送');
-                        }
-                    }
-                    //花悠星 国恋 勇记 万丽 陆丰暂时不支持免费配送
-                    if ($ghsShopId == 7687 || $ghsShopId == 7831 || $ghsShopId == 7778 || $ghsShopId == 12003 || $ghsShopId == 38128) {
-                        util::fail('暂不支持送货上门,请选其它配送方式!');
-                    }
+            $newShMethod = dict::getNewMethodShop();
+            if (in_array($ghsShopId, $newShMethod)) {
+                // 使用 xhShMethod 配置校验配送限制,替代旧版门店硬编码规则,关键词 sh_method_area
+                $shMethodError = ShMethodClass::checkLimit(
+                    $ghsShopId,
+                    $ghsMainId,
+                    $sendType,
+                    $respond->actPrice ?? 0,
+                    $respond->bigNum ?? 0,
+                    $post['packCost'] ?? 0,
+                    $post['sendCost'] ?? 0,
+                    $post['wlName'] ?? '',
+                    $customId,
+                    $ghsInfo
+                );
+                if ($shMethodError !== '') {
+                    $transaction->rollBack();
+                    util::fail($shMethodError);
+                }
+            } else {
 
-                    //广州鑫源花卉,选择送货上门必须选必选商品
-                    if ($ghsShopId == 12439) {
-                        $hasMust = array_intersect($ids, [3446945, 3446970, 3446973, 3446979, 3446995, 3447010, 3447023, 3459983, 4333184, 4317745, 1585738]);
-                        if (empty($hasMust)) {
-                            util::fail('请返回选择 必选商品');
+                if ($sendType == 0) {
+                    if (getenv('YII_ENV') == 'production') {
+                        //杭州斗南鲜花批发部,满500,10公里内免费配送,满1000,20公里免费配送
+                        if ($ghsShopId == 4608) {
+                            if ($respond->actPrice < 500) {
+                                $transaction->rollBack();
+                                util::fail('满500元支持免费配送');
+                            }
                         }
-                    }
-                    if ($ghsShopId == 100883) {
-                        $hasMust = array_intersect($ids, [5017957,5036067,5036089,5036099,5017958,5036063,5017948,5035980,5036073,5036075,5036076,5036117,5036118,5017949,5035979,5035976,5035928,5035930,5036061,5035879]);
-                        if (empty($hasMust)) {
-                            util::fail('请返回选择 必选商品');
+                        //叶上花,满500元市区免费配送
+                        if ($ghsShopId == 4804) {
+                            if ($respond->actPrice < 500) {
+                                $transaction->rollBack();
+                                util::fail('满500元支持免费配送');
+                            }
+                        }
+                        //花悠星 国恋 勇记 万丽 陆丰暂时不支持免费配送
+                        if ($ghsShopId == 7687 || $ghsShopId == 7831 || $ghsShopId == 7778 || $ghsShopId == 12003 || $ghsShopId == 38128) {
+                            util::fail('暂不支持送货上门,请选其它配送方式!');
                         }
-                    }
-
 
-                    //三明易批花
-                    if ($ghsShopId == 82200) {
-                        if ($respond->actPrice < 100 || $respond->bigNum < 15) {
-                            $hasMust = array_intersect($ids, [4283478]);
+                        //广州鑫源花卉,选择送货上门必须选必选商品
+                        if ($ghsShopId == 12439) {
+                            $hasMust = array_intersect($ids, [3446945, 3446970, 3446973, 3446979, 3446995, 3447010, 3447023, 3459983, 4333184, 4317745, 1585738]);
                             if (empty($hasMust)) {
-                                util::fail('没满100元且15扎,请返回选运费');
+                                util::fail('请返回选择 必选商品');
                             }
                         }
-                        // 按当天计时,把 sendTimeWant 要限制在两天的时间范围之内
-                        $future = date("Y-m-d", strtotime('+2 day'));
-                        if (strtotime($respond->sendTimeWant) > strtotime($future)) {
-                            util::fail('配送日期只能选最近二天');
-                        }
-                    }
 
-                    if ($ghsShopId == 77703) {
-                        //天天鲜花思明店,暂时关闭送货上门
-                        if ($respond->sendType == 0) {
-                            //util::fail('节日暂停送货上门,请选到店自取');
+                        //情意花卉,必选品
+                        if ($ghsShopId == 100883) {
+                            $hasMust = array_intersect($ids, [5017957,5036067,5036089,5036099,5017958,5036063,5017948,5035980,5036073,5036075,5036076,5036117,5036118,5017949,5035979,5035976,5035928,5035930,5036061,5035879]);
+                            if (empty($hasMust)) {
+                                util::fail('请返回选择 必选商品');
+                            }
                         }
-                    }
 
-                    if ($ghsShopId == 86726) {
-                        //藏花林
-                        if ($respond->transType != 4 && $respond->transType != 5) {
-                            util::fail('请选同城配送或到店自取');
+                        //三明易批花
+                        if ($ghsShopId == 82200) {
+                            if ($respond->actPrice < 100 || $respond->bigNum < 15) {
+                                $hasMust = array_intersect($ids, [4283478]);
+                                if (empty($hasMust)) {
+                                    util::fail('没满100元且15扎,请返回选运费');
+                                }
+                            }
+                            // 按当天计时,把 sendTimeWant 要限制在两天的时间范围之内
+                            $future = date("Y-m-d", strtotime('+2 day'));
+                            if (strtotime($respond->sendTimeWant) > strtotime($future)) {
+                                util::fail('配送日期只能选最近二天');
+                            }
                         }
-                    }
-
-                } else {
 
-                    //好运鲜花批发,选择送货上门必须选必选商品
-//                    if ($ghsShopId == 36523) {
-//                        if ($respond->transType != 4 && $respond->transType != 5) {
-//                            util::fail('请选同城配送或到店自取');
-//                        }
-//                    }
-
-//                    if ($ghsShopId == 36523) {
-//                        if ($respond->actPrice < 50 || $respond->bigNum < 10) {
-//                            $hasMust = array_intersect($ids, [85295]);
-//                            if (empty($hasMust)) {
-//                                util::fail('没满50元且满10扎,请运费必选商品');
-//                            }
-//                        }
-//                        // 按当天计时,把 sendTimeWant 要限制在两天的时间范围之内
-//                        $future = date("Y-m-d", strtotime('+2 day'));
-//                        if (strtotime($respond->sendTimeWant) > strtotime($future)) {
-//                            util::fail('配送日期只能选最近二天');
-//                        }
-//                    }
+                        if ($ghsShopId == 77703) {
+                            //天天鲜花思明店,暂时关闭送货上门
+                            if ($respond->sendType == 0) {
+                                //util::fail('节日暂停送货上门,请选到店自取');
+                            }
+                        }
 
-                }
+                        if ($ghsShopId == 86726) {
+                            //藏花林
+                            if ($respond->transType != 4 && $respond->transType != 5) {
+                                util::fail('请选同城配送或到店自取');
+                            }
+                        }
 
-                if (isset($ghsInfo['home'])) {
-                    if ($ghsInfo['home'] == 0) {
-                        util::fail('暂不支持送货上门,请选其它配送方式');
-                    }
-                    $homeAmount = $ghsInfo['homeAmount'] ? floatval($ghsInfo['homeAmount']) : 0;
-                    $homeNum = $ghsInfo['homeNum'] ? floatval($ghsInfo['homeNum']) : 0;
-                    if ($homeAmount > 0 && $homeAmount > $respond->actPrice) {
-                        util::fail("满{$homeAmount}元 可送货上门");
                     }
-                    if ($homeNum > 0 && $homeNum > $respond->bigNum) {
-                        util::fail("满{$homeNum}扎 可送货上门");
+
+                    if (isset($ghsInfo['home'])) {
+                        if ($ghsInfo['home'] == 0) {
+                            util::fail('暂不支持送货上门,请选其它配送方式');
+                        }
+                        $homeAmount = $ghsInfo['homeAmount'] ? floatval($ghsInfo['homeAmount']) : 0;
+                        $homeNum = $ghsInfo['homeNum'] ? floatval($ghsInfo['homeNum']) : 0;
+                        if ($homeAmount > 0 && $homeAmount > $respond->actPrice) {
+                            util::fail("满{$homeAmount}元 可送货上门");
+                        }
+                        if ($homeNum > 0 && $homeNum > $respond->bigNum) {
+                            util::fail("满{$homeNum}扎 可送货上门");
+                        }
                     }
-                }
 
-            }
+                }
 
-            if ($sendType == 2) {
-                //温州易批花,跑腿,不满100,要选10元的补运费商品
-                if ($ghsShopId == 91115) {
-                    if ($respond->actPrice < 100) {
-                        $transaction->rollBack();
-                        $hasMust = array_intersect($ids, [4449812, 4449811]);
-                        if (empty($hasMust)) {
-                            util::fail('不满100,必选商品 补运费10元');
+                if ($sendType == 2) {
+                    //温州易批花,跑腿,不满100,要选10元的补运费商品
+                    if ($ghsShopId == 91115) {
+                        if ($respond->actPrice < 100) {
+                            $transaction->rollBack();
+                            $hasMust = array_intersect($ids, [4449812, 4449811]);
+                            if (empty($hasMust)) {
+                                util::fail('不满100,必选商品 补运费10元');
+                            }
                         }
                     }
                 }
-            }
-            if ($sendType == 4) {
-                //温州易批花,快递,不满100,要选10元的补运费商品
-                if ($ghsShopId == 91115) {
-                    if ($respond->actPrice < 100) {
-                        $transaction->rollBack();
-                        $hasMust = array_intersect($ids, [4449812, 4449811]);
-                        if (empty($hasMust)) {
-                            util::fail('不满100,必选商品 补运费10元');
+                if ($sendType == 4) {
+                    //温州易批花,快递,不满100,要选10元的补运费商品
+                    if ($ghsShopId == 91115) {
+                        if ($respond->actPrice < 100) {
+                            $transaction->rollBack();
+                            $hasMust = array_intersect($ids, [4449812, 4449811]);
+                            if (empty($hasMust)) {
+                                util::fail('不满100,必选商品 补运费10元');
+                            }
                         }
                     }
                 }
-            }
-            if ($sendType == 3) {
-                //温州易批花,物流,不满200,要选10元的补运费商品
-                if ($ghsShopId == 91115) {
-                    if ($respond->actPrice < 200) {
-                        $transaction->rollBack();
-                        $hasMust = array_intersect($ids, [4449812, 4449811]);
-                        if (empty($hasMust)) {
-                            util::fail('不满200,必选商品 补运费10元');
+                if ($sendType == 3) {
+                    //温州易批花,物流,不满200,要选10元的补运费商品
+                    if ($ghsShopId == 91115) {
+                        if ($respond->actPrice < 200) {
+                            $transaction->rollBack();
+                            $hasMust = array_intersect($ids, [4449812, 4449811]);
+                            if (empty($hasMust)) {
+                                util::fail('不满200,必选商品 补运费10元');
+                            }
                         }
                     }
                 }
+
             }
 
             $transaction->commit();
@@ -929,11 +963,15 @@ class PurchaseController extends BaseController
                     Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
                 }
             } else {
-                if (isset($info->sendType) && $info->sendType == 4) {
-                    //标记当天已收一次包装费,岭南批发市场用的功能
-                    $current = date("Y_m_d");
-                    $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
+                //标记当配送方式已收一次包装费/运费,岭南批发市场用的功能,关键词 sh_method_area,只要有成功单就标记,不再要求金额必须>0
+                $current = date("Y_m_d");
+                if (isset($info->sendType) && in_array($info->sendType, [0, 4])) {
+                    $key = 'ghs_custom_today_has_get_pack_cost_' . $info->sendType . '_' . $current . '_' . $customId;
                     Yii::$app->redis->executeCommand('SETEX', [$key, 86400, '1']);
+
+                    // 兼容快递收运费的情况
+                    $sendKey = 'ghs_custom_today_has_get_send_cost_' . $info->sendType . '_' . $current . '_' . $customId;
+                    Yii::$app->redis->executeCommand('SETEX', [$sendKey, 86400, '1']);
                 }
             }
 
@@ -1172,7 +1210,7 @@ class PurchaseController extends BaseController
             $startTime = $get['startTime'] ?? '';
             $endTime = $get['endTime'] ?? '';
             $period = dateUtil::formatTime($searchTime, $startTime, $endTime);
-            $where['payTime'] = ['between', [$period['startTime'], $period['endTime']]];
+            $where['addTime'] = ['between', [$period['startTime'], $period['endTime']]];
         }
         $ghsId = $get['ghsId'] ?? 0;
         if (!empty($ghsId)) {

+ 79 - 0
app-hd/controllers/ShMethodController.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace hd\controllers;
+
+use bizGhs\order\classes\ShMethodClass;
+use bizHd\ghs\classes\GhsClass;
+use Yii;
+use common\components\util;
+
+class ShMethodController extends BaseController
+{
+
+    /**
+     * 获取供货商所有的5种配送方式配置
+     * 如果数据库里没有,则取默认配置进行初始化
+     */
+    public function actionGetAllMethod()
+    {
+        $ghsId = Yii::$app->request->get('ghsId', 0);
+        $ghs = GhsClass::getById($ghsId);
+        if (empty($ghs)) {
+            util::fail('没有供货商信息');
+        }
+        if ($ghs['ownMainId'] != $this->mainId) {
+            util::fail('不是你的供货商');
+        }
+        $shopId = $ghs['shopId'] ?? 0;
+        $mainId = $ghs['mainId'] ?? 0;
+
+        if (!in_array($shopId, [36523, 0])) {
+            util::success([]);
+        }
+
+        try {
+            $customId = $ghs['customId'] ?? 0;
+            $configs = ShMethodClass::getAllConfigs($shopId, $mainId);
+
+            if (isset($ghs['homeRule']) && $ghs['homeRule'] == 1) {
+                foreach ($configs as &$config) {
+                    if ($config['style'] == 0) {
+                        $config['status'] = $ghs['home'] ?? 0;
+                        $config['minAmount'] = $ghs['homeAmount'] ?? 0;
+                        $config['minNum'] = $ghs['homeNum'] ?? 0;
+                        $config['unMeet'] = $ghs['homeUnMeet'] ?? 0;
+                        $config['unMeetFee'] = $ghs['homeUnFee'] ?? 0;
+                    }
+                }
+            }
+
+            if ($customId > 0) {
+                foreach ($configs as &$config) {
+                    $style = (int)($config['style'] ?? 0);
+                    $unMeet = (int)($config['unMeet'] ?? 0);
+
+                    // 针对每个配送方式分别检查是否已支付运费或包装费
+                    $hasPaidSendCost = ShMethodClass::isSendCostPaidToday($customId, $style);
+                    $hasPaidPackCost = ShMethodClass::isPackPaidToday($customId, $style);
+
+                    // 如果是加收运费或加收包装费,并且今天已经收过对应的费用
+                    // 则将前端展示的条件清空(设为0),从而不再显示要收附加费的提示
+                    if ($unMeet === 0 && $hasPaidSendCost) {
+                        $config['minAmount'] = 0;
+                        $config['minNum'] = 0;
+                        $config['unMeetFee'] = 0;
+                    } elseif ($unMeet === 2 && $hasPaidPackCost) {
+                        $config['minAmount'] = 0;
+                        $config['minNum'] = 0;
+                        $config['unMeetFee'] = 0;
+                    }
+                }
+            }
+
+            util::success(['method' => $configs]);
+        } catch (\Exception $e) {
+            util::fail($e->getMessage());
+        }
+    }
+
+}

+ 3 - 3
app-mall/controllers/NoticeController.php

@@ -164,7 +164,7 @@ class NoticeController extends PublicController
 
             if ($capitalType == dict::getDict('capitalType', 'xhOrder', 'id')) {
                 //解决重复通知,重要
-                $cacheKey = 'mall_order_pay_' . $orderSn;
+                $cacheKey = 'pay_success_notice_' . $orderSn;
                 $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
                 if (empty($has)) {
                     Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 864000, 'has']);
@@ -272,7 +272,7 @@ class NoticeController extends PublicController
             echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
 
             //解决重复通知
-            $cacheKey = 'mall_order_pay_' . $orderSn;
+            $cacheKey = 'pay_success_notice_' . $orderSn;
             $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
             if (empty($has)) {
                 Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 864000, 'has']);
@@ -507,7 +507,7 @@ class NoticeController extends PublicController
 
                 if ($capitalType == dict::getDict('capitalType', 'xhOrder', 'id')) {
                     //避免重复
-                    $cacheKey = 'mall_order_pay_' . $orderSn;
+                    $cacheKey = 'pay_success_notice_' . $orderSn;
                     $has = Yii::$app->redis->executeCommand('GET', [$cacheKey]);
                     if (empty($has)) {
                         Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 864000, 'has']);

+ 2 - 3
app-mall/controllers/ShopController.php

@@ -51,10 +51,9 @@ class ShopController extends BaseController
                     $custom->save();
                 }
             }
+            StatVisitClass::addHdCustomVisit($shop->id, $user->id);
         }
 
-        StatVisitClass::addHdCustomVisit($shop->id, $user->id);
-
         util::success(['info' => $info, 'hd' => $hd, 'custom' => $custom]);
     }
 
@@ -83,4 +82,4 @@ class ShopController extends BaseController
         util::success(['ad' => $ad, 'shop' => $shop, 'newUserGift' => $newUserGift]);
     }
 
-}
+}

+ 2 - 2
app-pt/views/main/app.php

@@ -237,8 +237,8 @@
             const downloadUrls = {
                 'xiaohuabao': 'https://api.shop.hzghd.com/1312.apk', // 销花宝APP下载链接
                 'huazhanggui': 'https://api.shop.hzghd.com/246.apk', // 花掌柜APP下载链接
-                'huazhanggui_cashier': 'https://api.shop.hzghd.com/209.apk', // 花掌柜收银下载链接
-                'xiaohuabao_cashier': 'https://api.shop.hzghd.com/168.apk' // 销花宝收银下载链接
+                'huazhanggui_cashier': 'https://api.shop.hzghd.com/220.apk', // 花掌柜收银下载链接
+                'xiaohuabao_cashier': 'https://api.shop.hzghd.com/178.apk' // 销花宝收银下载链接
             };
             const url = downloadUrls[appType];
             if (url && url !== '#') {

+ 8 - 0
biz-ghs/order/classes/OrderClass.php

@@ -1960,6 +1960,14 @@ class OrderClass extends BaseClass
                     $showPrice = 0;
                 }
             }
+
+            //清流美朵花业线上下单不显示价格
+            if (isset($orderInfo->mainId) && $orderInfo->mainId == 99641) {
+                if (!empty($orderInfo->customShopAdminId)) {
+                    $showPrice = 0;
+                }
+            }
+
             //北京花篮子,线上下单,不显示价格
             if (isset($orderInfo->mainId) && $orderInfo->mainId == 10735) {
                 if (!empty($orderInfo->customShopAdminId)) {

+ 231 - 1
biz-ghs/order/classes/ShMethodClass.php

@@ -104,7 +104,7 @@ class ShMethodClass extends BaseClass
     public static function getAllConfigs($shopId, $mainId)
     {
         // 1. 一次性从数据库中查询当前商户的所有配送方式配置
-        $configsMap = self::getAllByCondition(['mainId' => $mainId], null, '*', 'style', true);
+        $configsMap = self::getAllByCondition(['mainId' => $mainId], 'sort asc', '*', 'style', true);
 
         // 2. 补齐缺失的配送方式,并做初始化入库
         for ($style = 0; $style <= 4; $style++) {
@@ -162,9 +162,239 @@ class ShMethodClass extends BaseClass
             $result[] = $config;
         }
 
+        // 按 sort 升序返回,供 hd/ghs GetAllConfig 等接口展示自定义排序
+        usort($result, function ($a, $b) {
+            $sortCompare = (int)($a['sort'] ?? 0) <=> (int)($b['sort'] ?? 0);
+            if ($sortCompare !== 0) {
+                return $sortCompare;
+            }
+            // sort 相同时按 style 稳定排序,避免顺序抖动
+            return (int)($a['style'] ?? 0) <=> (int)($b['style'] ?? 0);
+        });
+
         return $result;
     }
 
+    /**
+     * 判断配送方式配置是否未达最低消费(金额或扎数任一不满足即视为未达标)
+     * 与 hdApp affirm-sh-method-panel.checkShMethodBelowMinimum 规则一致
+     *
+     * @param array $config xhShMethod 配置
+     * @param float $actPrice 实付花材金额
+     * @param int|float $bigNum 下单扎数
+     * @return bool
+     */
+    /**
+     * 采购下单后校验 xhShMethod 配送限制
+     * 供 hd PurchaseController::actionCreateOrder 在 createPurchase 之后调用,与旧版 else 分支门店硬编码限制同级
+     *
+     * @param int $shopId 供货商门店 ID
+     * @param int $mainId 供货商商户 ID
+     * @param int $sendType 配送方式,与 xhShMethod.style 一致
+     * @param float $actPrice 下单后实付花材金额
+     * @param int|float $bigNum 下单扎数
+     * @param float $packCost 已写入采购单的包装费
+     * @param float $sendCost 已写入采购单的运费
+     * @param string $wlName 物流公司名称(style=3 时必填)
+     * @param int $customId 客户ID,用于判断当天是否已收过
+     * @param array|object $ghsInfo 客户与该供货商的关系信息(xhGhs)
+     * @return string 空字符串表示通过,否则为需提示用户的错误文案
+     */
+    public static function checkLimit($shopId, $mainId, $sendType, $actPrice, $bigNum, $packCost = 0, $sendCost = 0, $wlName = '', $customId = 0, $ghsInfo = [])
+    {
+        $style = (int)$sendType;
+        if ($style < 0 || $style > 4) {
+            return '配送方式无效';
+        }
+
+        $config = self::getConfig($shopId, $mainId, $style);
+
+        if (empty($config)) {
+            return '配送方式配置异常';
+        }
+
+        if ($style === 0 && !empty($ghsInfo) && isset($ghsInfo['homeRule']) && $ghsInfo['homeRule'] == 1) {
+            // 如果 homeRule == 1,特定字段取xhGhs的设置(优先级最高),其余(如name)保留原配置
+            $config['status'] = $ghsInfo['home'] ?? 0;
+            $config['minAmount'] = $ghsInfo['homeAmount'] ?? 0;
+            $config['minNum'] = $ghsInfo['homeNum'] ?? 0;
+            $config['unMeet'] = $ghsInfo['homeUnMeet'] ?? 0;
+            $config['unMeetFee'] = $ghsInfo['homeUnFee'] ?? 0;
+        }
+
+        $methodName = !empty($config['name']) ? $config['name'] : '该配送方式';
+
+        // 配送方式已禁用,对齐旧逻辑「暂不支持送货上门,请选其它配送方式」
+        if (isset($config['status']) && (int)$config['status'] === 0) {
+            return "暂不支持{$methodName},请选其它配送方式";
+        }
+
+        // 物流需填物流公司,与 hdApp validateBeforeSubmit 一致
+        if ($style === 3 && trim((string)$wlName) === '') {
+            return '请填选物流';
+        }
+
+        $minAmount = isset($config['minAmount']) ? (float)$config['minAmount'] : 0.00;
+        $minNum = isset($config['minNum']) ? (int)$config['minNum'] : 0;
+        
+        // 必须金额和数量同时满足(如果设置了的话),才算“达标”
+        $isBelowMinimum = false;
+        if ($minAmount > 0 && $actPrice < $minAmount) {
+            $isBelowMinimum = true;
+        }
+        if ($minNum > 0 && (float)$bigNum < $minNum) {
+            $isBelowMinimum = true;
+        }
+
+        if (!$isBelowMinimum) {
+            return '';
+        }
+
+        $unMeet = isset($config['unMeet']) ? (int)$config['unMeet'] : 0;
+        $unMeetFee = isset($config['unMeetFee']) ? (float)$config['unMeetFee'] : 0;
+
+        // 不满最低消费且不允许下单
+        if ($unMeet === 1) {
+            if ($minAmount > 0 && (float)$actPrice < $minAmount) {
+                return "满{$minAmount}元 可{$methodName}";
+            }
+            if ($minNum > 0 && (float)$bigNum < $minNum) {
+                return "满{$minNum}扎 可{$methodName}";
+            }
+            return '未达到最低消费,不能下单';
+        }
+
+        // 不满最低消费但允许加收费用时,校验包装费/运费是否已写入采购单,防止前端绕过
+        if (($unMeet === 0 || $unMeet === 2) && $unMeetFee > 0) {
+            // unMeet === 0 加收运费, unMeet === 2 加收包装费
+            $feeToCheck = $unMeet === 2 ? $packCost : $sendCost;
+            
+            // 如果今天已经收过对应的附加费用,则直接通过校验
+            if ($unMeet === 2 && self::isPackPaidToday($customId, $style)) {
+                return '';
+            }
+            if ($unMeet === 0 && self::isSendCostPaidToday($customId, $style)) {
+                return '';
+            }
+            
+            if (bccomp((string)$feeToCheck, (string)$unMeetFee, 2) < 0) {
+                $feeLabel = $unMeet === 2 ? '包装费' : '运费';
+                return "未达最低消费,需加收{$feeLabel}{$unMeetFee}元";
+            }
+        }
+
+        return '';
+    }
+
+    /**
+     * 判断当天是否已经收过附加费(包装费)
+     * 与其他逻辑共用同一个 Redis Key,保证一天只收一次
+     * @param int $customId 客户ID
+     * @param int $sendType 配送方式 (0: 送货, 4: 快递)
+     * @return bool
+     */
+    public static function isPackPaidToday($customId, $sendType = 0)
+    {
+        if (empty($customId)) {
+            return false;
+        }
+        $current = date("Y_m_d");
+        $key = 'ghs_custom_today_has_get_pack_cost_' . $sendType . '_' . $current . '_' . $customId;
+        $has = \Yii::$app->redis->executeCommand('GET', [$key]);
+        return (!empty($has) && $has == 1);
+    }
+
+    /**
+     * 判断当天是否已经收过运费
+     * @param int $customId 客户ID
+     * @param int $sendType 配送方式
+     * @return bool
+     */
+    public static function isSendCostPaidToday($customId, $sendType = 0)
+    {
+        if (empty($customId)) {
+            return false;
+        }
+        $current = date("Y_m_d");
+        $key = 'ghs_custom_today_has_get_send_cost_' . $sendType . '_' . $current . '_' . $customId;
+        $has = \Yii::$app->redis->executeCommand('GET', [$key]);
+        return (!empty($has) && $has == 1);
+    }
+
+    /**
+     * 计算采购单应写入的附加费用(不满最低消费时按 unMeet 加收运费或包装费)
+     * 供 createPurchase 前写入 sendCost 和 packCost,与 hdApp syncPackCostByMethod 一致
+     *
+     * @param int $shopId 供货商门店 ID
+     * @param int $mainId 供货商商户 ID
+     * @param int $sendType 配送方式
+     * @param float $itemTotalAmount 花材合计金额(下单前,与前端 commodityPrice 一致)
+     * @param int|float $bigNum 下单扎数
+     * @param int $customId 客户ID,用于判断当天是否已收过
+     * @param array|object $ghsInfo 客户与该供货商的关系信息(xhGhs)
+     * @return array ['sendCost' => 运费, 'packCost' => 包装费]
+     */
+    public static function calcFee($shopId, $mainId, $sendType, $itemTotalAmount, $bigNum, $customId = 0, $ghsInfo = [])
+    {
+        $costs = ['sendCost' => 0, 'packCost' => 0];
+        
+        $style = (int)$sendType;
+        if ($style < 0 || $style > 4) {
+            return $costs;
+        }
+
+        $config = self::getConfig($shopId, $mainId, $style);
+
+        if (empty($config)) {
+            return $costs;
+        }
+
+        if ($style === 0 && !empty($ghsInfo) && isset($ghsInfo['homeRule']) && $ghsInfo['homeRule'] == 1) {
+            // 如果 homeRule == 1,特定字段取xhGhs的设置(优先级最高),其余(如name)保留原配置
+            $config['status'] = $ghsInfo['home'] ?? 0;
+            $config['minAmount'] = $ghsInfo['homeAmount'] ?? 0;
+            $config['minNum'] = $ghsInfo['homeNum'] ?? 0;
+            $config['unMeet'] = $ghsInfo['homeUnMeet'] ?? 0;
+            $config['unMeetFee'] = $ghsInfo['homeUnFee'] ?? 0;
+        }
+
+        // 直接合并 isBelowMinimum 的逻辑,方便理解,不再套用额外的方法
+        $minAmount = isset($config['minAmount']) ? (float)$config['minAmount'] : 0.00;
+        $minNum = isset($config['minNum']) ? (int)$config['minNum'] : 0;
+        
+        // 必须金额和数量同时满足(如果设置了的话),才算“达标”
+        $isBelowMinimum = false;
+        if ($minAmount > 0 && $itemTotalAmount < $minAmount) {
+            $isBelowMinimum = true;
+        }
+        if ($minNum > 0 && (float)$bigNum < $minNum) {
+            $isBelowMinimum = true;
+        }
+
+        // 如果已经达标,不收取附加费用
+        if (!$isBelowMinimum) {
+            return $costs;
+        }
+
+        $unMeet = isset($config['unMeet']) ? (int)$config['unMeet'] : 0;
+        $unMeetFee = isset($config['unMeetFee']) ? (float)$config['unMeetFee'] : 0;
+        
+        if ($unMeetFee > 0) {
+            // unMeet: 0 加收运费(默认),2 加收包装费
+            if ($unMeet === 0) {
+                if (!self::isSendCostPaidToday($customId, $style)) {
+                    $costs['sendCost'] = $unMeetFee;
+                }
+            } elseif ($unMeet === 2) {
+                if (!self::isPackPaidToday($customId, $style)) {
+                    $costs['packCost'] = $unMeetFee;
+                }
+            }
+        }
+
+        return $costs;
+    }
+
     /**
      * 保存配送方式配置,包含说明项和满减规则
      * @param int $shopId 门店ID

+ 1 - 1
biz-ghs/product/classes/ProductClass.php

@@ -2225,7 +2225,7 @@ class ProductClass extends BaseClass
         $ratioType = $data['ratioType'] ?? 0;
         if ($ratioType == 0) {
             if (!isset($data['ratio']) || $data['ratio'] <= 0) {
-                util::fail('请填写单位比');
+                util::fail('请填写几支装');
             }
             $ratio = $data['ratio'];
         } else {

+ 6 - 3
biz-hd/purchase/services/PurchaseService.php

@@ -129,7 +129,7 @@ class PurchaseService extends BaseService
             'transType' => $transType,
             'sendDistance' => $sendDistance,
         ];
-        $result = OrderClass::addOrder($arr,$custom);
+        $result = OrderClass::addOrder($arr, $custom);
         $respond->saleId = $result['id'];
         $respond->save();
 
@@ -299,7 +299,7 @@ class PurchaseService extends BaseService
         $id = $purchase->id;
         $purchase = PurchaseClass::cancel($id);
         $saleId = $purchase->saleId;
-        
+
         //销售单失效
         OrderClass::cancel($saleId);
         $couponId = $purchase->hbId;
@@ -574,7 +574,10 @@ class PurchaseService extends BaseService
 
         $info->payStatus = 1;
         $payTime = date("Y-m-d H:i:s");
-        $info->payTime = $payTime;
+        if (empty($info->payTime) || $info->payTime == '0000-00-00 00:00:00') {
+            //如果外面没有设置支付时间,即账单时间,则赋值支付时间
+            $info->payTime = $payTime;
+        }
 
         if ($payWay == dict::getDict('payWay', 'debtPay')) {
             //欠款支付(批发开单若销售单已 payAfter,沿用其待结,支持开单余额抵挂账)

+ 3 - 5
biz-hd/shop/classes/ShopClass.php

@@ -46,11 +46,11 @@ class ShopClass extends BaseClass
     }
 
     //需要算上包装费
-    public static function needAddPackCost($ghsShop, $customId, $orderAmount = 0)
+    public static function needAddPackCost($ghsShop, $customId, $sendType = 0, $orderAmount = 0)
     {
+        $current = date("Y_m_d");
+        $key = 'ghs_custom_today_has_get_pack_cost_' . $sendType . '_' . $current . '_' . $customId;
         if (isset($ghsShop->pfLevel) && $ghsShop->pfLevel == 1) {
-            $current = date("Y_m_d");
-            $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
             $has = Yii::$app->redis->executeCommand('GET', [$key]);
             if (!empty($has) && $has == 1) {
                 return false;
@@ -63,8 +63,6 @@ class ShopClass extends BaseClass
             if ($lackExpend <= 0 || $packCost <= 0) {
                 return false;
             }
-            $current = date("Y_m_d");
-            $key = 'ghs_custom_today_has_get_pack_cost_' . $current . '_' . $customId;
             $has = Yii::$app->redis->executeCommand('GET', [$key]);
             if (!empty($has) && $has == 1) {
                 return false;

+ 4 - 4
common/components/book.php

@@ -104,7 +104,7 @@ class book
             ['style' => 'info', 'value' => '提现时间:第2天上午7点前,就会把昨天收入的钱打到你的银行卡,一般法人收款,也可以委托别人收款,签委托协议即可。',],
             ['style' => 'info', 'value' => '根据你自身门店情况,选择以下套餐。下面列出的套餐,已经过全国200多家鲜花批发店和13万家花店磨合使用,非常成熟好用,请放心购买使用,以下套餐已含第一年年费。',],
             ['style' => 'miniTitle', 'value' => '软件的研发成本巨大,不管是年费、费率和套餐,都已经底价,已无商谈的空间,请理解。付费后不支持退货。',],
-            ['style' => 'miniTitle', 'value' => '以下硬件请通过我们来购买,公司统一跟厂家采购,售后各方面比较有保障。',],
+            ['style' => 'miniTitle', 'value' => '小票机、收银机等硬件请通过我们这边购买,自行在外面购买,将无法连接使用,因为参数各方面不匹配。',],
             ['style' => 'info', 'value' => '小票机和标签机,使用的是飞鹅4G带切刀版本,比较好维护,里面带流量卡的,第二年开始,每年要充60块话费。请不要贪便宜使用wifi版,维护成本很高,很容易出问题。',],
             ['style' => 'info', 'value' => '提供上门培训服务,培训时间3天,需报销差旅住宿费用,公司地址在福建厦门。',],
             ['style' => 'info', 'value' => '首家年费1580元,第二家起每家年费800元',],
@@ -116,7 +116,7 @@ class book
             ['style' => 'blankLine', 'value' => '',],
             ['style' => 'smallTitle', 'value' => '门店版-单屏收银',],
             ['style' => 'info', 'value' => '整套软件功能(一年)',],
-            ['style' => 'info', 'value' => '色单屏收银机1台',],
+            ['style' => 'info', 'value' => '色单屏收银机1台',],
             ['style' => 'info', 'value' => '扫码枪1台',],
             ['style' => 'info', 'value' => '收款小闪1个',],
             ['style' => 'info', 'value' => '收钱箱1个',],
@@ -130,7 +130,7 @@ class book
             ['style' => 'blankLine', 'value' => '',],
             ['style' => 'smallTitle', 'value' => '门店版-双屏收银',],
             ['style' => 'info', 'value' => '整套软件功能(一年)',],
-            ['style' => 'info', 'value' => '色双屏收银机1台',],
+            ['style' => 'info', 'value' => '色双屏收银机1台',],
             ['style' => 'info', 'value' => '扫码枪1台',],
             ['style' => 'info', 'value' => '收款小闪1个',],
             ['style' => 'info', 'value' => '收钱箱1个',],
@@ -285,4 +285,4 @@ class book
         ],
     ];
 
-}
+}

+ 10 - 0
common/components/dict.php

@@ -688,4 +688,14 @@ class dict
         return $respond;
     }
 
+    public static function getNewMethodShop()
+    {
+        $newShop = !getenv('NEW_METHOD_SHOP') ? '' : getenv('NEW_METHOD_SHOP');
+        if (empty($newShop)) {
+            return [];
+        }
+        $newShop = trim($newShop);
+        return explode(',', $newShop);
+    }
+
 }

+ 1 - 1
common/config/main-local.php

@@ -17,4 +17,4 @@ if (getenv('YII_ENV') == 'production') {
         ],
     ];
 }
-return $config;
+return $config;