コード例 #1
0
    def validate(self, build, form, **kwargs):
        """
        Validation for the form:
        """

        quantity = form.cleaned_data.get('output_quantity', None)
        serials = form.cleaned_data.get('serial_numbers', None)

        # Check that the serial numbers are valid
        if serials:
            try:
                extracted = extract_serial_numbers(serials, quantity)

                if extracted:
                    # Check for conflicting serial numbers
                    conflicts = build.part.find_conflicting_serial_numbers(
                        extracted)

                    if len(conflicts) > 0:
                        msg = ",".join([str(c) for c in conflicts])
                        form.add_error(
                            'serial_numbers',
                            _('Serial numbers already exist') + ': ' + msg,
                        )

            except ValidationError as e:
                form.add_error('serial_numbers', e.messages)

        else:
            # If no serial numbers are provided, should they be?
            if build.part.trackable:
                form.add_error(
                    'serial_numbers',
                    _('Serial numbers required for trackable build output'))
コード例 #2
0
ファイル: serializers.py プロジェクト: matmair/InvenTree
    def validate(self, data):

        data = super().validate(data)

        line_item = data['line_item']
        quantity = data['quantity']
        serial_numbers = data.get('serial_numbers', '').strip()

        base_part = line_item.part.part

        # Does the quantity need to be "integer" (for trackable parts?)
        if base_part.trackable:

            if Decimal(quantity) != int(quantity):
                raise ValidationError({
                    'quantity':
                    _('An integer quantity must be provided for trackable parts'
                      ),
                })

        # If serial numbers are provided
        if serial_numbers:
            try:
                # Pass the serial numbers through to the parent serializer once validated
                data['serials'] = extract_serial_numbers(
                    serial_numbers, quantity,
                    base_part.getLatestSerialNumberInt())
            except DjangoValidationError as e:
                raise ValidationError({
                    'serial_numbers': e.messages,
                })

        return data
コード例 #3
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
コード例 #4
0
ファイル: views.py プロジェクト: rcludwick/InvenTree
    def save(self, form, **kwargs):
        """
        Create a new StockItem based on the provided form data.
        """

        data = form.cleaned_data

        part = data['part']

        quantity = data['quantity']

        if part.trackable:
            sn = data.get('serial_numbers', '')
            sn = str(sn).strip()

            # Create a single stock item for each provided serial number
            if len(sn) > 0:
                serials = extract_serial_numbers(sn, quantity)

                for serial in serials:
                    item = StockItem(
                        part=part,
                        quantity=1,
                        serial=serial,
                        supplier_part=data.get('supplier_part', None),
                        location=data.get('location', None),
                        batch=data.get('batch', None),
                        delete_on_deplete=False,
                        status=data.get('status'),
                        link=data.get('link', ''),
                    )

                    item.save(user=self.request.user)

            # Create a single StockItem of the specified quantity
            else:
                form._post_clean()

                item = form.save(commit=False)
                item.user = self.request.user
                item.save(user=self.request.user)

                return item

        # Non-trackable part
        else:

            form._post_clean()

            item = form.save(commit=False)
            item.user = self.request.user
            item.save(user=self.request.user)

            return item
コード例 #5
0
ファイル: views.py プロジェクト: rcludwick/InvenTree
    def post(self, request, *args, **kwargs):

        form = self.get_form()

        item = self.get_object()

        quantity = request.POST.get('quantity', 0)
        serials = request.POST.get('serial_numbers', '')
        dest_id = request.POST.get('destination', None)
        notes = request.POST.get('note', '')
        user = request.user

        valid = True

        try:
            destination = StockLocation.objects.get(pk=dest_id)
        except (ValueError, StockLocation.DoesNotExist):
            destination = None

        try:
            numbers = extract_serial_numbers(serials, quantity)
        except ValidationError as e:
            form.add_error('serial_numbers', e.messages)
            valid = False
            numbers = []

        if valid:
            try:
                item.serializeStock(quantity,
                                    numbers,
                                    user,
                                    notes=notes,
                                    location=destination)
            except ValidationError as e:
                messages = e.message_dict

                for k in messages.keys():
                    if k in ['quantity', 'destination', 'serial_numbers']:
                        form.add_error(k, messages[k])
                    else:
                        form.add_error(None, messages[k])

                valid = False

        data = {
            'form_valid': valid,
        }

        return self.renderJsonResponse(request, form, data=data)
コード例 #6
0
    def validate(self, build, form, **kwargs):
        """
        Validation for the form:
        """

        quantity = form.cleaned_data.get('output_quantity', None)
        serials = form.cleaned_data.get('serial_numbers', None)

        if quantity:
            build = self.get_object()

            # Check that requested output don't exceed build remaining quantity
            maximum_output = int(build.remaining - build.incomplete_count)
            if quantity > maximum_output:
                form.add_error(
                    'output_quantity',
                    _('Maximum output quantity is ') + str(maximum_output),
                )

        # Check that the serial numbers are valid
        if serials:
            try:
                extracted = extract_serial_numbers(serials, quantity)

                if extracted:
                    # Check for conflicting serial numbers
                    conflicts = build.part.find_conflicting_serial_numbers(
                        extracted)

                    if len(conflicts) > 0:
                        msg = ",".join([str(c) for c in conflicts])
                        form.add_error(
                            'serial_numbers',
                            _('Serial numbers already exist') + ': ' + msg,
                        )

            except ValidationError as e:
                form.add_error('serial_numbers', e.messages)

        else:
            # If no serial numbers are provided, should they be?
            if build.part.trackable:
                form.add_error(
                    'serial_numbers',
                    _('Serial numbers required for trackable build output'))
コード例 #7
0
ファイル: serializers.py プロジェクト: matmair/InvenTree
    def validate(self, data):
        """
        Perform form validation
        """

        part = self.get_part()

        # Cache a list of serial numbers (to be used in the "save" method)
        self.serials = None

        quantity = data['quantity']
        serial_numbers = data.get('serial_numbers', '')

        if serial_numbers:

            try:
                self.serials = extract_serial_numbers(
                    serial_numbers, quantity, part.getLatestSerialNumberInt())
            except DjangoValidationError as e:
                raise ValidationError({
                    'serial_numbers': e.messages,
                })

            # Check for conflicting serial numbesr
            existing = []

            for serial in self.serials:
                if part.checkIfSerialNumberExists(serial):
                    existing.append(serial)

            if len(existing) > 0:

                msg = _("The following serial numbers already exist")
                msg += " : "
                msg += ",".join([str(e) for e in existing])

                raise ValidationError({
                    'serial_numbers': msg,
                })

        return data
コード例 #8
0
    def save(self, build, form, **kwargs):
        """
        Create a new build output
        """

        data = form.cleaned_data

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

        serials = data.get('serial_numbers', None)

        if serials:
            serial_numbers = extract_serial_numbers(serials, quantity)
        else:
            serial_numbers = None

        build.create_build_output(
            quantity,
            serials=serial_numbers,
            batch=batch,
        )
コード例 #9
0
ファイル: views.py プロジェクト: rcludwick/InvenTree
    def validate(self, item, form):
        """
        Extra form validation steps
        """

        data = form.cleaned_data

        part = data['part']

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

        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:
                serials = extract_serial_numbers(sn, quantity)

                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)
コード例 #10
0
ファイル: serializers.py プロジェクト: wengtad/InvenTree
    def validate(self, data):
        """
        Validation for the serializer:

        - Ensure the serial_numbers and quantity fields match
        - Check that all serial numbers exist
        - Check that the serial numbers are not yet allocated
        """

        data = super().validate(data)

        line_item = data['line_item']
        quantity = data['quantity']
        serial_numbers = data['serial_numbers']

        part = line_item.part

        try:
            data['serials'] = extract_serial_numbers(serial_numbers, quantity)
        except DjangoValidationError as e:
            raise ValidationError({
                'serial_numbers': e.messages,
            })

        serials_not_exist = []
        serials_allocated = []
        stock_items_to_allocate = []

        for serial in data['serials']:
            items = stock.models.StockItem.objects.filter(
                part=part,
                serial=serial,
                quantity=1,
            )

            if not items.exists():
                serials_not_exist.append(str(serial))
                continue

            stock_item = items[0]

            if stock_item.unallocated_quantity() == 1:
                stock_items_to_allocate.append(stock_item)
            else:
                serials_allocated.append(str(serial))

        if len(serials_not_exist) > 0:

            error_msg = _("No match found for the following serial numbers")
            error_msg += ": "
            error_msg += ",".join(serials_not_exist)

            raise ValidationError({
                'serial_numbers': error_msg
            })

        if len(serials_allocated) > 0:

            error_msg = _("The following serial numbers are already allocated")
            error_msg += ": "
            error_msg += ",".join(serials_allocated)

            raise ValidationError({
                'serial_numbers': error_msg,
            })

        data['stock_items'] = stock_items_to_allocate

        return data
コード例 #11
0
ファイル: views.py プロジェクト: renatovelasquez/InvenTree
    def validate(self):

        data = self.form.cleaned_data

        # Extract hidden fields from posted data
        self.line = data.get('line', None)
        self.part = data.get('part', None)

        if self.line:
            self.form.fields['line'].widget = HiddenInput()
        else:
            self.form.add_error('line', _('Select line item'))

        if self.part:
            self.form.fields['part'].widget = HiddenInput()
        else:
            self.form.add_error('part', _('Select part'))

        if not self.form.is_valid():
            return

        # Form is otherwise valid - check serial numbers
        serials = data.get('serials', '')
        quantity = data.get('quantity', 1)

        # Save a list of serial_numbers
        self.serial_numbers = None
        self.stock_items = []

        try:
            self.serial_numbers = extract_serial_numbers(serials, quantity)

            for serial in self.serial_numbers:
                try:
                    # Find matching stock item
                    stock_item = StockItem.objects.get(part=self.part,
                                                       serial=serial)
                except StockItem.DoesNotExist:
                    self.form.add_error(
                        'serials',
                        _('No matching item for serial') + f" '{serial}'")
                    continue

                # Now we have a valid stock item - but can it be added to the sales order?

                # If not in stock, cannot be added to the order
                if not stock_item.in_stock:
                    self.form.add_error('serials',
                                        f"'{serial}' " + _("is not in stock"))
                    continue

                # Already allocated to an order
                if stock_item.is_allocated():
                    self.form.add_error(
                        'serials',
                        f"'{serial}' " + _("already allocated to an order"))
                    continue

                # Add it to the list!
                self.stock_items.append(stock_item)

        except ValidationError as e:
            self.form.add_error('serials', e.messages)
コード例 #12
0
ファイル: api.py プロジェクト: matmair/InvenTree
    def create(self, request, *args, **kwargs):
        """
        Create a new StockItem object via the API.

        We override the default 'create' implementation.

        If a location is *not* specified, but the linked *part* has a default location,
        we can pre-fill the location automatically.
        """

        user = request.user

        # Copy the request data, to side-step "mutability" issues
        data = OrderedDict()
        data.update(request.data)

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

        if quantity is None:
            raise ValidationError({
                'quantity': _('Quantity is required'),
            })

        try:
            part = Part.objects.get(pk=data.get('part', None))
        except (ValueError, Part.DoesNotExist):
            raise ValidationError({
                'part': _('Valid part must be supplied'),
            })

        # Set default location (if not provided)
        if 'location' not in data:
            location = part.get_default_location()

            if location:
                data['location'] = location.pk

        # An expiry date was *not* specified - try to infer it!
        if 'expiry_date' not in data and part.default_expiry > 0:
            data['expiry_date'] = datetime.now().date() + timedelta(
                days=part.default_expiry)

        # Attempt to extract serial numbers from submitted data
        serials = None

        # Check if a set of serial numbers was provided
        serial_numbers = data.get('serial_numbers', '')

        # Assign serial numbers for a trackable part
        if serial_numbers:

            if not part.trackable:
                raise ValidationError({
                    'serial_numbers': [
                        _("Serial numbers cannot be supplied for a non-trackable part"
                          )
                    ]
                })

            # If serial numbers are specified, check that they match!
            try:
                serials = extract_serial_numbers(
                    serial_numbers, quantity, part.getLatestSerialNumberInt())

                # Determine if any of the specified serial numbers already exist!
                existing = []

                for serial in serials:
                    if part.checkIfSerialNumberExists(serial):
                        existing.append(serial)

                if len(existing) > 0:

                    msg = _("The following serial numbers already exist")
                    msg += " : "
                    msg += ",".join([str(e) for e in existing])

                    raise ValidationError({
                        'serial_numbers': [msg],
                    })

            except DjangoValidationError as e:
                raise ValidationError({
                    'quantity': e.messages,
                    'serial_numbers': e.messages,
                })

        if serials is not None:
            """
            If the stock item is going to be serialized, set the quantity to 1
            """
            data['quantity'] = 1

        # De-serialize the provided data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)

        with transaction.atomic():

            # Create an initial StockItem object
            item = serializer.save()

            if serials:
                # Assign the first serial number to the "master" item
                item.serial = serials[0]

            # Save the item (with user information)
            item.save(user=user)

            if serials:
                for serial in serials[1:]:

                    # Create a duplicate stock item with the next serial number
                    item.pk = None
                    item.serial = serial

                    item.save(user=user)

                response_data = {
                    'quantity': quantity,
                    'serial_numbers': serials,
                }

            else:
                response_data = serializer.data

            return Response(response_data,
                            status=status.HTTP_201_CREATED,
                            headers=self.get_success_headers(serializer.data))
コード例 #13
0
ファイル: api.py プロジェクト: wengtad/InvenTree
    def create(self, request, *args, **kwargs):
        """
        Create a new StockItem object via the API.

        We override the default 'create' implementation.

        If a location is *not* specified, but the linked *part* has a default location,
        we can pre-fill the location automatically.
        """

        user = request.user
        data = request.data

        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)

        # Check if a set of serial numbers was provided
        serial_numbers = data.get('serial_numbers', '')

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

        if quantity is None:
            raise ValidationError({
                'quantity': _('Quantity is required'),
            })

        notes = data.get('notes', '')

        serials = None

        if serial_numbers:
            # If serial numbers are specified, check that they match!
            try:
                serials = extract_serial_numbers(serial_numbers,
                                                 data['quantity'])
            except DjangoValidationError as e:
                raise ValidationError({
                    'quantity': e.messages,
                    'serial_numbers': e.messages,
                })

        with transaction.atomic():

            # Create an initial stock item
            item = serializer.save()

            # A location was *not* specified - try to infer it
            if 'location' not in data:
                item.location = item.part.get_default_location()

            # An expiry date was *not* specified - try to infer it!
            if 'expiry_date' not in data:

                if item.part.default_expiry > 0:
                    item.expiry_date = datetime.now().date() + timedelta(
                        days=item.part.default_expiry)

            # Finally, save the item (with user information)
            item.save(user=user)

            if serials:
                """
                Serialize the stock, if required

                - Note that the "original" stock item needs to be created first, so it can be serialized
                - It is then immediately deleted
                """

                try:
                    item.serializeStock(
                        quantity,
                        serials,
                        user,
                        notes=notes,
                        location=item.location,
                    )

                    headers = self.get_success_headers(serializer.data)

                    # Delete the original item
                    item.delete()

                    response_data = {
                        'quantity': quantity,
                        'serial_numbers': serials,
                    }

                    return Response(response_data,
                                    status=status.HTTP_201_CREATED,
                                    headers=headers)

                except DjangoValidationError as e:
                    raise ValidationError({
                        'quantity': e.messages,
                        'serial_numbers': e.messages,
                    })

            # Return a response
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data,
                            status=status.HTTP_201_CREATED,
                            headers=headers)