21 KiB
Stock Management API Documentation
This document provides detailed documentation for the stock management module APIs, focusing on the three main stock change creation modes: Full, Relaxed, and Restricted.
Table of Contents
Overview
The stock management system handles all inventory movement operations including stock-in (入库) and stock-out (出库) transactions. The system supports three different modes of operation:
- Full Mode: Standard operation with explicit quantity lists
- Relaxed Mode: Automatically splits quantities based on total and unit count
- Restricted Mode: Strict "restricted-in/out" mode for warehouse operations
Stock Models
StockChangeRecord
Represents a stock change record (either stock-in or stock-out).
Fields:
id: Record IDtype: Change type (1=Stock-in, 2=Stock-out)warehouse: Associated warehousesource_type: Source of the change (1=Purchase, 6=Sales, etc.)source_id: ID of the source document (optional)created_by: User who created the recordis_finished: Whether the stock change is completedfinished_at: When the record was completedremarks: Additional notes
StockChangeDetail
Represents detailed items within a stock change record.
Fields:
id: Detail IDproduct: Associated productstock_change_record: Parent stock change recordquantity: Quantity of the productunit: Unit of measurementis_consumed: Whether this detail has been consumed (for restricted mode)consume_with: Reference to the inbound detail being consumed (for restricted mode)
Inventory
Represents current inventory levels for a product in a warehouse.
Fields:
id: Inventory IDproduct: Associated productwarehouse: Warehouse locationquantity: Current quantitynum_of_rolls: Number of rollsspec: Product specificationdescription: Additional notes
Stock Change Modes
Source Types
The system supports various source types for stock changes:
Incoming (入库) Sources:
1: Purchase (采购)2: Sales Return (销退)3: Transport In (调入)4: Recheck Addition (盘盈)5: Combine (合并)11: Offset (红冲,反向抵销入库)
Outgoing (出库) Sources:
6: Sales (销售)7: Purchase Return (采购退货)8: Transport Out (调出)9: Recheck Removal (盘亏)10: Explode (拆卷)11: Offset (红冲,反向抵销出库)
Warehouse Modes
Warehouses can operate in different modes:
1: Restricted In (严进) - Strict control on stock-in2: Restricted In/Out (严进严出) - Strict control on both stock-in and stock-out3: Unrestricted (宽进宽出) - Relaxed controls for both directions
API Endpoints
1. Full Mode Stock Change
URL: POST /api/v1/stock-change/
Description: Creates a stock change record with explicit quantity lists for each product.
Request Parameters:
{
"type": 1, // 1=入库, 2=出库
"warehouse": 1, // 仓库ID
"source_type": 1, // 来源类型,见上文说明
"source_id": 123, // 可选,来源单据ID
"products": [
{
"product": 1, // 产品ID
"quantity": [85.5, 75.2, 90.0] // 数量列表,每个值对应一条明细
},
{
"product": 2,
"quantity": [120.0]
}
]
}
Response:
{
"stock_change_record": {
"id": 15,
"type": 1,
"warehouse": 1,
"source_type": 1,
"source_id": 123,
"is_finished": false,
"created_at": "2025-11-25T10:30:00Z",
"updated_at": "2025-11-25T10:30:00Z"
},
"details": [
{
"id": 45,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 85.5,
"unit": 1,
"unit_display": "米",
"stock_change_record": 15,
"is_consumed": false,
"consume_with_id": null
},
{
"id": 46,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 75.2,
"unit": 1,
"unit_display": "米",
"stock_change_record": 15,
"is_consumed": false,
"consume_with_id": null
}
// ... 更多明细
],
"message": "成功创建库存变动记录及 3 条明细",
"created_details_count": 3
}
2. Relaxed Mode Stock Change
URL: POST /api/v1/stock-change/relaxed/
Description: Creates a stock change record using total quantity and unit count to automatically split into details.
Request Parameters:
{
"type": 1, // 1=入库, 2=出库
"warehouse": 1, // 仓库ID
"source_type": 1, // 来源类型
"source_id": 123, // 可选,来源单据ID
"products": [
{
"product": 1, // 产品ID
"quantity": {
"value": 250.8, // 总数量
"unit_count": 2.5 // 单条数量,默认为1
}
}
]
}
Response:
{
"stock_change_record": {
"id": 16,
"type": 1,
"warehouse": 1,
"source_type": 1,
"source_id": 123,
"is_finished": false,
"created_at": "2025-11-25T11:00:00Z",
"updated_at": "2025-11-25T11:00:00Z"
},
"details": [
{
"id": 48,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 100.0, // 自动拆分
"unit": 1,
"unit_display": "米",
"stock_change_record": 16,
"is_consumed": false,
"consume_with_id": null
},
{
"id": 49,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 100.0, // 自动拆分
"unit": 1,
"unit_display": "米",
"stock_change_record": 16,
"is_consumed": false,
"consume_with_id": null
},
{
"id": 50,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 50.8, // 剩余数量
"unit": 1,
"unit_display": "米",
"stock_change_record": 16,
"is_consumed": false,
"consume_with_id": null
}
],
"message": "成功创建库存变动记录及 3 条明细",
"created_details_count": 3
}
3. Restricted Mode Stock Change
URL: POST /api/v1/stock-change/restrict/
Description: Creates a stock change record in "restricted-in-out" mode where outbound details must reference existing inbound details.
Request Parameters:
{
"type": 2, // 1=入库, 2=出库
"warehouse": 1, // 仓库ID,必须为严进严出模式
"source_type": 6, // 来源类型
"source_id": 123, // 可选,来源单据ID
"products": [
{
"product": 1, // 产品ID
"quantity": [150.5], // 数量列表
"consume_with": [23, 24] // 必须指定消耗的入库明细ID列表
}
]
}
Response:
{
"stock_change_record": {
"id": 17,
"type": 2,
"warehouse": 1,
"source_type": 6,
"source_id": 123,
"is_finished": false,
"created_at": "2025-11-25T11:15:00Z",
"updated_at": "2025-11-25T11:15:00Z"
},
"details": [
{
"id": 51,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 75.25,
"unit": 1,
"unit_display": "米",
"stock_change_record": 17,
"is_consumed": false,
"consume_with_id": 23 // 消耗的入库明细ID
},
{
"id": 52,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 75.25,
"unit": 1,
"unit_display": "米",
"stock_change_record": 17,
"is_consumed": false,
"consume_with_id": 24 // 消耗的入库明细ID
}
],
"message": "成功创建库存变动记录及 2 条明细",
"created_details_count": 2
}
4. Stock Transfer (调拨)
URL: POST /api/v1/stock-change/transfer/
Description: Performs an in-transaction transfer between two warehouses that share the same warehouse mode (可以跨类型,例如整件仓 → 散件仓)。一次调用会同步创建调出与调入的 StockChangeRecord 并立即完成库存扣加,确保库存一致性。
Business Constraints:
from_warehouse与to_warehouse必须属于当前商户,且不可相同。- 两个仓库的
mode必须一致(RESTRICT_IN、UNRESTRICTED 均可)。目前不支持RESTRICT_IN_OUT(严进严出)的调拨。 - 请求在数据库事务内完成,不能依赖异步任务;支持
request_id幂等重试。 products列表沿用原出入库的 payload 结构,允许:quantities: 严谨/严进模式的显式数量数组;value + unit_count/num_of_rolls: 宽松模式的拆分定义;consume_detail_ids: 若未来开放严进严出调拨,可在此补充(当前会拒绝)。
Request Parameters:
{
"from_warehouse": 3,
"to_warehouse": 5,
"transfer_date": "2025-12-02", // 可选,默认当天
"remarks": "整件仓调拨到散件仓", // 可选
"request_id": "transfer-20251202-001", // 可选幂等键
"products": [
{ "product_id": 12, "quantities": ["10.50", "5.25"] },
{ "product_id": 27, "value": "120.0", "unit_count": "30" }
]
}
Response:
{
"id": 88,
"merchant": 6,
"from_warehouse": 3,
"from_warehouse_name": "整件一号仓",
"to_warehouse": 5,
"to_warehouse_name": "散件贵宾仓",
"mode": 1,
"mode_display": "严进宽出",
"operator": 24,
"transfer_date": "2025-12-02",
"status": 2,
"status_display": "已完成",
"remarks": "整件仓调拨到散件仓",
"request_id": "transfer-20251202-001",
"outgoing_record_id": 512,
"incoming_record_id": 513,
"items": [
{
"id": 143,
"product": 12,
"product_name": "贡缎白坯布",
"total_quantity": "15.75",
"unit": 1,
"unit_display": "米",
"num_of_rolls": 2
},
{
"id": 144,
"product": 27,
"product_name": "彩纱混纺",
"total_quantity": "120.00",
"unit": 1,
"unit_display": "米",
"num_of_rolls": 4
}
]
}
Error Cases:
| HTTP | Payload 示例 | 说明 |
|---|---|---|
| 400 | { "error": "调拨要求调出仓与调入仓的出入库模式一致" } |
两仓 mode 不同 |
| 400 | { "error": "调入仓与调出仓不能相同" } |
相同仓库 |
| 400 | { "error": "调出仓不存在或不属于当前商户" } |
仓库不属于当前商户 |
| 400 | { "error": "调拨产品明细不能为空" } |
products 为空 |
| 409 | { "error": "请求重复" } (未来可扩展) |
同一 request_id 重复提交(当前直接返回已存在记录) |
提示:响应中附带
outgoing_record_id与incoming_record_id,可继续使用既有的GET /api/v1/stock-change/<id>/接口查看具体的明细与快照。
Other Related Endpoints
List Stock Changes
URL: GET /api/v1/stock-changes/
Response: List of stock change records with pagination
{
"count": 100,
"next": "http://example.com/api/v1/stock-changes/?page=2",
"previous": null,
"results": [
{
"id": 15,
"type": 1,
"type_display": "入库",
"warehouse": 1,
"source_type": 1,
"source_type_display": "采购",
"is_finished": true,
"finished_at": "2025-11-25T12:00:00Z",
"created_at": "2025-11-25T10:30:00Z"
}
]
}
Get Stock Change Details
URL: GET /api/v1/stock-change/<id>/
Response: Detailed view of a specific stock change record with its details
{
"stock_change_record": {
"id": 15,
"type": 1,
"type_display": "入库",
"warehouse": 1,
"source_type": 1,
"source_type_display": "采购",
"is_finished": true,
"finished_at": "2025-11-25T12:00:00Z",
"created_at": "2025-11-25T10:30:00Z"
},
"details": [
{
"id": 45,
"product": 1,
"product_name": "纯棉印花布",
"quantity": 85.5,
"unit": 1,
"unit_display": "米",
"is_consumed": false,
"consume_with_id": null
}
]
}
4. 库存红冲(Stock Change Offset)
- URL:
POST /api/v1/stock-change/<id>/offset/ - 权限:登录员工,且仓库必须属于当前商户。
- 描述:针对已完成的库存变动记录生成反向库存记录,恢复库存数量并标记原快照
cancelled=true。
Request Body
{
"reason": "采购单作废,冲销库存",
"request_id": "rcf-20251201-0001", // 可选,幂等键
"extra_meta": { "source": "purchase_order", "operator": 18 }
}
注意:当前版本仅支持“全量红冲”,
items字段请留空;未来版本会按需要开放部分明细红冲能力。
Response
{
"status": "success",
"message": "红冲记录已创建",
"stock_change_record": {
"id": 602,
"type": 2,
"source_type": 11,
"source_id": 498,
"warehouse": 3,
"is_finished": true
},
"details": [
{
"id": 1880,
"product": 15,
"quantity": "100.00",
"unit": 1
}
],
"created_details_count": 1
}
错误返回
| HTTP | 状态 | 说明 |
|---|---|---|
| 400 | {"error": "仅允许对已完成的库存变动执行红冲"} |
原记录未完成或仍在处理中 |
| 400 | {"error": "该库存变动记录已执行红冲"} |
阻止重复红冲 |
| 403 | {"error": "无权访问该库存变动记录"} |
仓库不属于当前商户 |
| 404 | {"error": "库存变动记录ID xxx 不存在"} |
记录不存在 |
红冲成功后,会生成 source_type=OFFSET 的库存记录,source_id 指向原库存记录 ID;原 StockSnapshot 会设置 cancelled=true、offset_id=<新快照ID>,便于审计追踪。
5. Stock Snapshot List
- URL:
GET /api/v1/stock-snapshots/ - Description: Read-only list of
StockSnapshotentries. Supportslimit/offsetpagination,搜索与过滤。 - Query Parameters:
参数 说明 product/product_name/product_code指定产品或模糊搜索 warehouse/warehouse_name指定仓库或模糊搜索 stock_change_record关联的出入库记录 ID unit单位过滤 cancelledtrue/false,是否被标记取消has_offsettrue/false,筛选是否存在冲抵记录date_from/date_to创建时间范围( YYYY-MM-DD)search针对产品名、产品编码、仓库名的全文搜索 ordering排序字段,默认 -created_at
Response 示例:
{
"count": 2,
"results": [
{
"id": 901,
"product": 15,
"product_name": "纯棉印花布",
"warehouse": 3,
"warehouse_name": "严进仓",
"delta": "120.00",
"quantity_before": "80.00",
"quantity_after": "200.00",
"stock_change_record": 456,
"stock_change_record_type": "入库",
"stock_change_record_source": "采购",
"unit": 1,
"unit_display": "米",
"num_of_rolls": 3,
"offset_to": null,
"cancelled": false,
"created_at": "2025-11-25T12:05:00Z"
}
]
}
5. Merchant Auto Complete Setting
- URL:
POST /api/v1/set-merchant-auto-complete-stock-change/ - Description: 为当前商户开启 / 关闭“创建出入库记录后自动完成”功能。开启后,
create_*接口在事务内会立即调用stock.services.make_stock_change_completed,自动写入库存与快照。 - Request:
{
"auto_complete": true
}
- Response:
{
"status": "success"
}
只有具备员工身份的登录用户才可调用该接口。
6. Stock Change Completion Behavior
- 自动完成:当商户开启
auto_complete_stock_change时,任意模式的创建接口都会立即调用make_stock_change_completed,更新Inventory并生成StockSnapshot。 - 手动完成:当需要补处理或未开启自动完成时,可调用
POST /api/v1/stock-change/<id>/finish/手动触发make_stock_change_completed,也可直接在后台脚本里调用服务函数。 - 状态字段:
StockChangeRecord.is_finished/finished_at会在完成时标记,用于列表和详情接口判断记录是否已经生效。
7. Finish Stock Change Record (Manual)
- URL:
POST /api/v1/stock-change/<id>/finish/ - Description: 手动触发指定出入库记录的库存扣减与快照写入,适用于未开启自动完成或需要补处理的场景。仅当前商户下且仓库可见的员工可调用。
- Request: 无需请求体,只需保证 URL 中的
<id>为目标StockChangeRecord的 ID。 - Response:
{
"status": "success",
"message": "库存变动记录已标记为完成",
"stock_change_record": {
"id": 17,
"type": 1,
"warehouse": 1,
"warehouse_name": "严谨仓",
"source_type": 1,
"source_type_display": "采购",
"source_id": 123,
"is_finished": true,
"finished_at": "2025-11-25T12:30:00Z",
"created_at": "2025-11-25T11:50:00Z",
"created_by": "stock_admin",
"remarks": null
}
}
8. Stock Change Offset (Red Flush Placeholder)
- URL:
POST /api/v1/stock-change/<id>/offset/ - Description: 面向未来的库存红冲入口。当前仅提供占位实现,用于锁定最终接口形态;实际红冲逻辑尚未上线,因此调用会返回
501 Not Implemented,方便前端或上游业务在流程编排中预留节点。 - Request:
{
"reason": "审批错误,需要冲销",
"items": [
{
"product_id": 1,
"quantities": ["50.00"]
}
],
"request_id": "po-123-offset",
"extra_meta": {
"source": "purchase_order",
"operator": "warehouse_admin"
}
}
- Response(当前占位行为):
{
"error": "stock_offset_not_ready",
"message": "库存红冲功能尚未实现",
"record_id": 25
}
Examples
Example 1: Creating a Stock-in Record (Full Mode)
curl -X POST http://example.com/api/v1/stock-change/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token" \
-d '{
"type": 1,
"warehouse": 1,
"source_type": 1,
"products": [
{
"product": 1,
"quantity": [100.5, 75.3, 120.0]
}
]
}'
Example 2: Creating a Stock-out Record (Relaxed Mode)
curl -X POST http://example.com/api/v1/stock-change/relaxed/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token" \
-d '{
"type": 2,
"warehouse": 1,
"source_type": 6,
"products": [
{
"product": 2,
"quantity": {
"value": 250.8,
"unit_count": 2.5
}
}
]
}'
Example 3: Creating a Stock-out Record (Restricted Mode)
curl -X POST http://example.com/api/v1/stock-change/restrict/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token" \
-d '{
"type": 2,
"warehouse": 1,
"source_type": 6,
"products": [
{
"product": 3,
"quantity": [100.0, 50.0],
"consume_with": [45, 46]
}
]
}'
Example 4: Finish a Stock Change Record Manually
curl -X POST http://example.com/api/v1/stock-change/17/finish/ \
-H "Authorization: Bearer your_token"
Error Handling
Common Error Responses
Authentication Error
{
"error": "无权限访问"
}
Missing Required Parameters
{
"error": "缺少必要参数",
"message": "请提供 type, warehouse, source_type"
}
Validation Error
{
"error": "产品数据验证失败",
"details": {
"products": [
"产品列表中存在重复的产品ID"
]
}
}
Warehouse/Product Visibility Error
{
"error": "仓库ID 1 对当前用户不可见"
}
Business Logic Error
{
"error": "仓库出入库模式为【严进严出】,该模式暂未支持当前操作"
}
Business Rules
-
Warehouse Mode Restrictions:
- Full mode works with all warehouse modes
- Relaxed mode requires "unrestricted" (宽进宽出) or "restricted-in" (严进) warehouses
- Restricted mode requires "restricted-in-out" (严进严出) warehouses
-
Stock Change Validation:
- Stock-in can only use incoming source types (1, 2, 3, 4, 5)
- Stock-out can only use outgoing source types (6, 7, 8, 9, 10)
-
Restricted Mode Specific Rules:
- Outbound details must reference existing inbound details
- Referenced details must belong to the same warehouse
- Referenced details must not already be consumed
-
Permission Checks:
- Users can only access warehouses they have permission to see
- Users can only access products they have permission to see
- All stock change operations require proper authentication