コード例 #1
0
ファイル: test_part.py プロジェクト: inventree/InvenTree
    def test_custom(self):
        """Update some of the part values and re-test."""
        for val in [True, False]:
            InvenTreeSetting.set_setting('PART_COMPONENT', val, self.user)
            InvenTreeSetting.set_setting('PART_PURCHASEABLE', val, self.user)
            InvenTreeSetting.set_setting('PART_SALABLE', val, self.user)
            InvenTreeSetting.set_setting('PART_TRACKABLE', val, self.user)
            InvenTreeSetting.set_setting('PART_ASSEMBLY', val, self.user)
            InvenTreeSetting.set_setting('PART_TEMPLATE', val, self.user)

            self.assertEqual(val,
                             InvenTreeSetting.get_setting('PART_COMPONENT'))
            self.assertEqual(val,
                             InvenTreeSetting.get_setting('PART_PURCHASEABLE'))
            self.assertEqual(val, InvenTreeSetting.get_setting('PART_SALABLE'))
            self.assertEqual(val,
                             InvenTreeSetting.get_setting('PART_TRACKABLE'))

            part = self.make_part()

            self.assertEqual(part.component, val)
            self.assertEqual(part.purchaseable, val)
            self.assertEqual(part.salable, val)
            self.assertEqual(part.trackable, val)
            self.assertEqual(part.assembly, val)
            self.assertEqual(part.is_template, val)

            Part.objects.filter(pk=part.pk).delete()
コード例 #2
0
    def test_default_shipment(self):
        """Test sales order default shipment creation"""
        # Default setting value should be False
        self.assertEqual(
            False, InvenTreeSetting.get_setting('SALESORDER_DEFAULT_SHIPMENT'))

        # Create an order
        order_1 = SalesOrder.objects.create(customer=self.customer,
                                            reference='1235',
                                            customer_reference='ABC 55556')

        # Order should have no shipments when setting is False
        self.assertEqual(0, order_1.shipment_count)

        # Update setting to True
        InvenTreeSetting.set_setting('SALESORDER_DEFAULT_SHIPMENT', True, None)
        self.assertEqual(
            True, InvenTreeSetting.get_setting('SALESORDER_DEFAULT_SHIPMENT'))

        # Create a second order
        order_2 = SalesOrder.objects.create(customer=self.customer,
                                            reference='1236',
                                            customer_reference='ABC 55557')

        # Order should have one shipment
        self.assertEqual(1, order_2.shipment_count)
        self.assertEqual(1, order_2.pending_shipments().count())

        # Shipment should have default reference of '1'
        self.assertEqual('1', order_2.pending_shipments()[0].reference)
コード例 #3
0
ファイル: test_views.py プロジェクト: fablabbcn/InvenTree
    def test_binary_values(self):
        """
        Test for binary value
        """

        setting = InvenTreeSetting.get_setting_object('PART_COMPONENT')

        self.assertTrue(setting.as_bool())

        url = self.get_url(setting.pk)

        setting.value = True
        setting.save()

        # Try posting some invalid values
        # The value should be "cleaned" and stay the same
        for value in ['', 'abc', 'cat', 'TRUETRUETRUE']:
            self.post(url, {'value': value}, valid=True)

        # Try posting some valid (True) values
        for value in [True, 'True', '1', 'yes']:
            self.post(url, {'value': value}, valid=True)
            self.assertTrue(InvenTreeSetting.get_setting('PART_COMPONENT'))

        # Try posting some valid (False) values
        for value in [False, 'False']:
            self.post(url, {'value': value}, valid=True)
            self.assertFalse(InvenTreeSetting.get_setting('PART_COMPONENT'))
コード例 #4
0
ファイル: forms.py プロジェクト: matmair/InvenTree
    def __init__(self, *args, **kwargs):
        kwargs['email_required'] = InvenTreeSetting.get_setting(
            'LOGIN_MAIL_REQUIRED')

        super().__init__(*args, **kwargs)

        # check for two mail fields
        if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
            self.fields["email2"] = forms.EmailField(
                label=_("Email (again)"),
                widget=forms.TextInput(
                    attrs={
                        "type": "email",
                        "placeholder": _("Email address confirmation"),
                    }),
            )

        # check for two password fields
        if not InvenTreeSetting.get_setting('LOGIN_SIGNUP_PWD_TWICE'):
            self.fields.pop("password2")

        # reorder fields
        set_form_field_order(self, [
            "username",
            "email",
            "email2",
            "password1",
            "password2",
        ])
コード例 #5
0
ファイル: test_tasks.py プロジェクト: inventree/InvenTree
    def test_task_check_for_updates(self):
        """Test the task check_for_updates."""
        # Check that setting should be empty
        self.assertEqual(
            InvenTreeSetting.get_setting('INVENTREE_LATEST_VERSION'), '')

        # Get new version
        InvenTree.tasks.offload_task(InvenTree.tasks.check_for_updates)

        # Check that setting is not empty
        response = InvenTreeSetting.get_setting('INVENTREE_LATEST_VERSION')
        self.assertNotEqual(response, '')
        self.assertTrue(bool(response))
コード例 #6
0
    def validate(self, item, form):
        """ Check that owner is set if stock ownership control is enabled """

        parent = form.cleaned_data.get('parent', None)

        owner = form.cleaned_data.get('owner', None)

        # Is ownership control enabled?
        stock_ownership_control = InvenTreeSetting.get_setting(
            'STOCK_OWNERSHIP_CONTROL')

        if stock_ownership_control:
            if not owner and not self.request.user.is_superuser:
                form.add_error(
                    'owner',
                    _('Owner is required (ownership control is enabled)'))
            else:
                try:
                    if parent.owner:
                        if parent.owner != owner:
                            error = f'Owner requires to be equivalent to parent\'s owner ({parent.owner})'
                            form.add_error('owner', error)
                except AttributeError:
                    # No parent
                    pass
コード例 #7
0
ファイル: api.py プロジェクト: sfabris/InvenTree
        def convert_price(price, currency, decimal_places=4):
            """ Convert price field, returns Money field """

            price_adjusted = None

            # Get default currency from settings
            default_currency = InvenTreeSetting.get_setting(
                'INVENTREE_DEFAULT_CURRENCY')

            if price:
                if currency and default_currency:
                    try:
                        # Get adjusted price
                        price_adjusted = convert_money(Money(price, currency),
                                                       default_currency)
                    except MissingRate:
                        # No conversion rate set
                        price_adjusted = Money(price, currency)
                else:
                    # Currency exists
                    if currency:
                        price_adjusted = Money(price, currency)
                    # Default currency exists
                    if default_currency:
                        price_adjusted = Money(price, default_currency)

            if price_adjusted and decimal_places:
                price_adjusted.decimal_places = decimal_places

            return price_adjusted
コード例 #8
0
ファイル: apps.py プロジェクト: matmair/InvenTree
    def ready(self):
        if settings.PLUGINS_ENABLED:
            if not canAppAccessDatabase(allow_test=True):
                logger.info("Skipping plugin loading sequence")  # pragma: no cover
            else:
                logger.info('Loading InvenTree plugins')

                if not registry.is_loading:
                    # this is the first startup
                    try:
                        from common.models import InvenTreeSetting
                        if InvenTreeSetting.get_setting('PLUGIN_ON_STARTUP', create=False):
                            # make sure all plugins are installed
                            registry.install_plugin_file()
                    except:  # pragma: no cover
                        pass

                    # get plugins and init them
                    registry.collect_plugins()
                    registry.load_plugins()

                    # drop out of maintenance
                    # makes sure we did not have an error in reloading and maintenance is still active
                    set_maintenance_mode(False)

            # check git version
            registry.git_is_modern = check_git_version()
            if not registry.git_is_modern:  # pragma: no cover  # simulating old git seems not worth it for coverage
                log_error(_('Your enviroment has an outdated git version. This prevents InvenTree from loading plugin details.'), 'load')

        else:
            logger.info("Plugins not enabled - skipping loading sequence")  # pragma: no cover
コード例 #9
0
def navigation_enabled(*args, **kwargs):
    """
    Is plugin navigation enabled?
    """
    if djangosettings.PLUGIN_TESTING:
        return True
    return InvenTreeSetting.get_setting('ENABLE_PLUGINS_NAVIGATION')  # pragma: no cover
コード例 #10
0
ファイル: views.py プロジェクト: wengtad/InvenTree
    def get_form(self):
        """ Disable owner field when:
            - creating child location
            - and stock ownership control is enable
        """

        form = super().get_form()

        # Is ownership control enabled?
        stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')

        if not stock_ownership_control:
            # Hide owner field
            form.fields['owner'].widget = HiddenInput()
        else:
            # If user did not selected owner: automatically match to parent's owner
            if not form['owner'].data:
                try:
                    parent_id = form['parent'].value()
                    parent = StockLocation.objects.get(pk=parent_id)

                    if parent:
                        form.fields['owner'].initial = parent.owner
                        if not self.request.user.is_superuser:
                            form.fields['owner'].disabled = True
                except StockLocation.DoesNotExist:
                    pass
                except ValueError:
                    pass

        return form
コード例 #11
0
ファイル: helpers.py プロジェクト: wengtad/InvenTree
def construct_absolute_url(*arg):
    """
    Construct (or attempt to construct) an absolute URL from a relative URL.

    This is useful when (for example) sending an email to a user with a link
    to something in the InvenTree web framework.

    This requires the BASE_URL configuration option to be set!
    """

    base = str(InvenTreeSetting.get_setting('INVENTREE_BASE_URL'))

    url = '/'.join(arg)

    if not base:
        return url

    # Strip trailing slash from base url
    if base.endswith('/'):
        base = base[:-1]

    if url.startswith('/'):
        url = url[1:]

    url = f"{base}/{url}"

    return url
コード例 #12
0
ファイル: forms.py プロジェクト: sfabris/InvenTree
    def get_special_field(self, col_guess, row, file_manager):
        """ Set special fields """

        # set quantity field
        if 'quantity' in col_guess.lower():
            return forms.CharField(
                required=False,
                widget=forms.NumberInput(attrs={
                    'name': 'quantity' + str(row['index']),
                    'class': 'numberinput',
                    'type': 'number',
                    'min': '0',
                    'step': 'any',
                    'value': clean_decimal(row.get('quantity', '')),
                })
            )
        # set price field
        elif 'price' in col_guess.lower():
            return MoneyField(
                label=_(col_guess),
                default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'),
                decimal_places=5,
                max_digits=19,
                required=False,
                default_amount=clean_decimal(row.get('purchase_price', '')),
            )

        # return default
        return super().get_special_field(col_guess, row, file_manager)
コード例 #13
0
ファイル: test_views.py プロジェクト: sfabris/InvenTree
    def enable_ownership(self):
        # Enable stock location ownership

        InvenTreeSetting.set_setting('STOCK_OWNERSHIP_CONTROL', True,
                                     self.user)
        self.assertEqual(
            True, InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL'))
コード例 #14
0
def stock_expiry_enabled():
    """
    Returns True if the stock expiry feature is enabled
    """
    from common.models import InvenTreeSetting

    return InvenTreeSetting.get_setting('STOCK_ENABLE_EXPIRY')
コード例 #15
0
ファイル: events.py プロジェクト: inventree/InvenTree
def register_event(event, *args, **kwargs):
    """Register the event with any interested plugins.

    Note: This function is processed by the background worker,
    as it performs multiple database access operations.
    """
    from common.models import InvenTreeSetting

    logger.debug(f"Registering triggered event: '{event}'")

    # Determine if there are any plugins which are interested in responding
    if settings.PLUGIN_TESTING or InvenTreeSetting.get_setting(
            'ENABLE_PLUGINS_EVENTS'):

        with transaction.atomic():

            for slug, plugin in registry.plugins.items():

                if plugin.mixin_enabled('events'):

                    config = plugin.plugin_config()

                    if config and config.active:

                        logger.debug(
                            f"Registering callback for plugin '{slug}'")

                        # Offload a separate task for each plugin
                        offload_task(process_event, slug, event, *args,
                                     **kwargs)
コード例 #16
0
ファイル: report.py プロジェクト: hrshtt/InvenTree
def internal_link(link, text):
    """
    Make a <a></a> href which points to an InvenTree URL.

    Important Note: This only works if the INVENTREE_BASE_URL parameter is set!

    If the INVENTREE_BASE_URL parameter is not configured,
    the text will be returned (unlinked)
    """

    text = str(text)

    base_url = InvenTreeSetting.get_setting('INVENTREE_BASE_URL')

    # If the base URL is not set, just return the text
    if not base_url:
        return text

    if not base_url.endswith('/'):
        base_url += '/'

    if base_url.endswith('/') and link.startswith('/'):
        link = link[1:]

    url = f"{base_url}{link}"

    return mark_safe(f'<a href="{url}">{text}</a>')
コード例 #17
0
ファイル: report.py プロジェクト: hrshtt/InvenTree
def part_image(part):
    """
    Return a fully-qualified path for a part image
    """

    # If in debug mode, return URL to the image, not a local file
    debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')

    if type(part) is Part:
        img = part.image.name

    elif type(part) is StockItem:
        img = part.part.image.name

    else:
        img = ''

    if debug_mode:
        if img:
            return os.path.join(settings.MEDIA_URL, img)
        else:
            return os.path.join(settings.STATIC_URL, 'img', 'blank_image.png')

    else:
        path = os.path.join(settings.MEDIA_ROOT, img)
        path = os.path.abspath(path)

        if not os.path.exists(path) or not os.path.isfile(path):
            # Image does not exist
            # Return the 'blank' image
            path = os.path.join(settings.STATIC_ROOT, 'img', 'blank_image.png')
            path = os.path.abspath(path)

        return f"file://{path}"
コード例 #18
0
ファイル: views.py プロジェクト: wengtad/InvenTree
    def validate(self, item, form):
        """
        Extra form validation steps
        """

        data = form.cleaned_data

        part = data.get('part', None)

        quantity = data.get('quantity', None)

        owner = data.get('owner', None)

        if not part:
            return

        if not quantity:
            return

        try:
            quantity = Decimal(quantity)
        except (ValueError, InvalidOperation):
            form.add_error('quantity', _('Invalid quantity provided'))
            return

        if quantity < 0:
            form.add_error('quantity', _('Quantity cannot be negative'))

        # Trackable parts are treated differently
        if part.trackable:
            sn = data.get('serial_numbers', '')
            sn = str(sn).strip()

            if len(sn) > 0:
                try:
                    serials = extract_serial_numbers(sn, quantity)
                except ValidationError as e:
                    serials = None
                    form.add_error('serial_numbers', e.messages)

                if serials is not None:
                    existing = part.find_conflicting_serial_numbers(serials)

                    if len(existing) > 0:
                        exists = ','.join([str(x) for x in existing])

                        form.add_error(
                            'serial_numbers',
                            _('Serial numbers already exist') + ': ' + exists
                        )

        # Is ownership control enabled?
        stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')

        if stock_ownership_control:
            # Check if owner is set
            if not owner and not self.request.user.is_superuser:
                form.add_error('owner', _('Owner is required (ownership control is enabled)'))
                return
コード例 #19
0
 def require_2fa(self, request):
     """Use setting to check if MFA should be enforced for frontend page."""
     try:
         if url_matcher.resolve(request.path[1:]):
             return InvenTreeSetting.get_setting('LOGIN_ENFORCE_MFA')
     except Resolver404:
         pass
     return False
コード例 #20
0
 def require_2fa(self, request):
     # Superusers are require to have 2FA.
     try:
         if url_matcher.resolve(request.path[1:]):
             return InvenTreeSetting.get_setting('LOGIN_ENFORCE_MFA')
     except Resolver404:
         pass
     return False
コード例 #21
0
ファイル: inventree_extras.py プロジェクト: wengtad/InvenTree
def settings_value(key, *args, **kwargs):
    """
    Return a settings value specified by the given key
    """

    if 'user' in kwargs:
        return InvenTreeUserSetting.get_setting(key, user=kwargs['user'])

    return InvenTreeSetting.get_setting(key)
コード例 #22
0
def settings_value(key, *args, **kwargs):
    """Return a settings value specified by the given key."""
    if 'user' in kwargs:
        if not kwargs['user'] or (kwargs['user'] and
                                  kwargs['user'].is_authenticated is False):
            return InvenTreeUserSetting.get_setting(key)
        return InvenTreeUserSetting.get_setting(key, user=kwargs['user'])

    return InvenTreeSetting.get_setting(key)
コード例 #23
0
    def get_form(self):
        """ Customize form data for StockLocation editing.

        Limit the choices for 'parent' field to those which make sense.
        If ownership control is enabled and location has parent, disable owner field.
        """

        form = super(AjaxUpdateView, self).get_form()

        location = self.get_object()

        # Remove any invalid choices for the 'parent' field
        parent_choices = StockLocation.objects.all()
        parent_choices = parent_choices.exclude(
            id__in=location.getUniqueChildren())

        form.fields['parent'].queryset = parent_choices

        # Is ownership control enabled?
        stock_ownership_control = InvenTreeSetting.get_setting(
            'STOCK_OWNERSHIP_CONTROL')

        if not stock_ownership_control:
            # Hide owner field
            form.fields['owner'].widget = HiddenInput()
        else:
            # Get location's owner
            location_owner = location.owner

            if location_owner:
                if location.parent:
                    try:
                        # If location has parent and owner: automatically select parent's owner
                        parent_owner = location.parent.owner
                        form.fields['owner'].initial = parent_owner
                    except AttributeError:
                        pass
                else:
                    # If current owner exists: automatically select it
                    form.fields['owner'].initial = location_owner

                # Update queryset or disable field (only if not admin)
                if not self.request.user.is_superuser:
                    if type(location_owner.owner) is Group:
                        user_as_owner = Owner.get_owner(self.request.user)
                        queryset = location_owner.get_related_owners(
                            include_group=True)

                        if user_as_owner not in queryset:
                            # Only owners or admin can change current owner
                            form.fields['owner'].disabled = True
                        else:
                            form.fields['owner'].queryset = queryset

        return form
コード例 #24
0
ファイル: views.py プロジェクト: wengtad/InvenTree
    def validate(self, item, form):
        """ Check that owner is set if stock ownership control is enabled """

        owner = form.cleaned_data.get('owner', None)

        # Is ownership control enabled?
        stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')

        if stock_ownership_control:
            if not owner and not self.request.user.is_superuser:
                form.add_error('owner', _('Owner is required (ownership control is enabled)'))
コード例 #25
0
ファイル: report.py プロジェクト: eeintech/InvenTree
def logo_image(**kwargs):
    """Return a fully-qualified path for the logo image.

    - If a custom logo has been provided, return a path to that logo
    - Otherwise, return a path to the default InvenTree logo
    """

    # If in debug mode, return URL to the image, not a local file
    debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')

    return InvenTree.helpers.getLogoImage(as_file=not debug_mode, **kwargs)
コード例 #26
0
 def save_user(self, request, user, form, commit=True):
     user = super().save_user(request, user, form, commit=commit)
     start_group = InvenTreeSetting.get_setting('SIGNUP_GROUP')
     if start_group:
         try:
             group = Group.objects.get(id=start_group)
             user.groups.add(group)
         except Group.DoesNotExist:
             logger.error('The setting `SIGNUP_GROUP` contains an non existant group', start_group)
     user.save()
     return user
コード例 #27
0
    def clean(self):
        cleaned_data = super().clean()

        # check for two mail fields
        if InvenTreeSetting.get_setting('LOGIN_SIGNUP_MAIL_TWICE'):
            email = cleaned_data.get("email")
            email2 = cleaned_data.get("email2")
            if (email and email2) and email != email2:
                self.add_error("email2", _("You must type the same email each time."))

        return cleaned_data
コード例 #28
0
ファイル: settings.py プロジェクト: lookme2/InvenTree
def currency_code_default():
    """
    Returns the default currency code (or USD if not specified)
    """

    code = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY')

    if code not in CURRENCIES:
        code = 'USD'

    return code
コード例 #29
0
    def get_reference_pattern(cls):
        """Returns the reference pattern associated with this model.

        This is defined by a global setting object, specified by the REFERENCE_PATTERN_SETTING attribute
        """

        # By default, we return an empty string
        if cls.REFERENCE_PATTERN_SETTING is None:
            return ''

        return InvenTreeSetting.get_setting(cls.REFERENCE_PATTERN_SETTING, create=False).strip()
コード例 #30
0
def validate_part_ipn(value):
    """ Validate the Part IPN against regex rule """

    pattern = InvenTreeSetting.get_setting('part_ipn_regex')

    if pattern:
        match = re.search(pattern, value)

        if match is None:
            raise ValidationError(
                _('IPN must match regex pattern') +
                " '{pat}'".format(pat=pattern))