2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Remove references to old setting (#8018)

* Remove references to old setting

- Now offloaded to plugins

* Remove REPORT_ENABLE_TEST_REPORT setting

* Cleanup

* Add new boolean setting to control whether reports are attached automatically

* Attach generated report to model instance

* Update unit testing

* Bump API version
This commit is contained in:
Oliver 2024-09-06 15:15:16 +10:00 committed by GitHub
parent 9f92475af0
commit 07fac28b76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 86 additions and 36 deletions

View File

@ -1,13 +1,16 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 250 INVENTREE_API_VERSION = 251
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v251 - 2024-09-06 : https://github.com/inventree/InvenTree/pull/8018
- Adds "attach_to_model" field to the ReporTemplate model
v250 - 2024-09-04 : https://github.com/inventree/InvenTree/pull/8069 v250 - 2024-09-04 : https://github.com/inventree/InvenTree/pull/8069
- Fixes 'revision' field definition in Part serializer - Fixes 'revision' field definition in Part serializer

View File

@ -1704,20 +1704,6 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'default': 'A4', 'default': 'A4',
'choices': report.helpers.report_page_size_options, 'choices': report.helpers.report_page_size_options,
}, },
'REPORT_ENABLE_TEST_REPORT': {
'name': _('Enable Test Reports'),
'description': _('Enable generation of test reports'),
'default': True,
'validator': bool,
},
'REPORT_ATTACH_TEST_REPORT': {
'name': _('Attach Test Reports'),
'description': _(
'When printing a Test Report, attach a copy of the Test Report to the associated Stock Item'
),
'default': False,
'validator': bool,
},
'SERIAL_NUMBER_GLOBALLY_UNIQUE': { 'SERIAL_NUMBER_GLOBALLY_UNIQUE': {
'name': _('Globally Unique Serials'), 'name': _('Globally Unique Serials'),
'description': _('Serial numbers for stock items must be globally unique'), 'description': _('Serial numbers for stock items must be globally unique'),

View File

@ -228,9 +228,6 @@ class SettingsTest(InvenTreeTestCase):
report_size_obj = InvenTreeSetting.get_setting_object( report_size_obj = InvenTreeSetting.get_setting_object(
'REPORT_DEFAULT_PAGE_SIZE' 'REPORT_DEFAULT_PAGE_SIZE'
) )
report_test_obj = InvenTreeSetting.get_setting_object(
'REPORT_ENABLE_TEST_REPORT'
)
# check settings base fields # check settings base fields
self.assertEqual(instance_obj.name, 'Server Instance Name') self.assertEqual(instance_obj.name, 'Server Instance Name')
@ -260,7 +257,6 @@ class SettingsTest(InvenTreeTestCase):
# check setting_type # check setting_type
self.assertEqual(instance_obj.setting_type(), 'string') self.assertEqual(instance_obj.setting_type(), 'string')
self.assertEqual(report_test_obj.setting_type(), 'boolean')
self.assertEqual(stale_days.setting_type(), 'integer') self.assertEqual(stale_days.setting_type(), 'integer')
# check as_int # check as_int
@ -269,9 +265,6 @@ class SettingsTest(InvenTreeTestCase):
instance_obj.as_int(), 'InvenTree' instance_obj.as_int(), 'InvenTree'
) # not an int -> return default ) # not an int -> return default
# check as_bool
self.assertEqual(report_test_obj.as_bool(), True)
# check to_native_value # check to_native_value
self.assertEqual(stale_days.to_native_value(), 0) self.assertEqual(stale_days.to_native_value(), 0)

View File

@ -350,6 +350,15 @@ class ReportPrint(GenericAPIView):
output = template.render(instance, request) output = template.render(instance, request)
if template.attach_to_model:
# Attach the generated report to the model instance
data = output.get_document().write_pdf()
instance.create_attachment(
attachment=ContentFile(data, report_name),
comment=_('Report saved at time of printing'),
upload_user=request.user,
)
# Provide generated report to any interested plugins # Provide generated report to any interested plugins
for plugin in registry.with_mixin('report'): for plugin in registry.with_mixin('report'):
try: try:

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.15 on 2024-09-05 23:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('report', '0027_alter_labeltemplate_model_type_and_more'),
]
operations = [
migrations.AddField(
model_name='labeltemplate',
name='attach_to_model',
field=models.BooleanField(default=False, help_text='Save report output as an attachment against linked model instance when printing', verbose_name='Attach to Model on Print'),
),
migrations.AddField(
model_name='reporttemplate',
name='attach_to_model',
field=models.BooleanField(default=False, help_text='Save report output as an attachment against linked model instance when printing', verbose_name='Attach to Model on Print'),
),
]

View File

@ -163,6 +163,14 @@ class ReportTemplateBase(MetadataMixin, InvenTree.models.InvenTreeModel):
editable=False, editable=False,
) )
attach_to_model = models.BooleanField(
default=False,
verbose_name=_('Attach to Model on Print'),
help_text=_(
'Save report output as an attachment against linked model instance when printing'
),
)
def generate_filename(self, context, **kwargs): def generate_filename(self, context, **kwargs):
"""Generate a filename for this report.""" """Generate a filename for this report."""
template_string = Template(self.filename_pattern) template_string = Template(self.filename_pattern)

View File

@ -42,6 +42,7 @@ class ReportSerializerBase(InvenTreeModelSerializer):
'filename_pattern', 'filename_pattern',
'enabled', 'enabled',
'revision', 'revision',
'attach_to_model',
] ]
template = InvenTreeAttachmentSerializerField(required=True) template = InvenTreeAttachmentSerializerField(required=True)

View File

@ -555,8 +555,16 @@ class TestReportTest(PrintTestMixins, ReportTest):
template = ReportTemplate.objects.filter( template = ReportTemplate.objects.filter(
enabled=True, model_type='stockitem' enabled=True, model_type='stockitem'
).first() ).first()
self.assertIsNotNone(template) self.assertIsNotNone(template)
# Ensure that the 'attach_to_model' attribute is initially False
template.attach_to_model = False
template.save()
template.refresh_from_db()
self.assertFalse(template.attach_to_model)
url = reverse(self.print_url) url = reverse(self.print_url)
# Try to print without providing a valid StockItem # Try to print without providing a valid StockItem
@ -568,18 +576,37 @@ class TestReportTest(PrintTestMixins, ReportTest):
# Now print with a valid StockItem # Now print with a valid StockItem
item = StockItem.objects.first() item = StockItem.objects.first()
n = item.attachments.count()
response = self.post( response = self.post(
url, {'template': template.pk, 'items': [item.pk]}, expected_code=201 url, {'template': template.pk, 'items': [item.pk]}, expected_code=201
) )
# There should be a link to the generated PDF # There should be a link to the generated PDF
self.assertEqual(response.data['output'].startswith('/media/report/'), True) self.assertTrue(response.data['output'].startswith('/media/report/'))
self.assertTrue(response.data['output'].endswith('.pdf'))
# By default, this should *not* have created an attachment against this stockitem # By default, this should *not* have created an attachment against this stockitem
self.assertEqual(n, item.attachments.count())
self.assertFalse( self.assertFalse(
Attachment.objects.filter(model_id=item.pk, model_type='stockitem').exists() Attachment.objects.filter(model_id=item.pk, model_type='stockitem').exists()
) )
# Now try again, but attach the generated PDF to the StockItem
template.attach_to_model = True
template.save()
response = self.post(
url, {'template': template.pk, 'items': [item.pk]}, expected_code=201
)
# A new attachment should have been created
self.assertEqual(n + 1, item.attachments.count())
attachment = item.attachments.order_by('-pk').first()
# The attachment should be a PDF
self.assertTrue(attachment.attachment.name.endswith('.pdf'))
def test_mdl_build(self): def test_mdl_build(self):
"""Test the Build model.""" """Test the Build model."""
self.run_print_test(Build, 'build', label=False) self.run_print_test(Build, 'build', label=False)

View File

@ -54,19 +54,15 @@
</div> </div>
{% endif %} {% endif %}
<!-- Document / label menu --> <!-- Document / label menu -->
{% if test_report_enabled or labels_enabled %}
<div class='btn-group' role='group'> <div class='btn-group' role='group'>
<button id='document-options' title='{% trans "Printing actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'><span class='fas fa-print'></span> <span class='caret'></span></button> <button id='document-options' title='{% trans "Printing actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'><span class='fas fa-print'></span> <span class='caret'></span></button>
<ul class='dropdown-menu' role='menu'> <ul class='dropdown-menu' role='menu'>
{% if labels_enabled %} {% if labels_enabled %}
<li><a class='dropdown-item' href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li> <li><a class='dropdown-item' href='#' id='print-label'><span class='fas fa-tag'></span> {% trans "Print Label" %}</a></li>
{% endif %} {% endif %}
{% if test_report_enabled %} <li><a class='dropdown-item' href='#' id='stock-test-report'><span class='fas fa-file-pdf'></span> {% trans "Print Report" %}</a></li>
<li><a class='dropdown-item' href='#' id='stock-test-report'><span class='fas fa-file-pdf'></span> {% trans "Test Report" %}</a></li>
{% endif %}
</ul> </ul>
</div> </div>
{% endif %}
<!-- Stock adjustment menu --> <!-- Stock adjustment menu -->
{% if user_owns_item %} {% if user_owns_item %}

View File

@ -18,8 +18,6 @@
{% include "InvenTree/settings/setting.html" with key="REPORT_DEFAULT_PAGE_SIZE" icon="fa-print" %} {% include "InvenTree/settings/setting.html" with key="REPORT_DEFAULT_PAGE_SIZE" icon="fa-print" %}
{% include "InvenTree/settings/setting.html" with key="REPORT_DEBUG_MODE" icon="fa-laptop-code" %} {% include "InvenTree/settings/setting.html" with key="REPORT_DEBUG_MODE" icon="fa-laptop-code" %}
{% include "InvenTree/settings/setting.html" with key="REPORT_LOG_ERRORS" icon="fa-exclamation-circle" %} {% include "InvenTree/settings/setting.html" with key="REPORT_LOG_ERRORS" icon="fa-exclamation-circle" %}
{% include "InvenTree/settings/setting.html" with key="REPORT_ENABLE_TEST_REPORT" icon="fa-vial" %}
{% include "InvenTree/settings/setting.html" with key="REPORT_ATTACH_TEST_REPORT" icon="fa-file-upload" %}
</tbody> </tbody>
</table> </table>

View File

@ -4,7 +4,6 @@
{% plugins_enabled as plugins_enabled %} {% plugins_enabled as plugins_enabled %}
{% settings_value 'BARCODE_ENABLE' as barcodes %} {% settings_value 'BARCODE_ENABLE' as barcodes %}
{% settings_value 'REPORT_ENABLE_TEST_REPORT' as test_report_enabled %}
{% settings_value 'RETURNORDER_ENABLED' as return_order_enabled %} {% settings_value 'RETURNORDER_ENABLED' as return_order_enabled %}
{% settings_value "REPORT_ENABLE" as report_enabled %} {% settings_value "REPORT_ENABLE" as report_enabled %}
{% settings_value "SERVER_RESTART_REQUIRED" as server_restart_required %} {% settings_value "SERVER_RESTART_REQUIRED" as server_restart_required %}

View File

@ -21,6 +21,12 @@ export default function ReportTemplateTable() {
modelRenderer: (instance: any) => ( modelRenderer: (instance: any) => (
<YesNoButton value={instance.landscape} /> <YesNoButton value={instance.landscape} />
) )
},
attach_to_model: {
label: t`Attach to Model`,
modelRenderer: (instance: any) => (
<YesNoButton value={instance.attach_to_model} />
)
} }
} }
}} }}

View File

@ -161,9 +161,7 @@ export default function SystemSettings() {
'REPORT_ENABLE', 'REPORT_ENABLE',
'REPORT_DEFAULT_PAGE_SIZE', 'REPORT_DEFAULT_PAGE_SIZE',
'REPORT_DEBUG_MODE', 'REPORT_DEBUG_MODE',
'REPORT_LOG_ERRORS', 'REPORT_LOG_ERRORS'
'REPORT_ENABLE_TEST_REPORT',
'REPORT_ATTACH_TEST_REPORT'
]} ]}
/> />
) )

View File

@ -1184,7 +1184,7 @@ def frontend_build(c):
@task @task
def frontend_dev(c): def frontend_server(c):
"""Start frontend development server. """Start frontend development server.
Args: Args:
@ -1447,7 +1447,7 @@ def clear_generated(c):
development = Collection( development = Collection(
delete_data, delete_data,
docs_server, docs_server,
frontend_dev, frontend_server,
gunicorn, gunicorn,
import_fixtures, import_fixtures,
schema, schema,
@ -1458,6 +1458,7 @@ development = Collection(
test_translations, test_translations,
translate, translate,
) )
internal = Collection( internal = Collection(
clean_settings, clean_settings,
clear_generated, clear_generated,
@ -1474,6 +1475,7 @@ internal = Collection(
translate_stats, translate_stats,
worker, worker,
) )
ns = Collection( ns = Collection(
backup, backup,
export_records, export_records,
@ -1490,5 +1492,6 @@ ns = Collection(
version, version,
wait, wait,
) )
ns.add_collection(development, 'dev') ns.add_collection(development, 'dev')
ns.add_collection(internal, 'int') ns.add_collection(internal, 'int')