2019-04-27 12:49:16 +00:00
"""
Django Forms for interacting with Stock app
"""
2018-04-17 13:13:41 +00:00
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
2018-04-15 10:10:49 +00:00
from django import forms
2019-07-23 00:31:34 +00:00
from django . forms . utils import ErrorDict
2019-08-28 09:56:35 +00:00
from django . utils . translation import ugettext as _
2020-10-04 09:41:28 +00:00
from django . core . validators import MinValueValidator
2020-10-04 10:31:44 +00:00
from django . core . exceptions import ValidationError
2018-04-15 10:10:49 +00:00
2019-09-17 10:15:50 +00:00
from mptt . fields import TreeNodeChoiceField
2019-09-08 13:10:13 +00:00
from InvenTree . helpers import GetExportFormats
2019-07-23 00:31:34 +00:00
from InvenTree . forms import HelperForm
2020-05-15 11:16:00 +00:00
from InvenTree . fields import RoundingDecimalFormField
2020-08-23 11:03:29 +00:00
from report . models import TestReport
2020-10-04 12:45:52 +00:00
from part . models import Part
2020-05-16 14:26:10 +00:00
from . models import StockLocation , StockItem , StockItemTracking
from . models import StockItemAttachment
from . models import StockItemTestResult
2020-05-06 23:57:54 +00:00
class EditStockItemAttachmentForm ( HelperForm ) :
"""
Form for creating / editing a StockItemAttachment object
"""
class Meta :
model = StockItemAttachment
fields = [
' stock_item ' ,
' attachment ' ,
' comment '
]
2018-04-15 10:10:49 +00:00
2018-04-17 13:56:25 +00:00
2020-06-04 09:45:41 +00:00
class AssignStockItemToCustomerForm ( HelperForm ) :
"""
Form for manually assigning a StockItem to a Customer
"""
class Meta :
model = StockItem
fields = [
' customer ' ,
]
2020-08-07 23:05:33 +00:00
class ReturnStockItemForm ( HelperForm ) :
"""
Form for manually returning a StockItem into stock
"""
class Meta :
model = StockItem
fields = [
' location ' ,
]
2020-05-16 14:26:10 +00:00
class EditStockItemTestResultForm ( HelperForm ) :
"""
Form for creating / editing a StockItemTestResult object .
"""
class Meta :
model = StockItemTestResult
fields = [
' stock_item ' ,
' test ' ,
' result ' ,
' value ' ,
2020-05-17 06:17:05 +00:00
' attachment ' ,
2020-05-16 14:26:10 +00:00
' notes ' ,
]
2018-04-29 14:59:36 +00:00
class EditStockLocationForm ( HelperForm ) :
2019-04-27 12:49:16 +00:00
""" Form for editing a StockLocation """
2018-04-15 10:10:49 +00:00
class Meta :
model = StockLocation
fields = [
' name ' ,
' parent ' ,
' description '
]
2020-05-25 04:16:38 +00:00
class ConvertStockItemForm ( HelperForm ) :
"""
Form for converting a StockItem to a variant of its current part .
"""
class Meta :
model = StockItem
fields = [
' part '
]
2018-04-29 14:59:36 +00:00
class CreateStockItemForm ( HelperForm ) :
2019-04-27 12:49:16 +00:00
""" Form for creating a new StockItem """
2018-04-15 10:10:49 +00:00
2019-08-28 09:56:35 +00:00
serial_numbers = forms . CharField ( label = ' Serial numbers ' , required = False , help_text = _ ( ' Enter unique serial numbers (or leave blank) ' ) )
2019-07-23 00:31:34 +00:00
2020-05-16 01:55:10 +00:00
def __init__ ( self , * args , * * kwargs ) :
self . field_prefix = {
' serial_numbers ' : ' fa-hashtag ' ,
' link ' : ' fa-link ' ,
}
super ( ) . __init__ ( * args , * * kwargs )
2018-04-15 10:10:49 +00:00
class Meta :
model = StockItem
fields = [
' part ' ,
' supplier_part ' ,
' location ' ,
' quantity ' ,
2019-05-14 13:04:49 +00:00
' batch ' ,
2019-07-23 00:31:34 +00:00
' serial_numbers ' ,
2020-04-06 00:43:06 +00:00
' link ' ,
2019-05-09 13:06:19 +00:00
' delete_on_deplete ' ,
2018-04-16 10:08:04 +00:00
' status ' ,
2018-04-15 15:02:17 +00:00
]
2018-04-29 14:59:36 +00:00
2019-07-23 00:31:34 +00:00
# Custom clean to prevent complex StockItem.clean() logic from running (yet)
def full_clean ( self ) :
self . _errors = ErrorDict ( )
if not self . is_bound : # Stop further processing.
return
self . cleaned_data = { }
2020-05-16 01:55:10 +00:00
2019-07-23 00:31:34 +00:00
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self . empty_permitted and not self . has_changed ( ) :
return
# Don't run _post_clean() as this will run StockItem.clean()
self . _clean_fields ( )
self . _clean_form ( )
2018-04-29 14:59:36 +00:00
2020-05-15 11:16:00 +00:00
class SerializeStockForm ( HelperForm ) :
2019-08-28 11:46:26 +00:00
""" Form for serializing a StockItem. """
2019-09-17 10:19:05 +00:00
destination = TreeNodeChoiceField ( queryset = StockLocation . objects . all ( ) , label = ' Destination ' , required = True , help_text = ' Destination for serialized stock (by default, will remain in current location) ' )
2019-08-28 21:37:44 +00:00
serial_numbers = forms . CharField ( label = ' Serial numbers ' , required = True , help_text = ' Unique serial numbers (must match quantity) ' )
2019-09-17 10:19:05 +00:00
2019-08-28 12:04:04 +00:00
note = forms . CharField ( label = ' Notes ' , required = False , help_text = ' Add transaction note (optional) ' )
2019-08-28 11:46:26 +00:00
2020-05-15 11:16:00 +00:00
quantity = RoundingDecimalFormField ( max_digits = 10 , decimal_places = 5 )
def __init__ ( self , * args , * * kwargs ) :
# Extract the stock item
2020-05-16 01:55:10 +00:00
item = kwargs . pop ( ' item ' , None )
if item :
2020-05-16 07:52:25 +00:00
self . field_placeholder [ ' serial_numbers ' ] = item . part . getSerialNumberString ( item . quantity )
2020-05-15 23:33:34 +00:00
super ( ) . __init__ ( * args , * * kwargs )
2020-05-15 11:16:00 +00:00
2019-08-28 11:46:26 +00:00
class Meta :
model = StockItem
fields = [
' quantity ' ,
' serial_numbers ' ,
' destination ' ,
' note ' ,
]
2020-08-16 02:10:58 +00:00
class StockItemLabelSelectForm ( HelperForm ) :
""" Form for selecting a label template for a StockItem """
label = forms . ChoiceField (
label = _ ( ' Label ' ) ,
help_text = _ ( ' Select test report template ' )
)
class Meta :
model = StockItem
fields = [
' label ' ,
]
def get_label_choices ( self , labels ) :
choices = [ ]
if len ( labels ) > 0 :
for label in labels :
choices . append ( ( label . pk , label ) )
return choices
def __init__ ( self , labels , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
self . fields [ ' label ' ] . choices = self . get_label_choices ( labels )
2020-05-22 12:25:05 +00:00
class TestReportFormatForm ( HelperForm ) :
""" Form for selection a test report template """
class Meta :
model = StockItem
fields = [
' template ' ,
]
def __init__ ( self , stock_item , * args , * * kwargs ) :
self . stock_item = stock_item
super ( ) . __init__ ( * args , * * kwargs )
self . fields [ ' template ' ] . choices = self . get_template_choices ( )
def get_template_choices ( self ) :
2020-08-23 11:03:29 +00:00
"""
Generate a list of of TestReport options for the StockItem
"""
2020-05-22 12:25:05 +00:00
choices = [ ]
2020-08-23 11:03:29 +00:00
templates = TestReport . objects . filter ( enabled = True )
for template in templates :
if template . matches_stock_item ( self . stock_item ) :
2020-08-26 04:29:49 +00:00
choices . append ( ( template . pk , template ) )
2020-05-22 12:25:05 +00:00
return choices
template = forms . ChoiceField ( label = _ ( ' Template ' ) , help_text = _ ( ' Select test report template ' ) )
2019-09-08 12:37:27 +00:00
class ExportOptionsForm ( HelperForm ) :
""" Form for selecting stock export options """
file_format = forms . ChoiceField ( label = _ ( ' File Format ' ) , help_text = _ ( ' Select output file format ' ) )
include_sublocations = forms . BooleanField ( required = False , initial = True , help_text = _ ( " Include stock items in sub locations " ) )
class Meta :
model = StockLocation
fields = [
' file_format ' ,
' include_sublocations ' ,
]
def get_format_choices ( self ) :
""" File format choices """
2019-09-08 13:10:13 +00:00
choices = [ ( x , x . upper ( ) ) for x in GetExportFormats ( ) ]
2019-09-08 12:37:27 +00:00
return choices
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
self . fields [ ' file_format ' ] . choices = self . get_format_choices ( )
2020-10-04 09:41:28 +00:00
class InstallStockForm ( HelperForm ) :
"""
Form for manually installing a stock item into another stock item
"""
2020-10-04 12:45:52 +00:00
part = forms . ModelChoiceField (
queryset = Part . objects . all ( ) ,
2020-10-04 12:48:15 +00:00
widget = forms . HiddenInput ( )
2020-10-04 12:45:52 +00:00
)
2020-10-04 09:41:28 +00:00
stock_item = forms . ModelChoiceField (
required = True ,
queryset = StockItem . objects . filter ( StockItem . IN_STOCK_FILTER ) ,
help_text = _ ( ' Stock item to install ' )
)
2020-10-04 09:50:06 +00:00
quantity_to_install = RoundingDecimalFormField (
2020-10-04 09:41:28 +00:00
max_digits = 10 , decimal_places = 5 ,
2020-10-04 09:50:06 +00:00
initial = 1 ,
label = _ ( ' Quantity ' ) ,
2020-10-04 09:41:28 +00:00
help_text = _ ( ' Stock quantity to assign ' ) ,
validators = [
MinValueValidator ( 0.001 )
]
)
2020-10-04 10:31:44 +00:00
notes = forms . CharField (
required = False ,
help_text = _ ( ' Notes ' )
)
2020-10-04 09:41:28 +00:00
class Meta :
model = StockItem
fields = [
2020-10-04 12:45:52 +00:00
' part ' ,
2020-10-04 09:41:28 +00:00
' stock_item ' ,
2020-10-04 09:50:06 +00:00
' quantity_to_install ' ,
2020-10-04 10:31:44 +00:00
' notes ' ,
2020-10-04 09:41:28 +00:00
]
2020-10-04 10:31:44 +00:00
def clean ( self ) :
data = super ( ) . clean ( )
2020-10-04 12:48:15 +00:00
stock_item = data . get ( ' stock_item ' , None )
quantity = data . get ( ' quantity_to_install ' , None )
2020-10-04 10:31:44 +00:00
2020-10-04 12:48:15 +00:00
if stock_item and quantity and quantity > stock_item . quantity :
2020-10-04 10:31:44 +00:00
raise ValidationError ( { ' quantity_to_install ' : _ ( ' Must not exceed available quantity ' ) } )
return data
2020-10-04 09:41:28 +00:00
2020-09-28 11:27:27 +00:00
class UninstallStockForm ( forms . ModelForm ) :
"""
Form for uninstalling a stock item which is installed in another item .
"""
location = TreeNodeChoiceField ( queryset = StockLocation . objects . all ( ) , label = _ ( ' Location ' ) , help_text = _ ( ' Destination location for uninstalled items ' ) )
2020-09-28 11:52:23 +00:00
note = forms . CharField ( label = _ ( ' Notes ' ) , required = False , help_text = _ ( ' Add transaction note (optional) ' ) )
2020-09-28 11:27:27 +00:00
confirm = forms . BooleanField ( required = False , initial = False , label = _ ( ' Confirm uninstall ' ) , help_text = _ ( ' Confirm removal of installed stock items ' ) )
class Meta :
model = StockItem
fields = [
' location ' ,
2020-09-28 11:52:23 +00:00
' note ' ,
2020-09-28 11:27:27 +00:00
' confirm ' ,
]
2020-09-28 12:01:45 +00:00
2019-06-02 02:45:44 +00:00
class AdjustStockForm ( forms . ModelForm ) :
""" Form for performing simple stock adjustments.
2019-05-29 23:01:16 +00:00
2019-06-02 02:45:44 +00:00
- Add stock
- Remove stock
- Count stock
- Move stock
2019-05-29 23:01:16 +00:00
2019-06-02 02:45:44 +00:00
This form is used for managing stock adjuments for single or multiple stock items .
"""
2019-05-29 23:01:16 +00:00
2020-09-28 11:27:27 +00:00
destination = TreeNodeChoiceField ( queryset = StockLocation . objects . all ( ) , label = _ ( ' Destination ' ) , required = True , help_text = _ ( ' Destination stock location ' ) )
2019-09-17 10:15:50 +00:00
2020-09-28 11:27:27 +00:00
note = forms . CharField ( label = _ ( ' Notes ' ) , required = True , help_text = _ ( ' Add note (required) ' ) )
2019-09-17 10:15:50 +00:00
2019-06-01 12:04:03 +00:00
# transaction = forms.BooleanField(required=False, initial=False, label='Create Transaction', help_text='Create a stock transaction for these parts')
2019-09-17 10:15:50 +00:00
2020-09-28 11:27:27 +00:00
confirm = forms . BooleanField ( required = False , initial = False , label = _ ( ' Confirm stock adjustment ' ) , help_text = _ ( ' Confirm movement of stock items ' ) )
2019-09-05 09:59:00 +00:00
2020-09-28 11:27:27 +00:00
set_loc = forms . BooleanField ( required = False , initial = False , label = _ ( ' Set Default Location ' ) , help_text = _ ( ' Set the destination as the default location for selected parts ' ) )
2019-05-29 12:05:13 +00:00
2018-04-29 14:59:36 +00:00
class Meta :
model = StockItem
fields = [
2019-06-02 01:00:28 +00:00
' destination ' ,
2019-05-29 12:05:13 +00:00
' note ' ,
2019-06-01 12:04:03 +00:00
# 'transaction',
2019-05-29 12:05:13 +00:00
' confirm ' ,
2018-04-29 14:59:36 +00:00
]
class EditStockItemForm ( HelperForm ) :
2019-05-09 08:38:37 +00:00
""" Form for editing a StockItem object.
Note that not all fields can be edited here ( even if they can be specified during creation .
location - Must be updated in a ' move ' transaction
quantity - Must be updated in a ' stocktake ' transaction
part - Cannot be edited after creation
"""
2018-04-29 14:59:36 +00:00
class Meta :
model = StockItem
fields = [
2019-04-25 13:35:48 +00:00
' supplier_part ' ,
2019-07-25 01:04:45 +00:00
' serial ' ,
2018-04-29 14:59:36 +00:00
' batch ' ,
' status ' ,
2020-04-06 00:43:06 +00:00
' link ' ,
2019-07-25 01:04:45 +00:00
' delete_on_deplete ' ,
2019-04-13 23:23:24 +00:00
]
2019-07-15 14:10:24 +00:00
class TrackingEntryForm ( HelperForm ) :
""" Form for creating / editing a StockItemTracking object.
"""
class Meta :
model = StockItemTracking
fields = [
' title ' ,
' notes ' ,
2020-04-06 00:43:06 +00:00
' link ' ,
2019-07-15 14:10:24 +00:00
]