Compare commits

...

11 Commits
1.1.2 ... 0.9.2

Author SHA1 Message Date
Oliver
236ca36138 Update django-allauth lib version (#4141) (#4142)
* Update django-allauth lib version

* Clean up requirements file

* Capital, capital

(cherry picked from commit 6fb7c85949)
2023-01-04 07:42:49 +11:00
Oliver
3a1d180c34 Catch potential issues when importing data (#4130)
(cherry picked from commit aa7fb97292)
2023-01-01 00:51:07 +11:00
Oliver
c621c4746a Create missing entries for default reports (#4128) (#4131)
* Create missing default reports

Default reports are available but not accessible from the UI.
Added the missing report entries

* Forgot to add BOM report template to previous commit

(cherry picked from commit a012139677)

Co-authored-by: bloemp <pbloem@upcmail.nl>
2023-01-01 00:47:09 +11:00
Oliver
aca8ced4d4 Bump version number to 0.9.2 (#4125) 2022-12-31 07:45:16 +11:00
Oliver
44f26d8e80 Parameters table fix (#4120) (#4121)
* Account for paginated or unpaginated results

* Fix data loading when paginated

- Server-side paginated data needs to be provided in the correct format
- Look at how the original data were provided by the server
- Perform a single data load operation at the end

(cherry picked from commit 717a6ba5d2)
2022-12-31 00:04:55 +11:00
Oliver
93b51db089 Change overflow property in order to fix horizontal scrolling (#4117) (#4119)
(cherry picked from commit a2643b34bf)

Co-authored-by: miggland <miggland@users.noreply.github.com>
2022-12-30 22:58:08 +11:00
Oliver
5dd256db3c Replace include tag by the files contents (#4093) (#4098)
(cherry picked from commit bae81e8dae)

Co-authored-by: Marcel Pörner <me@nerade.de>
2022-12-22 10:52:02 +11:00
Oliver
641adb6ae8 Fix stock location structural check (#4089) (#4095)
* Fix stock location structural check

Exclude sub stock location items from preventing that a stock location can be switched to structural.

* Fix structural check on both storage location and parts category

Exclude children of sub- locations/categories in the check to allow this location/category to be structural

(cherry picked from commit 14a2c128a9)

Co-authored-by: bloemp <pbloem@upcmail.nl>
2022-12-22 07:48:50 +11:00
Oliver
eb7aba4dd8 Load plugins for collectstatic (#4077) (#4078)
(cherry picked from commit 1d411b26a9)

Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com>
2022-12-19 11:59:36 +11:00
Oliver
af8f1c6bab Bump version to 0.9.1 (#4079) 2022-12-19 11:21:53 +11:00
Oliver
eaca66ab64 Save newly created pricing object (#4076)
(cherry picked from commit ef411861b9)
2022-12-18 07:15:22 +11:00
13 changed files with 392 additions and 18 deletions

View File

@@ -32,7 +32,6 @@ def canAppAccessDatabase(allow_test: bool = False, allow_plugins: bool = False):
'prerender',
'rebuild_models',
'rebuild_thumbnails',
'collectstatic',
'makemessages',
'compilemessages',
'backup',
@@ -51,6 +50,7 @@ def canAppAccessDatabase(allow_test: bool = False, allow_plugins: bool = False):
excluded_commands.extend([
'makemigrations',
'migrate',
'collectstatic',
])
for cmd in excluded_commands:

View File

@@ -18,7 +18,7 @@
}
main {
overflow-x: clip;
overflow-x: auto;
}
.login-screen {

View File

@@ -13,7 +13,7 @@ import common.models
from InvenTree.api_version import INVENTREE_API_VERSION
# InvenTree software version
INVENTREE_SW_VERSION = "0.9.0"
INVENTREE_SW_VERSION = "0.9.2"
def inventreeInstanceName():

View File

@@ -1,2 +1,99 @@
{% extends "order/order_wizard/po_upload.html" %}
{% include "patterns/wizard/match_fields.html" %}
{% load inventree_extras %}
{% load i18n %}
{% load static %}
{% block form_alert %}
{% if missing_columns and missing_columns|length > 0 %}
<div class='alert alert-danger alert-block' style='margin-top:12px;' role='alert'>
{% trans "Missing selections for the following required columns" %}:
<br>
<ul>
{% for col in missing_columns %}
<li>{{ col }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if duplicates and duplicates|length > 0 %}
<div class='alert alert-danger alert-block' role='alert'>
{% trans "Duplicate selections found, see below. Fix them then retry submitting." %}
</div>
{% endif %}
{% endblock form_alert %}
{% block form_buttons_top %}
{% if wizard.steps.prev %}
<button name='wizard_goto_step' type='submit' value='{{ wizard.steps.prev }}' class='save btn btn-outline-secondary'>{% trans "Previous Step" %}</button>
{% endif %}
<button type='submit' class='save btn btn-outline-secondary'>{% trans "Submit Selections" %}</button>
{% endblock form_buttons_top %}
{% block form_content %}
<thead>
<tr>
<th>{% trans "File Fields" %}</th>
<th></th>
{% for col in form %}
<th>
<div>
<input type='hidden' name='col_name_{{ forloop.counter0 }}' value='{{ col.name }}'/>
{{ col.name }}
<button class='btn btn-outline-secondary btn-remove' onClick='removeColFromBomWizard()' id='del_col_{{ forloop.counter0 }}' style='display: inline; float: right;' title='{% trans "Remove column" %}'>
<span col_id='{{ forloop.counter0 }}' class='fas fa-trash-alt icon-red'></span>
</button>
</div>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
<td>{% trans "Match Fields" %}</td>
<td></td>
{% for col in form %}
<td>
{{ col }}
{% for duplicate in duplicates %}
{% if duplicate == col.value %}
<div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'>
<strong>{% trans "Duplicate selection" %}</strong>
</div>
{% endif %}
{% endfor %}
</td>
{% endfor %}
</tr>
{% for row in rows %}
{% with forloop.counter as row_index %}
<tr>
<td style='width: 32px;'>
<button class='btn btn-outline-secondary btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ row_index }}' style='display: inline; float: left;' title='{% trans "Remove row" %}'>
<span row_id='{{ row_index }}' class='fas fa-trash-alt icon-red'></span>
</button>
</td>
<td style='text-align: left;'>{{ row_index }}</td>
{% for item in row.data %}
<td>
<input type='hidden' name='row_{{ row_index }}_col_{{ forloop.counter0 }}' value='{{ item }}'/>
{{ item }}
</td>
{% endfor %}
</tr>
{% endwith %}
{% endfor %}
</tbody>
{% endblock form_content %}
{% block form_buttons_bottom %}
{% endblock form_buttons_bottom %}
{% block js_ready %}
{{ block.super }}
$('.fieldselect').select2({
width: '100%',
matcher: partialMatcher,
});
{% endblock %}

View File

@@ -12,12 +12,53 @@
{% block page_content %}
{% trans "Upload File for Purchase Order" as header_text %}
{% trans "Order is already processed. Files cannot be uploaded." as error_text %}
{% with "panel-upload-file" as panel_id %}
{% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %}
{% include "patterns/wizard/upload.html" with header_text=header_text upload_go_ahead=True error_text=error_text panel_id=panel_id %}
{% else %}
{% include "patterns/wizard/upload.html" with header_text=header_text upload_go_ahead=False error_text=error_text panel_id=panel_id %}
{% endif %}
{% with panel_id="panel-upload-file" %}
<div class='panel' id='{{ panel_id }}'>
<div class='panel-heading'>
<h4>
{{ header_text }}
{{ wizard.form.media }}
</h4>
</div>
<div class='panel-content'>
{% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %}
<p>{% blocktrans with step=wizard.steps.step1 count=wizard.steps.count %}Step {{step}} of {{count}}{% endblocktrans %}
{% if description %}- {{ description }}{% endif %}</p>
{% block form_alert %}
{% endblock form_alert %}
<form action='' method='post' class='js-modal-form' enctype='multipart/form-data'>
{% csrf_token %}
{% load crispy_forms_tags %}
{% block form_buttons_top %}
{% endblock form_buttons_top %}
<table class='table table-striped' style='margin-top: 12px; margin-bottom: 0px'>
{{ wizard.management_form }}
{% block form_content %}
{% crispy wizard.form %}
{% endblock form_content %}
</table>
{% block form_buttons_bottom %}
{% if wizard.steps.prev %}
<button name='wizard_goto_step' type='submit' value='{{ wizard.steps.prev }}' class='save btn btn-outline-secondary'>{% trans "Previous Step" %}</button>
{% endif %}
<button type='submit' class='save btn btn-outline-secondary'>{% trans "Upload File" %}</button>
</form>
{% endblock form_buttons_bottom %}
{% else %}
<div class='alert alert-danger alert-block' role='alert'>
{{ error_text }}
</div>
{% endif %}
</div>
</div>
{% endwith %}
{% endblock %}

View File

@@ -148,7 +148,7 @@ class PartCategory(MetadataMixin, InvenTreeTree):
- Ensure that the structural parameter cannot get set if products already assigned to the category
"""
if self.pk and self.structural and self.item_count > 0:
if self.pk and self.structural and self.partcount(False, False) > 0:
raise ValidationError(
_("You cannot make this part category structural because some parts "
"are already assigned to it!"))
@@ -2248,13 +2248,19 @@ class Part(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
@receiver(post_save, sender=Part, dispatch_uid='part_post_save_log')
def after_save_part(sender, instance: Part, created, **kwargs):
"""Function to be executed after a Part is saved."""
from pickle import PicklingError
from part import tasks as part_tasks
if not created and not InvenTree.ready.isImportingData():
if instance and not created and not InvenTree.ready.isImportingData():
# Check part stock only if we are *updating* the part (not creating it)
# Run this check in the background
InvenTree.tasks.offload_task(part_tasks.notify_low_stock_if_required, instance)
try:
InvenTree.tasks.offload_task(part_tasks.notify_low_stock_if_required, instance)
except PicklingError:
# Can sometimes occur if the referenced Part has issues
pass
class PartPricing(models.Model):

View File

@@ -123,4 +123,5 @@ def check_missing_pricing(limit=250):
for p in results:
pricing = p.pricing
pricing.save()
pricing.schedule_for_update()

View File

@@ -22,6 +22,9 @@ class ReportConfig(AppConfig):
if canAppAccessDatabase(allow_test=True):
self.create_default_test_reports()
self.create_default_build_reports()
self.create_default_bill_of_materials_reports()
self.create_default_purchase_order_reports()
self.create_default_sales_order_reports()
def create_default_reports(self, model, reports):
"""Copy defualt report files across to the media directory."""
@@ -96,6 +99,25 @@ class ReportConfig(AppConfig):
self.create_default_reports(TestReport, reports)
def create_default_bill_of_materials_reports(self):
"""Create database entries for the default Bill of Material templates (if they do not already exist)"""
try:
from .models import BillOfMaterialsReport
except Exception: # pragma: no cover
# Database is not ready yet
return
# List of Build reports to copy across
reports = [
{
'file': 'inventree_bill_of_materials_report.html',
'name': 'Bill of Materials',
'description': 'Bill of Materials report',
}
]
self.create_default_reports(BillOfMaterialsReport, reports)
def create_default_build_reports(self):
"""Create database entries for the default BuildReport templates (if they do not already exist)"""
try:
@@ -114,3 +136,41 @@ class ReportConfig(AppConfig):
]
self.create_default_reports(BuildReport, reports)
def create_default_purchase_order_reports(self):
"""Create database entries for the default SalesOrderReport templates (if they do not already exist)"""
try:
from .models import PurchaseOrderReport
except Exception: # pragma: no cover
# Database is not ready yet
return
# List of Build reports to copy across
reports = [
{
'file': 'inventree_po_report.html',
'name': 'InvenTree Purchase Order',
'description': 'Purchase Order example report',
}
]
self.create_default_reports(PurchaseOrderReport, reports)
def create_default_sales_order_reports(self):
"""Create database entries for the default Sales Order report templates (if they do not already exist)"""
try:
from .models import SalesOrderReport
except Exception: # pragma: no cover
# Database is not ready yet
return
# List of Build reports to copy across
reports = [
{
'file': 'inventree_so_report.html',
'name': 'InvenTree Sales Order',
'description': 'Sales Order example report',
}
]
self.create_default_reports(SalesOrderReport, reports)

View File

@@ -0,0 +1,162 @@
{% extends "report/inventree_report_base.html" %}
{% load i18n %}
{% load report %}
{% load barcode %}
{% load inventree_extras %}
{% block page_margin %}
margin: 2cm;
margin-top: 4cm;
{% endblock %}
{% block bottom_left %}
content: "v{{report_revision}} - {{ date.isoformat }}";
{% endblock %}
{% block bottom_center %}
content: "{% inventree_version shortstring=True %}";
{% endblock %}
{% block style %}
.header-right {
text-align: right;
float: right;
}
.logo {
height: 20mm;
vertical-align: middle;
}
.thumb-container {
width: 32px;
display: inline;
}
.part-thumb {
max-width: 32px;
max-height: 32px;
display: inline;
}
.part-text {
display: inline;
}
.part-logo {
max-width: 60px;
max-height: 60px;
display: inline;
}
table {
border: 1px solid #eee;
border-radius: 3px;
border-collapse: collapse;
width: 100%;
font-size: 80%;
}
table td {
border: 1px solid #eee;
}
table td.shrink {
white-space: nowrap
}
table td.expand {
width: 99%
}
.invisible-table {
border: 0px solid transparent;
border-collapse: collapse;
width: 100%;
font-size: 80%;
}
.invisible-table td {
border: 0px solid transparent;
}
.main-part-text {
display: inline;
}
.main-part-description {
display: inline;
}
{% endblock %}
{% block header_content %}
<img class='logo' src='{% logo_image %}' alt="Inventree logo" width='150'>
<div class='header-right'>
<h3>{% trans "Bill of Materials" %}</h3>
</div>
{% endblock %}
{% block page_content %}
<table class="invisible-table">
<thead>
<tr>
<th colspan="2"><h3>{% trans "Part" %}</h3></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class='main-part-text'>
{{ part.full_name }}
</div>
<br/>
<div class='main-part-description'>
{{ part.description }}
</div>
</td>
<td>
<div class='part-logo'>
<img src='{% part_image part %}' class='part-logo'>
</div>
</td>
</tr>
</tbody>
</table>
<h3>{% trans "Materials needed" %}</h3>
<table class='table table-striped table-condensed'>
<thead>
<tr>
<th>{% trans "Part" %}</th>
<th>{% trans "Quantity" %}</th>
<th>{% trans "Reference" %}</th>
<th>{% trans "Note" %}</th>
</tr>
</thead>
<tbody>
{% for line in bom_items.all %}
<tr>
<td>
<div class='thumb-container'>
<img src='{% part_image line.part %}' class='part-thumb'>
</div>
<div class='part-text'>
{{ line.part.full_name }}
</div>
</td>
<td>{% decimal line.quantity %}</td>
<td>{{ line.reference }}</td>
<td>{{ line.notes }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -152,7 +152,7 @@ class StockLocation(InvenTreeBarcodeMixin, MetadataMixin, InvenTreeTree):
- Ensure stock location can't be made structural if stock items already located to them
"""
if self.pk and self.structural and self.item_count > 0:
if self.pk and self.structural and self.stock_item_count(False) > 0:
raise ValidationError(
_("You cannot make this stock location structural because some stock items "
"are already located into it!"))

View File

@@ -1333,7 +1333,8 @@ function loadParametricPartTable(table, options={}) {
uniqueId: 'pk',
onLoadSuccess: function(response) {
var data = response.results;
// Data may be returned paginated, in which case we preference response.results
var data = response.results || response;
for (var idx = 0; idx < data.length; idx++) {
var row = data[idx];
@@ -1346,8 +1347,14 @@ function loadParametricPartTable(table, options={}) {
data[idx] = row;
}
if (response.results) {
response.results = data;
} else {
response = data;
}
// Update the table
$(table).bootstrapTable('load', data);
$(table).bootstrapTable('load', response);
}
});
}

View File

@@ -2,7 +2,7 @@
Django>=3.2.14,<4 # Django package
coreapi # API documentation for djangorestframework
cryptography==3.4.8 # Core cryptographic functionality
django-allauth # SSO for external providers via OpenID
django-allauth==0.52.0 # SSO for external providers via OpenID
django-allauth-2fa # MFA / 2FA
django-cleanup # Automated deletion of old / unused uploaded files
django-cors-headers # CORS headers extension for DRF

View File

@@ -68,7 +68,7 @@ django==3.2.16
# django-weasyprint
# django-xforwardedfor-middleware
# djangorestframework
django-allauth==0.51.0
django-allauth==0.52.0
# via
# -r requirements.in
# django-allauth-2fa