In Manufacturing, Configuration Is All You Need
OK, it's not all you need. You also need good people, good processes, etc. But in order to do instant website-to-production for custom manufacturing, you need to be able to automatically configure your bill of material and routing.
From a customer's perspective, the process looks something like this:
- A customer makes a request in a web portal
- The customer immediately receives a quote with the price and lead time for their request
- The customer places an order directly from the portal
- The order is automatically placed in the production queue
In order to achieve points 2 and 4, you need to be able to automatically determine what materials will be required to make the product (bill of materials), and what production steps will be required to make the product (routing).
What is Configuration?
Configuration is the set of functions that map your unique manufacturing parameters to the standard bill of material and routing.
Defining the Parameters
Let's say we're a door manufacturer. In order to do instant quoting-to-production, we need to create at an accurate bill of material and bill of process (routing) for each door. But customers can choose the exact dimensions of their door, they can choose the material, the hinges, etc.
It doesn't make sense for us to try to maintain a database of every possible door combination for two reasons.
- It's not scalable. Even with 3 or 4 variables, we can't possibly manually support every possible door configuration.
- It's impossible to maintain. Say we make a process improvement. We'd have to update the routing for every combination.
So we need a way to instantly create an accurate bill of material and routing (and cost estimate) for any possible door configuration from a constantly-evolving template.
Let's take a look at a few examples.
Example 1: Doors
Here's a simple example of how we might "define" a door to be manufactured represented in TypeScript:
type Params = {
wood: "Oak" | "Maple" | "Walnut" | "Cherry" | "Pine";
width: number;
height: number;
hinges: "Left" | "Right";
lock: "Single" | "Double";
};
If we look at a sheet metal part, we have a similar situation.
Example 2: Sheet Metal
type Params = {
material: "Aluminum" | "Steel" | "Stainless Steel";
thickness: "0.25" | "0.5" | "0.75" | "1";
width: number;
height: number;
cutDistance: number;
};
We might add parameters like number of bends, number of holes, etc. But the gist is the same. We have a set of parameters that can determine the bill of material and routing.
It might seem like a big leap, but the same idea holds true for any discrete manufacturing that is not mass-produced. Here's a slight oversimplified example of how a boat might be configured:
Example 3: Boat
type Params = {
engine: "XSB" | "XSB2";
autopilot: boolean;
color: "Red" | "Blue" | "Green" | "Yellow";
secondStation: boolean;
upholstery: "Gray" | "Navy";
ledUpgrades: boolean;
navigationUpgrade: boolean;
};
The idea is that for any made-to-order or made-to-print part, we can define a set of parameters that can determine the bill of material and routing.
Using the Configuration
OK, so now that we understand the problem, let's jump to the solution. The solution for instant website-to-production can be generalized into three steps:
- A customer-facing app allows the customer to select some options. This can basically be reduced to a set of dropdowns and checkboxes (and depending on the business, a CAD model and a drawing).
- Some proprietary system takes the inputs of step 1, and turns them into a set of parameters (like we defined above). In the sheet metal example, this might be an API that determines the cut length and number of bends from a CAD model. For a door and boat manufacturer, we might skip this step and just use the parameters from the customer-facing app.
- The system of record configures the BoM and routing by passing the parameters from step 2 and returns price back.
Here's a simplified look at how step 3 would work with the Carbon SDK:
const carbon = getCarbon();
// this comes from step 1 and step 2
const configuration = {
material: "Oak",
width: 36,
height: 80,
hinges: "Left",
lock: "Single",
};
const quote = await upsertQuote(carbon, {
customerId,
customerLocationId,
});
const quoteLine = await upsertConfiguredQuoteLine(carbon, {
quoteId: quote.data.id,
itemId: "DOOR",
quantity: [1, 10, 100],
configuration,
});
const prices = await getQuotePrices(carbon, {
quoteLineId: quoteLine.data.id,
markup: 0.3,
});
return prices.data;
Defining the Template
The careful reader might have noticed that we've so far said nothing about the configuration itself. Now that we know what we're trying to do, let's take a look at how the sausage is made.
A configuration is a function that takes the set of parameters and returns a value. It's like a little lambda function that you can use to define each aspect of the bill of material and routing.
// Setup time
/**
* Configure function that processes the provided params
* @returns an array of predefined values
* @param params.material: "Oak"
* @param params.width: number
* @param params.height: number
* @param params.hinges: "Left" | "Right"
* @param params.lock: "Single" | "Double"
**/
function configure(params: Params) {
if (params.material === "Pine") {
return 10;
}
return 20;
}
In this case, we're configuring setup time. Here's an example of how we might configure the material of the door.
// Item ID
function configure(params: Params): string {
const itemIds = {
Pine: "1234567890",
Oak: "1234567891",
Maple: "1234567892",
};
return itemIds[params.material];
}
For any field in the bill of material or routing, we can define a configuration function that takes the set of parameters and returns the value. We can get more sophisticated to include more complex logic for adding and removing parts and operations, but the idea is the same.
Conclusion
Configuration allows made-to-order or made-to-print manufacturers to instantly create the bill of material and routing that drives production.
If you're interested in learning more about CarbonOS, reach out and we'll schedule a call.