Coverage for src/backend/InvenTree/part/apps.py: 62%
41 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""part app specification."""
3from django.apps import AppConfig
4from django.db.utils import OperationalError, ProgrammingError
6import structlog
8import InvenTree.ready
9from InvenTree.apps import InvenTreeConfig
11logger = structlog.get_logger('inventree')
14class PartConfig(AppConfig):
15 """Config class for the 'part' app."""
17 name = 'part'
19 def ready(self):
20 """This function is called whenever the Part app is loaded."""
21 # skip loading if plugin registry is not loaded or we run in a background thread
22 if (
23 not InvenTree.ready.isPluginRegistryLoaded()
24 or not InvenTree.ready.isInMainThread()
25 ):
26 return
28 if InvenTree.ready.isRunningMigrations(): 28 ↛ 29line 28 didn't jump to line 29 because the condition on line 28 was never true
29 return
31 if InvenTree.ready.canAppAccessDatabase(): 31 ↛ exitline 31 didn't return from function 'ready' because the condition on line 31 was always true
32 # Ensure there are no open migrations
33 InvenTreeConfig.ensure_migrations_done()
35 self.update_trackable_status()
36 self.reset_part_pricing_flags()
38 def update_trackable_status(self):
39 """Check for any instances where a trackable part is used in the BOM for a non-trackable part.
41 In such a case, force the top-level part to be trackable too.
42 """
43 from .models import BomItem
45 try:
46 items = BomItem.objects.filter(
47 part__trackable=False, sub_part__trackable=True
48 )
50 for item in items: 50 ↛ 51line 50 didn't jump to line 51 because the loop on line 50 never started
51 logger.info("Marking part '%s' as trackable", item.part.name)
52 item.part.trackable = True
53 item.part.clean()
54 item.part.save()
55 except (OperationalError, ProgrammingError): # pragma: no cover
56 # Exception if the database has not been migrated yet
57 pass
59 def reset_part_pricing_flags(self):
60 """Performed on startup, to ensure that all pricing objects are in a "good" state.
62 Prevents issues with state machine if the server is restarted mid-update
63 """
64 from .models import PartPricing
66 if InvenTree.ready.isImportingData(): 66 ↛ 67line 66 didn't jump to line 67 because the condition on line 66 was never true
67 return
69 try:
70 items = PartPricing.objects.filter(scheduled_for_update=True)
72 if items.count() > 0: 72 ↛ 74line 72 didn't jump to line 74 because the condition on line 72 was never true
73 # Find any pricing objects which have the 'scheduled_for_update' flag set
74 logger.info(
75 'Resetting update flags for %s pricing objects...', items.count()
76 )
78 for pricing in items:
79 pricing.scheduled_for_update = False
80 pricing.save()
81 except Exception:
82 logger.exception('Failed to reset pricing flags - database not ready')