CRMEB标准版系统 的小程序商城对接 拉卡拉支付收银台 的完整代码示例,包含服务端和客户端的实现逻辑,并适配CRMEB的架构规范

一、服务端修改(PHP示例)

1. 新增拉卡拉支付驱动

文件路径:app/services/pay/LakalaPay

<?php
namespace app\services\pay;

use think\facade\Config;

class LakalaPayService
{
    private $merchantId; // 商户ID
    private $apiKey;     // API密钥
    private $apiUrl = 'https://openapi.lakala.com'; // 正式环境地址

    public function __construct()
    {
        $config = Config::get('payment.lakala');
        $this->merchantId = $config['merchant_id'];
        $this->apiKey = $config['api_key'];
    }

    /**
     * 创建收银台订单
     * @param array $order 订单数据(需包含order_id,price,title等)
     */
    public function createOrder($order)
    {
        $params = [
            'merchant_order_no' => $order['order_id'],
            'amount' => bcmul($order['price'], 100), // 转为分
            'subject' => mb_substr($order['title'], 0, 32), // 截断防超长
            'source' => 'WECHATMINI',
            'notify_url' => request()->domain() . '/api/lakala/notify',
            'extra' => json_encode(['user_id' => $order['uid']])
        ];

        $result = $this->httpPost('/v3/ccss/counter/order/special_create', $params);
        
        if ($result['code'] != 200) {
            throw new \Exception('拉卡拉下单失败:' . $result['msg']);
        }

        return $result['data']['counter_url']; // 返回收银台URL
    }

    private function httpPost($path, $data)
    {
        $url = $this->apiUrl . $path;
        $timestamp = time();
        $sign = $this->makeSign($data, $timestamp);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: ' . $this->merchantId,
            'Timestamp: ' . $timestamp,
            'Signature: ' . $sign
        ]);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);

        return json_decode($response, true);
    }

    private function makeSign($data, $timestamp)
    {
        ksort($data);
        $queryString = http_build_query($data);
        return md5($this->merchantId . $queryString . $timestamp . $this->apiKey);
    }
}
2. 配置支付方式

文件路径:config/payment.php 新增配置:

'lakala' => [
    'merchant_id' => env('LAKALA_MERCHANT_ID', ''),
    'api_key'     => env('LAKALA_API_KEY', '')
],
3. 添加支付回调处理

文件路径:app/api/controller/LakalaController.php

<?php
namespace app\api\controller;

use think\facade\Db;

class LakalaController
{
    // 支付结果回调
    public function notify()
    {
        $data = input('post.');
        $sign = $this->makeSign($data, $data['timestamp']);

        // 验签
        if ($sign != $data['sign']) {
            return json(['code' => 400, 'msg' => '签名错误']);
        }

        // 处理订单逻辑
        Db::name('store_order')
            ->where('order_id', $data['merchant_order_no'])
            ->update([
                'paid' => 1,
                'pay_time' => time()
            ]);

        return json(['code' => 200]);
    }

    private function makeSign($data, $timestamp)
    {
        // 与LakalaPayService中的签名方法一致
    }
}

二、小程序端修改(Uni-app示例)

1. 支付按钮触发逻辑

文件路径:uniapp/pages/order/pay.vue

import { lakalaPay } from '@/api/pay.js';

export default {
  methods: {
    async handleLakalaPay() {
      try {
        const orderId = this.orderInfo.order_id;
        const res = await lakalaPay({ order_id: orderId });
        
        // 解析返回的counterUrl
        const counterUrl = res.counter_url;
        let appId = 'wx889424d565967811'; // 默认appId
        
        // 根据域名判断小程序appId
        if (counterUrl.includes('q.lakala.com')) {
          appId = 'wxc3e4d1682da3053c';
        }

        // 跳转拉卡拉小程序
        uni.navigateToMiniProgram({
          appId,
          path: `/payment-cashier/pages/checkout/index?source=WECHATMINI&counterUrl=${encodeURIComponent(counterUrl)}`,
          success: () => {
            this.startPollResult(orderId); // 开始轮询支付结果
          }
        });
      } catch (e) {
        uni.showToast({ title: e.message, icon: 'none' });
      }
    },
    
    // 轮询支付结果
    startPollResult(orderId) {
      const timer = setInterval(async () => {
        const res = await checkPayStatus(orderId);
        if (res.paid) {
          clearInterval(timer);
          uni.redirectTo({ url: '/pages/order/result?id=' + orderId });
        }
      }, 3000);
    }
  }
}
2. 支付API封装

文件路径:uniapp/api/pay.js

import { request } from './request';

export const lakalaPay = (data) => {
  return request({
    url: '/api/order/lakala_pay',
    method: 'POST',
    data
  });
};

export const checkPayStatus = (orderId) => {
  return request({
    url: '/api/order/check_status',
    method: 'GET',
    data: { order_id: orderId }
  });
};

三、数据库修改

1. 新增支付方式

执行SQL:

INSERT INTO `eb_system_pay` (`name`, `icon`, `config`, `status`) 
VALUES ('拉卡拉支付', 'lakala.png', '{"merchant_id":"","api_key":""}', 1);

四、关键配置项

  1. 小程序跳转白名单

    • 在微信小程序后台配置navigateToMiniProgram白名单:

      • wx889424d565967811(聚合收银台)

      • wxc3e4d1682da3053c(收款宝)

  2. 域名配置

    • 确保服务器域名openapi.lakala.com加入CRMEB的请求白名单

  3. 安全设置

    • 拉卡拉商户平台配置IP白名单回调地址

五、支付流程时序

图表

代码

sequenceDiagram
  用户->>CRMEB: 提交订单
  CRMEB->>拉卡拉: 调用special_create接口
  拉卡拉-->>CRMEB: 返回counter_url
  CRMEB->>小程序: 返回支付参数
  小程序->>拉卡拉小程序: 跳转收银台
  用户->>拉卡拉小程序: 完成支付
  拉卡拉->>CRMEB: 异步回调通知
  CRMEB->>数据库: 更新订单状态
  小程序->>CRMEB: 轮询支付结果
  CRMEB-->>用户: 显示支付成功

常见问题处理

  1. 收银台无法跳转

    • 检查appId是否配置正确

    • 确认小程序基础库版本≥2.2.1

  2. 签名失败

    • 确保服务端和拉卡拉平台的API密钥一致

    • 检查时间戳同步(允许±5分钟误差)

  3. 跨域问题

    • 在CRMEB的middleware.php中添加拉卡拉域名到跨域白名单

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥仔全栈开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值