如何使用 Flask 和 Node.js 处理 Bitrix24 交易

你好,哈布尔!

今天,我们将使用 FlaskNode.jsBitrix24 中构建一个自动处理交易的服务。该服务将:

  • 接受 ONCRMDEALUPDATE Webhook。

  • 验证请求的签名和结构。

  • 提取。deal_id

  • 接收交易数据。

  • 检查交易金额和其他条件。

  • 更新交易阶段。

  • 为经理创建任务。

  • 防止递归和错误。

但首先......Bitrix 如何生成 webhook?当触发 ONCRMDEALUPDATE 事件时,Bitrix 会发送一个有效负载,其中所有交易数据(包括 )都在 FIELDS → ID 结构→数据内。deal_iddata['ID']

为了避免这种情况,我们总是使用 ,如果缺少所需的键,它会安全地返回 None,而不是抛出异常。这样我们就可以处理任何数据,并避免在数据结构由于某种原因发生变化或不完整时逻辑崩溃。.get()

用于处理 Webhook 的 Flask 服务器

让我们建立依赖关系:

pip install flask requests redis

服务器本身的代码:

from flask import Flask, request, jsonify
import hmac, hashlib, logging, requests
import redis

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

WEBHOOK_KEY = 'https://your.bitrix24.ru/rest/1/abc123xyz456789/'
SECRET = b'your_super_secret_key'  # если используешь подпись
REDIS = redis.Redis(host='localhost', port=6379, db=0)

TTL_SECONDS = 15  # анти-петля TTL

@app.route('/webhook', methods=['POST'])
def webhook():
    raw = request.data
    data = request.json
    sig = request.headers.get('X-Bitrix-Signature', '')

    # Валидация подписи (если настроена)
    if sig:
        expected = hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
        if not hmac.compare_digest(sig, expected):
            logging.warning("Invalid signature")
            return jsonify({'error': 'bad signature'}), 403

    deal_id = data.get('data', {}).get('FIELDS', {}).get('ID')
    if not deal_id:
        logging.error("No deal ID in payload")
        return jsonify({'error': 'no deal ID'}), 400

    if REDIS.get(deal_id):
        logging.info(f"Skip repeated deal ID: {deal_id}")
        return jsonify({'status': 'skipped'}), 200

    REDIS.set(deal_id, 1, ex=TTL_SECONDS)

    try:
        process_deal(deal_id)
    except Exception as e:
        logging.exception(f"Error during deal processing: {e}")
        return jsonify({'error': 'internal'}), 500

    return jsonify({'status': 'ok'})

通过 HMAC 验证签名以确保安全,并使用 .Redis 在这里防止同一笔交易在短时间内被重复处理,以避免循环。所有交易处理逻辑都包装在 .deal_id.get()try/except

交易处理的业务逻辑

现在我们来处理交易本身:

def process_deal(deal_id):
    r = requests.post(WEBHOOK_KEY + 'crm.deal.get', json={'id': deal_id})
    if r.status_code != 200:
        logging.warning(f"Bitrix GET failed: {r.status_code}")
        return

    deal = r.json().get('result')
    if not deal:
        logging.warning(f"Deal {deal_id} not found in response")
        return

    amount = float(deal.get('OPPORTUNITY', 0))
    manager = deal.get('ASSIGNED_BY_ID')
    current_stage = deal.get('STAGE_ID')

    logging.info(f"Deal #{deal_id}: amount={amount}, stage={current_stage}")

    if amount > 100000:
        update_stage(deal_id)
        create_task(deal_id, manager, amount)

向 Bitrix24 API 发送请求以获取有关交易的数据。检查状态代码是否响应的正确性,如果未找到交易,请记录它。我们还将交易金额的值转换为 ,因为它可以为空或字符串。如果金额超过 100,000,则更新阶段并为经理创建一个任务。crm.deal.getfloat

更改阶段并创建任务

更改交易阶段的代码:

def update_stage(deal_id):
    res = requests.post(WEBHOOK_KEY + 'crm.deal.update', json={
        'id': deal_id,
        'fields': {
            'STAGE_ID': 'NEW_STAGE_CODE'
        }
    })
    if res.status_code != 200:
        logging.warning(f"Failed to update stage for deal {deal_id}")
    else:
        logging.info(f"Stage updated for deal {deal_id}")

要更改事务的阶段,我们使用 Bitrix24 API。如果请求失败,则会记录下来。

用于创建任务的代码:

def create_task(deal_id, manager_id, amount):
    res = requests.post(WEBHOOK_KEY + 'tasks.task.add', json={
        'fields': {
            'TITLE': f'Сделка на {amount}',
            'DESCRIPTION': f'Сделка #{deal_id} превысила 100 000. Проверь.',
            'RESPONSIBLE_ID': manager_id
        }
    })
    if res.status_code != 200:
        logging.error(f"Ошибка создания задачи по сделке {deal_id}")
    else:
        logging.info(f"Задача создана по сделке {deal_id}")

如果交易超过一定数量,则为经理创建一个任务。该请求包含任务的描述和负责经理的 ID。

Node.js 版本

让我们建立依赖关系:

npm install express body-parser axios redis

Node.js上的服务器代码:

const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const Redis = require('ioredis');

const app = express();
app.use(express.json());

const redis = new Redis();
const BITRIX_WEBHOOK = 'https://your.bitrix24.ru/rest/1/abc123xyz456789/';
const SECRET = 'your_super_secret_key';

function isValidSig(body, signature) {
    const expected = crypto.createHmac('sha256', SECRET).update(JSON.stringify(body)).digest('hex');
    return signature === expected;
}

app.post('/webhook', async (req, res) => {
    const sig = req.headers['x-bitrix-signature'] || '';
    const dealId = req.body?.data?.FIELDS?.ID;

    if (sig && !isValidSig(req.body, sig)) {
        return res.status(403).send('Invalid signature');
    }

    if (!dealId) return res.status(400).send('Missing deal ID');

    const isDuplicate = await redis.get(dealId);
    if (isDuplicate) return res.status(200).send('Skipped');

    await redis.set(dealId, 1, 'EX', 15);

    try {
        const dealRes = await axios.post(BITRIX_WEBHOOK + 'crm.deal.get', { id: dealId });
        const deal = dealRes.data.result;
        const amount = parseFloat(deal.OPPORTUNITY);
        const manager = deal.ASSIGNED_BY_ID;

        if (amount > 100000) {
            await axios.post(BITRIX_WEBHOOK + 'crm.deal.update', {
                id: dealId,
                fields: { STAGE_ID: 'NEW_STAGE_CODE' }
            });

            await axios.post(BITRIX_WEBHOOK + 'tasks.task.add', {
                fields: {
                    TITLE: `Сделка на ${amount}`,
                    RESPONSIBLE_ID: manager,
                    DESCRIPTION: `Проверь сделку #${dealId}`
                }
            });
        }

        res.json({ status: 'ok' });
    } catch (err) {
        console.error('Ошибка обработки:', err.message);
        res.status(500).send('Server error');
    }
});

app.listen(3000, () => console.log('Слушаем порт 3000'));

该代码执行与 Flask 中相同的逻辑,但使用 Express。我们检查请求的签名,使用 Redis 来防止重新处理交易,并使用 Bitrix24 API 获取有关交易的信息,并在金额超过 100,000 时进行更新。


您对 Bitrix24 中的 webhook 和自动化有什么体验?在评论中分享。

这篇文章是为 Bitrix24 Integrator 在线课程的未来学生准备的。好消息是,作为本课程的一部分,学生将获得 Otus 职业中心的支持。 了解更多信息

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇