From d75ce451be171de7460334b60ef93f0065db0671 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 22 Nov 2021 20:51:55 +1100
Subject: [PATCH 01/10] Allow user to select file format when downloadin BOM
 import template

(cherry picked from commit 8030ca0bb9be0ce564d041b406f0024512f99000)
---
 .../part/bom_upload/upload_file.html          |  8 +++-
 InvenTree/templates/js/translated/bom.js      | 43 ++++++++++++++++---
 2 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/InvenTree/part/templates/part/bom_upload/upload_file.html b/InvenTree/part/templates/part/bom_upload/upload_file.html
index 6775176ede..40411f074a 100644
--- a/InvenTree/part/templates/part/bom_upload/upload_file.html
+++ b/InvenTree/part/templates/part/bom_upload/upload_file.html
@@ -32,7 +32,7 @@
     <div class='alert alert-info alert-block'>
         <strong>{% trans "Requirements for BOM upload" %}:</strong>
         <ul>
-            <li>{% trans "The BOM file must contain the required named columns as provided in the " %} <strong><a href="/part/bom_template/">{% trans "BOM Upload Template" %}</a></strong></li>
+            <li>{% trans "The BOM file must contain the required named columns as provided in the " %} <strong><a href='#' id='bom-template-download'>{% trans "BOM Upload Template" %}</a></strong></li>
             <li>{% trans "Each part must already exist in the database" %}</li>
         </ul>
     </div>
@@ -60,4 +60,8 @@
 
 enableSidebar('bom-upload');
 
-{% endblock js_ready %}
+$('#bom-template-download').click(function() {
+    downloadBomTemplate();
+});
+
+{% endblock js_ready %}
\ No newline at end of file
diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js
index 3cde5bca61..29a958d452 100644
--- a/InvenTree/templates/js/translated/bom.js
+++ b/InvenTree/templates/js/translated/bom.js
@@ -2,6 +2,7 @@
 
 /* globals
     constructForm,
+    exportFormatOptions,
     imageHoverIcon,
     inventreeGet,
     inventreePut,
@@ -14,6 +15,7 @@
 */
 
 /* exported
+    downloadBomTemplate,
     newPartFromBomWizard,
     loadBomTable,
     loadUsedInTable,
@@ -21,12 +23,41 @@
     removeColFromBomWizard,
 */
 
-/* BOM management functions.
- * Requires follwing files to be loaded first:
- * - api.js
- * - part.js
- * - modals.js
- */
+function downloadBomTemplate(options={}) {
+
+    var format = options.format;
+
+    if (!format) {
+        format = inventreeLoad('bom-export-format', 'csv');
+    }
+
+    constructFormBody({}, {
+        title: '{% trans "Download BOM Template" %}',
+        fields: {
+            format: {
+                label: '{% trans "Format" %}',
+                help_text: '{% trans "Select file format" %}',
+                required: true,
+                type: 'choice',
+                value: format,
+                choices: exportFormatOptions(),
+            }
+        },
+        onSubmit: function(fields, opts) {
+            var format = getFormFieldValue('format', fields['format'], opts);
+
+            // Save the format for next time
+            inventreeSave('bom-export-format', format);
+
+            // Hide the modal
+            $(opts.modal).modal('hide');
+
+            // Download the file
+            location.href = `{% url "bom-upload-template" %}?format=${format}`;
+
+        }
+    });
+}
 
 
 function bomItemFields() {

From 88fc0393b73bd854e634d020f2fca0cef65bd9ed Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 22 Nov 2021 21:46:45 +1100
Subject: [PATCH 02/10] Logic fix for boolean fields in JS forms

(cherry picked from commit 10dec7743e083ccffdd819b36b231189b26ca8d9)
---
 InvenTree/templates/js/translated/forms.js | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/InvenTree/templates/js/translated/forms.js b/InvenTree/templates/js/translated/forms.js
index def7e41358..43e8d5ce62 100644
--- a/InvenTree/templates/js/translated/forms.js
+++ b/InvenTree/templates/js/translated/forms.js
@@ -811,7 +811,9 @@ function updateFieldValue(name, value, field, options) {
 
     switch (field.type) {
     case 'boolean':
-        el.prop('checked', value);
+        if (value == true || value.toString().toLowerCase() == 'true') {
+            el.prop('checked');
+        }
         break;
     case 'related field':
         // Clear?
@@ -2034,8 +2036,15 @@ function constructInputOptions(name, classes, type, parameters) {
     }
 
     if (parameters.value != null) {
-        // Existing value?
-        opts.push(`value='${parameters.value}'`);
+        if (parameters.type == 'boolean') {
+            // Special consideration of a boolean (checkbox) value
+            if (parameters.value == true || parameters.value.toString().toLowerCase() == 'true') {
+                opts.push('checked');
+            }
+        } else {
+            // Existing value?
+            opts.push(`value='${parameters.value}'`);
+        }
     } else if (parameters.default != null) {
         // Otherwise, a defualt value?
         opts.push(`value='${parameters.default}'`);

From 01ce752a8cd29df7d9c9d58f1d7d22e914247834 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 22 Nov 2021 21:51:32 +1100
Subject: [PATCH 03/10] BOM export options are now han

(cherry picked from commit c797eb07037237a6ce273d1783f99d43551f77de)
---
 InvenTree/part/forms.py                   | 30 ---------
 InvenTree/part/templates/part/detail.html |  8 +--
 InvenTree/part/views.py                   |  4 --
 InvenTree/templates/js/translated/bom.js  | 81 +++++++++++++++++++++++
 4 files changed, 82 insertions(+), 41 deletions(-)

diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py
index 609acec917..a5c4f87c89 100644
--- a/InvenTree/part/forms.py
+++ b/InvenTree/part/forms.py
@@ -55,36 +55,6 @@ class PartImageDownloadForm(HelperForm):
         ]
 
 
-class BomExportForm(forms.Form):
-    """ Simple form to let user set BOM export options,
-    before exporting a BOM (bill of materials) file.
-    """
-
-    file_format = forms.ChoiceField(label=_("File Format"), help_text=_("Select output file format"))
-
-    cascading = forms.BooleanField(label=_("Cascading"), required=False, initial=True, help_text=_("Download cascading / multi-level BOM"))
-
-    levels = forms.IntegerField(label=_("Levels"), required=True, initial=0, help_text=_("Select maximum number of BOM levels to export (0 = all levels)"))
-
-    parameter_data = forms.BooleanField(label=_("Include Parameter Data"), required=False, initial=False, help_text=_("Include part parameters data in exported BOM"))
-
-    stock_data = forms.BooleanField(label=_("Include Stock Data"), required=False, initial=False, help_text=_("Include part stock data in exported BOM"))
-
-    manufacturer_data = forms.BooleanField(label=_("Include Manufacturer Data"), required=False, initial=True, help_text=_("Include part manufacturer data in exported BOM"))
-
-    supplier_data = forms.BooleanField(label=_("Include Supplier Data"), required=False, initial=True, help_text=_("Include part supplier data in exported BOM"))
-
-    def get_choices(self):
-        """ BOM export format choices """
-
-        return [(x, x.upper()) for x in GetExportFormats()]
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-
-        self.fields['file_format'].choices = self.get_choices()
-
-
 class BomDuplicateForm(HelperForm):
     """
     Simple confirmation form for BOM duplication.
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index f1b47bc4e2..d16de22e1b 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -620,13 +620,7 @@
         });
 
         $("#download-bom").click(function () {
-            launchModalForm("{% url 'bom-export' part.id %}",
-                {
-                    success: function(response) {
-                        location.href = response.url;
-                    },
-                }
-            );
+            exportBom({{ part.id }});
         });
 
         {% if report_enabled %}
diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py
index 6e742dc571..af35cf9c1f 100644
--- a/InvenTree/part/views.py
+++ b/InvenTree/part/views.py
@@ -1192,14 +1192,10 @@ class BomExport(AjaxView):
     """
 
     model = Part
-    form_class = part_forms.BomExportForm
     ajax_form_title = _("Export Bill of Materials")
 
     role_required = 'part.view'
 
-    def get(self, request, *args, **kwargs):
-        return self.renderJsonResponse(request, self.form_class())
-
     def post(self, request, *args, **kwargs):
 
         # Extract POSTed form data
diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js
index 29a958d452..f345db6976 100644
--- a/InvenTree/templates/js/translated/bom.js
+++ b/InvenTree/templates/js/translated/bom.js
@@ -16,6 +16,7 @@
 
 /* exported
     downloadBomTemplate,
+    exportBom,
     newPartFromBomWizard,
     loadBomTable,
     loadUsedInTable,
@@ -60,6 +61,86 @@ function downloadBomTemplate(options={}) {
 }
 
 
+/**
+ * Export BOM (Bill of Materials) for the specified Part instance
+ */
+function exportBom(part_id, options={}) {
+
+    constructFormBody({}, {
+        title: '{% trans "Export BOM" %}',
+        fields: {
+            format: {
+                label: '{% trans "Format" %}',
+                help_text: '{% trans "Select file format" %}',
+                required: true,
+                type: 'choice',
+                value: inventreeLoad('bom-export-format', 'csv'),
+                choices: exportFormatOptions(),
+            },
+            cascading: {
+                label: '{% trans "Cascading" %}',
+                help_text: '{% trans "Download cascading / mmulti-level BOM" %}',
+                type: 'boolean',
+                value: inventreeLoad('bom-export-cascading', true),
+            },
+            levels: {
+                label: '{% trans "Levels" %}',
+                help_text: '{% trans "Select maximum number of BOM levels to export (0 = all levels)" %}',
+                type: 'integer',
+                value: 0,
+                min_value: 0,
+            },
+            parameter_data: {
+                label: '{% trans "Include Parameter Data" %}',
+                help_text: '{% trans "Include part  parameter data in exported BOM" %}',
+                type: 'boolean',
+                value: inventreeLoad('bom-export-parameter_data', false),
+            },
+            stock_data: {
+                label: '{% trans "Include Stock Data" %}',
+                help_text: '{% trans "Include part stock data in exported BOM" %}',
+                type: 'boolean',
+                value: inventreeLoad('bom-export-stock_data', false),
+            },
+            manufacturer_data: {
+                label: '{% trans "Include Manufacturer Data" %}',
+                help_text: '{% trans "Include part manufacturer data in exported BOM" %}',
+                type: 'boolean',
+                value: inventreeLoad('bom-export-manufacturer_data', false),
+            },
+            supplier_data: {
+                label: '{% trans "Include Supplier Data" %}',
+                help_text: '{% trans "Include part supplier data in exported BOM" %}',
+                type: 'boolean',
+                value: inventreeLoad('bom-export-supplier_data', false),
+            }
+        },
+        onSubmit: function(fields, opts) {
+
+            // Extract values from the form
+            var field_names = ['format', 'cascading', 'levels', 'parameter_data', 'stock_data', 'manufacturer_data', 'supplier_data'];
+
+            var url = `/part/${part_id}/bom-download/?`;
+
+            field_names.forEach(function(fn) {
+                var val = getFormFieldValue(fn, fields[fn], opts);
+
+                // Update user preferences
+                inventreeSave(`bom-export-${fn}`, val);
+
+                url += `${fn}=${val}&`;
+            });
+
+            $(opts.modal).modal('hide');
+
+            // Redirect to the BOM file download
+            location.href = url;
+        }
+    });
+
+}
+
+
 function bomItemFields() {
 
     return {

From 922b8b1c3078f599db00db5f3ad415589f1baad6 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 22 Nov 2021 22:17:13 +1100
Subject: [PATCH 04/10] Fix typo

(cherry picked from commit 673a5779f9dd08aee3b821104e8c4bec3c83280e)
---
 InvenTree/templates/js/translated/bom.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js
index f345db6976..ffd8195e07 100644
--- a/InvenTree/templates/js/translated/bom.js
+++ b/InvenTree/templates/js/translated/bom.js
@@ -79,7 +79,7 @@ function exportBom(part_id, options={}) {
             },
             cascading: {
                 label: '{% trans "Cascading" %}',
-                help_text: '{% trans "Download cascading / mmulti-level BOM" %}',
+                help_text: '{% trans "Download cascading / multi-level BOM" %}',
                 type: 'boolean',
                 value: inventreeLoad('bom-export-cascading', true),
             },

From 36026a9217bdbfe73fa0b71309f8af1175a34d27 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 13 Dec 2021 23:15:06 +1100
Subject: [PATCH 05/10] PEP fixes

---
 InvenTree/part/forms.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py
index a5c4f87c89..2d9ae4dc30 100644
--- a/InvenTree/part/forms.py
+++ b/InvenTree/part/forms.py
@@ -11,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _
 from mptt.fields import TreeNodeChoiceField
 
 from InvenTree.forms import HelperForm
-from InvenTree.helpers import GetExportFormats, clean_decimal
+from InvenTree.helpers import clean_decimal
 from InvenTree.fields import RoundingDecimalFormField
 
 import common.models

From 8d4f8204ca6f7551268728b3101a9f021fce46cf Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Mon, 13 Dec 2021 23:48:30 +1100
Subject: [PATCH 06/10] call apt-get update in workflow scripts

---
 .github/workflows/qc_checks.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index 929a299e93..04489e360d 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -229,6 +229,7 @@ jobs:
           cache: 'pip'
       - name: Install Dependencies
         run: |
+          sudo apt-get update
           sudo apt-get install libpq-dev
           pip3 install invoke
           pip3 install psycopg2
@@ -282,6 +283,7 @@ jobs:
           cache: 'pip'
       - name: Install Dependencies
         run: |
+          sudo apt-get update
           sudo apt-get install mysql-server libmysqlclient-dev
           pip3 install invoke
           pip3 install mysqlclient

From 967584b25a7fc4a8935c61a3a95abbbefdc9d1e2 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Tue, 14 Dec 2021 17:35:36 +1100
Subject: [PATCH 07/10] Specify mysql version

---
 .github/workflows/qc_checks.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index 04489e360d..41b00a785a 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -284,7 +284,7 @@ jobs:
       - name: Install Dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install mysql-server libmysqlclient-dev
+          sudo apt-get install mysql-server-8.0 mysql-client-8.0 libmysqlclient-dev
           pip3 install invoke
           pip3 install mysqlclient
           invoke install

From a9d09c7d2981d2bec8523ebb178ba57463d2c746 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Tue, 14 Dec 2021 19:56:34 +1100
Subject: [PATCH 08/10] Fix mysql installs for github actions

---
 .github/workflows/qc_checks.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index 41b00a785a..ba7a64f6d4 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -284,9 +284,9 @@ jobs:
       - name: Install Dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install mysql-server-8.0 mysql-client-8.0 libmysqlclient-dev
+          sudo apt-get install mysql-server-8.0 mysql-client-8.0 default-libmysqlclient-dev
           pip3 install invoke
-          pip3 install mysqlclient
+          pip3 install mysqlclient==2.1.0
           invoke install
       - name: Run Tests
         run: invoke test

From 070d01b2f41e297daa22435a2b6be9bd6ab08e55 Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Tue, 14 Dec 2021 22:48:44 +1100
Subject: [PATCH 09/10] Try with newer python

---
 .github/workflows/qc_checks.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index ba7a64f6d4..e0f4af3739 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -12,7 +12,7 @@ on:
       - l10*
 
 env:
-  python_version: 3.7
+  python_version: 3.8
   node_version: 16
 
   server_start_sleep: 60
@@ -284,9 +284,9 @@ jobs:
       - name: Install Dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install mysql-server-8.0 mysql-client-8.0 default-libmysqlclient-dev
+          sudo apt-get install mysql-server default-libmysqlclient-dev
           pip3 install invoke
-          pip3 install mysqlclient==2.1.0
+          pip3 install mysqlclient
           invoke install
       - name: Run Tests
         run: invoke test

From 4805540b4cd005b18f1936edc2dc6775e6792d9d Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Tue, 14 Dec 2021 22:52:14 +1100
Subject: [PATCH 10/10] try simplifying

---
 .github/workflows/qc_checks.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml
index e0f4af3739..598f518f27 100644
--- a/.github/workflows/qc_checks.yaml
+++ b/.github/workflows/qc_checks.yaml
@@ -284,7 +284,7 @@ jobs:
       - name: Install Dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install mysql-server default-libmysqlclient-dev
+          sudo apt-get install libmysqlclient-dev
           pip3 install invoke
           pip3 install mysqlclient
           invoke install