feat: migrate ERP configuration from .env to per-user database storage
- Moved ERP credentials (URL, username, password) from environment variables to dbo_BIPUsers table - Each user now has their own ERP configuration stored in the database - Added UserErpConfigService for managing per-user ERP settings - Updated cleaner and extractor handlers to fetch ERP config from database instead of .env - Removed ERP fields from ConfigManager UI editable fields - Added new IPC handlers and preload APIs for user ERP config management - Includes migration script to transfer existing .env ERP settings to database - Added migration guide documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
171
docs/MIGRATION_GUIDE.md
Normal file
171
docs/MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# BIPUsers 表 ERP 参数迁移指南
|
||||
|
||||
## 概述
|
||||
|
||||
本次迁移将 ERP 配置参数(`ERP_URL`, `ERP_USERNAME`, `ERP_PASSWORD`)从 `.env` 文件迁移到 `dbo_BIPUsers` 数据库表中,实现每个用户独立的 ERP 配置。
|
||||
|
||||
## 迁移步骤
|
||||
|
||||
### 步骤 1:连接到 MySQL 数据库
|
||||
|
||||
使用你喜欢的 MySQL 客户端工具连接:
|
||||
|
||||
**方式 A: MySQL 命令行**
|
||||
|
||||
```bash
|
||||
mysql -h 192.168.31.83 -P 3306 -u remote_user -p'3.1415926Beeke' BLD_DB
|
||||
```
|
||||
|
||||
**方式 B: MySQL Workbench / Navicat / DBeaver**
|
||||
|
||||
- Host: `192.168.31.83`
|
||||
- Port: `3306`
|
||||
- Username: `remote_user`
|
||||
- Password: `3.1415926Beeke`
|
||||
- Database: `BLD_DB`
|
||||
|
||||
### 步骤 2:执行迁移 SQL
|
||||
|
||||
运行以下 SQL 脚本添加新字段:
|
||||
|
||||
```sql
|
||||
-- ============================================
|
||||
-- BIPUsers 表迁移:添加 ERP 参数字段
|
||||
-- ============================================
|
||||
|
||||
USE BLD_DB;
|
||||
|
||||
-- 1. 添加 ERP_URL 字段
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN IF NOT EXISTS ERP_URL VARCHAR(500) NULL COMMENT 'ERP 系统 URL';
|
||||
|
||||
-- 2. 添加 ERP_Username 字段
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN IF NOT EXISTS ERP_Username VARCHAR(255) NULL COMMENT 'ERP 用户名';
|
||||
|
||||
-- 3. 添加 ERP_Password 字段
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN IF NOT EXISTS ERP_Password VARCHAR(255) NULL COMMENT 'ERP 密码';
|
||||
|
||||
-- 4. 验证字段已添加
|
||||
DESCRIBE dbo_BIPUsers;
|
||||
```
|
||||
|
||||
**注意:** 如果你的 MySQL 版本不支持 `ADD COLUMN IF NOT EXISTS`,请使用:
|
||||
|
||||
```sql
|
||||
USE BLD_DB;
|
||||
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN ERP_URL VARCHAR(500) NULL COMMENT 'ERP 系统 URL';
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN ERP_Username VARCHAR(255) NULL COMMENT 'ERP 用户名';
|
||||
ALTER TABLE dbo_BIPUsers ADD COLUMN ERP_Password VARCHAR(255) NULL COMMENT 'ERP 密码';
|
||||
```
|
||||
|
||||
### 步骤 3:初始化 ERP 配置
|
||||
|
||||
将所有现有用户的 ERP 配置设置为当前 `.env` 中的值:
|
||||
|
||||
```sql
|
||||
-- 更新所有用户的 ERP 配置
|
||||
UPDATE dbo_BIPUsers
|
||||
SET
|
||||
ERP_URL = 'https://68.11.34.30:8082/',
|
||||
ERP_Username = '在这里填写你的 ERP 用户名',
|
||||
ERP_Password = '在这里填写你的 ERP 密码'
|
||||
WHERE ERP_URL IS NULL OR ERP_URL = '';
|
||||
```
|
||||
|
||||
**请将上面的占位符替换为实际的 ERP 凭证!**
|
||||
|
||||
### 步骤 4:验证迁移结果
|
||||
|
||||
```sql
|
||||
-- 检查所有用户的 ERP 配置
|
||||
SELECT
|
||||
UserName,
|
||||
UserType,
|
||||
ERP_URL,
|
||||
ERP_Username,
|
||||
CreateTime
|
||||
FROM dbo_BIPUsers
|
||||
ORDER BY UserName;
|
||||
```
|
||||
|
||||
## 迁移后配置
|
||||
|
||||
### 更新 .env 文件(可选)
|
||||
|
||||
迁移完成后,`.env` 文件中的 ERP 配置将不再使用,但为了向后兼容可以保留:
|
||||
|
||||
```bash
|
||||
# ERP 配置(已废弃,仅用于向后兼容)
|
||||
# ERP_URL=https://68.11.34.30:8082/
|
||||
# ERP_USERNAME=your_username
|
||||
# ERP_PASSWORD=your_password
|
||||
```
|
||||
|
||||
### 在应用中配置用户 ERP 参数
|
||||
|
||||
迁移完成后,每个用户可以通过应用界面配置自己的 ERP 参数:
|
||||
|
||||
1. 登录应用
|
||||
2. 进入设置页面
|
||||
3. 配置个人 ERP 连接信息
|
||||
4. 测试连接
|
||||
5. 保存
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 问题 1:字段已存在错误
|
||||
|
||||
```
|
||||
Error: Duplicate column name 'ERP_URL'
|
||||
```
|
||||
|
||||
**解决方案:** 字段已经存在,跳过添加步骤,直接执行步骤 3 初始化数据。
|
||||
|
||||
### 问题 2:连接被拒绝
|
||||
|
||||
```
|
||||
Error: Access denied for user 'remote_user'@'%'
|
||||
```
|
||||
|
||||
**解决方案:** 检查数据库用户权限,确保 `remote_user` 有 `ALTER` 和 `UPDATE` 权限。
|
||||
|
||||
### 问题 3:连接超时
|
||||
|
||||
```
|
||||
Error: connect ETIMEDOUT
|
||||
```
|
||||
|
||||
**解决方案:**
|
||||
|
||||
- 检查网络连接
|
||||
- 确认 MySQL 服务器正在运行
|
||||
- 检查防火墙设置
|
||||
|
||||
## 回滚方案
|
||||
|
||||
如果需要回滚,可以删除新增的字段:
|
||||
|
||||
```sql
|
||||
-- ⚠️ 警告:这将永久删除 ERP 配置数据
|
||||
ALTER TABLE dbo_BIPUsers DROP COLUMN ERP_URL;
|
||||
ALTER TABLE dbo_BIPUsers DROP COLUMN ERP_Username;
|
||||
ALTER TABLE dbo_BIPUsers DROP COLUMN ERP_Password;
|
||||
```
|
||||
|
||||
## 完成确认
|
||||
|
||||
迁移完成后,请确认以下事项:
|
||||
|
||||
- [ ] 三个新字段已成功添加到 `dbo_BIPUsers` 表
|
||||
- [ ] 所有现有用户的 ERP 配置已初始化
|
||||
- [ ] 应用程序可以正常启动
|
||||
- [ ] 数据提取和物料清理功能正常工作
|
||||
|
||||
---
|
||||
|
||||
**迁移脚本文件:**
|
||||
|
||||
- `src/main/services/user/migration/add-erp-params-to-bipusers-mysql.sql` - 完整 SQL 脚本
|
||||
- `src/main/services/user/migration/run-migration.ts` - TypeScript 自动迁移脚本(需要网络访问)
|
||||
|
||||
**创建时间:** 2026-03-05
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
ExportResultItem,
|
||||
ExportResultResponse
|
||||
} from '../types/cleaner.types'
|
||||
import { UserErpConfigService } from '../services/user/user-erp-config-service'
|
||||
|
||||
const log = createLogger('CleanerHandler')
|
||||
|
||||
@@ -75,6 +76,27 @@ async function getDatabaseService(): Promise<MySqlService | SqlServerService> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for current user
|
||||
*/
|
||||
async function getErpConfig(): Promise<{
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
}> {
|
||||
const erpConfigService = UserErpConfigService.getInstance()
|
||||
const config = await erpConfigService.getCurrentUserErpConfig()
|
||||
|
||||
if (!config || !config.url || !config.username || !config.password) {
|
||||
throw new ValidationError(
|
||||
'ERP 配置不完整。请在设置中配置 ERP URL、用户名和密码',
|
||||
'VAL_MISSING_REQUIRED'
|
||||
)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
export function registerCleanerHandlers(): void {
|
||||
ipcMain.handle(
|
||||
'cleaner:run',
|
||||
@@ -85,24 +107,18 @@ export function registerCleanerHandlers(): void {
|
||||
return withErrorHandling(async () => {
|
||||
let authService: ErpAuthService | null = null
|
||||
let dbService: MySqlService | SqlServerService | null = null
|
||||
let erpConfigService: UserErpConfigService | null = null
|
||||
|
||||
try {
|
||||
const erpUrl = process.env.ERP_URL || ''
|
||||
const erpUsername = process.env.ERP_USERNAME || ''
|
||||
const erpPassword = process.env.ERP_PASSWORD || ''
|
||||
// Get ERP configuration from database for current user
|
||||
log.info('Fetching ERP configuration from database...')
|
||||
const erpConfig = await getErpConfig()
|
||||
|
||||
log.info('Config check', {
|
||||
url: erpUrl ? 'configured' : 'EMPTY',
|
||||
username: erpUsername ? 'configured' : 'EMPTY'
|
||||
log.info('ERP config retrieved', {
|
||||
url: erpConfig.url ? 'configured' : 'EMPTY',
|
||||
username: erpConfig.username ? 'configured' : 'EMPTY'
|
||||
})
|
||||
|
||||
if (!erpUrl || !erpUsername || !erpPassword) {
|
||||
throw new ValidationError(
|
||||
'ERP 配置不完整。请检查 .env 文件中的 ERP_URL, ERP_USERNAME, ERP_PASSWORD',
|
||||
'VAL_MISSING_REQUIRED'
|
||||
)
|
||||
}
|
||||
|
||||
const dbType = process.env.DB_TYPE?.toLowerCase()
|
||||
log.info(
|
||||
`Connecting to ${dbType === 'sqlserver' || dbType === 'mssql' ? 'SQL Server' : 'MySQL'} for order resolution...`
|
||||
@@ -138,9 +154,9 @@ export function registerCleanerHandlers(): void {
|
||||
log.info('Resolved order numbers', { count: validOrderNumbers.length })
|
||||
|
||||
authService = new ErpAuthService({
|
||||
url: erpUrl,
|
||||
username: erpUsername,
|
||||
password: erpPassword,
|
||||
url: erpConfig.url,
|
||||
username: erpConfig.username,
|
||||
password: erpConfig.password,
|
||||
headless: input.headless ?? true
|
||||
})
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { createLogger } from '../services/logger'
|
||||
import { withErrorHandling, type IpcResult } from './index'
|
||||
import { ErpConnectionError, ValidationError, DatabaseQueryError } from '../types/errors'
|
||||
import type { ExtractorInput, ExtractorResult, ExtractionProgress } from '../types/extractor.types'
|
||||
import { UserErpConfigService } from '../services/user/user-erp-config-service'
|
||||
|
||||
const log = createLogger('ExtractorHandler')
|
||||
|
||||
@@ -36,6 +37,27 @@ function sendLog(windowId: number, level: string, message: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for current user
|
||||
*/
|
||||
async function getErpConfig(): Promise<{
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
}> {
|
||||
const erpConfigService = UserErpConfigService.getInstance()
|
||||
const config = await erpConfigService.getCurrentUserErpConfig()
|
||||
|
||||
if (!config || !config.url || !config.username || !config.password) {
|
||||
throw new ValidationError(
|
||||
'ERP 配置不完整。请在设置中配置 ERP URL、用户名和密码',
|
||||
'VAL_MISSING_REQUIRED'
|
||||
)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* Register IPC handlers for extractor service
|
||||
*/
|
||||
@@ -48,25 +70,18 @@ export function registerExtractorHandlers(): void {
|
||||
return withErrorHandling(async () => {
|
||||
let authService: ErpAuthService | null = null
|
||||
let dbService: IDatabaseService | null = null
|
||||
let erpConfigService: UserErpConfigService | null = null
|
||||
|
||||
try {
|
||||
// Check environment variables
|
||||
const erpUrl = process.env.ERP_URL || ''
|
||||
const erpUsername = process.env.ERP_USERNAME || ''
|
||||
const erpPassword = process.env.ERP_PASSWORD || ''
|
||||
// Get ERP configuration from database for current user
|
||||
log.info('Fetching ERP configuration from database...')
|
||||
const erpConfig = await getErpConfig()
|
||||
|
||||
log.info('Config check', {
|
||||
url: erpUrl ? 'configured' : 'EMPTY',
|
||||
username: erpUsername ? 'configured' : 'EMPTY'
|
||||
log.info('ERP config retrieved', {
|
||||
url: erpConfig.url ? 'configured' : 'EMPTY',
|
||||
username: erpConfig.username ? 'configured' : 'EMPTY'
|
||||
})
|
||||
|
||||
if (!erpUrl || !erpUsername || !erpPassword) {
|
||||
throw new ValidationError(
|
||||
'ERP 配置不完整。请检查 .env 文件中的 ERP_URL, ERP_USERNAME, ERP_PASSWORD',
|
||||
'VAL_MISSING_REQUIRED'
|
||||
)
|
||||
}
|
||||
|
||||
// Create database service using factory
|
||||
log.info('Connecting to database for order resolution...')
|
||||
sendProgress(windowId, '连接数据库...', 3.33, {
|
||||
@@ -115,9 +130,9 @@ export function registerExtractorHandlers(): void {
|
||||
|
||||
// Create auth service and login
|
||||
authService = new ErpAuthService({
|
||||
url: erpUrl,
|
||||
username: erpUsername,
|
||||
password: erpPassword,
|
||||
url: erpConfig.url,
|
||||
username: erpConfig.username,
|
||||
password: erpConfig.password,
|
||||
headless: true
|
||||
})
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { registerAuthHandlers } from './auth-handler'
|
||||
import { registerValidationHandlers } from './validation-handler'
|
||||
import { registerSettingsHandlers } from './settings-handler'
|
||||
import { registerMaterialTypeHandlers } from './material-type-handler'
|
||||
import { registerUserErpConfigHandlers } from './user-erp-config-handler'
|
||||
import { createLogger } from '../services/logger'
|
||||
import { getErrorMessage, getErrorCode, isBaseError } from '../types/errors'
|
||||
|
||||
@@ -75,5 +76,6 @@ export function registerIpcHandlers(): void {
|
||||
registerValidationHandlers()
|
||||
registerSettingsHandlers()
|
||||
registerMaterialTypeHandlers()
|
||||
registerUserErpConfigHandlers()
|
||||
log.info('All IPC handlers registered')
|
||||
}
|
||||
|
||||
191
src/main/ipc/user-erp-config-handler.ts
Normal file
191
src/main/ipc/user-erp-config-handler.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* IPC handlers for User ERP Configuration
|
||||
*
|
||||
* Provides APIs for the renderer process to:
|
||||
* - Get current user's ERP configuration
|
||||
* - Update current user's ERP configuration
|
||||
* - Test ERP connection with provided credentials
|
||||
*/
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { UserErpConfigService } from '../services/user/user-erp-config-service'
|
||||
import { ErpAuthService } from '../services/erp/erp-auth'
|
||||
import { createLogger } from '../services/logger'
|
||||
import type { UserInfo } from '../types/user.types'
|
||||
|
||||
const log = createLogger('UserErpConfigHandler')
|
||||
|
||||
/**
|
||||
* ERP Configuration request
|
||||
*/
|
||||
export interface ErpConfigRequest {
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
/**
|
||||
* ERP Configuration response
|
||||
*/
|
||||
export interface ErpConfigResponse {
|
||||
success: boolean
|
||||
config?: ErpConfigRequest
|
||||
error?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection test result
|
||||
*/
|
||||
export interface ConnectionTestResult {
|
||||
success: boolean
|
||||
message?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Register IPC handlers for user ERP configuration
|
||||
*/
|
||||
export function registerUserErpConfigHandlers(): void {
|
||||
const erpConfigService = UserErpConfigService.getInstance()
|
||||
|
||||
/**
|
||||
* Get current user's ERP configuration
|
||||
*/
|
||||
ipcMain.handle('user-erp-config:getCurrent', async (): Promise<ErpConfigResponse> => {
|
||||
try {
|
||||
log.info('Fetching current user ERP config')
|
||||
const config = await erpConfigService.getCurrentUserErpConfig()
|
||||
|
||||
if (!config) {
|
||||
return {
|
||||
success: false,
|
||||
error: '未找到 ERP 配置。请先配置 ERP 连接参数。'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
config: {
|
||||
url: config.url,
|
||||
username: config.username,
|
||||
password: config.password
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
log.error('Get current user ERP config failed', { error: message })
|
||||
return {
|
||||
success: false,
|
||||
error: `获取 ERP 配置失败:${message}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Update current user's ERP configuration
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'user-erp-config:update',
|
||||
async (_event, config: ErpConfigRequest): Promise<ErpConfigResponse> => {
|
||||
try {
|
||||
log.info('Updating current user ERP config', {
|
||||
url: config.url,
|
||||
username: config.username
|
||||
})
|
||||
|
||||
const success = await erpConfigService.updateCurrentUserErpConfig(config)
|
||||
|
||||
if (success) {
|
||||
log.info('ERP config updated successfully')
|
||||
return {
|
||||
success: true,
|
||||
config
|
||||
}
|
||||
} else {
|
||||
log.error('Failed to update ERP config')
|
||||
return {
|
||||
success: false,
|
||||
error: '更新 ERP 配置失败'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
log.error('Update ERP config failed', { error: message })
|
||||
return {
|
||||
success: false,
|
||||
error: `更新 ERP 配置失败:${message}`
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Test ERP connection with provided credentials
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'user-erp-config:testConnection',
|
||||
async (_event, config: ErpConfigRequest): Promise<ConnectionTestResult> => {
|
||||
try {
|
||||
log.info('Testing ERP connection', { url: config.url, username: config.username })
|
||||
|
||||
if (!config.url || !config.username || !config.password) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'ERP 配置不完整,请确保 URL、用户名和密码都已填写'
|
||||
}
|
||||
}
|
||||
|
||||
const authService = new ErpAuthService({
|
||||
url: config.url,
|
||||
username: config.username,
|
||||
password: config.password,
|
||||
headless: true
|
||||
})
|
||||
|
||||
try {
|
||||
await authService.login()
|
||||
await authService.close()
|
||||
|
||||
log.info('ERP connection test successful')
|
||||
return {
|
||||
success: true,
|
||||
message: 'ERP 连接测试成功'
|
||||
}
|
||||
} catch (error) {
|
||||
await authService.close().catch(() => {})
|
||||
throw error
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error'
|
||||
log.error('ERP connection test failed', { error: message })
|
||||
return {
|
||||
success: false,
|
||||
message: `ERP 连接测试失败:${message}`
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Get all users' ERP configurations (admin only)
|
||||
*/
|
||||
ipcMain.handle(
|
||||
'user-erp-config:getAll',
|
||||
async (): Promise<
|
||||
Array<{
|
||||
username: string
|
||||
erpUrl: string
|
||||
erpUsername: string
|
||||
}>
|
||||
> => {
|
||||
try {
|
||||
log.info('Fetching all users ERP config')
|
||||
const configs = await erpConfigService.getAllUsersErpConfig()
|
||||
log.info('Retrieved ERP configs for all users', { count: configs.length })
|
||||
return configs
|
||||
} catch (error) {
|
||||
log.error('Get all users ERP config failed', { error })
|
||||
return []
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -108,11 +108,13 @@ function deepMerge<T>(source: T, target: Partial<T>): T {
|
||||
/**
|
||||
* UI editable field whitelist
|
||||
* Fields that can be modified through the settings UI
|
||||
* Note: ERP fields are no longer editable here - they are managed per-user in the database
|
||||
*/
|
||||
const UI_EDITABLE_FIELDS: string[] = [
|
||||
'erp.url',
|
||||
'erp.username',
|
||||
'erp.password'
|
||||
// ERP fields removed - ERP config is now stored in dbo_BIPUsers table per user
|
||||
// 'erp.url',
|
||||
// 'erp.username',
|
||||
// 'erp.password'
|
||||
// Add more fields as UI expands
|
||||
]
|
||||
|
||||
@@ -254,17 +256,14 @@ export class ConfigManager {
|
||||
// Build .env content from cache
|
||||
const lines: string[] = []
|
||||
|
||||
// ERP Configuration
|
||||
// ERP Configuration - REMOVED
|
||||
// ERP parameters are now stored in the database (dbo_BIPUsers table)
|
||||
// This section is kept for backward compatibility but values are not used
|
||||
lines.push('# ===========================')
|
||||
lines.push('# ERP 系统配置')
|
||||
lines.push('# ERP 系统配置(已迁移到数据库)')
|
||||
lines.push('# ===========================')
|
||||
lines.push(`ERP_URL=${this.configCache.get('ERP_URL') || DEFAULT_SETTINGS.erp.url}`)
|
||||
lines.push(
|
||||
`ERP_USERNAME=${this.configCache.get('ERP_USERNAME') || DEFAULT_SETTINGS.erp.username}`
|
||||
)
|
||||
lines.push(
|
||||
`ERP_PASSWORD=${this.configCache.get('ERP_PASSWORD') || DEFAULT_SETTINGS.erp.password}`
|
||||
)
|
||||
lines.push('# ERP_URL, ERP_USERNAME, ERP_PASSWORD 已从 .env 移除')
|
||||
lines.push('# 这些参数现在存储在 dbo_BIPUsers 表中,每个用户可以有自己的 ERP 配置')
|
||||
lines.push('')
|
||||
|
||||
// Database Configuration - SQL Server
|
||||
@@ -406,13 +405,16 @@ export class ConfigManager {
|
||||
|
||||
/**
|
||||
* Get all settings as SettingsData object
|
||||
* Note: ERP configuration is now stored in database, not .env
|
||||
* The ERP values here are for UI display only and will not be used for actual ERP operations
|
||||
*/
|
||||
public getAllSettings(): SettingsData {
|
||||
return {
|
||||
erp: {
|
||||
url: this.get('ERP_URL', DEFAULT_SETTINGS.erp.url),
|
||||
username: this.get('ERP_USERNAME', DEFAULT_SETTINGS.erp.username),
|
||||
password: this.get('ERP_PASSWORD', DEFAULT_SETTINGS.erp.password),
|
||||
// ERP config is now from database, these are placeholder defaults for UI
|
||||
url: DEFAULT_SETTINGS.erp.url,
|
||||
username: DEFAULT_SETTINGS.erp.username,
|
||||
password: DEFAULT_SETTINGS.erp.password,
|
||||
headless: true,
|
||||
ignoreHttpsErrors: true,
|
||||
autoCloseBrowser: true
|
||||
@@ -487,12 +489,11 @@ export class ConfigManager {
|
||||
|
||||
/**
|
||||
* Save settings from SettingsData object
|
||||
* Note: ERP settings are NOT saved to .env anymore - they are stored in the database
|
||||
*/
|
||||
public async saveAllSettings(settings: SettingsData): Promise<boolean> {
|
||||
// ERP settings - use underscore uppercase keys to match .env file
|
||||
this.set('ERP_URL', settings.erp.url)
|
||||
this.set('ERP_USERNAME', settings.erp.username)
|
||||
this.set('ERP_PASSWORD', settings.erp.password)
|
||||
// ERP settings are now stored in the database (dbo_BIPUsers table)
|
||||
// They are NOT saved to .env file anymore
|
||||
|
||||
// Database settings
|
||||
this.set('DB_TYPE', settings.database.dbType)
|
||||
|
||||
@@ -28,7 +28,11 @@ export const BIP_USERS_CONFIG = {
|
||||
USER_TYPE: 'UserType',
|
||||
PASSWORD: 'Password',
|
||||
COMPUTER_NAME: 'ComputerName',
|
||||
CREATE_TIME: 'CreateTime'
|
||||
CREATE_TIME: 'CreateTime',
|
||||
// ERP Configuration columns
|
||||
ERP_URL: 'ERP_URL',
|
||||
ERP_USERNAME: 'ERP_Username',
|
||||
ERP_PASSWORD: 'ERP_Password'
|
||||
}
|
||||
} as const
|
||||
|
||||
@@ -480,6 +484,162 @@ export class BIPUsersDAO {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for a user
|
||||
* @param username - The username to get ERP config for
|
||||
* @returns ERP configuration object or null if not found
|
||||
*/
|
||||
async getUserErpConfig(username: string): Promise<{
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
} | null> {
|
||||
try {
|
||||
const dbService = await this.getDatabaseService()
|
||||
const tableName = this.getTableName()
|
||||
const cols = BIP_USERS_CONFIG.COLUMNS
|
||||
|
||||
if (this.dbType === 'sqlserver') {
|
||||
const sqlString = `
|
||||
SELECT ${cols.ERP_URL}, ${cols.ERP_USERNAME}, ${cols.ERP_PASSWORD}
|
||||
FROM ${tableName}
|
||||
WHERE UserName = @username
|
||||
`
|
||||
|
||||
const result = await (dbService as SqlServerService).queryWithParams(sqlString, {
|
||||
username: { value: username, type: sql.NVarChar(255) }
|
||||
})
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
const row = result.rows[0]
|
||||
return {
|
||||
url: (row[cols.ERP_URL] as string) || '',
|
||||
username: (row[cols.ERP_USERNAME] as string) || '',
|
||||
password: (row[cols.ERP_PASSWORD] as string) || ''
|
||||
}
|
||||
}
|
||||
return null
|
||||
} else {
|
||||
const sqlString = `
|
||||
SELECT ${cols.ERP_URL}, ${cols.ERP_USERNAME}, ${cols.ERP_PASSWORD}
|
||||
FROM ${tableName}
|
||||
WHERE UserName = ?
|
||||
`
|
||||
|
||||
const result = await (dbService as MySqlService).query(sqlString, [username])
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
const row = result.rows[0]
|
||||
return {
|
||||
url: (row[cols.ERP_URL] as string) || '',
|
||||
username: (row[cols.ERP_USERNAME] as string) || '',
|
||||
password: (row[cols.ERP_PASSWORD] as string) || ''
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[BIPUsersDAO] Get user ERP config error:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ERP configuration for a user
|
||||
* @param username - The username to update ERP config for
|
||||
* @param erpUrl - The ERP URL
|
||||
* @param erpUsername - The ERP username
|
||||
* @param erpPassword - The ERP password
|
||||
* @returns True if successful
|
||||
*/
|
||||
async updateUserErpConfig(
|
||||
username: string,
|
||||
erpUrl: string,
|
||||
erpUsername: string,
|
||||
erpPassword: string
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const dbService = await this.getDatabaseService()
|
||||
const tableName = this.getTableName()
|
||||
const cols = BIP_USERS_CONFIG.COLUMNS
|
||||
|
||||
if (this.dbType === 'sqlserver') {
|
||||
const sqlString = `
|
||||
UPDATE ${tableName}
|
||||
SET ${cols.ERP_URL} = @erpUrl,
|
||||
${cols.ERP_USERNAME} = @erpUsername,
|
||||
${cols.ERP_PASSWORD} = @erpPassword
|
||||
WHERE UserName = @username
|
||||
`
|
||||
|
||||
await (dbService as SqlServerService).queryWithParams(sqlString, {
|
||||
username: { value: username, type: sql.NVarChar(255) },
|
||||
erpUrl: { value: erpUrl, type: sql.NVarChar(500) },
|
||||
erpUsername: { value: erpUsername, type: sql.NVarChar(255) },
|
||||
erpPassword: { value: erpPassword, type: sql.NVarChar(255) }
|
||||
})
|
||||
return true
|
||||
} else {
|
||||
const sqlString = `
|
||||
UPDATE ${tableName}
|
||||
SET ${cols.ERP_URL} = ?,
|
||||
${cols.ERP_USERNAME} = ?,
|
||||
${cols.ERP_PASSWORD} = ?
|
||||
WHERE UserName = ?
|
||||
`
|
||||
|
||||
await (dbService as MySqlService).query(sqlString, [
|
||||
erpUrl,
|
||||
erpUsername,
|
||||
erpPassword,
|
||||
username
|
||||
])
|
||||
return true
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[BIPUsersDAO] Update user ERP config error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for all users (for migration/audit purposes)
|
||||
* @returns List of users with their ERP configurations
|
||||
*/
|
||||
async getAllUsersErpConfig(): Promise<
|
||||
Array<{
|
||||
username: string
|
||||
erpUrl: string
|
||||
erpUsername: string
|
||||
}>
|
||||
> {
|
||||
try {
|
||||
const dbService = await this.getDatabaseService()
|
||||
const tableName = this.getTableName()
|
||||
const cols = BIP_USERS_CONFIG.COLUMNS
|
||||
|
||||
const sqlString = `
|
||||
SELECT ${cols.USERNAME}, ${cols.ERP_URL}, ${cols.ERP_USERNAME}
|
||||
FROM ${tableName}
|
||||
ORDER BY ${cols.USERNAME}
|
||||
`
|
||||
|
||||
const result =
|
||||
this.dbType === 'sqlserver'
|
||||
? await (dbService as SqlServerService).query(sqlString)
|
||||
: await (dbService as MySqlService).query(sqlString)
|
||||
|
||||
return result.rows.map((row) => ({
|
||||
username: row[cols.USERNAME] as string,
|
||||
erpUrl: (row[cols.ERP_URL] as string) || '',
|
||||
erpUsername: (row[cols.ERP_USERNAME] as string) || ''
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('[BIPUsersDAO] Get all users ERP config error:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from database
|
||||
*/
|
||||
|
||||
316
src/main/services/user/migration/add-erp-params-migration.ts
Normal file
316
src/main/services/user/migration/add-erp-params-migration.ts
Normal file
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* Migration Script: Add ERP parameters to BIPUsers table
|
||||
*
|
||||
* This script adds ERP_URL, ERP_Username, and ERP_Password columns
|
||||
* to the dbo_BIPUsers table and initializes all existing users
|
||||
* with the same ERP credentials from the current .env configuration.
|
||||
*
|
||||
* Usage:
|
||||
* npx tsx src/main/services/user/migration/add-erp-params-migration.ts
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname } from 'path'
|
||||
import { ConfigManager } from '../../config/config-manager'
|
||||
import { MySqlService } from '../../database/mysql'
|
||||
import { SqlServerService } from '../../database/sql-server'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
/**
|
||||
* Migration configuration
|
||||
*/
|
||||
const MIGRATION_CONFIG = {
|
||||
sqlFile: path.join(__dirname, 'add-erp-params-to-bipusers.sql'),
|
||||
tableName: {
|
||||
mysql: 'dbo_BIPUsers',
|
||||
sqlserver: '[dbo].[BIPUsers]'
|
||||
},
|
||||
columns: ['ERP_URL', 'ERP_Username', 'ERP_Password']
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if column exists in MySQL table
|
||||
*/
|
||||
async function checkColumnExistsMySQL(
|
||||
mysqlService: MySqlService,
|
||||
tableName: string,
|
||||
columnName: string
|
||||
): Promise<boolean> {
|
||||
const sql = `
|
||||
SELECT COUNT(*) as count
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?
|
||||
`
|
||||
const result = await mysqlService.query(sql, [tableName, columnName])
|
||||
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if column exists in SQL Server table
|
||||
*/
|
||||
async function checkColumnExistsSqlServer(
|
||||
sqlServerService: SqlServerService,
|
||||
tableName: string,
|
||||
columnName: string
|
||||
): Promise<boolean> {
|
||||
const sql = `
|
||||
SELECT COUNT(*) as count
|
||||
FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(${tableName})
|
||||
AND name = @columnName
|
||||
`
|
||||
const result = await sqlServerService.queryWithParams(sql, {
|
||||
columnName: { value: columnName.replace('ERP_', ''), type: require('mssql').NVarChar(128) }
|
||||
})
|
||||
return result.rows.length > 0 && (result.rows[0].count as number) > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to MySQL table
|
||||
*/
|
||||
async function addColumnMySQL(
|
||||
mysqlService: MySqlService,
|
||||
tableName: string,
|
||||
columnName: string,
|
||||
columnType: string
|
||||
): Promise<void> {
|
||||
const sql = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType} NULL`
|
||||
await mysqlService.query(sql)
|
||||
console.log(` ✓ Added column ${columnName} to ${tableName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to SQL Server table
|
||||
*/
|
||||
async function addColumnSqlServer(
|
||||
sqlServerService: SqlServerService,
|
||||
tableName: string,
|
||||
columnName: string,
|
||||
columnType: string
|
||||
): Promise<void> {
|
||||
const sql = `ALTER TABLE ${tableName} ADD ${columnName} ${columnType} NULL`
|
||||
await sqlServerService.query(sql)
|
||||
console.log(` ✓ Added column ${columnName} to ${tableName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all users with ERP credentials from .env
|
||||
*/
|
||||
async function initializeErpCredentialsMySQL(
|
||||
mysqlService: MySqlService,
|
||||
erpUrl: string,
|
||||
erpUsername: string,
|
||||
erpPassword: string
|
||||
): Promise<number> {
|
||||
const sql = `
|
||||
UPDATE ${MIGRATION_CONFIG.tableName.mysql}
|
||||
SET ERP_URL = ?, ERP_Username = ?, ERP_Password = ?
|
||||
WHERE ERP_URL IS NULL OR ERP_URL = ''
|
||||
`
|
||||
const result = await mysqlService.query(sql, [erpUrl, erpUsername, erpPassword])
|
||||
return result.rowCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all users with ERP credentials from .env (SQL Server)
|
||||
*/
|
||||
async function initializeErpCredentialsSqlServer(
|
||||
sqlServerService: SqlServerService,
|
||||
erpUrl: string,
|
||||
erpUsername: string,
|
||||
erpPassword: string
|
||||
): Promise<number> {
|
||||
const sql = `
|
||||
UPDATE ${MIGRATION_CONFIG.tableName.sqlserver}
|
||||
SET ERP_URL = @erpUrl, ERP_Username = @erpUsername, ERP_Password = @erpPassword
|
||||
WHERE ERP_URL IS NULL OR ERP_URL = ''
|
||||
`
|
||||
const result = await sqlServerService.queryWithParams(sql, {
|
||||
erpUrl: { value: erpUrl, type: require('mssql').NVarChar(500) },
|
||||
erpUsername: { value: erpUsername, type: require('mssql').NVarChar(255) },
|
||||
erpPassword: { value: erpPassword, type: require('mssql').NVarChar(255) }
|
||||
})
|
||||
return result.rowCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Run migration for MySQL
|
||||
*/
|
||||
async function runMySQLMigration(configManager: ConfigManager): Promise<void> {
|
||||
console.log('\n📦 Running MySQL Migration...')
|
||||
|
||||
// Read database config from .env file with correct key names
|
||||
const mysqlHost = configManager.get('DB_MYSQL_HOST', 'localhost')
|
||||
const mysqlPort = configManager.getNumber('DB_MYSQL_PORT', 3306)
|
||||
const mysqlUser = configManager.get('DB_USERNAME', 'root')
|
||||
const mysqlPassword = configManager.get('DB_PASSWORD', '')
|
||||
const mysqlDatabase = configManager.get('DB_NAME', '')
|
||||
|
||||
console.log(`Connecting to MySQL: ${mysqlHost}:${mysqlPort}/${mysqlDatabase}`)
|
||||
|
||||
const mysqlService = new MySqlService({
|
||||
host: mysqlHost,
|
||||
port: mysqlPort,
|
||||
user: mysqlUser,
|
||||
password: mysqlPassword,
|
||||
database: mysqlDatabase
|
||||
})
|
||||
|
||||
try {
|
||||
await mysqlService.connect()
|
||||
console.log('✓ Connected to MySQL')
|
||||
|
||||
const tableName = MIGRATION_CONFIG.tableName.mysql
|
||||
|
||||
// Check and add columns
|
||||
for (const [columnName, columnType] of [
|
||||
['ERP_URL', 'VARCHAR(500)'],
|
||||
['ERP_Username', 'VARCHAR(255)'],
|
||||
['ERP_Password', 'VARCHAR(255)']
|
||||
] as const) {
|
||||
const exists = await checkColumnExistsMySQL(mysqlService, tableName, columnName)
|
||||
if (exists) {
|
||||
console.log(` ✓ Column ${columnName} already exists`)
|
||||
} else {
|
||||
await addColumnMySQL(mysqlService, tableName, columnName, columnType)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ERP credentials from .env
|
||||
const erpUrl = configManager.get('ERP_URL', '')
|
||||
const erpUsername = configManager.get('ERP_USERNAME', '')
|
||||
const erpPassword = configManager.get('ERP_PASSWORD', '')
|
||||
|
||||
if (erpUrl && erpUsername && erpPassword) {
|
||||
const updatedCount = await initializeErpCredentialsMySQL(
|
||||
mysqlService,
|
||||
erpUrl,
|
||||
erpUsername,
|
||||
erpPassword
|
||||
)
|
||||
console.log(` ✓ Updated ${updatedCount} users with ERP credentials`)
|
||||
} else {
|
||||
console.log(' ⚠ Skipping ERP credential initialization (missing .env values)')
|
||||
}
|
||||
|
||||
console.log('✅ MySQL Migration completed successfully!\n')
|
||||
} catch (error) {
|
||||
console.error('❌ MySQL Migration failed:', error)
|
||||
throw error
|
||||
} finally {
|
||||
await mysqlService.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run migration for SQL Server
|
||||
*/
|
||||
async function runSqlServerMigration(configManager: ConfigManager): Promise<void> {
|
||||
console.log('\n📦 Running SQL Server Migration...')
|
||||
|
||||
const mssql = await import('mssql')
|
||||
const sqlServerService = new SqlServerService({
|
||||
server: configManager.get('DB_SERVER', 'localhost'),
|
||||
port: configManager.getNumber('DB_SQLSERVER_PORT', 1433),
|
||||
user: configManager.get('DB_USERNAME', 'sa'),
|
||||
password: configManager.get('DB_PASSWORD', ''),
|
||||
database: configManager.get('DB_NAME', ''),
|
||||
options: {
|
||||
encrypt: false,
|
||||
trustServerCertificate: configManager.get('DB_TRUST_SERVER_CERTIFICATE') === 'yes'
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await sqlServerService.connect()
|
||||
console.log('✓ Connected to SQL Server')
|
||||
|
||||
const tableName = MIGRATION_CONFIG.tableName.sqlserver
|
||||
|
||||
// Check and add columns
|
||||
for (const [columnName, columnType] of [
|
||||
['ERP_URL', 'NVARCHAR(500)'],
|
||||
['ERP_Username', 'NVARCHAR(255)'],
|
||||
['ERP_Password', 'NVARCHAR(255)']
|
||||
] as const) {
|
||||
const exists = await checkColumnExistsSqlServer(sqlServerService, tableName, columnName)
|
||||
if (exists) {
|
||||
console.log(` ✓ Column ${columnName} already exists`)
|
||||
} else {
|
||||
await addColumnSqlServer(sqlServerService, tableName, columnName, columnType)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ERP credentials from .env
|
||||
const erpUrl = configManager.get('ERP_URL', '')
|
||||
const erpUsername = configManager.get('ERP_USERNAME', '')
|
||||
const erpPassword = configManager.get('ERP_PASSWORD', '')
|
||||
|
||||
if (erpUrl && erpUsername && erpPassword) {
|
||||
const updatedCount = await initializeErpCredentialsSqlServer(
|
||||
sqlServerService,
|
||||
erpUrl,
|
||||
erpUsername,
|
||||
erpPassword
|
||||
)
|
||||
console.log(` ✓ Updated ${updatedCount} users with ERP credentials`)
|
||||
} else {
|
||||
console.log(' ⚠ Skipping ERP credential initialization (missing .env values)')
|
||||
}
|
||||
|
||||
console.log('✅ SQL Server Migration completed successfully!\n')
|
||||
} catch (error) {
|
||||
console.error('❌ SQL Server Migration failed:', error)
|
||||
throw error
|
||||
} finally {
|
||||
await sqlServerService.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main migration runner
|
||||
*/
|
||||
async function runMigration(): Promise<void> {
|
||||
console.log('==============================================')
|
||||
console.log('BIPUsers Table Migration: Add ERP Parameters')
|
||||
console.log('==============================================\n')
|
||||
|
||||
const configManager = ConfigManager.getInstance()
|
||||
await configManager.initialize()
|
||||
|
||||
const dbType = configManager.get('DB_TYPE', 'mysql').toLowerCase()
|
||||
const isSqlServer = dbType === 'sqlserver' || dbType === 'mssql'
|
||||
|
||||
try {
|
||||
if (isSqlServer) {
|
||||
await runSqlServerMigration(configManager)
|
||||
} else {
|
||||
await runMySQLMigration(configManager)
|
||||
}
|
||||
|
||||
console.log('==============================================')
|
||||
console.log('Migration Summary:')
|
||||
console.log('==============================================')
|
||||
console.log(`Database Type: ${isSqlServer ? 'SQL Server' : 'MySQL'}`)
|
||||
console.log('Columns Added/Verified:')
|
||||
console.log(' - ERP_URL (VARCHAR/NVARCHAR 500)')
|
||||
console.log(' - ERP_Username (VARCHAR/NVARCHAR 255)')
|
||||
console.log(' - ERP_Password (VARCHAR/NVARCHAR 255)')
|
||||
console.log('==============================================\n')
|
||||
} catch (error) {
|
||||
console.error('\n❌ Migration failed with error:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Run migration
|
||||
runMigration().catch((error) => {
|
||||
console.error('Unexpected error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,89 @@
|
||||
-- ============================================
|
||||
-- BIPUsers Table Migration: Add ERP Parameters
|
||||
-- Database: MySQL
|
||||
-- ============================================
|
||||
-- This script adds three new columns to store ERP connection parameters:
|
||||
-- - ERP_URL: The ERP system URL
|
||||
-- - ERP_Username: The ERP username
|
||||
-- - ERP_Password: The ERP password
|
||||
--
|
||||
-- Usage: Run this script in your MySQL client
|
||||
-- Example: mysql -u root -p BLD_DB < add-erp-params-to-bipusers-mysql.sql
|
||||
-- ============================================
|
||||
|
||||
USE BLD_DB;
|
||||
|
||||
-- Add ERP_URL column if not exists
|
||||
SET @dbname = DATABASE();
|
||||
SET @tablename = 'dbo_BIPUsers';
|
||||
SET @columnname = 'ERP_URL';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(500) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Add ERP_Username column if not exists
|
||||
SET @columnname = 'ERP_Username';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Add ERP_Password column if not exists
|
||||
SET @columnname = 'ERP_Password';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Verify columns were added
|
||||
SELECT
|
||||
COLUMN_NAME,
|
||||
DATA_TYPE,
|
||||
CHARACTER_MAXIMUM_LENGTH,
|
||||
IS_NULLABLE
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'dbo_BIPUsers'
|
||||
AND COLUMN_NAME IN ('ERP_URL', 'ERP_Username', 'ERP_Password');
|
||||
|
||||
-- Optional: Update all existing users with the same ERP credentials
|
||||
-- Replace the values below with your actual ERP credentials
|
||||
-- Example:
|
||||
-- UPDATE dbo_BIPUsers
|
||||
-- SET ERP_URL = 'https://68.11.34.30:8082/',
|
||||
-- ERP_Username = 'your_username',
|
||||
-- ERP_Password = 'your_password'
|
||||
-- WHERE ERP_URL IS NULL;
|
||||
|
||||
SELECT 'Migration completed successfully!' AS status;
|
||||
114
src/main/services/user/migration/add-erp-params-to-bipusers.sql
Normal file
114
src/main/services/user/migration/add-erp-params-to-bipusers.sql
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Database Migration Script
|
||||
* Add ERP configuration fields to dbo_BIPUsers table
|
||||
*
|
||||
* This script adds three new columns to store ERP connection parameters:
|
||||
* - ERP_URL: The ERP system URL
|
||||
* - ERP_USERNAME: The ERP username
|
||||
* - ERP_PASSWORD: The ERP password (encrypted in production)
|
||||
*
|
||||
* IMPORTANT:
|
||||
* - For SQL Server: Run this script on the SQL Server database
|
||||
* - For MySQL: Run this script on the MySQL database (syntax is auto-detected)
|
||||
* - All existing users will have the same ERP credentials (to be configured individually later)
|
||||
*/
|
||||
|
||||
-- ===========================================
|
||||
-- SQL Server Version
|
||||
-- ===========================================
|
||||
-- Uncomment and run this section for SQL Server
|
||||
/*
|
||||
IF NOT EXISTS (SELECT * FROM sys.columns
|
||||
WHERE object_id = OBJECT_ID(N'[dbo].[BIPUsers]')
|
||||
AND name = 'ERP_URL')
|
||||
BEGIN
|
||||
ALTER TABLE [dbo].[BIPUsers]
|
||||
ADD ERP_URL NVARCHAR(500) NULL;
|
||||
|
||||
ALTER TABLE [dbo].[BIPUsers]
|
||||
ADD ERP_Username NVARCHAR(255) NULL;
|
||||
|
||||
ALTER TABLE [dbo].[BIPUsers]
|
||||
ADD ERP_Password NVARCHAR(255) NULL;
|
||||
|
||||
PRINT 'ERP columns added successfully to [dbo].[BIPUsers]';
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
PRINT 'ERP columns already exist in [dbo].[BIPUsers]';
|
||||
END
|
||||
|
||||
-- Optional: Update all existing users with the same ERP credentials
|
||||
-- Replace the values below with your actual ERP credentials
|
||||
-- UPDATE [dbo].[BIPUsers]
|
||||
-- SET ERP_URL = 'https://your-erp-system.com',
|
||||
-- ERP_Username = 'your_username',
|
||||
-- ERP_Password = 'your_password'
|
||||
-- WHERE ERP_URL IS NULL;
|
||||
*/
|
||||
|
||||
-- ===========================================
|
||||
-- MySQL Version
|
||||
-- ===========================================
|
||||
-- Run this section for MySQL
|
||||
|
||||
-- Add ERP_URL column if not exists
|
||||
SET @dbname = DATABASE();
|
||||
SET @tablename = 'dbo_BIPUsers';
|
||||
SET @columnname = 'ERP_URL';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(500) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Add ERP_Username column if not exists
|
||||
SET @columnname = 'ERP_Username';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Add ERP_Password column if not exists
|
||||
SET @columnname = 'ERP_Password';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
CONCAT('ALTER TABLE ', @tablename, ' ADD COLUMN ', @columnname, ' VARCHAR(255) NULL')
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
|
||||
-- Optional: Update all existing users with the same ERP credentials
|
||||
-- Replace the values below with your actual ERP credentials
|
||||
-- UPDATE dbo_BIPUsers
|
||||
-- SET ERP_URL = 'https://your-erp-system.com',
|
||||
-- ERP_Username = 'your_username',
|
||||
-- ERP_Password = 'your_password'
|
||||
-- WHERE ERP_URL IS NULL;
|
||||
98
src/main/services/user/migration/manual-migration.sql
Normal file
98
src/main/services/user/migration/manual-migration.sql
Normal file
@@ -0,0 +1,98 @@
|
||||
-- ============================================
|
||||
-- BIPUsers 表迁移:添加 ERP 参数字段
|
||||
-- 数据库:MySQL
|
||||
-- 目标数据库:BLD_DB
|
||||
-- ============================================
|
||||
-- 使用说明:
|
||||
-- 1. 在 MySQL Workbench / Navicat / DBeaver 中打开此文件
|
||||
-- 2. 连接到数据库 192.168.31.83:3306/BLD_DB
|
||||
-- 3. 执行全部 SQL 语句
|
||||
-- ============================================
|
||||
|
||||
-- 切换到目标数据库
|
||||
USE BLD_DB;
|
||||
|
||||
-- ============================================
|
||||
-- 步骤 1: 添加新字段
|
||||
-- ============================================
|
||||
|
||||
-- 添加 ERP_URL 字段(如果不存在)
|
||||
-- 注意:如果 MySQL 版本不支持 ADD COLUMN IF NOT EXISTS,请移除 IF NOT EXISTS
|
||||
ALTER TABLE dbo_BIPUsers
|
||||
ADD COLUMN ERP_URL VARCHAR(500) NULL COMMENT 'ERP 系统 URL';
|
||||
|
||||
-- 添加 ERP_Username 字段
|
||||
ALTER TABLE dbo_BIPUsers
|
||||
ADD COLUMN ERP_Username VARCHAR(255) NULL COMMENT 'ERP 用户名';
|
||||
|
||||
-- 添加 ERP_Password 字段
|
||||
ALTER TABLE dbo_BIPUsers
|
||||
ADD COLUMN ERP_Password VARCHAR(255) NULL COMMENT 'ERP 密码';
|
||||
|
||||
-- ============================================
|
||||
-- 步骤 2: 验证字段已添加
|
||||
-- ============================================
|
||||
|
||||
-- 显示表结构,确认新字段已添加
|
||||
SELECT '字段添加验证' AS step;
|
||||
DESCRIBE dbo_BIPUsers;
|
||||
|
||||
-- 或者使用以下查询确认新字段
|
||||
SELECT
|
||||
COLUMN_NAME AS '字段名',
|
||||
DATA_TYPE AS '数据类型',
|
||||
CHARACTER_MAXIMUM_LENGTH AS '最大长度',
|
||||
IS_NULLABLE AS '允许 NULL',
|
||||
COLUMN_COMMENT AS '注释'
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'BLD_DB'
|
||||
AND TABLE_NAME = 'dbo_BIPUsers'
|
||||
AND COLUMN_NAME IN ('ERP_URL', 'ERP_Username', 'ERP_Password')
|
||||
ORDER BY COLUMN_NAME;
|
||||
|
||||
-- ============================================
|
||||
-- 步骤 3: 初始化 ERP 配置
|
||||
-- 注意:请根据实际情况修改下面的配置值!
|
||||
-- ============================================
|
||||
|
||||
SELECT '=== 请修改下面的 ERP 配置值 ===' AS notice;
|
||||
SELECT '当前数据库中的用户:' AS notice;
|
||||
SELECT UserName, UserType, ComputerName FROM dbo_BIPUsers ORDER BY UserName;
|
||||
|
||||
-- 更新所有用户的 ERP 配置
|
||||
-- ⚠️ 请修改下面的配置值为你实际的 ERP 凭证!
|
||||
UPDATE dbo_BIPUsers
|
||||
SET
|
||||
ERP_URL = 'https://68.11.34.30:8082/', -- 修改为你的 ERP 系统 URL
|
||||
ERP_Username = 'your_erp_username', -- 修改为你的 ERP 用户名
|
||||
ERP_Password = 'your_erp_password' -- 修改为你的 ERP 密码
|
||||
WHERE ERP_URL IS NULL OR ERP_URL = '';
|
||||
|
||||
-- 显示更新后的结果
|
||||
SELECT
|
||||
'更新后的 ERP 配置' AS notice,
|
||||
UserName,
|
||||
ERP_URL,
|
||||
ERP_Username
|
||||
FROM dbo_BIPUsers
|
||||
ORDER BY UserName;
|
||||
|
||||
-- ============================================
|
||||
-- 步骤 4: 完成确认
|
||||
-- ============================================
|
||||
|
||||
SELECT '================================' AS '';
|
||||
SELECT '迁移完成!' AS message;
|
||||
SELECT '================================' AS '';
|
||||
SELECT '请确认:' AS notice;
|
||||
SELECT '1. 所有用户都有 ERP_URL 配置' AS check1;
|
||||
SELECT '2. ERP_URL 格式正确' AS check2;
|
||||
SELECT '3. ERP 用户名和密码正确' AS check3;
|
||||
SELECT '================================' AS '';
|
||||
|
||||
-- 统计信息
|
||||
SELECT
|
||||
COUNT(*) AS total_users,
|
||||
COUNT(ERP_URL) AS users_with_erp_url,
|
||||
COUNT(ERP_Username) AS users_with_erp_username
|
||||
FROM dbo_BIPUsers;
|
||||
184
src/main/services/user/migration/run-migration.ts
Normal file
184
src/main/services/user/migration/run-migration.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Simple Migration Script: Add ERP parameters to BIPUsers table
|
||||
*
|
||||
* This script adds ERP_URL, ERP_Username, and ERP_Password columns
|
||||
* to the dbo_BIPUsers table.
|
||||
*
|
||||
* Usage:
|
||||
* npx tsx src/main/services/user/migration/run-migration.ts
|
||||
*/
|
||||
|
||||
import * as mysql from 'mysql2/promise'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname } from 'path'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
/**
|
||||
* Load .env file manually
|
||||
*/
|
||||
function loadEnv(filePath: string): Map<string, string> {
|
||||
const envMap = new Map<string, string>()
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.warn(`.env file not found: ${filePath}`)
|
||||
return envMap
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
const lines = content.split('\n')
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmedLine = line.trim()
|
||||
if (!trimmedLine || trimmedLine.startsWith('#')) {
|
||||
continue
|
||||
}
|
||||
|
||||
const [key, ...valueParts] = trimmedLine.split('=')
|
||||
if (key && valueParts.length > 0) {
|
||||
const value = valueParts.join('=').trim()
|
||||
envMap.set(key.trim(), value)
|
||||
}
|
||||
}
|
||||
|
||||
return envMap
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if column exists in MySQL table
|
||||
*/
|
||||
async function checkColumnExists(
|
||||
connection: mysql.Connection,
|
||||
tableName: string,
|
||||
columnName: string
|
||||
): Promise<boolean> {
|
||||
const sql = `
|
||||
SELECT COUNT(*) as count
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?
|
||||
`
|
||||
const [rows] = await connection.query(sql, [tableName, columnName])
|
||||
const result = rows as any[]
|
||||
return result.length > 0 && result[0].count > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to MySQL table
|
||||
*/
|
||||
async function addColumn(
|
||||
connection: mysql.Connection,
|
||||
tableName: string,
|
||||
columnName: string,
|
||||
columnType: string
|
||||
): Promise<void> {
|
||||
const sql = `ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType} NULL`
|
||||
await connection.query(sql)
|
||||
console.log(` ✓ Added column ${columnName} to ${tableName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Main migration function
|
||||
*/
|
||||
async function runMigration(): Promise<void> {
|
||||
console.log('==============================================')
|
||||
console.log('BIPUsers Table Migration: Add ERP Parameters')
|
||||
console.log('==============================================\n')
|
||||
|
||||
// Load .env file from project root
|
||||
const envPath = path.resolve(process.cwd(), '.env')
|
||||
console.log(`Loading .env from: ${envPath}`)
|
||||
const env = loadEnv(envPath)
|
||||
|
||||
// Get database configuration
|
||||
const dbHost = env.get('DB_MYSQL_HOST') || 'localhost'
|
||||
const dbPort = parseInt(env.get('DB_MYSQL_PORT') || '3306', 10)
|
||||
const dbUser = env.get('DB_USERNAME') || 'root'
|
||||
const dbPassword = env.get('DB_PASSWORD') || ''
|
||||
const dbName = env.get('DB_NAME') || ''
|
||||
|
||||
console.log(`Database: ${dbHost}:${dbPort}/${dbName}`)
|
||||
console.log(`Username: ${dbUser}`)
|
||||
console.log('')
|
||||
|
||||
let connection: mysql.Connection | null = null
|
||||
|
||||
try {
|
||||
// Connect to MySQL
|
||||
console.log('Connecting to MySQL...')
|
||||
connection = await mysql.createConnection({
|
||||
host: dbHost,
|
||||
port: dbPort,
|
||||
user: dbUser,
|
||||
password: dbPassword,
|
||||
database: dbName
|
||||
})
|
||||
console.log('✓ Connected to MySQL\n')
|
||||
|
||||
const tableName = 'dbo_BIPUsers'
|
||||
|
||||
// Check and add columns
|
||||
console.log('Checking columns...')
|
||||
for (const [columnName, columnType] of [
|
||||
['ERP_URL', 'VARCHAR(500)'],
|
||||
['ERP_Username', 'VARCHAR(255)'],
|
||||
['ERP_Password', 'VARCHAR(255)']
|
||||
] as const) {
|
||||
const exists = await checkColumnExists(connection, tableName, columnName)
|
||||
if (exists) {
|
||||
console.log(` ✓ Column ${columnName} already exists`)
|
||||
} else {
|
||||
await addColumn(connection, tableName, columnName, columnType)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n==============================================')
|
||||
console.log('Migration Summary:')
|
||||
console.log('==============================================')
|
||||
console.log('Database Type: MySQL')
|
||||
console.log('Database: ' + dbName)
|
||||
console.log('Columns Added/Verified:')
|
||||
console.log(' - ERP_URL (VARCHAR 500)')
|
||||
console.log(' - ERP_Username (VARCHAR 255)')
|
||||
console.log(' - ERP_Password (VARCHAR 255)')
|
||||
console.log('==============================================')
|
||||
console.log('\n✅ Migration completed successfully!\n')
|
||||
console.log('Next steps:')
|
||||
console.log('1. Update ERP credentials for users in dbo_BIPUsers table')
|
||||
console.log('2. Example SQL:')
|
||||
console.log(` UPDATE ${tableName}`)
|
||||
console.log(` SET ERP_URL = 'https://your-erp.com',`)
|
||||
console.log(` ERP_Username = 'your_username',`)
|
||||
console.log(` ERP_Password = 'your_password'`)
|
||||
console.log(` WHERE ERP_URL IS NULL;\n`)
|
||||
} catch (error) {
|
||||
console.error('\n❌ Migration failed with error:')
|
||||
console.error(error)
|
||||
console.error('\nTroubleshooting:')
|
||||
console.error('1. Check if MySQL server is running')
|
||||
console.error('2. Verify database credentials in .env file')
|
||||
console.error('3. Ensure database "' + dbName + '" exists')
|
||||
console.error('4. Check network connectivity to ' + dbHost + ':' + dbPort)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
// Disconnect
|
||||
if (connection) {
|
||||
try {
|
||||
await connection.end()
|
||||
console.log('Disconnected from MySQL')
|
||||
} catch (e) {
|
||||
// Ignore disconnect errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run migration
|
||||
runMigration().catch((error) => {
|
||||
console.error('Unexpected error:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
200
src/main/services/user/user-erp-config-service.ts
Normal file
200
src/main/services/user/user-erp-config-service.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* User ERP Configuration Service
|
||||
*
|
||||
* Manages ERP configuration (URL, username, password) stored in the BIPUsers table.
|
||||
* Each user can have their own ERP credentials.
|
||||
*
|
||||
* Features:
|
||||
* - Get current user's ERP config
|
||||
* - Update current user's ERP config
|
||||
* - Get ERP config for any user (admin only)
|
||||
*/
|
||||
|
||||
import { BIPUsersDAO } from './bip-users-dao'
|
||||
import { SessionManager } from './session-manager'
|
||||
import { createLogger } from '../logger'
|
||||
|
||||
const log = createLogger('UserErpConfigService')
|
||||
|
||||
/**
|
||||
* ERP Configuration object
|
||||
*/
|
||||
export interface ErpConfig {
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
/**
|
||||
* User ERP Configuration Service Class
|
||||
*/
|
||||
export class UserErpConfigService {
|
||||
private static instance: UserErpConfigService | null = null
|
||||
private dao: BIPUsersDAO
|
||||
|
||||
private constructor() {
|
||||
this.dao = new BIPUsersDAO()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance
|
||||
*/
|
||||
public static getInstance(): UserErpConfigService {
|
||||
if (UserErpConfigService.instance === null) {
|
||||
UserErpConfigService.instance = new UserErpConfigService()
|
||||
}
|
||||
return UserErpConfigService.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for the current authenticated user
|
||||
* @returns ERP configuration or null if not found
|
||||
*/
|
||||
async getCurrentUserErpConfig(): Promise<ErpConfig | null> {
|
||||
try {
|
||||
const sessionManager = SessionManager.getInstance()
|
||||
const currentUser = sessionManager.getUserInfo()
|
||||
|
||||
if (!currentUser) {
|
||||
log.warn('No authenticated user found')
|
||||
return null
|
||||
}
|
||||
|
||||
log.info('Fetching ERP config for user', { username: currentUser.username })
|
||||
const config = await this.dao.getUserErpConfig(currentUser.username)
|
||||
|
||||
if (!config) {
|
||||
log.warn('No ERP config found for user', { username: currentUser.username })
|
||||
return null
|
||||
}
|
||||
|
||||
log.info('ERP config retrieved successfully', {
|
||||
username: currentUser.username,
|
||||
hasUrl: !!config.url,
|
||||
hasUsername: !!config.username,
|
||||
hasPassword: !!config.password
|
||||
})
|
||||
|
||||
return config
|
||||
} catch (error) {
|
||||
log.error('Error getting current user ERP config', { error })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for a specific user (admin only)
|
||||
* @param username - The username to get ERP config for
|
||||
* @returns ERP configuration or null if not found
|
||||
*/
|
||||
async getUserErpConfig(username: string): Promise<ErpConfig | null> {
|
||||
try {
|
||||
log.info('Fetching ERP config for user', { username })
|
||||
const config = await this.dao.getUserErpConfig(username)
|
||||
|
||||
if (!config) {
|
||||
log.warn('No ERP config found for user', { username })
|
||||
return null
|
||||
}
|
||||
|
||||
return config
|
||||
} catch (error) {
|
||||
log.error('Error getting user ERP config', { error })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ERP configuration for the current authenticated user
|
||||
* @param config - ERP configuration to save
|
||||
* @returns True if successful
|
||||
*/
|
||||
async updateCurrentUserErpConfig(config: ErpConfig): Promise<boolean> {
|
||||
try {
|
||||
const sessionManager = SessionManager.getInstance()
|
||||
const currentUser = sessionManager.getUserInfo()
|
||||
|
||||
if (!currentUser) {
|
||||
log.warn('No authenticated user found')
|
||||
return false
|
||||
}
|
||||
|
||||
log.info('Updating ERP config for user', { username: currentUser.username })
|
||||
const success = await this.dao.updateUserErpConfig(
|
||||
currentUser.username,
|
||||
config.url,
|
||||
config.username,
|
||||
config.password
|
||||
)
|
||||
|
||||
if (success) {
|
||||
log.info('ERP config updated successfully', { username: currentUser.username })
|
||||
} else {
|
||||
log.error('Failed to update ERP config', { username: currentUser.username })
|
||||
}
|
||||
|
||||
return success
|
||||
} catch (error) {
|
||||
log.error('Error updating current user ERP config', { error })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ERP configuration for a specific user (admin only)
|
||||
* @param username - The username to update ERP config for
|
||||
* @param config - ERP configuration to save
|
||||
* @returns True if successful
|
||||
*/
|
||||
async updateUserErpConfig(username: string, config: ErpConfig): Promise<boolean> {
|
||||
try {
|
||||
log.info('Updating ERP config for user', { username })
|
||||
const success = await this.dao.updateUserErpConfig(
|
||||
username,
|
||||
config.url,
|
||||
config.username,
|
||||
config.password
|
||||
)
|
||||
|
||||
if (success) {
|
||||
log.info('ERP config updated successfully', { username })
|
||||
} else {
|
||||
log.error('Failed to update ERP config', { username })
|
||||
}
|
||||
|
||||
return success
|
||||
} catch (error) {
|
||||
log.error('Error updating user ERP config', { error })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ERP configuration for all users (admin only, for migration/audit)
|
||||
* @returns List of users with their ERP configurations
|
||||
*/
|
||||
async getAllUsersErpConfig(): Promise<
|
||||
Array<{
|
||||
username: string
|
||||
erpUrl: string
|
||||
erpUsername: string
|
||||
}>
|
||||
> {
|
||||
try {
|
||||
log.info('Fetching ERP config for all users')
|
||||
const configs = await this.dao.getAllUsersErpConfig()
|
||||
log.info('Retrieved ERP configs for all users', { count: configs.length })
|
||||
return configs
|
||||
} catch (error) {
|
||||
log.error('Error getting all users ERP config', { error })
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from database
|
||||
*/
|
||||
async disconnect(): Promise<void> {
|
||||
await this.dao.disconnect()
|
||||
}
|
||||
}
|
||||
34
src/preload/index.d.ts
vendored
34
src/preload/index.d.ts
vendored
@@ -235,6 +235,39 @@ export interface MaterialTypeAPI {
|
||||
}>
|
||||
}
|
||||
|
||||
/**
|
||||
* User ERP Configuration API
|
||||
*/
|
||||
export interface UserErpConfigAPI {
|
||||
/**
|
||||
* Get current user's ERP configuration
|
||||
*/
|
||||
getCurrent: () => Promise<{
|
||||
success: boolean
|
||||
config?: { url: string; username: string; password: string }
|
||||
error?: string
|
||||
}>
|
||||
/**
|
||||
* Update current user's ERP configuration
|
||||
*/
|
||||
update: (config: { url: string; username: string; password: string }) => Promise<{
|
||||
success: boolean
|
||||
config?: { url: string; username: string; password: string }
|
||||
error?: string
|
||||
}>
|
||||
/**
|
||||
* Test ERP connection with provided credentials
|
||||
*/
|
||||
testConnection: (config: { url: string; username: string; password: string }) => Promise<{
|
||||
success: boolean
|
||||
message?: string
|
||||
}>
|
||||
/**
|
||||
* Get all users' ERP configurations (admin only)
|
||||
*/
|
||||
getAll: () => Promise<Array<{ username: string; erpUrl: string; erpUsername: string }>>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron: {
|
||||
@@ -263,6 +296,7 @@ declare global {
|
||||
materials: MaterialsAPI
|
||||
settings: SettingsAPI
|
||||
materialType: MaterialTypeAPI
|
||||
userErpConfig: UserErpConfigAPI
|
||||
}
|
||||
api: unknown
|
||||
}
|
||||
|
||||
@@ -137,6 +137,16 @@ const api = {
|
||||
ipcRenderer.invoke('materialType:delete', { materialName, managerName }),
|
||||
upsertBatch: (request: MaterialTypeBatchRequest) =>
|
||||
ipcRenderer.invoke('materialType:upsertBatch', request)
|
||||
},
|
||||
|
||||
// User ERP Configuration service
|
||||
userErpConfig: {
|
||||
getCurrent: () => ipcRenderer.invoke('user-erp-config:getCurrent'),
|
||||
update: (config: { url: string; username: string; password: string }) =>
|
||||
ipcRenderer.invoke('user-erp-config:update', config),
|
||||
testConnection: (config: { url: string; username: string; password: string }) =>
|
||||
ipcRenderer.invoke('user-erp-config:testConnection', config),
|
||||
getAll: () => ipcRenderer.invoke('user-erp-config:getAll')
|
||||
}
|
||||
} as const
|
||||
|
||||
|
||||
Reference in New Issue
Block a user