{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a3f78912-3944-4f54-82b1-0575f8cb35a4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Списано 1500 ₽ за заказ order-42\n",
            "Списано 1500 ₽ за заказ order-42\n",
            "\n",
            "Всего списаний: 2, на сумму 3000 ₽\n"
          ]
        }
      ],
      "source": [
        "import sqlite3\n",
        "\n",
        "conn = sqlite3.connect(':memory:')\n",
        "conn.execute('''\n",
        "    CREATE TABLE payments (\n",
        "        id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
        "        order_id TEXT,\n",
        "        amount INTEGER\n",
        "    )\n",
        "''')\n",
        "\n",
        "def charge(order_id, amount):\n",
        "    conn.execute(\n",
        "        'INSERT INTO payments (order_id, amount) VALUES (?, ?)',\n",
        "        (order_id, amount)\n",
        "    )\n",
        "    conn.commit()\n",
        "    print(f'Списано {amount} ₽ за заказ {order_id}')\n",
        "\n",
        "# Клиент не получил ответ вовремя и повторил тот же запрос\n",
        "charge('order-42', 1500)\n",
        "charge('order-42', 1500)\n",
        "\n",
        "total = conn.execute(\n",
        "    'SELECT COUNT(*), SUM(amount) FROM payments WHERE order_id = ?',\n",
        "    ('order-42',)\n",
        ").fetchone()\n",
        "print(f'\\nВсего списаний: {total[0]}, на сумму {total[1]} ₽')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "22cd8458-eab3-4fa7-834f-9e5fbef0fc63",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Списано 1500 ₽ за заказ order-42\n",
            "Операция retry-key-abc123 уже выполнена, повторное списание пропущено\n",
            "\n",
            "Всего списаний: 1, на сумму 1500 ₽\n"
          ]
        }
      ],
      "source": [
        "conn2 = sqlite3.connect(':memory:')\n",
        "conn2.execute('''\n",
        "    CREATE TABLE payments (\n",
        "        id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
        "        idempotency_key TEXT UNIQUE,\n",
        "        order_id TEXT,\n",
        "        amount INTEGER\n",
        "    )\n",
        "''')\n",
        "\n",
        "def charge_idempotent(idempotency_key, order_id, amount):\n",
        "    try:\n",
        "        conn2.execute(\n",
        "            'INSERT INTO payments (idempotency_key, order_id, amount) VALUES (?, ?, ?)',\n",
        "            (idempotency_key, order_id, amount)\n",
        "        )\n",
        "        conn2.commit()\n",
        "        print(f'Списано {amount} ₽ за заказ {order_id}')\n",
        "    except sqlite3.IntegrityError:\n",
        "        print(f'Операция {idempotency_key} уже выполнена, повторное списание пропущено')\n",
        "\n",
        "# Клиент повторяет запрос с тем же ключом идемпотентности\n",
        "charge_idempotent('retry-key-abc123', 'order-42', 1500)\n",
        "charge_idempotent('retry-key-abc123', 'order-42', 1500)\n",
        "\n",
        "total = conn2.execute(\n",
        "    'SELECT COUNT(*), SUM(amount) FROM payments WHERE order_id = ?',\n",
        "    ('order-42',)\n",
        ").fetchone()\n",
        "print(f'\\nВсего списаний: {total[0]}, на сумму {total[1]} ₽')"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
