django-bom 1.243__py3-none-any.whl → 1.257__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bom/admin.py CHANGED
@@ -1,3 +1,4 @@
1
+ from django.conf import settings
1
2
  from django.contrib import admin
2
3
  from django.contrib.auth import get_user_model
3
4
  from django.contrib.auth.admin import UserAdmin
@@ -6,29 +7,31 @@ from .models import (
6
7
  Assembly,
7
8
  Manufacturer,
8
9
  ManufacturerPart,
9
- Organization,
10
10
  Part,
11
11
  PartClass,
12
12
  PartRevision,
13
+ PartRevisionProperty,
14
+ PartRevisionPropertyDefinition,
13
15
  Seller,
14
16
  SellerPart,
15
17
  Subpart,
16
- UserMeta,
18
+ UnitDefinition,
19
+ QuantityOfMeasure,
20
+ get_organization_model,
21
+ get_user_meta_model
17
22
  )
18
23
 
19
-
20
24
  User = get_user_model()
25
+ UserMeta = get_user_meta_model()
26
+ Organization = get_organization_model()
21
27
 
22
28
  class UserMetaInline(admin.TabularInline):
23
29
  model = UserMeta
30
+ verbose_name = 'BOM User Meta'
24
31
  raw_id_fields = ('organization',)
25
32
  can_delete = False
26
33
 
27
34
 
28
- class UserAdmin(UserAdmin):
29
- inlines = (UserMetaInline,)
30
-
31
-
32
35
  class OrganizationAdmin(admin.ModelAdmin):
33
36
  list_display = ('name',)
34
37
 
@@ -88,7 +91,10 @@ class PartClassAdmin(admin.ModelAdmin):
88
91
 
89
92
  class PartRevisionAdminInline(admin.TabularInline):
90
93
  model = PartRevision
94
+ extra = 0
91
95
  raw_id_fields = ('assembly',)
96
+ readonly_fields = ('timestamp',)
97
+ show_change_link = True
92
98
 
93
99
 
94
100
  class PartAdmin(admin.ModelAdmin):
@@ -98,8 +104,10 @@ class PartAdmin(admin.ModelAdmin):
98
104
  'organization',
99
105
  'get_full_part_number',
100
106
  )
107
+ list_filter = ('organization', 'number_class',)
101
108
  raw_id_fields = ('number_class', 'primary_manufacturer_part',)
102
109
  inlines = [
110
+ PartRevisionAdminInline,
103
111
  ManufacturerPartAdminInline,
104
112
  ]
105
113
 
@@ -110,10 +118,22 @@ class PartAdmin(admin.ModelAdmin):
110
118
  get_full_part_number.admin_order_field = 'number_class__part_number'
111
119
 
112
120
 
121
+ class QuantityOfMeasureAdmin(admin.ModelAdmin):
122
+ list_display = ('name', 'organization')
123
+ list_filter = ('organization',)
124
+
125
+
126
+ class PartRevisionPropertyInline(admin.TabularInline):
127
+ model = PartRevisionProperty
128
+ extra = 1
129
+ raw_id_fields = ('property_definition', 'part_revision', 'unit_definition')
130
+
131
+
113
132
  class PartRevisionAdmin(admin.ModelAdmin):
114
133
  list_display = ('part', 'revision', 'description', 'get_assembly_size', 'timestamp',)
115
134
  raw_id_fields = ('assembly',)
116
135
  readonly_fields = ('timestamp',)
136
+ inlines = [PartRevisionPropertyInline]
117
137
 
118
138
  def get_assembly_size(self, obj):
119
139
  return None if obj.assembly is None else obj.assembly.subparts.count()
@@ -142,14 +162,37 @@ class AssemblyAdmin(admin.ModelAdmin):
142
162
  ]
143
163
 
144
164
 
145
- # Try to unregister User model
146
- try:
147
- admin.site.unregister(User)
148
- except admin.sites.NotRegistered:
149
- pass
165
+ class UnitDefinitionAdmin(admin.ModelAdmin):
166
+ list_display = ('name', 'symbol', 'quantity_of_measure', 'base_multiplier', 'organization')
167
+ list_filter = ('organization',)
168
+
169
+
170
+ class PartRevisionPropertyDefinitionAdmin(admin.ModelAdmin):
171
+ list_display = ('code', 'name', 'type', 'organization', 'quantity_of_measure')
172
+ list_filter = ('organization',)
173
+
174
+
175
+ if settings.BOM_USER_META_MODEL == 'bom.UserMeta':
176
+ current_user_admin = admin.site._registry.get(User)
177
+
178
+ if current_user_admin:
179
+ user_admin_class = current_user_admin.__class__
180
+ existing_inlines = list(user_admin_class.inlines or [])
181
+ if UserMetaInline not in existing_inlines:
182
+ existing_inlines.append(UserMetaInline)
183
+ user_admin_class.inlines = existing_inlines
184
+ else:
185
+ class BomUserAdmin(UserAdmin):
186
+ inlines = [UserMetaInline]
187
+
188
+
189
+ admin.site.register(User, BomUserAdmin)
190
+
191
+ if settings.BOM_ORGANIZATION_MODEL == 'bom.Organization':
192
+ from .models import Organization
193
+
194
+ admin.site.register(Organization, OrganizationAdmin)
150
195
 
151
- admin.site.register(User, UserAdmin)
152
- admin.site.register(Organization, OrganizationAdmin)
153
196
  admin.site.register(Seller, SellerAdmin)
154
197
  admin.site.register(SellerPart, SellerPartAdmin)
155
198
  admin.site.register(ManufacturerPart, ManufacturerPartAdmin)
@@ -159,3 +202,6 @@ admin.site.register(PartRevision, PartRevisionAdmin)
159
202
  admin.site.register(Manufacturer, ManufacturerAdmin)
160
203
  admin.site.register(Assembly, AssemblyAdmin)
161
204
  admin.site.register(Subpart, SubpartAdmin)
205
+ admin.site.register(UnitDefinition, UnitDefinitionAdmin)
206
+ admin.site.register(PartRevisionPropertyDefinition, PartRevisionPropertyDefinitionAdmin)
207
+ admin.site.register(QuantityOfMeasure, QuantityOfMeasureAdmin)
bom/auth_backends.py CHANGED
@@ -1,7 +1,9 @@
1
1
  from typing import Optional
2
2
 
3
3
  from . import constants
4
- from .models import Organization
4
+ from .models import get_organization_model
5
+
6
+ Organization = get_organization_model()
5
7
 
6
8
 
7
9
  class OrganizationPermissionBackend:
bom/constants.py CHANGED
@@ -34,6 +34,13 @@ DATA_SOURCES = (
34
34
  (DATA_SOURCE_MOUSER, 'mouser'),
35
35
  )
36
36
 
37
+ PART_REVISION_PROPERTY_TYPE_STRING = 'S'
38
+ PART_REVISION_PROPERTY_TYPE_DECIMAL = 'D'
39
+ PART_REVISION_PROPERTY_TYPE_BOOLEAN = 'B'
40
+ PART_REVISION_PROPERTY_TYPES = ((PART_REVISION_PROPERTY_TYPE_STRING, 'String'),
41
+ (PART_REVISION_PROPERTY_TYPE_DECIMAL, 'Number'),
42
+ (PART_REVISION_PROPERTY_TYPE_BOOLEAN, 'Boolean'),)
43
+
37
44
  VALUE_UNITS = (
38
45
  NO_CHOICE,
39
46
  ('Ohms', '\u03A9'),
bom/csv_headers.py CHANGED
@@ -35,8 +35,11 @@ class CSVHeader:
35
35
  class CSVHeaders(ABC):
36
36
  all_headers_defns = []
37
37
 
38
+ def __init__(self, *args, **kwargs):
39
+ self.headers_defns = list(self.all_headers_defns)
40
+
38
41
  def get_synoynms(self, hdr_name):
39
- for defn in self.all_headers_defns:
42
+ for defn in self.headers_defns:
40
43
  if hdr_name in defn:
41
44
  return defn.synonyms()
42
45
  else:
@@ -53,7 +56,7 @@ class CSVHeaders(ABC):
53
56
 
54
57
  # Preserves order of definitions as listed in all_header_defns:
55
58
  def get_default_all(self):
56
- return [d.name for d in self.all_headers_defns]
59
+ return [d.name for d in self.headers_defns]
57
60
 
58
61
  # Given a list of header names returns the default name for each. The return list
59
62
  # matches the order of the input list. If a name is not recognized, then returns
@@ -151,6 +154,9 @@ class CSVHeaders(ABC):
151
154
  return True
152
155
  raise CSVHeaderError(f'Missing column named {header}')
153
156
 
157
+ def add_header(self, header):
158
+ self.headers_defns.append(header)
159
+
154
160
 
155
161
  #
156
162
  # For each CSV header class, a static data member dictionary uses the key as the default name for the header while the
@@ -190,52 +196,25 @@ class PartClassesCSVHeaders(CSVHeaders):
190
196
  ]
191
197
 
192
198
 
193
- class PartsListCSVHeaders(CSVHeaders):
194
- part_attributes = [
195
- CSVHeader('value', name_options=['val', 'val.', ]),
196
- CSVHeader('value_units', name_options=['value units', 'val. units', 'val units', ]),
197
- CSVHeader('tolerance', name_options=[]),
198
- CSVHeader('attribute', name_options=[]),
199
- CSVHeader('package', name_options=[]),
200
- CSVHeader('pin_count', name_options=[]),
201
- CSVHeader('frequency', name_options=[]),
202
- CSVHeader('frequency_units', name_options=[]),
203
- CSVHeader('wavelength', name_options=[]),
204
- CSVHeader('wavelength_units', name_options=[]),
205
- CSVHeader('memory', name_options=[]),
206
- CSVHeader('memory_units', name_options=[]),
207
- CSVHeader('interface', name_options=[]),
208
- CSVHeader('supply_voltage', name_options=[]),
209
- CSVHeader('supply_voltage_units', name_options=[]),
210
- CSVHeader('temperature_rating', name_options=[]),
211
- CSVHeader('temperature_rating_units', name_options=[]),
212
- CSVHeader('power_rating', name_options=[]),
213
- CSVHeader('power_rating_units', name_options=[]),
214
- CSVHeader('voltage_rating', name_options=[]),
215
- CSVHeader('voltage_rating_units', name_options=[]),
216
- CSVHeader('current_rating', name_options=[]),
217
- CSVHeader('current_rating_units', name_options=[]),
218
- CSVHeader('material', name_options=[]),
219
- CSVHeader('color', name_options=[]),
220
- CSVHeader('finish', name_options=[]),
221
- CSVHeader('length', name_options=[]),
222
- CSVHeader('length_units', name_options=[]),
223
- CSVHeader('width', name_options=[]),
224
- CSVHeader('width_units', name_options=[]),
225
- CSVHeader('height', name_options=[]),
226
- CSVHeader('height_units', name_options=[]),
227
- CSVHeader('weight', name_options=[]),
228
- CSVHeader('weight_units', name_options=[]),
229
- ]
199
+ class PartRevisionPropertyCSVHeaders(CSVHeaders):
200
+ def add_dynamic_headers(self, definitions):
201
+ for defn in definitions:
202
+ self.add_header(
203
+ CSVHeader(defn.form_field_name,
204
+ name_options=[defn.name, f'property_{defn.code}', f'property_{defn.name}', 'p']))
205
+ if defn.quantity_of_measure:
206
+ self.add_header(
207
+ CSVHeader(defn.form_unit_field_name, name_options=[f'{defn.name} Units', f'{defn.code}_units']))
208
+
230
209
 
210
+ class PartsListCSVHeaders(PartRevisionPropertyCSVHeaders):
231
211
  all_headers_defns = [
232
212
  CSVHeader('description', name_options=['desc', 'desc.', ]),
233
213
  CSVHeader('manufacturer_name', name_options=['mfg_name', 'manufacturer_name', 'part_manufacturer', 'mfg', 'manufacturer', 'manufacturer name', ]),
234
214
  CSVHeader('manufacturer_part_number', name_options=['mpn', 'mfg_part_number', 'part_manufacturer_part_number', 'mfg part number', 'manufacturer part number']),
235
215
  CSVHeader('part_number', name_options=['part number', 'part no', ]),
236
216
  CSVHeader('revision', name_options=['rev', 'part_revision', ]),
237
- ] + part_attributes \
238
- + SellerPartCSVHeaders.all_headers_defns
217
+ ] + SellerPartCSVHeaders.all_headers_defns
239
218
 
240
219
 
241
220
  class PartsListCSVHeadersSemiIntelligent(PartsListCSVHeaders):
@@ -246,11 +225,10 @@ class PartsListCSVHeadersSemiIntelligent(PartsListCSVHeaders):
246
225
  CSVHeader('part_class', name_options=['class', 'part_category']),
247
226
  CSVHeader('part_number', name_options=['part number', 'part no', ]),
248
227
  CSVHeader('revision', name_options=['rev', 'part_revision', ]),
249
- ] + PartsListCSVHeaders.part_attributes \
250
- + SellerPartCSVHeaders.all_headers_defns
228
+ ] + SellerPartCSVHeaders.all_headers_defns
251
229
 
252
230
 
253
- class BOMFlatCSVHeaders(CSVHeaders):
231
+ class BOMFlatCSVHeaders(PartRevisionPropertyCSVHeaders):
254
232
  all_headers_defns = [
255
233
  CSVHeader('part_number', name_options=['part number', 'part no', ]),
256
234
  CSVHeader('quantity', name_options=['count', 'qty', 'quantity', ]),