Add default build order report

Toot toot refactor tractor
This commit is contained in:
Oliver Walters 2021-02-16 20:39:07 +11:00
parent f87b15e4ea
commit 46f20593c5
4 changed files with 276 additions and 51 deletions

View File

@ -18,6 +18,66 @@ class ReportConfig(AppConfig):
"""
self.create_default_test_reports()
self.create_default_build_reports()
def create_default_reports(self, model, reports):
"""
Copy defualt report files across to the media directory.
"""
# Source directory for report templates
src_dir = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'templates',
'report',
)
# Destination directory
dst_dir = os.path.join(
settings.MEDIA_ROOT,
'report',
'inventree',
model.getSubdir(),
)
if not os.path.exists(dst_dir):
logger.info(f"Creating missing directory: '{dst_dir}'")
os.makedirs(dst_dir, exist_ok=True)
# Copy each report template across (if required)
for report in reports:
# Destination filename
filename = os.path.join(
'report',
'inventree',
model.getSubdir(),
report['file'],
)
src_file = os.path.join(src_dir, report['file'])
dst_file = os.path.join(settings.MEDIA_ROOT, filename)
if not os.path.exists(dst_file):
logger.info(f"Copying test report template '{dst_file}'")
shutil.copyfile(src_file, dst_file)
try:
# Check if a report matching the template already exists
if model.objects.filter(template=filename).exists():
continue
logger.info(f"Creating new TestReport for '{report['name']}'")
model.objects.create(
name=report['name'],
description=report['description'],
template=filename,
enabled=True
)
except:
pass
def create_default_test_reports(self):
"""
@ -31,23 +91,6 @@ class ReportConfig(AppConfig):
# Database is not ready yet
return
src_dir = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'templates',
'report',
)
dst_dir = os.path.join(
settings.MEDIA_ROOT,
'report',
'inventree', # Stored in secret directory!
'test',
)
if not os.path.exists(dst_dir):
logger.info(f"Creating missing directory: '{dst_dir}'")
os.makedirs(dst_dir, exist_ok=True)
# List of test reports to copy across
reports = [
{
@ -57,36 +100,27 @@ class ReportConfig(AppConfig):
},
]
for report in reports:
self.create_default_reports(TestReport, reports)
# Create destination file name
filename = os.path.join(
'report',
'inventree',
'test',
report['file']
)
def create_default_build_reports(self):
"""
Create database entries for the default BuildReport templates
(if they do not already exist)
"""
src_file = os.path.join(src_dir, report['file'])
dst_file = os.path.join(settings.MEDIA_ROOT, filename)
try:
from .models import BuildReport
except:
# Database is not ready yet
return
if not os.path.exists(dst_file):
logger.info(f"Copying test report template '{dst_file}'")
shutil.copyfile(src_file, dst_file)
# List of Build reports to copy across
reports = [
{
'file': 'inventree_build_order.html',
'name': 'InvenTree Build Order',
'description': 'Build Order job sheet',
}
]
try:
# Check if a report matching the template already exists
if TestReport.objects.filter(template=filename).exists():
continue
logger.info(f"Creating new TestReport for '{report['name']}'")
TestReport.objects.create(
name=report['name'],
description=report['description'],
template=filename,
filters='',
enabled=True
)
except:
pass
self.create_default_reports(BuildReport, reports)

View File

@ -62,7 +62,6 @@ class ReportFileUpload(FileSystemStorage):
def get_available_name(self, name, max_length=None):
print("Name:", name)
return super().get_available_name(name, max_length)
@ -128,7 +127,8 @@ class ReportBase(models.Model):
def __str__(self):
return "{n} - {d}".format(n=self.name, d=self.description)
def getSubdir(self):
@classmethod
def getSubdir(cls):
return ''
def rename_file(self, filename):
@ -267,7 +267,8 @@ class TestReport(ReportTemplateBase):
Render a TestReport against a StockItem object.
"""
def getSubdir(self):
@classmethod
def getSubdir(cls):
return 'test'
filters = models.CharField(
@ -313,7 +314,8 @@ class BuildReport(ReportTemplateBase):
Build order / work order report
"""
def getSubdir(self):
@classmethod
def getSubdir(cls):
return 'build'
filters = models.CharField(
@ -349,7 +351,8 @@ class BillOfMaterialsReport(ReportTemplateBase):
Render a Bill of Materials against a Part object
"""
def getSubdir(self):
@classmethod
def getSubdir(cls):
return 'bom'
filters = models.CharField(

View File

@ -0,0 +1,3 @@
{% extends "report/inventree_build_order_base.html" %}
<!-- Refer to the inventree_build_order_base template -->

View File

@ -0,0 +1,185 @@
{% extends "report/inventree_report_base.html" %}
{% load i18n %}
{% load report %}
{% load inventree_extras %}
{% load markdownify %}
{% block page_margin %}
margin: 2cm;
margin-top: 4cm;
{% endblock %}
{% block style %}
.header-right {
text-align: right;
float: right;
}
.logo {
height: 20mm;
vertical-align: middle;
}
.float-right {
float: right;
}
.part-image {
border: 1px solid;
border-radius: 2px;
vertical-align: middle;
height: 40mm;
display: inline-block;
z-index: 100;
}
.details-image {
max-width: 25%;
float: right;
}
.details {
width: 100%;
border: 1px solid;
border-radius: 3px;
padding: 5px;
min-height: 42mm;
}
.details table {
overflow-x: scroll
overflow-wrap: break-word;
word-wrap: break-word;
width: 70%;
table-layout: fixed;
font-size: 75%;
}
.details table td:not(:last-child){
white-space: nowrap;
}
.details table td:last-child{
width: 50%;
padding-left: 1cm;
padding-right: 1cm;
}
.details-table td {
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #555;
}
{% endblock %}
{% block bottom_left %}
content: "v{{report_revision}} - {{ date.isoformat }}";
{% endblock %}
{% block bottom_center %}
content: "www.currawong.aero";
{% endblock %}
{% block header_content %}
<img class='logo' src="{% asset 'logo_black_with_black_bird.png' %}" alt="hello" width="150">
<div class='header-right'>
<h3>
Build Order {{ build }}
</h3>
<small>{{ quantity }} x {{ part.full_name }}</small>
<br>
</div>
<hr>
{% endblock %}
{% block page_content %}
<div class='details'>
<div class='details-image float-right'>
<img class='part-image' src="{% part_image part %}">
</div>
<div class='details-container'>
<table class='details-table'>
<tr>
<th>{% trans "Build Order" %}</th>
<td>{% internal_link build.get_absolute_url build %}</td>
</tr>
<tr>
<th>{% trans "Part" %}</th>
<td>{% internal_link part.get_absolute_url part.full_name %}</td>
</tr>
<tr>
<th>{% trans "Quantity" %}</th>
<td>{{ build.quantity }}</td>
</tr>
<tr>
<th>{% trans "Description" %}</th>
<td>{{ build.title }}</td>
</tr>
<tr>
<th>{% trans "Issued" %}</th>
<td>{{ build.creation_date }}</td>
</tr>
<tr>
<th>{% trans "Target Date" %}</th>
<td>
{% if build.target_date %}
{{ build.target_date }}
{% else %}
<i>Not specified</i>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans "Sales Order" %}</th>
<td>
{% if build.sales_order %}
{% internal_link build.sales_order.get_absolute_url build.sales_order %}
{% else %}
<i>Not specified</i>
{% endif %}
</td>
</tr>
{% if build.parent %}
<tr>
<th>{% trans "Required For" %}</th>
<td>{% internal_link build.parent.get_absolute_url build.parent %}</td>
</tr>
{% endif %}
{% if build.issued_by %}
<tr>
<th>{% trans "Issued By" %}</th>
<td>{{ build.issued_by }}</td>
</tr>
{% endif %}
{% if build.responsible %}
<tr>
<th>{% trans "Responsible" %}</th>
<td>{{ build.responsible }}</td>
</tr>
{% endif %}
{% if build.link %}
<tr>
<th>{% trans "Link" %}</th>
<td><a href="{{ build.link }}">{{ build.link }}</a></td>
</tr>
{% endif %}
</table>
</div>
</div>
<h3>{% trans "Notes" %}</h3>
{% if build.notes %}
{{ build.notes|markdownify }}
{% endif %}
{% endblock %}