added option to expand sub-storage stocks to display all components from sub_storages
this comes in handy for assortment boxes using sub storages for each individual compartment which usually only holds a single stock
This commit is contained in:
		@@ -101,7 +101,8 @@ class ChangeStorageForm(forms.Form):
 | 
				
			|||||||
                                              foreign_model=get_user_model(),
 | 
					                                              foreign_model=get_user_model(),
 | 
				
			||||||
                                              prepend='@')
 | 
					                                              prepend='@')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    is_template = forms.BooleanField(label='is_template', required=False)
 | 
					    expand_sub_storage_stocks = forms.BooleanField(label='Expand sub storage Stocks', required=False)
 | 
				
			||||||
 | 
					    is_template = forms.BooleanField(label='Is template', required=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AddSubStorageForm(ChangeStorageForm):
 | 
					class AddSubStorageForm(ChangeStorageForm):
 | 
				
			||||||
    template = AutocompleteForeingKeyField(api_search_url='storage-template-list',
 | 
					    template = AutocompleteForeingKeyField(api_search_url='storage-template-list',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.1.3 on 2025-01-25 13:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('parts', '0012_storage_verbose_name'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='storage',
 | 
				
			||||||
 | 
					            name='expand_sub_storage_stocks',
 | 
				
			||||||
 | 
					            field=models.BooleanField(default=False),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -65,6 +65,7 @@ class Storage(models.Model):
 | 
				
			|||||||
	verbose_name = models.CharField(max_length=100, null=True, blank=True)
 | 
						verbose_name = models.CharField(max_length=100, null=True, blank=True)
 | 
				
			||||||
	parent_storage = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
 | 
						parent_storage = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
 | 
				
			||||||
	responsible = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, blank=True, null=True)
 | 
						responsible = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, blank=True, null=True)
 | 
				
			||||||
 | 
						expand_sub_storage_stocks = models.BooleanField(default=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	# allow storages to be templates which can be selected when adding new storages
 | 
						# allow storages to be templates which can be selected when adding new storages
 | 
				
			||||||
	is_template = models.BooleanField(default=False)
 | 
						is_template = models.BooleanField(default=False)
 | 
				
			||||||
@@ -106,6 +107,13 @@ class Storage(models.Model):
 | 
				
			|||||||
		else:
 | 
							else:
 | 
				
			||||||
			return self.storage_set.all()
 | 
								return self.storage_set.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def get_tree(self):
 | 
				
			||||||
 | 
							self.sub_storages = list(self.storage_set.all())
 | 
				
			||||||
 | 
							for storage in self.sub_storages:
 | 
				
			||||||
 | 
								self.sub_storages += storage.get_tree()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return self.sub_storages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	def validate_unique(self, exclude=None):
 | 
						def validate_unique(self, exclude=None):
 | 
				
			||||||
		if Storage.objects.exclude(id=self.id).filter(name=self.name, parent_storage__isnull=True).exists():
 | 
							if Storage.objects.exclude(id=self.id).filter(name=self.name, parent_storage__isnull=True).exists():
 | 
				
			||||||
			if self.parent_storage is None:
 | 
								if self.parent_storage is None:
 | 
				
			||||||
@@ -407,5 +415,6 @@ def auto_apply_template_structure(sender, instance, created, **kwargs):
 | 
				
			|||||||
                Storage.objects.create(name=sub_storage.name,
 | 
					                Storage.objects.create(name=sub_storage.name,
 | 
				
			||||||
                                       parent_storage=instance,
 | 
					                                       parent_storage=instance,
 | 
				
			||||||
                                       responsible=instance.responsible,
 | 
					                                       responsible=instance.responsible,
 | 
				
			||||||
 | 
					                                       expand_sub_storage_stocks=instance.expand_sub_storage_stocks,
 | 
				
			||||||
                                       is_template=False,
 | 
					                                       is_template=False,
 | 
				
			||||||
                                       template=sub_storage)
 | 
					                                       template=sub_storage)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,13 @@ class StockViewDetail(LoginRequiredMixin, BaseTemplateMixin, DetailView):
 | 
				
			|||||||
        return crumbs
 | 
					        return crumbs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def search_stock_queryset(self, search):
 | 
					    def search_stock_queryset(self, search):
 | 
				
			||||||
        stocks_in_storage = Stock.objects.filter(storage=self.object).order_by(Lower('component__name'))
 | 
					
 | 
				
			||||||
 | 
					        if self.object.expand_sub_storage_stocks:
 | 
				
			||||||
 | 
					            stocks_in_storage = Stock.objects.filter(storage__in=self.object.get_tree())
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            stocks_in_storage = Stock.objects.filter(storage=self.object)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stocks_in_storage = stocks_in_storage.order_by(Lower('component__name'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if search is None or search == '':
 | 
					        if search is None or search == '':
 | 
				
			||||||
            return stocks_in_storage
 | 
					            return stocks_in_storage
 | 
				
			||||||
@@ -139,6 +145,7 @@ class StockViewDetail(LoginRequiredMixin, BaseTemplateMixin, DetailView):
 | 
				
			|||||||
                                        verbose_name=f.cleaned_data.get('verbose_name'),
 | 
					                                        verbose_name=f.cleaned_data.get('verbose_name'),
 | 
				
			||||||
                                        parent_storage=self.object,
 | 
					                                        parent_storage=self.object,
 | 
				
			||||||
                                        responsible=f.cleaned_data['responsible'],
 | 
					                                        responsible=f.cleaned_data['responsible'],
 | 
				
			||||||
 | 
					                                        expand_sub_storage_stocks=f.cleaned_data['expand_sub_storage_stocks'],
 | 
				
			||||||
                                        is_template=f.cleaned_data['is_template'],
 | 
					                                        is_template=f.cleaned_data['is_template'],
 | 
				
			||||||
                                        template=f.cleaned_data.get('template'))
 | 
					                                        template=f.cleaned_data.get('template'))
 | 
				
			||||||
            except ValidationError as v_err:
 | 
					            except ValidationError as v_err:
 | 
				
			||||||
@@ -154,6 +161,7 @@ class StockViewDetail(LoginRequiredMixin, BaseTemplateMixin, DetailView):
 | 
				
			|||||||
                self.object.name = f.cleaned_data['storage_name']
 | 
					                self.object.name = f.cleaned_data['storage_name']
 | 
				
			||||||
                self.object.verbose_name = f.cleaned_data.get('verbose_name')
 | 
					                self.object.verbose_name = f.cleaned_data.get('verbose_name')
 | 
				
			||||||
                self.object.responsible = f.cleaned_data['responsible']
 | 
					                self.object.responsible = f.cleaned_data['responsible']
 | 
				
			||||||
 | 
					                self.object.expand_sub_storage_stocks = f.cleaned_data['expand_sub_storage_stocks']
 | 
				
			||||||
                self.object.is_template = f.cleaned_data['is_template']
 | 
					                self.object.is_template = f.cleaned_data['is_template']
 | 
				
			||||||
                self.object.save()
 | 
					                self.object.save()
 | 
				
			||||||
            except ValidationError as v_err:
 | 
					            except ValidationError as v_err:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user