2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 11:35:41 +00:00

Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters
2022-10-09 13:03:21 +11:00
42 changed files with 9719 additions and 9568 deletions

View File

@ -1,25 +0,0 @@
# welcome new contributers
name: Welcome
on:
pull_request:
types: [ opened ]
issues:
types: [ opened ]
jobs:
run:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/first-interaction@bd33205aa5c96838e10fd65df0d01efd613677c1 # pin@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: |
Welcome to InvenTree! Please check the [contributing docs](https://inventree.readthedocs.io/en/latest/contribute/) on how to help.
If you experience setup / install issues please read all [install docs]( https://inventree.readthedocs.io/en/latest/start/intro/).
pr-message: |
This is your first PR, welcome!
Please check [Contributing](https://github.com/inventree/InvenTree/blob/master/CONTRIBUTING.md) to make sure your submission fits our general code-style and workflow.
Make sure to document why this PR is needed and to link connected issues so we can review it faster.

View File

@ -15,7 +15,7 @@ repos:
- id: check-added-large-files
- id: mixed-line-ending
- repo: https://github.com/pycqa/flake8
rev: '5.0.0'
rev: '5.0.4'
hooks:
- id: flake8
additional_dependencies: [

View File

@ -13,7 +13,7 @@ def isImportingData():
return 'loaddata' in sys.argv
def canAppAccessDatabase(allow_test=False):
def canAppAccessDatabase(allow_test: bool = False, allow_plugins: bool = False):
"""Returns True if the apps.py file can access database records.
There are some circumstances where we don't want the ready function in apps.py
@ -25,8 +25,6 @@ def canAppAccessDatabase(allow_test=False):
'flush',
'loaddata',
'dumpdata',
'makemigrations',
'migrate',
'check',
'shell',
'createsuperuser',
@ -43,6 +41,12 @@ def canAppAccessDatabase(allow_test=False):
# Override for testing mode?
excluded_commands.append('test')
if not allow_plugins:
excluded_commands.extend([
'makemigrations',
'migrate',
])
for cmd in excluded_commands:
if cmd in sys.argv:
return False

View File

@ -236,6 +236,11 @@ class Build(MPTTModel, ReferenceIndexingMixin):
help_text=_('Build status code')
)
@property
def status_text(self):
"""Return the text representation of the status field"""
return BuildStatus.text(self.status)
batch = models.CharField(
verbose_name=_('Batch Code'),
max_length=100,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -248,6 +248,11 @@ class PurchaseOrder(Order):
status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(),
help_text=_('Purchase order status'))
@property
def status_text(self):
"""Return the text representation of the status field"""
return PurchaseOrderStatus.text(self.status)
supplier = models.ForeignKey(
Company, on_delete=models.SET_NULL,
null=True,
@ -645,6 +650,11 @@ class SalesOrder(Order):
status = models.PositiveIntegerField(default=SalesOrderStatus.PENDING, choices=SalesOrderStatus.items(),
verbose_name=_('Status'), help_text=_('Purchase order status'))
@property
def status_text(self):
"""Return the text representation of the status field"""
return SalesOrderStatus.text(self.status)
customer_reference = models.CharField(max_length=64, blank=True, verbose_name=_('Customer Reference '), help_text=_("Customer order reference code"))
target_date = models.DateField(

View File

@ -286,6 +286,12 @@
</div>
<div class='panel-content'>
{% include "part/bom.html" with part=part %}
{% if roles.part.change %}
<button class='btn btn-success' type='button' title='{% trans "New BOM Item" %}' id='bom-item-new-footer'>
<span class='fas fa-plus-circle'></span> {% trans "Add BOM Item" %}
</button>
<br/>
{% endif %}
</div>
</div>
@ -611,7 +617,7 @@
});
});
$("#bom-item-new").click(function () {
$("[id^=bom-item-new]").click(function () {
var fields = bomItemFields();

View File

@ -27,7 +27,7 @@ class PluginAppConfig(AppConfig):
def ready(self):
"""The ready method is extended to initialize plugins."""
if settings.PLUGINS_ENABLED:
if not canAppAccessDatabase(allow_test=True):
if not canAppAccessDatabase(allow_test=True, allow_plugins=True):
logger.info("Skipping plugin loading sequence") # pragma: no cover
else:
logger.info('Loading InvenTree plugins')

View File

@ -670,6 +670,11 @@ class StockItem(InvenTreeBarcodeMixin, MetadataMixin, MPTTModel):
choices=StockStatus.items(),
validators=[MinValueValidator(0)])
@property
def status_text(self):
"""Return the text representation of the status field"""
return StockStatus.text(self.status)
notes = InvenTreeNotesField(help_text=_('Stock Item Notes'))
purchase_price = InvenTreeModelMoneyField(

View File

@ -23,9 +23,7 @@
</td>
<td>
{% if setting.is_bool %}
<div class='form-check form-switch'>
<input class='form-check-input boolean-setting' fieldname='{{ setting.key.upper }}' pk='{{ setting.pk }}' setting='{{ setting.key.upper }}' id='setting-value-{{ setting.pk }}-{{ setting.typ }}' type='checkbox' {% if setting.as_bool %}checked=''{% endif %}{{reference}}>
</div>
{% include "InvenTree/settings/setting_boolean.html" %}
{% else %}
<div id='setting-{{ setting.pk }}'>
<span id='setting-value-{{ setting.pk }}-{{ setting.typ }}' fieldname='{{ setting.key.upper }}'>
@ -41,7 +39,18 @@
</span>
{{ setting.units }}
<div class='btn-group float-right'>
<button class='btn btn-outline-secondary btn-small btn-edit-setting' pk='{{ setting.pk }}' setting='{{ setting.key.upper }}' title='{% trans "Edit setting" %}' {% if plugin %}plugin='{{ plugin.slug }}'{% endif %}{% if user_setting %}user='{{request.user.id}}'{% endif %}>
<button
class='btn btn-outline-secondary btn-small btn-edit-setting'
title='{% trans "Edit setting" %}'
pk='{{ setting.pk }}'
setting='{{ setting.key.upper }}'
{% if plugin %}plugin='{{ plugin.slug }}'{% endif %}
{% if user_setting or notification_setting %}user='{{request.user.id}}'{% endif %}
{% if notification_setting %}
notification=true
method='{{ setting.method }}'
{% endif %}
>
<span class='fas fa-edit icon-green'></span>
</button>
</div>

View File

@ -0,0 +1,18 @@
<div class='form-check form-switch'>
<input
class='form-check-input boolean-setting'
fieldname='{{ setting.key.upper }}'
pk='{{ setting.pk }}'
setting='{{ setting.key.upper }}'
id='setting-value-{{setting.pk }}-{{ setting.typ }}'
type='checkbox'
{% if setting.as_bool %}checked=''{% endif %}
{{ reference }}
{% if plugin %}plugin='{{ plugin.slug }}'{% endif %}
{% if user_setting or notification_setting %}user='{{ request.user.pk }}'{% endif %}
{% if notification_setting %}
notification=true
method='{{ setting.method }}'
{% endif %}
>
</div>

View File

@ -78,12 +78,12 @@ $('table').find('.boolean-setting').change(function() {
// Global setting by default
var url = `/api/settings/global/${setting}/`;
if (plugin) {
if (notification) {
url = `/api/settings/notification/${pk}/`;
} else if (plugin) {
url = `/api/plugin/settings/${plugin}/${setting}/`;
} else if (user) {
url = `/api/settings/user/${setting}/`;
} else if (notification) {
url = `/api/settings/notification/${pk}/`;
}
inventreePut(

View File

@ -43,7 +43,9 @@ function makeBarcodeInput(placeholderText='', hintText='') {
<span class='fas fa-qrcode'></span>
</span>
<input id='barcode' class='textinput textInput form-control' type='text' name='barcode' placeholder='${placeholderText}'>
<button id='barcode_scan_btn' class='btn btn-secondary' onclick='onBarcodeScanClicked()' style='display: none;'><span class='fas fa-camera'></span></button>
<button id='barcode_scan_btn' type='button' class='btn btn-secondary' onclick='onBarcodeScanClicked()' style='display: none;'>
<span class='fas fa-camera'></span>
</button>
</div>
<div id='hint_barcode_data' class='help-block'>${hintText}</div>
</div>
@ -571,8 +573,13 @@ function barcodeCheckIn(location_id, options={}) {
},
onScan: function(response) {
if ('stockitem' in response) {
var stockitem = response.stockitem;
var pk = response.stockitem.pk;
inventreeGet(
`/api/stock/${pk}/`,
{},
{
success: function(stockitem) {
var duplicate = false;
items.forEach(function(item) {
@ -597,7 +604,9 @@ function barcodeCheckIn(location_id, options={}) {
reloadTable();
}
}
}
);
} else {
// Barcode does not match a stock item
showBarcodeMessage(modal, '{% trans "Barcode does not match Stock Item" %}', 'warning');
@ -696,12 +705,26 @@ function scanItemsIntoLocation(item_list, options={}) {
onScan: function(response) {
updateLocationInfo(null);
if ('stocklocation' in response) {
// Barcode corresponds to a StockLocation
stock_location = response.stocklocation;
var pk = response.stocklocation.pk;
inventreeGet(`/api/stock/location/${pk}/`, {}, {
success: function(response) {
stock_location = response;
updateLocationInfo(stock_location);
modalEnable(modal, true);
},
error: function() {
// Barcode does *NOT* correspond to a StockLocation
showBarcodeMessage(
modal,
'{% trans "Barcode does not match a valid location" %}',
'warning',
);
}
});
} else {
// Barcode does *NOT* correspond to a StockLocation
showBarcodeMessage(

View File

@ -971,7 +971,7 @@ function adjustStock(action, items, options={}) {
var item = items[idx];
if ((item.serial != null) && !allowSerializedStock) {
if ((item.serial != null) && (item.serial != '') && !allowSerializedStock) {
continue;
}
@ -1729,7 +1729,11 @@ function loadStockTable(table, options) {
switchable: params['part_detail'],
formatter: function(value, row) {
var ipn = row.part_detail.IPN;
if (ipn) {
return withTitle(shortenString(ipn), ipn);
} else {
return '-';
}
},
};

View File

@ -208,7 +208,7 @@ class InvenTreeUserAdmin(UserAdmin):
(And it's confusing!)
"""
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'last_login') # display last connection for each user in user admin panel.
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),

View File

@ -47,6 +47,9 @@ server {
# Media files require user authentication
auth_request /auth;
# Content header to force download
add_header Content-disposition "attachment";
}
# Use the 'user' API endpoint for auth

View File

@ -46,6 +46,9 @@ server {
# Media files require user authentication
auth_request /auth;
# Content header to force download
add_header Content-disposition "attachment";
}
# Use the 'user' API endpoint for auth