Artifact 13936dc824ed4706ab3e0858c79d3bd8dcbf2bc0a24b8201dc068a18f67088dd:
- File
backend/src/picking.gleam
— part of check-in
[5bb18ed4d4]
at
2026-10-23 03:34:10
on branch trunk
— 把来肯对接和本地库落到可切换的后端。
账号从环境读取,商品由人工增量同步,订单按五分钟轮询并缓存登录会话。开发期用 SQLite,同一套结构可切到 PostgreSQL。 (user: pluto size: 4022)
import gleam/json import gleam/list import gleam/string import ql361api.{type SalesOrder, type SalesOrderItem} pub type PickingMode { SingleOrder WavePicking } pub type OrderAllocation { OrderAllocation( order_code: String, slot_id: String, qty: Float, unit: String, ) } pub type PickingLineItem { PickingLineItem( sku_id: Int, goods_code: String, goods_name: String, barcode: String, spec: String, suggested_location: String, package_qty: Float, package_unit: String, base_qty: Float, base_unit: String, picked_base_qty: Float, allocations: List(OrderAllocation), ) } pub type PickingTask { PickingTask( task_no: String, warehouse_id: Int, warehouse_name: String, mode: String, source_order_codes: List(String), total_skus: Int, total_pieces: Float, status: String, items: List(PickingLineItem), ) } pub fn generate_single_order_picking(order: SalesOrder) -> PickingTask { let task_no = "PK-" <> order.bill_code let picking_items = list.map(order.items, fn(item: SalesOrderItem) { PickingLineItem( sku_id: item.sku_id, goods_code: item.goods_code, goods_name: item.goods_name, barcode: item.barcode, spec: item.spec, suggested_location: item.position_code, package_qty: item.package_qty, package_unit: item.package_unit, base_qty: item.base_qty, base_unit: item.base_unit, picked_base_qty: 0.0, allocations: [ OrderAllocation( order_code: order.bill_code, slot_id: order.bill_code, qty: item.base_qty, unit: item.base_unit, ), ], ) }) |> sort_by_location let total_pieces = list.fold(picking_items, 0.0, fn(acc, it) { acc +. it.base_qty }) PickingTask( task_no: task_no, warehouse_id: order.warehouse_id, warehouse_name: order.warehouse_name, mode: "SINGLE_ORDER", source_order_codes: [order.bill_code], total_skus: list.length(picking_items), total_pieces: total_pieces, status: "PENDING_PICK", items: picking_items, ) } fn sort_by_location(items: List(PickingLineItem)) -> List(PickingLineItem) { list.sort(items, fn(a, b) { string.compare(a.suggested_location, b.suggested_location) }) } pub fn task_to_json(task: PickingTask) -> json.Json { json.object([ #("task_no", json.string(task.task_no)), #("warehouse_id", json.int(task.warehouse_id)), #("warehouse_name", json.string(task.warehouse_name)), #("mode", json.string(task.mode)), #( "source_order_codes", json.array(task.source_order_codes, of: json.string), ), #("total_skus", json.int(task.total_skus)), #("total_pieces", json.float(task.total_pieces)), #("status", json.string(task.status)), #( "items", json.array(task.items, of: fn(item) { json.object([ #("sku_id", json.int(item.sku_id)), #("goods_code", json.string(item.goods_code)), #("goods_name", json.string(item.goods_name)), #("barcode", json.string(item.barcode)), #("spec", json.string(item.spec)), #("suggested_location", json.string(item.suggested_location)), #("package_qty", json.float(item.package_qty)), #("package_unit", json.string(item.package_unit)), #("base_qty", json.float(item.base_qty)), #("base_unit", json.string(item.base_unit)), #("picked_base_qty", json.float(item.picked_base_qty)), #( "allocations", json.array(item.allocations, of: fn(alloc) { json.object([ #("order_code", json.string(alloc.order_code)), #("slot_id", json.string(alloc.slot_id)), #("qty", json.float(alloc.qty)), #("unit", json.string(alloc.unit)), ]) }), ), ]) }), ), ]) }