diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html
index e4b527097a..365931a3ec 100644
--- a/InvenTree/build/templates/build/allocate.html
+++ b/InvenTree/build/templates/build/allocate.html
@@ -24,53 +24,11 @@
{% block js_ready %}
{{ block.super }}
- function makeInnerTable(pk) {
- var table = "
";
- return table;
- }
-
- $('#build-table').bootstrapTable({
- sortable: true,
- detailView: true,
- detailFormatter: function(index, row, element) {
- return makeInnerTable(row.pk);
- },
- onExpandRow: function(index, row, $detail) {
- $('#part-table-' + row.pk).bootstrapTable({
- columns: [
- {
- field: 'stock_item_detail.location_name',
- title: 'Location',
- },
- {
- field: 'stock_item_detail.quantity',
- title: 'Available',
- },
- {
- field: 'quantity',
- title: 'Allocated',
- },
- ],
- url: "/api/build/item/?build={{ build.pk }}&part=" + row.sub_part,
- });
- },
- columns: [
- {
- field: 'sub_part_detail.name',
- title: 'Part',
- },
- {
- title: 'Source',
- },
- {
- field: 'quantity',
- title: 'Quantity',
- },
- ],
- });
-
- getBomList({part: {{ build.part.id }}}).then(function(response) {
- $("#build-table").bootstrapTable('load', response);
- });
+ makeBuildTable($('#build-table'),
+ {
+ build: {{ build.pk }},
+ part: {{ build.part.pk }},
+ }
+ );
{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/static/script/inventree/build.js b/InvenTree/static/script/inventree/build.js
new file mode 100644
index 0000000000..7e31fdae81
--- /dev/null
+++ b/InvenTree/static/script/inventree/build.js
@@ -0,0 +1,106 @@
+function makeBuildTable(table, options) {
+ /* Construct a table for allocation items to a build.
+ * Each row contains a sub_part for the BOM.
+ * Each row can be expended to allocate stock items against that part.
+ *
+ * options:
+ * build - ID of the build object
+ * part - ID of the part object for the build
+ *
+ */
+
+ table.bootstrapTable({
+ sortable: false,
+ detailView: true,
+ detailFormatter: function(index, row, element) {
+ return makeAllocationTable({
+ part: row.pk
+ });
+ },
+ onExpandRow: function(index, row, $detail) {
+ fillAllocationTable(
+ $("#part-table-" + row.pk),
+ row,
+ {
+ build: options.build
+ },
+ );
+ },
+ columns: [
+ {
+ field: 'sub_part_detail.name',
+ title: 'Part',
+ },
+ {
+ field: 'quantity',
+ title: 'Required',
+ },
+ {
+ field: 'allocated',
+ title: 'Allocated',
+ }
+ ],
+ });
+
+ getBomList(
+ {
+ part: options.part
+ }).then(function(response) {
+ table.bootstrapTable('load', response)
+ });
+}
+
+
+function makeAllocationTable(options) {
+ /* Construct an allocation table for a single row
+ * in the Build table.
+ * Each allocation table is a 'detailView' of a parent Part row
+ *
+ * Options:
+ * part: Primary key of the part item
+ */
+
+ var table = "";
+
+ return table;
+}
+
+function fillAllocationTable(table, parent_row, options) {
+ /* Load data into an allocation table,
+ * and update the total stock allocation count in the parent row.
+ *
+ * table - the part allocation table
+ * row - parent row in the build allocation table
+ *
+ * options:
+ * build - pk of the Build object
+ */
+
+ table.bootstrapTable({
+ columns: [
+ {
+ field: 'stock_item_detail',
+ title: 'Stock Item',
+ formatter: function(value, row, index, field) {
+ return '' + value.quantity + ' x ' + value.part_name;
+ },
+ },
+ {
+ field: 'stock_item_detail.location_name',
+ title: 'Location',
+ },
+ {
+ field: 'stock_item_detail.quantity',
+ title: 'Available',
+ },
+ {
+ field: 'quantity',
+ title: 'Allocated'
+ },
+ ],
+ url: "/api/build/item?build=" + options.build + "&part=" + parent_row.sub_part,
+ });
+}
\ No newline at end of file