crmeb多门店对接拉卡拉支付小程序聚合收银台集成全流程详解

一、商户注册与配置

  1. ​注册支付平台账号​​:在拉卡拉开放平台注册商户账号(私信联系注册)
  2. ​创建应用​​:获取小程序应用ID(AppID)
  3. ​配置支付参数​​:
    • 商户号(MID)
    • 终端号(TID)
    • API密钥
    • 支付回调地址

二、配置拉卡拉参数(后台)

app/admin/controller/system/config/PayConfig.php中添加:

// 文件路径:app/admin/controller/system/config/PayConfig.phppublic function index()
{//...已有代码...$list = [// 添加拉卡拉支付配置['menu_name' => '拉卡拉支付','config' => [// 商户编号['type'      => 'text','name'      => 'lakala_merchant_id','title'     => '商户号(MID)',],// 终端号['type'      => 'text','name'      => 'lakala_terminal_id','title'     => '终端号(TID)',],// API密钥['type'      => 'text','name'      => 'lakala_api_key','title'     => 'API密钥',],// 应用ID(小程序)['type'      => 'text','name'      => 'lakala_app_id','title'     => '小程序AppID',],// 是否启用['type'      => 'radio','name'      => 'lakala_status','title'     => '启用状态','value'     => 0,'options'   => [['label' => '关闭', 'value' => 0],['label' => '开启', 'value' => 1]]]]]];//...后续代码...
}

三、支付服务层(核心)

// 文件路径:app/services/pay/LakalaPayService.php<?php
namespace app\services\pay;use think\facade\Config;
use app\services\BaseServices;
use app\services\order\StoreOrderServices;class LakalaPayService extends BaseServices
{protected $apiUrl = 'https://api.lakala.com/payment/gateway'; // 正式环境// protected $apiUrl = 'https://test.api.lakala.com/payment/gateway'; // 测试环境// 小程序支付下单public function miniPay($order){$config = $this->getConfig();if (!$config['status']) throw new \Exception('拉卡拉支付未开启');$params = ['version'       => '1.0','merchant_id'   => $config['merchant_id'],'terminal_id'   => $config['terminal_id'],'biz_type'      => 'MINIPRO','trade_type'    => 'JSAPI','notify_url'    => sys_config('site_url') . '/api/pay/lakala/notify','out_trade_no'  => $order['order_id'],'total_fee'     => bcmul($order['pay_price'], 100), // 转为分'body'          => '订单支付','sub_appid'     => $config['app_id'],'sub_openid'    => $order['openid'], // 小程序用户openid'attach'        => 'store_id:' . $order['store_id'] // 多门店标识];// 生成签名$params['sign'] = $this->generateSign($params, $config['api_key']);// 请求拉卡拉接口$result = $this->curlPost($this->apiUrl, $params);if ($result['return_code'] != 'SUCCESS') {throw new \Exception('拉卡拉支付请求失败: ' . $result['return_msg']);}// 返回小程序支付参数return ['appId'     => $config['app_id'],'package'   => 'prepay_id=' . $result['prepay_id'],'timeStamp' => (string) time(),'nonceStr'  => get_nonce(16),'signType'  => 'MD5','paySign'   => $this->generateJsSign($result, $config['api_key'])];}// 生成支付签名private function generateSign($data, $key){ksort($data);$string = '';foreach ($data as $k => $v) {if ($v === '' || $k == 'sign') continue;$string .= $k . '=' . $v . '&';}$string .= 'key=' . $key;return strtoupper(md5($string));}// 生成JS支付签名private function generateJsSign($result, $key){$data = ['appId'     => $result['appid'],'timeStamp' => (string) time(),'nonceStr'  => get_nonce(16),'package'   => 'prepay_id=' . $result['prepay_id'],'signType'  => 'MD5'];ksort($data);$string = implode('&', array_map(function($k, $v) {return "$k=$v";}, array_keys($data), $data));$string .= '&key=' . $key;return strtoupper(md5($string));}// 处理支付回调public function handleNotify(){$xml = file_get_contents('php://input');$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);// 验证签名$sign = $data['sign'];unset($data['sign']);if ($sign != $this->generateSign($data, config('pay.lakala_api_key'))) {return false;}// 获取门店ID$attach = explode(':', $data['attach']);$storeId = isset($attach[1]) ? intval($attach[1]) : 0;/** @var StoreOrderServices $orderService */$orderService = app()->make(StoreOrderServices::class);return $orderService->successPay($data['out_trade_no'], ['pay_type'  => 'lakala','store_id'  => $storeId]);}// 获取配置private function getConfig(){return ['merchant_id' => sys_config('lakala_merchant_id'),'terminal_id' => sys_config('lakala_terminal_id'),'api_key'     => sys_config('lakala_api_key'),'app_id'      => sys_config('lakala_app_id'),'status'      => sys_config('lakala_status')];}// HTTP POST请求private function curlPost($url, $data){$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);$response = curl_exec($ch);curl_close($ch);return json_decode(json_encode(simplexml_load_string($response)), true);}
}

四、支付控制器

// 文件路径:app/api/controller/v1/pay/PayController.phppublic function lakalaPay()
{$orderId = $this->request->param('order_id');$openid = $this->request->param('openid'); // 小程序获取的openid// 验证订单$order = $this->validateOrder($orderId, $openid);try {/** @var LakalaPayService $lakala */$lakala = app()->make(LakalaPayService::class);$payment = $lakala->miniPay(['order_id'   => $orderId,'pay_price'  => $order['pay_price'],'openid'     => $openid,'store_id'   => $order['store_id']]);return $this->success(compact('payment'));} catch (\Throwable $e) {return $this->fail($e->getMessage());}
}

五、小程序端调用

// 小程序端支付调用
wx.request({url: '/api/pay/lakala',method: 'POST',data: {order_id: '订单ID',openid: '用户openid'},success: (res) => {const payment = res.data.payment;wx.requestPayment({appId: payment.appId,timeStamp: payment.timeStamp,nonceStr: payment.nonceStr,package: payment.package,signType: payment.signType,paySign: payment.paySign,success: () => {wx.showToast({ title: '支付成功' });},fail: (err) => {wx.showToast({ title: '支付失败', icon: 'error' });}});}
});

六、回调路由设置

// 文件路径:route/app.phpRoute::post('api/pay/lakala/notify', 'api/pay.Pay/lakalaNotify');

七、回调控制器

// 文件路径:app/api/controller/pay/Pay.phppublic function lakalaNotify()
{/** @var LakalaPayService $lakala */$lakala = app()->make(LakalaPayService::class);try {$result = $lakala->handleNotify();if ($result) {return response('<xml><return_code>SUCCESS</return_code></xml>', 200, [], 'xml');}} catch (\Throwable $e) {Log::error('拉卡拉回调异常:' . $e->getMessage());}return response('<xml><return_code>FAIL</return_code></xml>', 200, [], 'xml');
}

配置注意事项:

  1. ​拉卡拉参数​​:在后台系统中配置商户号、终端号、API密钥和小程序AppID
  2. ​商户证书​​:如需双向验证,需在CURL请求中添加证书配置
  3. ​多门店处理​​:
    • 支付请求中附加store_id参数
    • 回调中解析门店ID并更新对应门店订单
  4. ​跨域问题​​:确保API路由支持小程序跨域请求

签名验证流程:

  1. 所有参数按参数名ASCII码升序排序
  2. 使用URL键值对格式拼接参数
  3. 拼接API密钥(&key=XXX
  4. 对结果进行MD5签名(转大写)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88818.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88818.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#将树图节点展示到NetronLight图表中

之前写过NetronLight开源框架 C#使用开源框架NetronLight绘制流程图-CSDN博客 我们这里将TreeView树图的节点内容展示到NetronLight图表中&#xff0c;按照树的层次【深度Level】展示 新建窗体应用程序ShowTreeNodeToDiagram&#xff0c;将默认的Form1重命名为FormShowNode&…

精密模具大深径比微孔尺寸检测方案 —— 激光频率梳 3D 轮廓检测

引言精密模具中大深径比微孔&#xff08;深径比&#xff1e;20:1&#xff0c;孔径&#xff1c;1mm&#xff09;的尺寸精度直接影响注塑件、电子元件等产品的成型质量。此类微孔具有孔径小、深度大、表面质量要求高&#xff08;Ra≤0.1μm&#xff09;等特点&#xff0c;传统检测…

defer学习指南

一、源头&#xff1a;早期管理资源&#xff08;如数据库连接、锁、文件句柄、网络连接&#xff09;和状态清理异常麻烦。 必须在每个可能的返回点&#xff08;return、err、panic&#xff09;手动重复清理代码&#xff0c;极易遗漏且打断主要逻辑思路&#xff01;像Java语言虽然…

NLP_知识图谱_大模型——个人学习记录

1. 自然语言处理、知识图谱、对话系统三大技术研究与应用 https://github.com/lihanghang/NLP-Knowledge-Graph 深度学习-自然语言处理(NLP)-知识图谱&#xff1a;知识图谱构建流程【本体构建、知识抽取&#xff08;实体抽取、 关系抽取、属性抽取&#xff09;、知识表示、知…

linux:进程详解(1)

目录 ​编辑 1.进程基本概念与基本操作 1.1 概念 1.2 描述进程-PCB 1.2.1PCB的基本概念 1.2.2 task_ struct 1.2.3 查看进程 2.进程状态 2.1 Linux内核源码展示 2.2 进程状态查看 ​编辑 2.3 Z(zombie)-僵⼫进程 2.4 僵尸进程的危害 2.5 孤儿进程 3.进程优先级 …

碳中和目标下的全球产业链重构:深度解析与未来路径

引言&#xff1a;气候临界点与产业链的系统性风险2023年&#xff0c;全球平均气温较工业化前上升1.2℃&#xff0c;南极冰盖年消融量达1500亿吨&#xff0c;极端天气事件导致的经济损失占全球GDP的2.3%。这一系列数据背后&#xff0c;暴露出传统产业链的致命缺陷——其设计逻辑…

FPGA实现SDI转LVDS视频发送,基于GTX+OSERDES2原语架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目本博已有的 SDI 编解码方案FPGA实现LVDS视频收发方案 3、工程详细设计方案工程设计原理框图SDI 输入设备Gv8601a 均衡器GTX 解串SMPTE SD/HD/3G SDI IP核BT1120转RGB奇…

新手向:使用Python构建高效的日志处理系统

本文将详细讲解如何使用Python开发一个专业的日志分析工具&#xff0c;能够自动化处理、分析和可视化各类日志文件&#xff0c;大幅提升运维效率。环境准备开发本工具需要以下环境配置&#xff1a;Python环境&#xff1a;建议Python 3.8或更高版本必要库&#xff1a;pandas&…

大模型-量化技术

简介 模型量化是一种重要的模型压缩技术。其核心目标是在可控精度损失下&#xff0c;将大模型中浮点型权重&#xff08;通常为 float32 等高精度格式&#xff09;近似转换为低精度离散值表示&#xff08;通常为 int8&#xff09;。 具体而言&#xff0c;该技术通过将模型的权重…

【C语言网络编程】HTTP 客户端请求(域名解析过程)

在做 C 语言网络编程或模拟 HTTP 客户端时&#xff0c;第一步就离不开“把域名解析为 IP 地址”这一步。很多人可能直接复制粘贴一段 gethostbyname 的代码&#xff0c;但未必真正理解它的原理。 本篇博客将围绕一个经典函数&#xff1a; char *host_to_ip(const char *hostna…

Node.js特训专栏-实战进阶:16. RBAC权限模型设计

🔥 欢迎来到 Node.js 实战专栏!在这里,每一行代码都是解锁高性能应用的钥匙,让我们一起开启 Node.js 的奇妙开发之旅! Node.js 特训专栏主页 专栏内容规划详情 我将从RBAC权限模型的基础概念、核心组件讲起,详细阐述其设计原则、数据库模型设计,还会结合代码示例展示在…

mac上BRPC的CMakeLists.txt优化:解决Protobuf路径问题

问题背景与挑战 在构建高性能RPC框架BRPC时&#xff0c;​Protobuf依赖路径的配置往往是开发者面临的主要挑战之一。原始CMake配置在寻找Protobuf库时存在以下痛点&#xff1a; ​路径搜索不精确​&#xff1a;默认find_library无法定位自定义安装路径下的Protobuf​版本兼容…

Go 性能分析利器:pprof 工具实战指南

在 Go 语言开发中&#xff0c;性能问题往往是项目上线后最棘手的挑战之一。无论是 CPU 占用过高、内存泄漏&#xff0c;还是 goroutine 失控&#xff0c;都可能导致服务响应缓慢甚至崩溃。而pprof作为 Go 官方提供的性能分析工具&#xff0c;就像一把精准的手术刀&#xff0c;能…

fio测试SSD直接I/O(Direct IO)性能仅有100MB/s的问题解决

针对您使用fio测试SSD直接I/O&#xff08;Direct IO&#xff09;性能仅有100MB/s的问题&#xff0c;结合SSD特性和fio测试原理 fio测试SSD直接I/O&#xff08;Direct IO&#xff09;性能仅有100MB/s的问题 - LinuxGuideLinuxGuide 以下是可能的原因及优化方案&#xff1a; &a…

EVO-0:具有隐空间理解的视觉-语言-动作模型

25年6月来自上海交大、EvoMind Tech 和上海算法创新研究院&#xff08;IAAR-Shanghai&#xff09;的论文“EVO-0: Vision-Language-Action Model with Implicit Spatial Understanding”。 视觉-语言-动作 (VLA) 模型已成为一种有前途的框架&#xff0c;可使通用机器人能够在现…

文心大模型4.5开源测评:轻量化部署实践与多维度能力验证

前言&#xff1a;开源浪潮下的轻量化革命 2025年百度文心大模型4.5系列的开源&#xff0c;标志着国产大模型从“参数竞赛”转向“实用落地”的关键转折。当行业仍在追逐千亿参数模型时&#xff0c;文心4.5以0.3B轻量级模型撕开一条新赛道——单卡部署、低成本运维、中文场景高…

LeetCode 2401.最长优雅子数组

给你一个由 正 整数组成的数组 nums 。 如果 nums 的子数组中位于 不同 位置的每对元素按位 与&#xff08;AND&#xff09;运算的结果等于 0 &#xff0c;则称该子数组为 优雅 子数组。 返回 最长 的优雅子数组的长度。 子数组 是数组中的一个 连续 部分。 注意&#xff1a;长…

中华心法问答系统的解读(1)

中华心法问答系统一、研究背景1. 研究意义2. 研究目的3. 信息检索技术二、主要研究内容三、相关技术介绍1. Flask框架技术2. BERT模型&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;BERT解决的问题&#xff08;3&#xff09;BERT的核心结构a. 模型结构b. 预训练任…

Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要快速生成与检索优化(345)

Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要快速生成与检索优化&#xff08;345&#xff09;引言&#xff1a;正文&#xff1a;一、Java 构建的全场景视频处理系统&#xff08;含校园 / 工厂 / 矿区适配&#xff09;1.1 校园宿舍区夜间检索方案&#xff08;…

信号量机制,互斥的避免自旋锁的实现方法(操作系统)

这次的比喻场景要升级了&#xff0c;因为它既能解决互斥问题&#xff0c;也能解决同步问题。我们用一个更综合的场景&#xff1a;一个拥有多辆共享单车的站点。共享单车 (资源)&#xff1a;站点里有多辆共享单车&#xff0c;数量是有限的。你 (进程)&#xff1a;想借一辆车去办…