iDempiere REST API 概述
iDempiere Mobile 透過 idempiere-rest 外掛的 OData REST API 與 iDempiere ERP 伺服器通訊。所有資料存取都使用標準的 HTTP 方法操作 REST 端點。
┌─────────────────────┐ HTTPS/JWT ┌──────────────────────┐ │ Flutter App │ <──────────────────► │ iDempiere ERP │ │ (iOS/Android/Web/ │ idempiere-rest API │ + idempiere-rest │ │ macOS) │ /api/v1/... │ plugin │ └─────────────────────┘ └──────────────────────┘
認證流程(兩步驟)
認證分為兩個步驟:先登入取得臨時 token 和可用角色列表,再選擇角色取得正式 session token。
步驟 1:登入
POST /api/v1/auth/tokens
Content-Type: application/json
{
"userName": "your-username",
"password": "your-password"
}
# 回應:
{
"token": "jwt-temporary-token...",
"clients": [
{
"id": 11,
"name": "GardenWorld",
"roles": [
{ "id": 102, "name": "GardenAdmin" }
]
}
]
}
步驟 2:選擇角色
PUT /api/v1/auth/tokens
Authorization: Bearer jwt-temporary-token
Content-Type: application/json
{
"clientId": 11,
"roleId": 102,
"organizationId": 11,
"language": "zh_TW"
}
# 回應:
{
"token": "jwt-session-token..."
}
- 步驟 1 回傳臨時 token 和可用的 client/role 列表
- 步驟 2 選擇工作的 client/role/org 並回傳正式 session token
- Token 儲存在
FlutterSecureStorage(iOS Keychain / Android EncryptedSharedPreferences) - 後續所有請求由
AuthInterceptor自動附加Authorization: Bearer <token>
CRUD 操作
所有資料存取使用 GET/POST/PUT/DELETE 操作 /api/v1/models/{tableName}:
| HTTP 方法 | 端點 | 用途 |
|---|---|---|
| GET | /api/v1/models/{tableName} |
查詢記錄列表 |
| GET | /api/v1/models/{tableName}/{id} |
取得單筆記錄 |
| POST | /api/v1/models/{tableName} |
新增記錄 |
| PUT | /api/v1/models/{tableName}/{id} |
更新記錄 |
| DELETE | /api/v1/models/{tableName}/{id} |
刪除記錄 |
Dart 程式碼範例
// ApiClient 封裝了所有 CRUD 操作
final api = ref.watch(apiClientProvider);
// 查詢列表(含篩選、排序、展開外鍵)
final data = await api.getRecords('C_Order',
filter: "IsSOTrx eq 'Y' and DocStatus eq 'DR'",
orderBy: 'DateOrdered desc',
expand: 'C_BPartner_ID,C_DocType_ID',
top: 20,
skip: 0,
);
// 取得單筆記錄(含展開欄位)
final record = await api.getRecord('C_Order', 12345,
expand: 'C_BPartner_ID,C_DocType_ID,M_Warehouse_ID',
);
// 新增記錄
final newRecord = await api.createRecord('C_Order', {
'C_DocTypeTarget_ID': 132,
'C_BPartner_ID': 118,
'DateOrdered': '2026-02-17',
});
// 更新記錄
await api.updateRecord('C_Order', 12345, {
'Description': 'Updated description',
});
// 刪除記錄
await api.deleteRecord('C_Order', 12345);
OData 查詢
idempiere-rest 支援 OData 風格的查詢參數:
| 參數 | 用途 | 範例 |
|---|---|---|
$filter |
篩選條件 | IsSOTrx eq 'Y' and DocStatus eq 'DR' |
$expand |
展開外鍵欄位 | C_BPartner_ID,C_DocType_ID |
$orderby |
排序 | DateOrdered desc |
$top |
取得筆數 | 20 |
$skip |
跳過筆數(分頁) | 40 |
OData 篩選注意事項
這是最常見的 bug 來源。Boolean 欄位和 Char 欄位的篩選語法不同:
| 欄位類型 | 正確語法 | 錯誤語法 |
|---|---|---|
| Boolean 欄位 | IsActive eq true |
IsActive eq 'Y'(悄悄回傳錯誤資料) |
| Boolean 欄位 | IsSummary eq false |
IsSummary eq 'N' |
| Char 欄位 | IsSOTrx eq 'Y' |
– |
| Char 欄位 | DocStatus eq 'CO' |
– |
Document Framework 透過 StatusFilter.isBoolean 自動處理這個差異。
文件工作流程
iDempiere 文件(如銷售訂單、付款等)遵循三步驟工作流程:
# 1. 建立文件標頭
POST /api/v1/models/C_Order
{
"C_DocTypeTarget_ID": 132,
"C_BPartner_ID": 118,
"DateOrdered": "2026-02-17"
}
# 回傳: { "id": 12345, ... }
# 2. 建立明細行
POST /api/v1/models/C_OrderLine
{
"C_Order_ID": 12345,
"M_Product_ID": 456,
"QtyOrdered": 10
}
# 3. 完成文件(doc-action)
PUT /api/v1/models/C_Order/12345
{
"doc-action": "CO"
}
常用 doc-action 代碼
| 代碼 | 動作 | 說明 |
|---|---|---|
CO |
Complete | 完成文件 |
VO |
Void | 作廢文件 |
CL |
Close | 關閉文件 |
RC |
Reverse – Correct | 沖銷更正 |
PR |
Prepare | 準備文件 |
攔截器
API 客戶端使用 Dio 攔截器處理橫切關注點:
| 攔截器 | 用途 | 說明 |
|---|---|---|
AuthInterceptor |
JWT 認證 | 自動附加 Bearer token,401 時自動刷新 |
ContextInterceptor |
上下文標頭 | 自動附加 AD_Language 和上下文標頭 |
RetryInterceptor |
網路重試 | 網路錯誤時自動重試(3 次,指數退避) |
認證攔截器流程
HTTP 請求
│
▼
AuthInterceptor 附加 Bearer token
│
▼
伺服器回應
│
├── 200 OK → 正常回傳
│
└── 401 Unauthorized
│
▼
自動刷新 token(PUT /api/v1/auth/tokens)
│
▼
使用新 token 重新發送原始請求
附件上傳/下載
// 上傳附件
final attachmentApi = AttachmentApi(api.dio);
await attachmentApi.upload(
tableName: 'C_Order',
recordId: 12345,
file: selectedFile,
);
// 下載附件
final bytes = await attachmentApi.download(
tableName: 'C_Order',
recordId: 12345,
attachmentId: 67890,
);
選單樹 API
// 取得角色的選單樹
final menuTree = await api.getMenuTree(treeId);
// 回傳巢狀選單項目,每個項目含有:
// - action: 'W' (Window), 'P' (Process), 'R' (Report), 'X' (Form)
// - targetId: AD_Window_ID / AD_Process_ID / AD_Form_ID
// - name, description
表格對應參考
| 應用概念 | iDempiere 表格 | 關鍵欄位 |
|---|---|---|
| 銷售訂單 | C_Order |
DocumentNo, DateOrdered, C_BPartner_ID, GrandTotal, DocStatus |
| 採購訂單 | C_Order |
同上(以 IsSOTrx=’N’ 區分) |
| 發票 | C_Invoice |
DocumentNo, DateInvoiced, C_BPartner_ID, GrandTotal, DocStatus |
| 付款/收款 | C_Payment |
DocumentNo, DateTrx, C_BPartner_ID, PayAmt, DocStatus |
| 產品 | M_Product |
Value, Name, M_Product_Category_ID, C_UOM_ID |
| 商業夥伴 | C_BPartner |
Value, Name, IsCustomer, IsVendor |
| 庫存移動 | M_Movement |
DocumentNo, MovementDate, Description, DocStatus |
| 庫存移動明細 | M_MovementLine |
M_Movement_ID, M_Product_ID, M_Locator_ID, M_LocatorTo_ID, MovementQty |
| 總帳分錄 | GL_Journal |
DocumentNo, DateAcct, Description, TotalDr, TotalCr |
| 資產 | A_Asset |
Value, Name, A_Asset_Group_ID, DateAcct |
🌐 English Version
iDempiere REST API Overview
iDempiere Mobile communicates with iDempiere ERP via the idempiere-rest plugin’s OData REST API.
Authentication Flow (Two Steps)
- POST
/api/v1/auth/tokenswith username/password → returns temporary token + client/role list - PUT
/api/v1/auth/tokenswith clientId/roleId/orgId → returns session JWT token
The token is stored in FlutterSecureStorage and attached to all subsequent requests via AuthInterceptor.
CRUD Operations
All data access uses GET/POST/PUT/DELETE on /api/v1/models/{tableName}.
OData Queries
Supported parameters: $filter, $expand, $orderby, $top, $skip.
OData Filter Gotcha
Boolean columns use unquoted true/false. Char columns use quoted values like 'Y'. Using IsActive eq 'Y' silently returns wrong data.
Document Workflow
- POST to create header
- POST to create line items
- PUT with
{"doc-action": "CO"}to complete
Interceptors
| Interceptor | Purpose |
|---|---|
AuthInterceptor |
JWT Bearer token + auto-refresh on 401 |
ContextInterceptor |
AD_Language and context headers |
RetryInterceptor |
Automatic retry on network errors (3 attempts, exponential backoff) |
Attachments
Use AttachmentApi for file upload/download operations on any record.
Table Mapping
| Concept | Table | Key Fields |
|---|---|---|
| Sales Order | C_Order |
DocumentNo, DateOrdered, C_BPartner_ID, GrandTotal |
| Invoice | C_Invoice |
DocumentNo, DateInvoiced, C_BPartner_ID, GrandTotal |
| Payment | C_Payment |
DocumentNo, DateTrx, C_BPartner_ID, PayAmt |
| Product | M_Product |
Value, Name, M_Product_Category_ID |
| Business Partner | C_BPartner |
Value, Name, IsCustomer, IsVendor |
| Movement | M_Movement |
DocumentNo, MovementDate, DocStatus |
| GL Journal | GL_Journal |
DocumentNo, DateAcct, TotalDr, TotalCr |