tb-order-sync 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ """Value parsing and normalization utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+
8
+ def parse_number(value: object) -> Optional[float]:
9
+ """Parse a value to float.
10
+
11
+ Handles: int, float, numeric strings (with whitespace).
12
+ Returns None for anything that cannot be safely parsed as a pure number.
13
+
14
+ Examples:
15
+ >>> parse_number("650")
16
+ 650.0
17
+ >>> parse_number(" 12.5 ")
18
+ 12.5
19
+ >>> parse_number(None)
20
+ >>> parse_number("没报价")
21
+ """
22
+ if value is None:
23
+ return None
24
+ if isinstance(value, (int, float)):
25
+ return float(value)
26
+ if isinstance(value, str):
27
+ stripped = value.strip()
28
+ if not stripped:
29
+ return None
30
+ try:
31
+ return float(stripped)
32
+ except ValueError:
33
+ return None
34
+ return None
35
+
36
+
37
+ def normalize_order_no(value: object) -> str:
38
+ """Normalize an order number string.
39
+
40
+ Rules (v1 – strict):
41
+ - trim leading/trailing whitespace
42
+ - preserve original characters
43
+ - return empty string for None / empty
44
+
45
+ Future hook: could add prefix normalization, dedup hyphens, etc.
46
+ """
47
+ if value is None:
48
+ return ""
49
+ s = str(value).strip()
50
+ return s
package/utils/retry.py ADDED
@@ -0,0 +1,26 @@
1
+ """Retry / backoff helpers built on tenacity."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from tenacity import (
6
+ retry,
7
+ retry_if_exception_type,
8
+ stop_after_attempt,
9
+ wait_exponential,
10
+ before_sleep_log,
11
+ )
12
+
13
+ from utils.logger import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ def default_retry(max_attempts: int = 3):
19
+ """Decorator: retry with exponential backoff on transient errors."""
20
+ return retry(
21
+ stop=stop_after_attempt(max_attempts),
22
+ wait=wait_exponential(multiplier=1, min=2, max=30),
23
+ retry=retry_if_exception_type((IOError, ConnectionError, TimeoutError)),
24
+ before_sleep=before_sleep_log(logger, log_level=20), # INFO
25
+ reraise=True,
26
+ )
@@ -0,0 +1,125 @@
1
+ @echo off
2
+ chcp 65001 >nul 2>&1
3
+ title 多表格同步服务
4
+ cd /d "%~dp0"
5
+
6
+ echo.
7
+ echo ╔══════════════════════════════════════╗
8
+ echo ║ 多表格同步与退款标记服务 ║
9
+ echo ╚══════════════════════════════════════╝
10
+ echo.
11
+
12
+ :: ── 优先级1:已有打包好的 exe ────────────────────────
13
+ if exist "sync_service.exe" (
14
+ set "CMD=sync_service.exe"
15
+ goto :menu
16
+ )
17
+
18
+ :: ── 优先级2:已有虚拟环境 ───────────────────────────
19
+ if exist ".venv\Scripts\python.exe" (
20
+ set "CMD=.venv\Scripts\python main.py"
21
+ goto :menu
22
+ )
23
+
24
+ :: ── 优先级3:系统有 Python ──────────────────────────
25
+ echo [*] 首次运行,正在初始化环境...
26
+ echo.
27
+
28
+ where python >nul 2>&1
29
+ if not errorlevel 1 (
30
+ echo [*] 检测到系统 Python,创建虚拟环境...
31
+ goto :venv_setup
32
+ )
33
+
34
+ :: ── 优先级4:使用嵌入式 Python(自动下载)───────────
35
+ if exist "python_embed\python.exe" (
36
+ echo [*] 使用本地嵌入式 Python...
37
+ goto :venv_from_embed
38
+ )
39
+
40
+ echo [*] 未检测到 Python,正在自动下载嵌入式 Python...
41
+ echo (约 15MB,仅需下载一次)
42
+ echo.
43
+
44
+ :: 创建下载目录
45
+ if not exist "python_embed" mkdir python_embed
46
+
47
+ :: 使用 PowerShell 下载 Python 3.12 嵌入式版本
48
+ :: Windows 内置 PowerShell,无需额外依赖
49
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
50
+ "$url = 'https://www.python.org/ftp/python/3.12.8/python-3.12.8-embed-amd64.zip'; " ^
51
+ "$zip = 'python_embed\python_embed.zip'; " ^
52
+ "Write-Host ' 下载中...' ; " ^
53
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; " ^
54
+ "Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing; " ^
55
+ "Write-Host ' 解压中...' ; " ^
56
+ "Expand-Archive -Path $zip -DestinationPath 'python_embed' -Force; " ^
57
+ "Remove-Item $zip -Force; " ^
58
+ "Write-Host ' 完成!' "
59
+
60
+ if not exist "python_embed\python.exe" (
61
+ echo.
62
+ echo [!] Python 下载失败,请检查网络连接
63
+ echo 或手动下载 Python 3.12+ 安装: https://www.python.org/downloads/
64
+ echo.
65
+ pause
66
+ exit /b 1
67
+ )
68
+
69
+ :: 启用嵌入式 Python 的 pip 支持
70
+ :: 需要修改 python312._pth 文件,取消注释 import site
71
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
72
+ "$pth = Get-ChildItem 'python_embed\python*._pth' | Select-Object -First 1; " ^
73
+ "if ($pth) { " ^
74
+ " $content = Get-Content $pth.FullName; " ^
75
+ " $content = $content -replace '^#import site', 'import site'; " ^
76
+ " Set-Content $pth.FullName $content; " ^
77
+ "} "
78
+
79
+ :: 安装 pip
80
+ echo.
81
+ echo [*] 安装 pip...
82
+ powershell -NoProfile -ExecutionPolicy Bypass -Command ^
83
+ "Invoke-WebRequest -Uri 'https://bootstrap.pypa.io/get-pip.py' -OutFile 'python_embed\get-pip.py' -UseBasicParsing"
84
+ python_embed\python.exe python_embed\get-pip.py --no-warn-script-location -q 2>nul
85
+ del python_embed\get-pip.py 2>nul
86
+
87
+ :venv_from_embed
88
+ echo [*] 使用嵌入式 Python 安装依赖...
89
+ echo.
90
+ python_embed\python.exe -m pip install -q -r requirements.txt --target=".deps" 2>nul
91
+ set "PYTHONPATH=%~dp0.deps;%~dp0"
92
+ set "CMD=python_embed\python.exe main.py"
93
+ goto :menu
94
+
95
+ :venv_setup
96
+ echo [1/3] 创建虚拟环境...
97
+ python -m venv .venv
98
+ if errorlevel 1 (
99
+ echo [!] 虚拟环境创建失败
100
+ pause
101
+ exit /b 1
102
+ )
103
+
104
+ echo [2/3] 安装依赖...
105
+ .venv\Scripts\pip install -q -r requirements.txt
106
+ if errorlevel 1 (
107
+ echo [!] 依赖安装失败
108
+ pause
109
+ exit /b 1
110
+ )
111
+
112
+ echo [3/3] 环境初始化完成!
113
+ echo.
114
+ set "CMD=.venv\Scripts\python main.py"
115
+
116
+ :: ── 启动 Rich 控制台 / 执行指定命令 ────────────────
117
+ if "%~1"=="" (
118
+ %CMD%
119
+ echo.
120
+ pause
121
+ exit /b 0
122
+ )
123
+
124
+ %CMD% %*
125
+ exit /b %errorlevel%
@@ -0,0 +1,125 @@
1
+ #!/bin/bash
2
+ # macOS 一键启动脚本 — 双击即可运行
3
+ # .command 文件在 macOS 上双击会自动在 Terminal 中打开
4
+
5
+ cd "$(dirname "$0")"
6
+
7
+ echo ""
8
+ echo " ╔══════════════════════════════════════╗"
9
+ echo " ║ 多表格同步与退款标记服务 ║"
10
+ echo " ╚══════════════════════════════════════╝"
11
+ echo ""
12
+
13
+ # ── 优先级1:已有打包好的可执行文件 ──────────────────
14
+ if [ -x "./sync_service" ]; then
15
+ CMD="./sync_service"
16
+ elif [ -x "./dist/sync_service/sync_service" ]; then
17
+ CMD="./dist/sync_service/sync_service"
18
+
19
+ # ── 优先级2:已有虚拟环境 ────────────────────────────
20
+ elif [ -f ".venv/bin/python" ]; then
21
+ CMD=".venv/bin/python main.py"
22
+
23
+ # ── 优先级3:需要初始化 ─────────────────────────────
24
+ else
25
+ echo " [*] 首次运行,正在初始化环境..."
26
+ echo ""
27
+
28
+ # 查找可用的 Python 3.11+
29
+ PYTHON=""
30
+ for p in python3.14 python3.13 python3.12 python3.11 python3 python; do
31
+ if command -v "$p" &>/dev/null; then
32
+ ver=$("$p" -c "import sys; print(sys.version_info[:2] >= (3,11))" 2>/dev/null)
33
+ if [ "$ver" = "True" ]; then
34
+ PYTHON="$p"
35
+ break
36
+ fi
37
+ fi
38
+ done
39
+
40
+ # 没有 Python:尝试自动安装
41
+ if [ -z "$PYTHON" ]; then
42
+ echo " [!] 未检测到 Python 3.11+"
43
+ echo ""
44
+
45
+ # macOS: 尝试用 Homebrew 安装
46
+ if [ "$(uname)" = "Darwin" ]; then
47
+ if command -v brew &>/dev/null; then
48
+ echo " [*] 检测到 Homebrew,正在自动安装 Python 3.12..."
49
+ echo ""
50
+ brew install python@3.12
51
+ PYTHON="$(brew --prefix python@3.12)/bin/python3.12"
52
+ else
53
+ echo " [*] 正在安装 Homebrew(macOS 包管理器)..."
54
+ echo ""
55
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
56
+
57
+ # Apple Silicon vs Intel
58
+ if [ -f "/opt/homebrew/bin/brew" ]; then
59
+ eval "$(/opt/homebrew/bin/brew shellenv)"
60
+ elif [ -f "/usr/local/bin/brew" ]; then
61
+ eval "$(/usr/local/bin/brew shellenv)"
62
+ fi
63
+
64
+ if command -v brew &>/dev/null; then
65
+ echo ""
66
+ echo " [*] Homebrew 安装完成,正在安装 Python..."
67
+ brew install python@3.12
68
+ PYTHON="$(brew --prefix python@3.12)/bin/python3.12"
69
+ fi
70
+ fi
71
+
72
+ # Linux: 尝试用系统包管理器
73
+ elif [ -f /etc/os-release ]; then
74
+ if command -v apt-get &>/dev/null; then
75
+ echo " [*] 正在通过 apt 安装 Python 3.12..."
76
+ sudo apt-get update -qq && sudo apt-get install -y -qq python3.12 python3.12-venv python3-pip
77
+ PYTHON="python3.12"
78
+ elif command -v dnf &>/dev/null; then
79
+ echo " [*] 正在通过 dnf 安装 Python 3.12..."
80
+ sudo dnf install -y python3.12
81
+ PYTHON="python3.12"
82
+ fi
83
+ fi
84
+
85
+ # 最终检查
86
+ if [ -z "$PYTHON" ] || ! command -v "$PYTHON" &>/dev/null; then
87
+ echo ""
88
+ echo " [!] Python 自动安装失败,请手动安装:"
89
+ echo " macOS: brew install python@3.12"
90
+ echo " Ubuntu: sudo apt install python3.12 python3.12-venv"
91
+ echo " 或访问: https://www.python.org/downloads/"
92
+ echo ""
93
+ read -p " 按回车退出..." _
94
+ exit 1
95
+ fi
96
+ fi
97
+
98
+ echo " [1/3] 创建虚拟环境 (使用 $PYTHON)..."
99
+ "$PYTHON" -m venv .venv || {
100
+ echo " [!] 创建失败"
101
+ read -p " 按回车退出..." _
102
+ exit 1
103
+ }
104
+
105
+ echo " [2/3] 安装依赖..."
106
+ .venv/bin/pip install -q -r requirements.txt || {
107
+ echo " [!] 安装失败"
108
+ read -p " 按回车退出..." _
109
+ exit 1
110
+ }
111
+
112
+ echo " [3/3] 环境初始化完成!"
113
+ echo ""
114
+
115
+ CMD=".venv/bin/python main.py"
116
+ fi
117
+
118
+ # ── 启动 Rich 控制台 / 执行指定命令 ──────────────────
119
+ if [ "$#" -gt 0 ]; then
120
+ $CMD "$@"
121
+ else
122
+ $CMD
123
+ echo ""
124
+ read -p " 按回车关闭窗口..." _
125
+ fi