Goods Stock Transfer (T139)
Transfer inventory quantities between registered branches for the same taxpayer. This endpoint supports both standard goods and fuel products, with optional rollback on error handling. Request and response are encrypted.
Endpoint Overviewβ
| Property | Value |
|---|---|
| Interface Code | T139 |
| Request Encrypted | β Yes |
| Response Encrypted | β Yes |
| Request Body | { "goodsStockTransfer": {...}, "goodsStockTransferItem": [...] } |
| Response Format | JSON Array |
Flow Descriptionβ
- Client submits transfer request with source/destination branch IDs and item list.
- Server validates branch ownership, stock availability, and field constraints.
- Server processes transfer:
- Decrements stock at
sourceBranchId - Increments stock at
destinationBranchId - For fuel products: validates
sourceFuelTankId/destinationFuelTankIdmappings
- Decrements stock at
- Server returns per-item status with
returnCodeandreturnMessage. - If
rollBackIfError=1and any item fails, entire transaction is rolled back.
π‘ Tip: Call T138 (Get All Branches) first to retrieve valid
branchIdvalues. For fuel products, ensure tank IDs match the branch via T169 before transferring.
- PHP
- JavaScript / TypeScript
- Python
try {
// Call T139: Goods Stock Transfer
$transferData = [
'goodsStockTransfer' => [
'sourceBranchId' => '206637525568955296',
'destinationBranchId' => '206637528324276772',
'transferTypeCode' => '101', // Out of Stock Adjust
'remarks' => 'Monthly stock rebalance',
'rollBackIfError' => '1',
'goodsTypeCode' => '101' // 101=Goods, 102=Fuel
],
'goodsStockTransferItem' => [
[
'commodityGoodsId' => '287700992426868373',
// OR use goodsCode if commodityGoodsId unavailable:
// 'goodsCode' => 'PROD_001',
'measureUnit' => '101',
'quantity' => '100',
'remarks' => 'Transfer from warehouse A to B',
// For fuel products only:
// 'sourceFuelTankId' => '568654903587001037',
// 'destinationFuelTankId' => '568654903587001038'
]
]
];
$response = $client->transferStock($transferData);
$items = $response['data']['content'] ?? $response;
if (is_array($items)) {
foreach ($items as $item) {
if (($item['returnCode'] ?? '00') === '00') {
echo "β
Item transferred: {$item['commodityGoodsId']}\n";
} else {
echo "β Item failed: {$item['returnCode']} - {$item['returnMessage']}\n";
}
}
}
} catch (\UraEfrisSdk\Exceptions\APIException $e) {
echo "β Transfer failed: " . $e->getMessage() . "\n";
echo " Return Code: " . $e->getReturnCode() . "\n";
}
try {
// Call T139: Goods Stock Transfer
const transferData = {
goodsStockTransfer: {
sourceBranchId: '206637525568955296',
destinationBranchId: '206637528324276772',
transferTypeCode: '101', // Out of Stock Adjust
remarks: 'Monthly stock rebalance',
rollBackIfError: '1',
goodsTypeCode: '101' // 101=Goods, 102=Fuel
},
goodsStockTransferItem: [
{
commodityGoodsId: '287700992426868373',
// OR use goodsCode if commodityGoodsId unavailable:
// goodsCode: 'PROD_001',
measureUnit: '101',
quantity: '100',
remarks: 'Transfer from warehouse A to B',
// For fuel products only:
// sourceFuelTankId: '568654903587001037',
// destinationFuelTankId: '568654903587001038'
}
]
};
const response = await client.transferStock(transferData);
const items = response?.data?.content ?? response;
if (Array.isArray(items)) {
for (const item of items) {
if ((item.returnCode ?? '00') === '00') {
console.log(`β
Item transferred: ${item.commodityGoodsId}`);
} else {
console.error(`β Item failed: ${item.returnCode} - ${item.returnMessage}`);
}
}
}
} catch (error: any) {
console.error(`β Transfer failed: ${error.message}`);
if (error.returnCode) {
console.error(` Return Code: ${error.returnCode}`);
}
throw error;
}
try:
# Call T139: Goods Stock Transfer
transfer_data = {
"goodsStockTransfer": {
"sourceBranchId": "206637525568955296",
"destinationBranchId": "206637528324276772",
"transferTypeCode": "101", # Out of Stock Adjust
"remarks": "Monthly stock rebalance",
"rollBackIfError": "1",
"goodsTypeCode": "101" # 101=Goods, 102=Fuel
},
"goodsStockTransferItem": [
{
"commodityGoodsId": "287700992426868373",
# OR use goodsCode if commodityGoodsId unavailable:
# "goodsCode": "PROD_001",
"measureUnit": "101",
"quantity": "100",
"remarks": "Transfer from warehouse A to B",
# For fuel products only:
# "sourceFuelTankId": "568654903587001037",
# "destinationFuelTankId": "568654903587001038"
}
]
}
response = client.transfer_stock(transfer_data)
items = response.get("data", {}).get("content", response)
if isinstance(items, list):
for item in items:
if item.get("returnCode", "00") == "00":
print(f"β
Item transferred: {item['commodityGoodsId']}")
else:
print(f"β Item failed: {item.get('returnCode')} - {item.get('returnMessage')}")
except Exception as e:
print(f"β Transfer failed: {e}")
if hasattr(e, "return_code"):
print(f" Return Code: {e.return_code}")
raise
Request Structureβ
{
"data": {
"content": "BASE64_ENCRYPTED_PAYLOAD",
"signature": "JKQWJK34K32JJEK2JQWJ5678",
"dataDescription": {
"codeType": "1",
"encryptCode": "2",
"zipCode": "0"
}
},
"globalInfo": {
"interfaceCode": "T139",
"appId": "AP04",
"version": "1.1.20191201",
"tin": "1000029771",
"deviceNo": "TCS9e0df01728335239",
"taxpayerID": "1"
}
}
Request Fields (Encrypted Payload)β
GoodsStockTransfer Objectβ
| Field | Required | Type | Length | Description |
|---|---|---|---|---|
sourceBranchId | β Yes | String | β€18 | Source branch identifier (must belong to current taxpayer) |
destinationBranchId | β Yes | String | β€18 | Destination branch identifier (must belong to current taxpayer; cannot equal sourceBranchId) |
transferTypeCode | β Yes | String | β€20 | 101=Out of Stock Adjust, 102=Error Adjust, 103=Others (multiple values separated by commas, e.g., "101,102") |
remarks | β No | String | β€1024 | Transfer description; required if transferTypeCode includes 103 |
rollBackIfError | β No | String (1) | 1 | 0=Continue on error, 1=Rollback entire transaction on first error (default: 0) |
goodsTypeCode | β No | String (3) | 3 | 101=Standard Goods, 102=Fuel Products (default: 101) |
GoodsStockTransferItem Array (One or More Required)β
| Field | Required | Type | Length | Description |
|---|---|---|---|---|
commodityGoodsId | β οΈ Conditional | String | β€18 | Goods identifier from T130; required if goodsCode is empty |
goodsCode | β οΈ Conditional | String | β€50 | Goods code from T130; required if commodityGoodsId is empty |
measureUnit | β No | String (3) | 3 | Unit of measure code from T115 rateUnit; must match maintained commodity unit |
quantity | β Yes | Number | β€18 | Transfer quantity; must be positive and not exceed available stock at source |
remarks | β No | String | β€1024 | Item-level transfer notes |
sourceFuelTankId | β No | String | β€18 | Fuel only: Source tank identifier (must match branch and goods) |
destinationFuelTankId | β No | String | β€18 | Fuel only: Destination tank identifier (must match branch and goods) |
π‘ Tip: Either
commodityGoodsIdORgoodsCodemust be provided per itemβnever both empty. For fuel products (goodsTypeCode=102), tank IDs are mandatory and must be validated via T169.
Response Structureβ
{
"data": {
"content": [
{
"commodityGoodsId": "287700992426868373",
"goodsCode": "287700992426",
"measureUnit": "101",
"quantity": "100",
"remarks": "Transfer from warehouse A to B",
"sourceFuelTankId": "568654903587001037",
"destinationFuelTankId": "568654903587001038",
"returnCode": "00",
"returnMessage": "SUCCESS"
}
]
},
"globalInfo": {
"interfaceCode": "T139",
"returnStateInfo": {
"returnCode": "00",
"returnMessage": "SUCCESS"
}
}
}
Response Fieldsβ
Per-Item Response Arrayβ
| Field | Required | Type | Description |
|---|---|---|---|
commodityGoodsId | β Yes | String (18) | Goods identifier (echoed from request) |
goodsCode | β Yes | String (50) | Goods code (echoed from request) |
measureUnit | β Yes | String (3) | Unit of measure (echoed from request) |
quantity | β Yes | Number | Transferred quantity (echoed from request) |
remarks | β No | String | Item remarks (echoed from request) |
sourceFuelTankId | β No | String (18) | Source tank ID (fuel products only) |
destinationFuelTankId | β No | String (18) | Destination tank ID (fuel products only) |
returnCode | β Yes | String (10) | Item-level status code (00=success, else error) |
returnMessage | β Yes | String | Human-readable status message |
Return Codesβ
| Code | Message | Description |
|---|---|---|
00 | SUCCESS | Transfer completed successfully |
99 | Unknown error | Generic server error |
400 | Device does not exist | deviceNo not registered for this TIN |
402 | Device key expired | Device credentials expired; re-run T102 |
403 | Device status is abnormal | Device blocked or suspended |
2141 | destinationBranchId cannot be empty! | Missing destination branch |
2142 | destinationBranchId:Byte length cannot be greater than 18! | Destination branch ID too long |
2143 | sourceBranchId does not belong to current taxpayer! | Source branch not owned by TIN |
2144 | destinationBranchId does not belong to current taxpayer! | Destination branch not owned by TIN |
2145 | sourceBranchId and destinationBranchId cannot be the same! | Self-transfer not allowed |
2146 | transferTypeCode:cannot be empty! | Missing transfer type |
2148 | transferTypeCode: invalid field value! | Invalid transfer type code |
2149 | remarks:cannot be empty! | Remarks required when transferTypeCode=103 |
2152 | transferred quantity exceeds the original stock | Insufficient stock at source branch |
2153 | sourceBranchId cannot be empty | Missing source branch |
2194 | goodsCode:cannot be empty! | Both commodityGoodsId and goodsCode empty |
2196 | commodityGoodsId and goodsCode cannot be empty at the same time! | At least one identifier required |
2242 | goodsStockTransferItem can not be empty! | No items provided for transfer |
2243 | measureUnit: inconsistent with the maintained commodity unit! | Unit mismatch with T130 registration |
2890-2892 | rollBackIfError validation errors | Invalid rollback flag format/value |
3008-3015 | Fuel tank validation errors | Tank ID mismatches, product type conflicts |
π‘ Tip: A
returnCodeof00per item indicates successful transfer. IfrollBackIfError=1, any non-00code triggers rollback of all items.
Common Use Casesβ
-
Inter-Branch Stock Rebalancing
Move excess inventory from overstocked branches to locations with higher demand. -
Error Correction Transfers
UsetransferTypeCode=102to correct stock discrepancies identified during audits. -
Fuel Depot Management
Transfer fuel between tanks/branches with tank-specific tracking viasourceFuelTankId/destinationFuelTankId. -
Rollback-Safe Bulk Transfers
SetrollBackIfError=1for critical transfers where partial completion is unacceptable. -
Multi-Item Consolidation
Transfer multiple SKUs in a single API call to reduce network overhead and ensure atomicity. -
Compliance Auditing
Log all transfer requests withremarksfor traceability in stock movement reports.
Integration Checklistβ
β
Call T138 first to validate sourceBranchId and destinationBranchId belong to taxpayer
β
Ensure sourceBranchId β destinationBranchId to avoid validation errors
β
Provide either commodityGoodsId OR goodsCode per item (never both empty)
β
Validate measureUnit matches T115 rateUnit and T130 commodity registration
β
For fuel products (goodsTypeCode=102): validate tank IDs via T169 before transfer
β
Check available stock at source branch before submitting (avoid 2152 errors)
β
Use rollBackIfError=1 for critical transfers where atomicity is required
β
Parse per-item returnCode in responseβpartial success is possible if rollback disabled
β
Log transfer remarks and transferTypeCode for audit trail compliance
β
Re-query stock levels via T128/T147 post-transfer to confirm successful movement