def receive_line_item(self, line, location, quantity, user): """ Receive a line item (or partial line item) against this PO """ if not self.status == OrderStatus.PLACED: raise ValidationError({ "status": _("Lines can only be received against an order marked as 'Placed'" ) }) try: quantity = int(quantity) if quantity <= 0: raise ValidationError( {"quantity": _("Quantity must be greater than zero")}) except ValueError: raise ValidationError({"quantity": _("Invalid quantity provided")}) # Create a new stock item if line.part: stock = StockItem(part=line.part.part, supplier_part=line.part, location=location, quantity=quantity, purchase_order=self) stock.save() # Add a new transaction note to the newly created stock item stock.addTransactionNote( "Received items", user, "Received {q} items against order '{po}'".format(q=quantity, po=str(self))) # Update the number of parts received against the particular line item line.received += quantity line.save() # Has this order been completed? if len(self.pending_line_items()) == 0: self.received_by = user self.complete_order() # This will save the model
def done(self, form_list, **kwargs): """Create items.""" items = self.get_clean_items() import_done = 0 import_error = [] # Create Part instances for part_data in items.values(): # set related parts optional_matches = {} for idx in self.file_manager.OPTIONAL_MATCH_HEADERS: if idx.lower() in part_data: try: optional_matches[idx] = self.allowed_items[idx].get( pk=int(part_data[idx.lower()])) except (ValueError, self.allowed_items[idx].model.DoesNotExist, self. allowed_items[idx].model.MultipleObjectsReturned): optional_matches[idx] = None else: optional_matches[idx] = None # add part new_part = Part( name=part_data.get('name', ''), description=part_data.get('description', ''), keywords=part_data.get('keywords', None), IPN=part_data.get('ipn', None), revision=part_data.get('revision', None), link=part_data.get('link', None), default_expiry=part_data.get('default_expiry', 0), minimum_stock=part_data.get('minimum_stock', 0), units=part_data.get('units', None), notes=part_data.get('notes', None), category=optional_matches['Category'], default_location=optional_matches['default_location'], default_supplier=optional_matches['default_supplier'], variant_of=optional_matches['variant_of'], active=str2bool(part_data.get('active', True)), base_cost=part_data.get('base_cost', 0), multiple=part_data.get('multiple', 1), assembly=str2bool( part_data.get('assembly', part_settings.part_assembly_default())), component=str2bool( part_data.get('component', part_settings.part_component_default())), is_template=str2bool( part_data.get('is_template', part_settings.part_template_default())), purchaseable=str2bool( part_data.get('purchaseable', part_settings.part_purchaseable_default())), salable=str2bool( part_data.get('salable', part_settings.part_salable_default())), trackable=str2bool( part_data.get('trackable', part_settings.part_trackable_default())), virtual=str2bool( part_data.get('virtual', part_settings.part_virtual_default())), ) try: new_part.save() # add stock item if set if part_data.get('stock', None): stock = StockItem( part=new_part, location=new_part.default_location, quantity=int(part_data.get('stock', 1)), ) stock.save() import_done += 1 except ValidationError as _e: import_error.append(', '.join(set(_e.messages))) # Set alerts if import_done: alert = f"<strong>{_('Part-Import')}</strong><br>{_('Imported {n} parts').format(n=import_done)}" messages.success(self.request, alert) if import_error: error_text = '\n'.join([ f'<li><strong>x{import_error.count(a)}</strong>: {a}</li>' for a in set(import_error) ]) messages.error( self.request, f"<strong>{_('Some errors occured:')}</strong><br><ul>{error_text}</ul>" ) return HttpResponseRedirect(reverse('part-index'))
def post(self, request, *args, **kwargs): """ Handle POST request. Mark the build as COMPLETE - If the form validation passes, the Build objects completeBuild() method is called - Otherwise, the form is passed back to the client """ build = self.get_object() form = self.get_form() confirm = str2bool(request.POST.get('confirm', False)) loc_id = request.POST.get('location', None) valid = False if confirm is False: form.errors['confirm'] = [ 'Confirm completion of build', ] else: try: location = StockLocation.objects.get(id=loc_id) valid = True except StockLocation.DoesNotExist: form.errors['location'] = ['Invalid location selected'] serials = [] if build.part.trackable: # A build for a trackable part must specify serial numbers sn = request.POST.get('serial_numbers', '') sn = str(sn).strip() # If the user has specified serial numbers, check they are valid if len(sn) > 0: try: # Exctract a list of provided serial numbers serials = ExtractSerialNumbers(sn, build.quantity) existing = [] for serial in serials: if not StockItem.check_serial_number( build.part, serial): existing.append(serial) if len(existing) > 0: exists = ",".join([str(x) for x in existing]) form.errors['serial_numbers'] = [ _('The following serial numbers already exist: ({sn})' .format(sn=exists)) ] valid = False except ValidationError as e: form.errors['serial_numbers'] = e.messages valid = False if valid: build.completeBuild(location, serials, request.user) data = { 'form_valid': valid, } return self.renderJsonResponse(request, form, data, context=self.get_context_data())