Skip to main content

Tutorial: Using GraphQL as a batch picking backend

This tutorial describes how to use the SELVEO GraphQL as a backend for your own batch picking implementation/frontend.

Updated over 3 years ago

Prerequisites

This tutorial assumes that you already:

  • Created a selection list with the orders you want to batch pick

  • Added orders to that selection list

  • Have a physical wagon with barcodes on it and optionally totes with barcodes on them to place on the wagon

  • Are familiar with SELVEO GraphQL.

Overview

In this tutorial, we are going to:

  1. Create a (virtual) tote type representing the type of tote you will use for batch picking.

  2. Create a wagon type.

  3. Use SELVEO to generate product transfers for assigning orders to the wagon.

  4. Assign product transfers to totes on the wagon.

Creating a tote type

First of all, we are going to create a tote type to represent the physical totes that are placed on the wagon shelves. You only need one tote type for each unique kind of tote you have. Typically this will only be 1 or 2 different types. You cannot create more than five tote types.

If you pick directly onto the wagon shelves and not into totes, you will create a "virtual" tote type following the barcode pattern on the wagon.

Creating a tote type requires you to specify a barcode prefix. We recommend using the prefix T- so that tote barcodes are called T-0001, T-0002, T-0003, and so forth. The prefix is used to create totes dynamically.

Use the following GraphQL Mutation to create a tote type:

mutation CreateToteType($prefix: String!, $volume: Float!) {
createToteType(attributes: {prefix: $prefix, volume: $volume, volume_unit: "cm3"}) {
created {
_id
}
}
}

The volume is a field reserved for future usage and is currently not used for anything. For now, you can type something arbitrary like 1000.

After running the mutation, save the newly created tote types _id for the next step.

Creating a wagon type

Next, we will create a wagon type. A wagon type also needs a way to dynamically identify the wagon to create wagons behind the scenes. In this tutorial, we assume your wagons to have a barcode system starting with W followed by any series of numbers.

Wagon position barcodes (the barcodes on each shelf position) must currently follow the pattern wagonBarcode-01, wagonBarcode-02, etc.

A wagon type must also have one or more layouts. A layout tells SELVEO how many shelves the wagon has and how many totes fit on each shelf. Each layout has an associated tote type; you might be able to fit four larger totes on one shelf, whereas eight smaller totes might fit side by side on the same shelf. That would create two layouts, one for each tote type.

In this tutorial, we'll create only one layout for the tote type we just created, which also makes things easier:

mutation CreateWagonType($toteTypeID: String!, $totesPerShelf: Int!, $shelvesOnWagon: Int!) {
createWagonType(attributes: {
layouts: [{tote_type_id: $toteTypeID, height: $shelvesOnWagon, width: $totesPerShelf, depth: 1}],
matchers:[{type:"regex", pattern:"^W\\d+$"}]
}) {
created {
_id
}
}
}

Generating product transfers

Having created a wagon and tote type, we are now ready to reserve some orders for picking. We will use the reserveNextOrdersForPicking mutation to do so. Note! If you run the mutation multiple times, you will not get the same orders, and eventually, you won't get any. This is because SELVEO keeps track of which orders are already being picked so that no orders will accidentally get picked twice.

Product transfers in the source stage, i.e., products that have not yet been moved from the location into the tote, will automatically expire after 12 hours. This period can be changed by specifying the reservation_seconds parameter on the mutation. When all transfers on a specific order have expired, the order will be released back into the picking queue.

mutation ReserveForBatchPicking($list: String!, $wagonBarcode: String!) {
reserveNextOrdersForPicking(selection_list: $list, wagon_identifier: $wagonBarcode) {
transfers {
_id
batch_id
sub_batch_id
quantity
product {
ssin
barcodes
name
}
source_stage {
...StageAttributes
}
via_stage {
...StageAttributes
}
}
}
}

fragment StageAttributes on ProductTransferStage {
__typename
... on Location {
location
}
... on Tote {
identifier
}
}

In this case, the batch_id is the wagon barcode, and sub_batch_id is the order number. These can be used to look up transfers on that particular wagon (or order).

After running the mutation, you will get a sorted list of transfers.

Assigning orders to totes

You now have a list of product transfers ready to be picked and where to pick them from. Use this list to generate a picking list.

If you're creating a simple pick-by-paper implementation, just run it immediately for all transfers; else, run it every time a picker scans a product/location and a tote.

For each product transfer, call the following mutation:

mutation PickProduct($transferID: String!, $wagonBarcode: String!, $wagonPositionBarcode:String!, $toteBarcode: String, $quantity:Float!) {
assignProductTransferToWagonTote(pick_product_into_batch: {
tote_identifier: $toteBarcode,
transfer_id: $transferID,
wagon_identifier: $wagonBarcode,
wagon_position_barcode:$wagonPositionBarcode,
quantity:$quantity
}) {
success
updated_transfers {
_id
via_stage {
... on Tote {
identifier
}
}
}
}
}

This will assign the specified product transfer to the tote on the wagon position you specified and mark it as picked (set current_stage to via).

All the "sibling transfers", i.e. all the other transfers for the same order, will be assigned to the same tote. You can access those transfers to update your UI via the updated_transfers selection field.

Variable explanation:

  • transferID: The ID of the product transfer you're working with

  • wagonBarcode: The barcode of the wagon barcode you're working on, i.e., W02.

  • wagonPositionBarcode: The shelf position barcode from the wagon, i.e., W02-03

  • quantity: The of products picked. This will typically be the same as the transfers quantity attribute unless only a smaller amount was picked.

  • toteBarcode: (optional) The barcode of the tote you placed the products into.

Did this answer your question?