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'))