Fosi Fossil Service
Small teams. Open source. Built on Fossil.

IaC / SwiftFlow

High-performance WMS with wave picking, smart routing, and real-time inventory visibility.

Public | Owner: IaC | Default branch: trunk | Last update: 2026-10-23 14:37

Artifact 13936dc824ed4706ab3e0858c79d3bd8dcbf2bc0a24b8201dc068a18f67088dd:


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)),
              ])
            }),
          ),
        ])
      }),
    ),
  ])
}

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/IaC/SwiftFlow

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.