mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #895 from SchrodingersGat/return-to-stock
Return to stock
This commit is contained in:
commit
2cd6c0b9fc
@ -167,10 +167,6 @@ class StockStatus(StatusCode):
|
|||||||
# This can be used as a quick check for filtering
|
# This can be used as a quick check for filtering
|
||||||
NOT_IN_STOCK = 100
|
NOT_IN_STOCK = 100
|
||||||
|
|
||||||
SHIPPED = 110 # Item has been shipped to a customer
|
|
||||||
ASSIGNED_TO_BUILD = 120
|
|
||||||
ASSIGNED_TO_OTHER_ITEM = 130
|
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
OK: _("OK"),
|
OK: _("OK"),
|
||||||
ATTENTION: _("Attention needed"),
|
ATTENTION: _("Attention needed"),
|
||||||
@ -179,9 +175,6 @@ class StockStatus(StatusCode):
|
|||||||
LOST: _("Lost"),
|
LOST: _("Lost"),
|
||||||
REJECTED: _("Rejected"),
|
REJECTED: _("Rejected"),
|
||||||
RETURNED: _("Returned"),
|
RETURNED: _("Returned"),
|
||||||
SHIPPED: _('Shipped'),
|
|
||||||
ASSIGNED_TO_BUILD: _("Used for Build"),
|
|
||||||
ASSIGNED_TO_OTHER_ITEM: _("Installed in Stock Item")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
@ -190,9 +183,6 @@ class StockStatus(StatusCode):
|
|||||||
DAMAGED: 'red',
|
DAMAGED: 'red',
|
||||||
DESTROYED: 'red',
|
DESTROYED: 'red',
|
||||||
REJECTED: 'red',
|
REJECTED: 'red',
|
||||||
SHIPPED: 'green',
|
|
||||||
ASSIGNED_TO_BUILD: 'blue',
|
|
||||||
ASSIGNED_TO_OTHER_ITEM: 'blue',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# The following codes correspond to parts that are 'available' or 'in stock'
|
# The following codes correspond to parts that are 'available' or 'in stock'
|
||||||
@ -208,9 +198,6 @@ class StockStatus(StatusCode):
|
|||||||
DESTROYED,
|
DESTROYED,
|
||||||
LOST,
|
LOST,
|
||||||
REJECTED,
|
REJECTED,
|
||||||
SHIPPED,
|
|
||||||
ASSIGNED_TO_BUILD,
|
|
||||||
ASSIGNED_TO_OTHER_ITEM,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# The following codes are available for receiving goods
|
# The following codes are available for receiving goods
|
||||||
|
@ -21,7 +21,7 @@ from markdownx.models import MarkdownxField
|
|||||||
|
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from mptt.models import MPTTModel, TreeForeignKey
|
||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus, StockStatus
|
from InvenTree.status_codes import BuildStatus
|
||||||
from InvenTree.fields import InvenTreeURLField
|
from InvenTree.fields import InvenTreeURLField
|
||||||
from InvenTree.helpers import decimal2string
|
from InvenTree.helpers import decimal2string
|
||||||
|
|
||||||
@ -501,7 +501,6 @@ class BuildItem(models.Model):
|
|||||||
|
|
||||||
# TODO - If the item__part object is not trackable, delete the stock item here
|
# TODO - If the item__part object is not trackable, delete the stock item here
|
||||||
|
|
||||||
item.status = StockStatus.ASSIGNED_TO_BUILD
|
|
||||||
item.build_order = self.build
|
item.build_order = self.build
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
|
@ -211,15 +211,12 @@ class BuildTest(TestCase):
|
|||||||
# New stock items created and assigned to the build
|
# New stock items created and assigned to the build
|
||||||
self.assertEqual(StockItem.objects.get(pk=4).quantity, 50)
|
self.assertEqual(StockItem.objects.get(pk=4).quantity, 50)
|
||||||
self.assertEqual(StockItem.objects.get(pk=4).build_order, self.build)
|
self.assertEqual(StockItem.objects.get(pk=4).build_order, self.build)
|
||||||
self.assertEqual(StockItem.objects.get(pk=4).status, status.StockStatus.ASSIGNED_TO_BUILD)
|
|
||||||
|
|
||||||
self.assertEqual(StockItem.objects.get(pk=5).quantity, 50)
|
self.assertEqual(StockItem.objects.get(pk=5).quantity, 50)
|
||||||
self.assertEqual(StockItem.objects.get(pk=5).build_order, self.build)
|
self.assertEqual(StockItem.objects.get(pk=5).build_order, self.build)
|
||||||
self.assertEqual(StockItem.objects.get(pk=5).status, status.StockStatus.ASSIGNED_TO_BUILD)
|
|
||||||
|
|
||||||
self.assertEqual(StockItem.objects.get(pk=6).quantity, 250)
|
self.assertEqual(StockItem.objects.get(pk=6).quantity, 250)
|
||||||
self.assertEqual(StockItem.objects.get(pk=6).build_order, self.build)
|
self.assertEqual(StockItem.objects.get(pk=6).build_order, self.build)
|
||||||
self.assertEqual(StockItem.objects.get(pk=6).status, status.StockStatus.ASSIGNED_TO_BUILD)
|
|
||||||
|
|
||||||
# And a new stock item created for the build output
|
# And a new stock item created for the build output
|
||||||
self.assertEqual(StockItem.objects.get(pk=7).quantity, 1)
|
self.assertEqual(StockItem.objects.get(pk=7).quantity, 1)
|
||||||
|
@ -46,6 +46,18 @@ class AssignStockItemToCustomerForm(HelperForm):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnStockItemForm(HelperForm):
|
||||||
|
"""
|
||||||
|
Form for manually returning a StockItem into stock
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = StockItem
|
||||||
|
fields = [
|
||||||
|
'location',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class EditStockItemTestResultForm(HelperForm):
|
class EditStockItemTestResultForm(HelperForm):
|
||||||
"""
|
"""
|
||||||
Form for creating / editing a StockItemTestResult object.
|
Form for creating / editing a StockItemTestResult object.
|
||||||
|
19
InvenTree/stock/migrations/0048_auto_20200807_2344.py
Normal file
19
InvenTree/stock/migrations/0048_auto_20200807_2344.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-08-07 23:44
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0047_auto_20200605_0932'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stockitem',
|
||||||
|
name='status',
|
||||||
|
field=models.PositiveIntegerField(choices=[(10, 'OK'), (50, 'Attention needed'), (55, 'Damaged'), (60, 'Destroyed'), (70, 'Lost'), (65, 'Rejected'), (85, 'Returned')], default=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
]
|
@ -140,6 +140,7 @@ class StockItem(MPTTModel):
|
|||||||
sales_order=None,
|
sales_order=None,
|
||||||
build_order=None,
|
build_order=None,
|
||||||
belongs_to=None,
|
belongs_to=None,
|
||||||
|
customer=None,
|
||||||
status__in=StockStatus.AVAILABLE_CODES
|
status__in=StockStatus.AVAILABLE_CODES
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -219,12 +220,6 @@ class StockItem(MPTTModel):
|
|||||||
|
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
if self.status == StockStatus.ASSIGNED_TO_OTHER_ITEM and self.belongs_to is None:
|
|
||||||
raise ValidationError({
|
|
||||||
'belongs_to': "Belongs_to field must be specified as statis is marked as ASSIGNED_TO_OTHER_ITEM",
|
|
||||||
'status': 'Status cannot be marked as ASSIGNED_TO_OTHER_ITEM if the belongs_to field is not set',
|
|
||||||
})
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.part.trackable:
|
if self.part.trackable:
|
||||||
# Trackable parts must have integer values for quantity field!
|
# Trackable parts must have integer values for quantity field!
|
||||||
@ -477,7 +472,6 @@ class StockItem(MPTTModel):
|
|||||||
|
|
||||||
# Update StockItem fields with new information
|
# Update StockItem fields with new information
|
||||||
item.sales_order = order
|
item.sales_order = order
|
||||||
item.status = StockStatus.SHIPPED
|
|
||||||
item.customer = customer
|
item.customer = customer
|
||||||
item.location = None
|
item.location = None
|
||||||
|
|
||||||
@ -495,6 +489,23 @@ class StockItem(MPTTModel):
|
|||||||
# Return the reference to the stock item
|
# Return the reference to the stock item
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
def returnFromCustomer(self, location, user=None):
|
||||||
|
"""
|
||||||
|
Return stock item from customer, back into the specified location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.addTransactionNote(
|
||||||
|
_("Returned from customer") + " " + self.customer.name,
|
||||||
|
user,
|
||||||
|
notes=_("Returned to location") + " " + location.name,
|
||||||
|
system=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.customer = None
|
||||||
|
self.location = location
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
# If stock item is incoming, an (optional) ETA field
|
# If stock item is incoming, an (optional) ETA field
|
||||||
# expected_arrival = models.DateField(null=True, blank=True)
|
# expected_arrival = models.DateField(null=True, blank=True)
|
||||||
|
|
||||||
@ -599,6 +610,10 @@ class StockItem(MPTTModel):
|
|||||||
if self.build_order is not None:
|
if self.build_order is not None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# Not 'in stock' if it has been assigned to a customer
|
||||||
|
if self.customer is not None:
|
||||||
|
return False
|
||||||
|
|
||||||
# Not 'in stock' if the status code makes it unavailable
|
# Not 'in stock' if the status code makes it unavailable
|
||||||
if self.status in StockStatus.UNAVAILABLE_CODES:
|
if self.status in StockStatus.UNAVAILABLE_CODES:
|
||||||
return False
|
return False
|
||||||
|
@ -86,30 +86,34 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% if item.in_stock %}
|
|
||||||
<!-- Stock adjustment menu -->
|
<!-- Stock adjustment menu -->
|
||||||
<div class='dropdown dropdown-buttons'>
|
<div class='dropdown dropdown-buttons'>
|
||||||
<button id='stock-options' title='{% trans "Stock adjustment actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
<button id='stock-options' title='{% trans "Stock adjustment actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
|
||||||
<ul class='dropdown-menu' role='menu'>
|
<ul class='dropdown-menu' role='menu'>
|
||||||
|
{% if item.in_stock %}
|
||||||
{% if not item.serialized %}
|
{% if not item.serialized %}
|
||||||
<li><a href='#' id='stock-count' title='{% trans "Count stock" %}'><span class='fas fa-clipboard-list'></span> {% trans "Count stock" %}</a></li>
|
<li><a href='#' id='stock-count' title='{% trans "Count stock" %}'><span class='fas fa-clipboard-list'></span> {% trans "Count stock" %}</a></li>
|
||||||
<li><a href='#' id='stock-add' title='{% trans "Add stock" %}'><span class='fas fa-plus-circle icon-green'></span> {% trans "Add stock" %}</a></li>
|
<li><a href='#' id='stock-add' title='{% trans "Add stock" %}'><span class='fas fa-plus-circle icon-green'></span> {% trans "Add stock" %}</a></li>
|
||||||
<li><a href='#' id='stock-remove' title='{% trans "Remove stock" %}'><span class='fas fa-minus-circle icon-red'></span> {% trans "Remove stock" %}</a></li>
|
<li><a href='#' id='stock-remove' title='{% trans "Remove stock" %}'><span class='fas fa-minus-circle icon-red'></span> {% trans "Remove stock" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href='#' id='stock-move' title='{% trans "Transfer stock" %}'><span class='fas fa-exchange-alt icon-blue'></span> {% trans "Transfer stock" %}</a></li>
|
<li><a href='#' id='stock-move' title='{% trans "Transfer stock" %}'><span class='fas fa-exchange-alt icon-blue'></span> {% trans "Transfer stock" %}</a></li>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<!-- Edit stock item -->
|
|
||||||
<div class='dropdown dropdown-buttons'>
|
|
||||||
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
|
|
||||||
<ul class='dropdown-menu' role='menu'>
|
|
||||||
{% if item.part.trackable and not item.serialized %}
|
{% if item.part.trackable and not item.serialized %}
|
||||||
<li><a href='#' id='stock-serialize' title='{% trans "Serialize stock" %}'><span class='fas fa-hashtag'></span> {% trans "Serialize stock" %}</a> </li>
|
<li><a href='#' id='stock-serialize' title='{% trans "Serialize stock" %}'><span class='fas fa-hashtag'></span> {% trans "Serialize stock" %}</a> </li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% if item.part.salable and not item.customer %}
|
{% if item.part.salable and not item.customer %}
|
||||||
<li><a href='#' id='stock-assign-to-customer' title='{% trans "Assign to customer" %}'><span class='fas fa-user-tie'></span> {% trans "Assign to customer" %}</a></li>
|
<li><a href='#' id='stock-assign-to-customer' title='{% trans "Assign to customer" %}'><span class='fas fa-user-tie'></span> {% trans "Assign to customer" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if item.customer %}
|
||||||
|
<li><a href='#' id='stock-return-from-customer' title='{% trans "Return to stock" %}'><span class='fas fa-undo'></span> {% trans "Return to stock" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<!-- Edit stock item -->
|
||||||
|
<div class='dropdown dropdown-buttons'>
|
||||||
|
<button id='stock-edit-actions' title='{% trans "Stock actions" %}' class='btn btn-default dropdown-toggle' type='button' data-toggle='dropdown'><span class='fas fa-tools'></span> <span class='caret'></span></button>
|
||||||
|
<ul class='dropdown-menu' role='menu'>
|
||||||
|
|
||||||
{% if item.part.has_variants %}
|
{% if item.part.has_variants %}
|
||||||
<li><a href='#' id='stock-convert' title='{% trans "Convert to variant" %}'><span class='fas fa-screwdriver'></span> {% trans "Convert to variant" %}</a></li>
|
<li><a href='#' id='stock-convert' title='{% trans "Convert to variant" %}'><span class='fas fa-screwdriver'></span> {% trans "Convert to variant" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -157,7 +161,7 @@ InvenTree | {% trans "Stock Item" %} - {{ item }}
|
|||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-user-tie'></span></td>
|
<td><span class='fas fa-user-tie'></span></td>
|
||||||
<td>{% trans "Customer" %}</td>
|
<td>{% trans "Customer" %}</td>
|
||||||
<td><a href="{% url 'company-detail' item.customer.id %}">{{ item.customer.name }}</a></td>
|
<td><a href="{% url 'company-detail-assigned-stock' item.customer.id %}">{{ item.customer.name }}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if item.belongs_to %}
|
{% if item.belongs_to %}
|
||||||
@ -349,7 +353,6 @@ $("#unlink-barcode").click(function() {
|
|||||||
|
|
||||||
{% if item.in_stock %}
|
{% if item.in_stock %}
|
||||||
|
|
||||||
{% if item.part.salable %}
|
|
||||||
$("#stock-assign-to-customer").click(function() {
|
$("#stock-assign-to-customer").click(function() {
|
||||||
launchModalForm("{% url 'stock-item-assign' item.id %}",
|
launchModalForm("{% url 'stock-item-assign' item.id %}",
|
||||||
{
|
{
|
||||||
@ -357,7 +360,6 @@ $("#stock-assign-to-customer").click(function() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
function itemAdjust(action) {
|
function itemAdjust(action) {
|
||||||
launchModalForm("/stock/adjust/",
|
launchModalForm("/stock/adjust/",
|
||||||
@ -398,6 +400,16 @@ $('#stock-add').click(function() {
|
|||||||
itemAdjust('add');
|
itemAdjust('add');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
$("#stock-return-from-customer").click(function() {
|
||||||
|
launchModalForm("{% url 'stock-item-return' item.id %}",
|
||||||
|
{
|
||||||
|
reload: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
$("#stock-delete").click(function () {
|
$("#stock-delete").click(function () {
|
||||||
|
@ -24,6 +24,7 @@ stock_item_detail_urls = [
|
|||||||
url(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'),
|
url(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'),
|
||||||
url(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'),
|
url(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'),
|
||||||
url(r'^assign/', views.StockItemAssignToCustomer.as_view(), name='stock-item-assign'),
|
url(r'^assign/', views.StockItemAssignToCustomer.as_view(), name='stock-item-assign'),
|
||||||
|
url(r'^return/', views.StockItemReturnToStock.as_view(), name='stock-item-return'),
|
||||||
|
|
||||||
url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
|
url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'),
|
||||||
|
|
||||||
|
@ -260,6 +260,41 @@ class StockItemAssignToCustomer(AjaxUpdateView):
|
|||||||
return self.renderJsonResponse(request, self.get_form(), data)
|
return self.renderJsonResponse(request, self.get_form(), data)
|
||||||
|
|
||||||
|
|
||||||
|
class StockItemReturnToStock(AjaxUpdateView):
|
||||||
|
"""
|
||||||
|
View for returning a stock item (which is assigned to a customer) to stock.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model = StockItem
|
||||||
|
ajax_form_title = _("Return to Stock")
|
||||||
|
context_object_name = "item"
|
||||||
|
form_class = StockForms.ReturnStockItemForm
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
location = request.POST.get('location', None)
|
||||||
|
|
||||||
|
if location:
|
||||||
|
try:
|
||||||
|
location = StockLocation.objects.get(pk=location)
|
||||||
|
except (ValueError, StockLocation.DoesNotExist):
|
||||||
|
location = None
|
||||||
|
|
||||||
|
if location:
|
||||||
|
stock_item = self.get_object()
|
||||||
|
|
||||||
|
stock_item.returnFromCustomer(location, request.user)
|
||||||
|
else:
|
||||||
|
raise ValidationError({'location': _("Specify a valid location")})
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'form_valid': True,
|
||||||
|
'success': _("Stock item returned from customer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.renderJsonResponse(request, self.get_form(), data)
|
||||||
|
|
||||||
|
|
||||||
class StockItemDeleteTestData(AjaxUpdateView):
|
class StockItemDeleteTestData(AjaxUpdateView):
|
||||||
"""
|
"""
|
||||||
View for deleting all test data
|
View for deleting all test data
|
||||||
|
@ -425,16 +425,10 @@ function loadStockTable(table, options) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
|
|
||||||
var url = '';
|
var url = `/stock/item/${row.pk}/`;
|
||||||
var thumb = row.part_detail.thumbnail;
|
var thumb = row.part_detail.thumbnail;
|
||||||
var name = row.part_detail.full_name;
|
var name = row.part_detail.full_name;
|
||||||
|
|
||||||
if (row.supplier_part) {
|
|
||||||
url = `/supplier-part/${row.supplier_part}/`;
|
|
||||||
} else {
|
|
||||||
url = `/part/${row.part}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
html = imageHoverIcon(thumb) + renderLink(name, url);
|
html = imageHoverIcon(thumb) + renderLink(name, url);
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
|
@ -18,14 +18,18 @@ function {{ label }}StatusDisplay(key) {
|
|||||||
|
|
||||||
key = String(key);
|
key = String(key);
|
||||||
|
|
||||||
var value = {{ label }}Codes[key].value;
|
var value = null;
|
||||||
|
var label = null;
|
||||||
|
|
||||||
|
if (key in {{ label }}Codes) {
|
||||||
|
value = {{ label }}Codes[key].value;
|
||||||
|
label = {{ label }}Codes[key].label;
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null || value.length == 0) {
|
if (value == null || value.length == 0) {
|
||||||
value = key;
|
value = key;
|
||||||
|
label = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the label color
|
|
||||||
var label = {{ label }}Codes[key].label ?? '';
|
|
||||||
|
|
||||||
return `<span class='label ${label}'>${value}</span>`;
|
return `<span class='label ${label}'>${value}</span>`;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ django-crispy-forms==1.8.1 # Form helpers
|
|||||||
django-import-export==2.0.0 # Data import / export for admin interface
|
django-import-export==2.0.0 # Data import / export for admin interface
|
||||||
django-cleanup==4.0.0 # Manage deletion of old / unused uploaded files
|
django-cleanup==4.0.0 # Manage deletion of old / unused uploaded files
|
||||||
django-qr-code==1.2.0 # Generate QR codes
|
django-qr-code==1.2.0 # Generate QR codes
|
||||||
flake8==3.3.0 # PEP checking
|
flake8==3.8.3 # PEP checking
|
||||||
coverage==4.0.3 # Unit test coverage
|
coverage==4.0.3 # Unit test coverage
|
||||||
python-coveralls==2.9.1 # Coveralls linking (for Travis)
|
python-coveralls==2.9.1 # Coveralls linking (for Travis)
|
||||||
rapidfuzz==0.7.6 # Fuzzy string matching
|
rapidfuzz==0.7.6 # Fuzzy string matching
|
||||||
|
Loading…
Reference in New Issue
Block a user