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 5f4f817e7eee3794b96ab7792e7e9d0f56e0fc0392fdec0291a67201e6fcd9c8:


import gleam/dynamic/decode
import gleam/json
import gleam/option.{type Option, None, Some}
import gleam/result
import ql361api/client.{type Client}
import ql361api/json_codec
import ql361api/models.{
  type ApiError, type Page, type PurchaseOrder, type PurchaseOrderSummary, JsonError,
  Page, PurchaseOrder, PurchaseOrderItem, PurchaseOrderSummary,
}
import ql361api/orders

/// 来肯采购订单。状态 20 是待收货,入库仓库字段是 sinid / sinfullname。
pub const purchase_order_billtype = 504

pub const purchase_receipt_billtype = 501

pub const pending_receipt_status = 20

pub const posted_receipt_status = 20

pub const page_size = 100

pub fn fetch_purchase_order_page(
  client client: Client,
  begin_date begin_date: String,
  end_date end_date: String,
  status status: Option(Int),
  page page: Int,
  page_size page_size: Int,
) -> Result(Page(PurchaseOrderSummary), ApiError) {
  fetch_bill_page(
    client,
    purchase_order_billtype,
    begin_date,
    end_date,
    status,
    page,
    page_size,
  )
}

pub fn fetch_purchase_receipt_page(
  client client: Client,
  begin_date begin_date: String,
  end_date end_date: String,
  page page: Int,
  page_size page_size: Int,
) -> Result(Page(PurchaseOrderSummary), ApiError) {
  fetch_bill_page(
    client,
    purchase_receipt_billtype,
    begin_date,
    end_date,
    Some(posted_receipt_status),
    page,
    page_size,
  )
}

fn fetch_bill_page(
  client: Client,
  billtype: Int,
  begin_date: String,
  end_date: String,
  status: Option(Int),
  page: Int,
  page_size: Int,
) -> Result(Page(PurchaseOrderSummary), ApiError) {
  let condition = [
    #("begindate", json.string(begin_date)),
    #("enddate", json.string(end_date)),
    #("billtype", json.int(billtype)),
  ]
  let condition = case status {
    Some(value) -> [#("status", json.int(value)), ..condition]
    None -> condition
  }

  let payload =
    json.object([
      #(
        "reportparam",
        json.object([
          #("orders", json.string("")),
          #("parid", json.int(0)),
          #("pagetype", json.string("erp")),
          #("displaytype", json.string("tree")),
          #("pagerow", json.int(page_size)),
          #("pagenumber", json.int(page)),
        ]),
      ),
      #("conditionparam", json.object(condition)),
    ])
    |> json.to_string

  use raw_json <- result.try(
    client.post_rpc(client, orders.query_orders_method, "erp", payload),
  )
  parse_purchase_orders_body(raw_json)
}

pub fn fetch_purchase_order_detail(
  client client: Client,
  bill_id bill_id: Int,
) -> Result(PurchaseOrder, ApiError) {
  fetch_bill_detail(client, purchase_order_billtype, bill_id)
}

pub fn fetch_purchase_receipt_detail(
  client client: Client,
  bill_id bill_id: Int,
) -> Result(PurchaseOrder, ApiError) {
  fetch_bill_detail(client, purchase_receipt_billtype, bill_id)
}

fn fetch_bill_detail(
  client: Client,
  billtype: Int,
  bill_id: Int,
) -> Result(PurchaseOrder, ApiError) {
  let payload =
    json.object([
      #("billid", json.int(bill_id)),
      #("billtype", json.int(billtype)),
    ])
    |> json.to_string

  use raw_json <- result.try(
    client.post_rpc(client, orders.get_full_data_method, "erp", payload),
  )
  parse_purchase_detail_body(raw_json)
}

pub fn parse_purchase_orders_body(
  body: String,
) -> Result(Page(PurchaseOrderSummary), ApiError) {
  let summary_decoder = {
    use bill_id <- decode.field("billid", json_codec.int())
    use bill_code <- decode.optional_field("billcode", "", decode.string)
    use supplier_name <- decode.optional_field("dfullname", "", decode.string)
    use contact_person <- decode.optional_field("contactor", "", decode.string)
    use phone <- decode.optional_field("phone", "", decode.string)
    use warehouse_name <- decode.optional_field("sinfullname", "", decode.string)
    use warehouse_id <- decode.optional_field("sinid", 0, json_codec.int())
    use bill_date <- decode.optional_field("billdate", "", decode.string)
    use order_status <- decode.optional_field("status", 0, json_codec.int())
    use status_name <- decode.optional_field("statusname", "", decode.string)
    use total_qty <- decode.optional_field("qty", 0.0, json_codec.number())
    use total_money <- decode.optional_field("totalmoney", 0.0, json_codec.number())
    use remark <- decode.optional_field("remark", "", decode.string)
    use ifred <- decode.optional_field("ifred", 0, json_codec.int())
    decode.success(PurchaseOrderSummary(
      bill_id: bill_id,
      bill_code: bill_code,
      supplier_name: supplier_name,
      contact_person: contact_person,
      phone: phone,
      warehouse_name: warehouse_name,
      warehouse_id: warehouse_id,
      bill_date: bill_date,
      status: order_status,
      status_name: status_name,
      total_qty: total_qty,
      total_money: total_money,
      remark: remark,
      ifred: ifred,
    ))
  }

  let data_decoder = {
    use items <- decode.field("datasource", decode.list(of: summary_decoder))
    use total <- decode.optional_field("rowcount", 0, json_codec.int())
    decode.success(Page(items: items, total: total))
  }

  let wrapper_decoder = {
    use data <- decode.field("data", data_decoder)
    decode.success(data)
  }

  case json.parse(body, wrapper_decoder) {
    Ok(page) -> Ok(page)
    Error(_) -> Error(JsonError("采购订单列表响应无法解析"))
  }
}

pub fn parse_purchase_detail_body(body: String) -> Result(PurchaseOrder, ApiError) {
  let item_decoder = {
    use bill_detail_id <- decode.optional_field("billdetailid", 0, json_codec.int())
    use sku_id <- decode.optional_field("skuid", 0, json_codec.int())
    use goods_code <- decode.optional_field("gcode", "", decode.string)
    use goods_name <- decode.optional_field("gfullname", "", decode.string)
    use barcode <- decode.optional_field("barcode", "", decode.string)
    use spec <- decode.optional_field("spec", "", decode.string)
    use package_qty <- decode.optional_field("mqty", 0.0, json_codec.number())
    use package_unit <- decode.optional_field("mufullname", "", decode.string)
    use base_qty <- decode.optional_field("qty", 0.0, json_codec.number())
    use base_unit <- decode.optional_field("bufullname", "", decode.string)
    use price <- decode.optional_field("price", 0.0, json_codec.number())
    use total_money <- decode.optional_field("totalmoney", 0.0, json_codec.number())
    use position_code <- decode.optional_field("gpcode", "", decode.string)
    use area_code <- decode.optional_field("sacode", "", decode.string)
    decode.success(PurchaseOrderItem(
      bill_detail_id: bill_detail_id,
      sku_id: sku_id,
      goods_code: goods_code,
      goods_name: goods_name,
      barcode: barcode,
      spec: spec,
      package_qty: package_qty,
      package_unit: package_unit,
      base_qty: base_qty,
      base_unit: base_unit,
      price: price,
      total_money: total_money,
      position_code: position_code,
      area_code: area_code,
    ))
  }

  let body0_decoder = {
    use datasource <- decode.field("datasource", decode.list(of: item_decoder))
    decode.success(datasource)
  }

  let header_decoder = {
    use bill_id <- decode.field("billid", json_codec.int())
    use bill_code <- decode.optional_field("billcode", "", decode.string)
    use supplier_name <- decode.optional_field("dfullname", "", decode.string)
    use contact_person <- decode.optional_field("contactor", "", decode.string)
    use phone <- decode.optional_field("phone", "", decode.string)
    use warehouse_name <- decode.optional_field("sinfullname", "", decode.string)
    use warehouse_id <- decode.optional_field("sinid", 0, json_codec.int())
    use bill_date <- decode.optional_field("billdate", "", decode.string)
    use order_status <- decode.optional_field("status", 0, json_codec.int())
    use status_name <- decode.optional_field("statusname", "", decode.string)
    use total_qty <- decode.optional_field("qty", 0.0, json_codec.number())
    use total_money <- decode.optional_field("totalmoney", 0.0, json_codec.number())
    use remark <- decode.optional_field("remark", "", decode.string)
    decode.success(#(
      bill_id,
      bill_code,
      supplier_name,
      contact_person,
      phone,
      warehouse_name,
      warehouse_id,
      bill_date,
      order_status,
      status_name,
      total_qty,
      total_money,
      remark,
    ))
  }

  let data_decoder = {
    use header <- decode.field("header", header_decoder)
    use body0 <- decode.field("body0", body0_decoder)
    decode.success(PurchaseOrder(
      bill_id: header.0,
      bill_code: header.1,
      supplier_name: header.2,
      contact_person: header.3,
      phone: header.4,
      warehouse_name: header.5,
      warehouse_id: header.6,
      bill_date: header.7,
      status: header.8,
      status_name: header.9,
      total_qty: header.10,
      total_money: header.11,
      remark: header.12,
      items: body0,
    ))
  }

  let wrapper_decoder = {
    use data <- decode.field("data", data_decoder)
    decode.success(data)
  }

  case json.parse(body, wrapper_decoder) {
    Ok(order) -> Ok(order)
    Error(_) -> Error(JsonError("采购订单明细响应无法解析"))
  }
}

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.