django-bom 1.252__py3-none-any.whl → 1.258__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/views/views.py CHANGED
@@ -47,10 +47,14 @@ from bom.forms import (
47
47
  PartInfoForm,
48
48
  PartRevisionForm,
49
49
  PartRevisionNewForm,
50
+ PartRevisionPropertyDefinitionForm,
51
+ PartRevisionPropertyDefinitionFormSet,
52
+ QuantityOfMeasureForm,
50
53
  Seller,
51
54
  SellerForm,
52
55
  SellerPartForm,
53
56
  SubpartForm,
57
+ UnitDefinitionFormSet,
54
58
  UploadBOMForm,
55
59
  UserAddForm,
56
60
  UserCreateForm,
@@ -66,8 +70,11 @@ from bom.models import (
66
70
  Part,
67
71
  PartClass,
68
72
  PartRevision,
73
+ PartRevisionPropertyDefinition,
74
+ QuantityOfMeasure,
69
75
  SellerPart,
70
76
  Subpart,
77
+ UnitDefinition,
71
78
  User,
72
79
  get_user_meta_model
73
80
  )
@@ -245,7 +252,7 @@ def home(request):
245
252
  for field_name in csv_headers.get_default_all():
246
253
  if field_name not in csv_headers.get_defaults_list(['part_number', 'part_category', 'part_synopsis', 'part_revision', 'part_manufacturer', 'part_manufacturer_part_number', ]
247
254
  + seller_csv_headers.get_default_all()):
248
- attr = getattr(part_rev, field_name)
255
+ attr = part_rev.get_field_value(field_name)
249
256
  row.update({csv_headers.get_default(field_name): attr if attr is not None else ''})
250
257
  else:
251
258
  row = {
@@ -258,7 +265,7 @@ def home(request):
258
265
  for field_name in csv_headers.get_default_all():
259
266
  if field_name not in csv_headers.get_defaults_list(['part_number', 'part_synopsis', 'part_revision', 'part_manufacturer', 'part_manufacturer_part_number', ]
260
267
  + seller_csv_headers.get_default_all()):
261
- attr = getattr(part_rev, field_name)
268
+ attr = part_rev.get_field_value(field_name)
262
269
  row.update({csv_headers.get_default(field_name): attr if attr is not None else ''})
263
270
 
264
271
  sellerparts = part_rev.part.seller_parts()
@@ -356,6 +363,9 @@ def bom_settings(request, tab_anchor=None):
356
363
  name = 'settings'
357
364
 
358
365
  part_classes = PartClass.objects.all().filter(organization=organization)
366
+ property_definitions = PartRevisionPropertyDefinition.objects.available_to(organization=organization).order_by(
367
+ 'name')
368
+ quantities_of_measure = QuantityOfMeasure.objects.available_to(organization=organization).order_by('name')
359
369
 
360
370
  users_in_organization = User.objects.filter(
361
371
  id__in=UserMeta.objects.filter(organization=organization).values_list('user', flat=True)).order_by(
@@ -395,6 +405,9 @@ def bom_settings(request, tab_anchor=None):
395
405
  messages.error(request, "You need a Pro subscription to add users.")
396
406
  elif not user_can_manage_members:
397
407
  messages.error(request, "You are not allowed to manage users, contact your organization admin.")
408
+ elif not has_member_capacity:
409
+ messages.error(request,
410
+ "You have reached your organization's member capacity. Manage subscription to add more members.")
398
411
  else:
399
412
  user_add_form = UserAddForm(request.POST, organization=organization)
400
413
  if user_add_form.is_valid():
@@ -708,29 +721,19 @@ def seller_delete(request, seller_id):
708
721
 
709
722
  @login_required(login_url=BOM_LOGIN_URL)
710
723
  def user_meta_edit(request, user_meta_id):
711
- user = request.user
712
- profile = user.bom_profile()
713
- organization = profile.organization
714
-
715
724
  user_meta = get_object_or_404(UserMeta, pk=user_meta_id)
716
- user_meta_user = get_object_or_404(User, pk=user_meta.user.id)
717
- title = 'Edit User {}'.format(user_meta.user.__str__())
725
+ user = user_meta.user
726
+ organization = user_meta.organization
727
+ title = f'Manage Member'
718
728
 
719
729
  if request.method == 'POST':
720
- user_meta_user_form = UserForm(request.POST, instance=user_meta_user)
721
- if user_meta_user_form.is_valid():
722
- user_meta_form = UserMetaForm(request.POST, instance=user_meta, organization=organization)
723
- if user_meta_form.is_valid():
724
- user_meta_user_form.save()
725
- user_meta_form.save()
726
- return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'organization'}))
727
-
730
+ form = UserAddForm(request.POST, instance=user_meta, organization=organization, exclude_username=True)
731
+ if form.is_valid():
732
+ form.save()
733
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'organization'}))
728
734
  return TemplateResponse(request, 'bom/edit-user-meta.html', locals())
729
-
730
735
  else:
731
- user_meta_user_form = UserForm(instance=user_meta_user)
732
- user_meta_form = UserMetaForm(instance=user_meta, organization=organization)
733
-
736
+ form = UserAddForm(instance=user_meta, organization=organization, exclude_username=True)
734
737
  return TemplateResponse(request, 'bom/edit-user-meta.html', locals())
735
738
 
736
739
 
@@ -951,7 +954,7 @@ def upload_bom(request):
951
954
  else:
952
955
  messages.error(request, upload_bom_form.errors)
953
956
  else:
954
- upload_bom_form = UploadBOMForm(initial={'organization': organization})
957
+ upload_bom_form = UploadBOMForm(organization=organization, initial={'organization': organization})
955
958
  bom_csv_form = BOMCSVForm()
956
959
 
957
960
  return TemplateResponse(request, 'bom/upload-bom.html', locals())
@@ -1030,22 +1033,15 @@ def export_part_list(request):
1030
1033
  'number_item',
1031
1034
  'number_variation')
1032
1035
 
1033
- fieldnames = [
1034
- 'part_number',
1035
- 'part_synopsis',
1036
- 'part_revision',
1037
- 'part_manufacturer',
1038
- 'part_manufacturer_part_number',
1039
- ]
1040
-
1041
1036
  csv_headers = organization.part_list_csv_headers()
1042
- writer = csv.DictWriter(response, fieldnames=fieldnames)
1037
+ writer = csv.DictWriter(response, fieldnames=csv_headers.get_default_all())
1043
1038
  writer.writeheader()
1044
1039
  for item in parts:
1045
1040
  try:
1041
+ latest_rev = item.latest()
1046
1042
  row = {
1047
1043
  csv_headers.get_default('part_number'): item.full_part_number(),
1048
- csv_headers.get_default('part_revision'): item.latest().revision,
1044
+ csv_headers.get_default('part_revision'): latest_rev.revision if latest_rev else '',
1049
1045
  csv_headers.get_default('part_manufacturer'): item.primary_manufacturer_part.manufacturer.name if item.primary_manufacturer_part is not None and item.primary_manufacturer_part.manufacturer is not None else '',
1050
1046
  csv_headers.get_default('part_manufacturer_part_number'): item.primary_manufacturer_part.manufacturer_part_number if item.primary_manufacturer_part is not None and item.primary_manufacturer_part.manufacturer is not None else '',
1051
1047
  }
@@ -1053,7 +1049,7 @@ def export_part_list(request):
1053
1049
  if field_name not in csv_headers.get_defaults_list(
1054
1050
  ['part_number', 'part_category', 'part_synopsis', 'part_revision', 'part_manufacturer',
1055
1051
  'part_manufacturer_part_number', ]):
1056
- attr = getattr(item, field_name)
1052
+ attr = latest_rev.get_field_value(field_name) if latest_rev else None
1057
1053
  row.update({csv_headers.get_default(field_name): attr if attr is not None else ''})
1058
1054
  writer.writerow({k: smart_str(v) for k, v in row.items()})
1059
1055
 
@@ -1082,7 +1078,7 @@ def create_part(request):
1082
1078
  part_form = PartForm(request.POST, organization=organization)
1083
1079
  manufacturer_form = ManufacturerForm(request.POST)
1084
1080
  manufacturer_part_form = ManufacturerPartForm(request.POST, organization=organization)
1085
- part_revision_form = PartRevisionForm(request.POST)
1081
+ part_revision_form = PartRevisionForm(request.POST, organization=organization)
1086
1082
  # Checking if part form is valid checks for number uniqueness
1087
1083
  if part_form.is_valid() and manufacturer_form.is_valid() and manufacturer_part_form.is_valid():
1088
1084
  mpn = manufacturer_part_form.cleaned_data['manufacturer_part_number']
@@ -1107,6 +1103,8 @@ def create_part(request):
1107
1103
  new_part.number_class = None
1108
1104
  new_part.number_variation = None
1109
1105
 
1106
+ part_revision_form = PartRevisionForm(request.POST, part_class=new_part.number_class,
1107
+ organization=organization)
1110
1108
  if part_revision_form.is_valid():
1111
1109
  # Save the Part before the PartRevision, as this will again check for part
1112
1110
  # number uniqueness. This way if someone else(s) working concurrently is also
@@ -1117,7 +1115,8 @@ def create_part(request):
1117
1115
  pr.part = new_part # Associate PartRevision with Part
1118
1116
  pr.save()
1119
1117
  except IntegrityError as err:
1120
- messages.error(request, "Error! Already created a part with part number {0}-{1}-{3}}".format(new_part.number_class.code, new_part.number_item, new_part.number_variation))
1118
+ messages.error(request, "Error! Already created a part with part number {0}-{1}-{2}}".format(
1119
+ new_part.number_class.code, new_part.number_item, new_part.number_variation))
1121
1120
  return TemplateResponse(request, 'bom/create-part.html', locals())
1122
1121
  else:
1123
1122
  messages.error(request, part_revision_form.errors)
@@ -1137,7 +1136,8 @@ def create_part(request):
1137
1136
  else:
1138
1137
  # Initialize organization in the form's model and in the form itself:
1139
1138
  part_form = PartForm(initial={'organization': organization}, organization=organization)
1140
- part_revision_form = PartRevisionForm(initial={'revision': 1, 'organization': organization})
1139
+ part_revision_form = PartRevisionForm(initial={'revision': 1, 'organization': organization},
1140
+ organization=organization)
1141
1141
  manufacturer_form = ManufacturerForm(initial={'organization': organization})
1142
1142
  manufacturer_part_form = ManufacturerPartForm(organization=organization)
1143
1143
 
@@ -1277,6 +1277,117 @@ def remove_subpart(request, part_id, part_revision_id, subpart_id):
1277
1277
  reverse('bom:part-manage-bom', kwargs={'part_id': part_id, 'part_revision_id': part_revision_id}))
1278
1278
 
1279
1279
 
1280
+ @login_required(login_url=BOM_LOGIN_URL)
1281
+ def property_definition_edit(request, property_definition_id=None):
1282
+ user = request.user
1283
+ profile = user.bom_profile()
1284
+ organization = profile.organization
1285
+
1286
+ if property_definition_id:
1287
+ property_definition = get_object_or_404(PartRevisionPropertyDefinition, pk=property_definition_id)
1288
+ if property_definition.organization != organization:
1289
+ messages.error(request, "Can't access a property definition that is not yours!")
1290
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1291
+ title = f'Edit Property Definition {property_definition.name}'
1292
+ else:
1293
+ property_definition = None
1294
+ title = 'Add Property Definition'
1295
+
1296
+ if request.method == 'POST':
1297
+ form = PartRevisionPropertyDefinitionForm(request.POST, instance=property_definition, organization=organization)
1298
+ if form.is_valid():
1299
+ property_definition = form.save(commit=False)
1300
+ property_definition.organization = organization
1301
+ property_definition.save()
1302
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1303
+ else:
1304
+ form = PartRevisionPropertyDefinitionForm(instance=property_definition, organization=organization)
1305
+
1306
+ return TemplateResponse(request, 'bom/bom-form.html', locals())
1307
+
1308
+
1309
+ @login_required(login_url=BOM_LOGIN_URL)
1310
+ @organization_admin
1311
+ def property_definition_delete(request, property_definition_id):
1312
+ user = request.user
1313
+ profile = user.bom_profile()
1314
+ organization = profile.organization
1315
+ property_definition = get_object_or_404(PartRevisionPropertyDefinition, pk=property_definition_id)
1316
+ if property_definition.organization != organization:
1317
+ messages.error(request, "Can't delete a property definition that is not yours!")
1318
+ else:
1319
+ property_definition.delete()
1320
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1321
+
1322
+
1323
+ @login_required(login_url=BOM_LOGIN_URL)
1324
+ def quantity_of_measure_edit(request, quantity_of_measure_id=None):
1325
+ user = request.user
1326
+ profile = user.bom_profile()
1327
+ organization = profile.organization
1328
+
1329
+ if quantity_of_measure_id:
1330
+ quantity_of_measure = get_object_or_404(QuantityOfMeasure, pk=quantity_of_measure_id)
1331
+ if quantity_of_measure.organization != organization:
1332
+ messages.error(request, "Can't access a quantity of measure that is not yours!")
1333
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1334
+ title = f'Edit Quantity of Measure {quantity_of_measure.name}'
1335
+ else:
1336
+ quantity_of_measure = None
1337
+ title = 'Add Quantity of Measure'
1338
+
1339
+ if request.method == 'POST':
1340
+ form = QuantityOfMeasureForm(request.POST, instance=quantity_of_measure, organization=organization)
1341
+ unit_formset = UnitDefinitionFormSet(
1342
+ request.POST,
1343
+ queryset=quantity_of_measure.units.all() if quantity_of_measure else UnitDefinition.objects.none(),
1344
+ form_kwargs={'organization': organization},
1345
+ prefix='units'
1346
+ )
1347
+
1348
+ if form.is_valid() and unit_formset.is_valid():
1349
+ quantity_of_measure = form.save()
1350
+ units = unit_formset.save(commit=False)
1351
+ base_multipliers = [float(unit.base_multiplier) for unit in units]
1352
+ if 1.0 not in base_multipliers:
1353
+ messages.error(request, "Must have a base multiplier of 1.0 for at least 1 unit.")
1354
+ return TemplateResponse(request, 'bom/edit-quantity-of-measure.html', locals())
1355
+
1356
+ for unit in units:
1357
+ unit.organization = organization
1358
+ unit.quantity_of_measure = quantity_of_measure
1359
+ unit.save()
1360
+ for obj in unit_formset.deleted_objects:
1361
+ obj.delete()
1362
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1363
+ else:
1364
+ messages.error(request, form.errors)
1365
+ messages.error(request, unit_formset.errors)
1366
+ else:
1367
+ form = QuantityOfMeasureForm(instance=quantity_of_measure, organization=organization)
1368
+ unit_formset = UnitDefinitionFormSet(
1369
+ queryset=quantity_of_measure.units.all() if quantity_of_measure else UnitDefinition.objects.none(),
1370
+ form_kwargs={'organization': organization},
1371
+ prefix='units'
1372
+ )
1373
+
1374
+ return TemplateResponse(request, 'bom/edit-quantity-of-measure.html', locals())
1375
+
1376
+
1377
+ @login_required(login_url=BOM_LOGIN_URL)
1378
+ @organization_admin
1379
+ def quantity_of_measure_delete(request, quantity_of_measure_id):
1380
+ user = request.user
1381
+ profile = user.bom_profile()
1382
+ organization = profile.organization
1383
+ quantity_of_measure = get_object_or_404(QuantityOfMeasure, pk=quantity_of_measure_id)
1384
+ if quantity_of_measure.organization != organization:
1385
+ messages.error(request, "Can't delete a quantity of measure that is not yours!")
1386
+ else:
1387
+ quantity_of_measure.delete()
1388
+ return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1389
+
1390
+
1280
1391
  @login_required(login_url=BOM_LOGIN_URL)
1281
1392
  def part_class_edit(request, part_class_id):
1282
1393
  user = request.user
@@ -1288,15 +1399,40 @@ def part_class_edit(request, part_class_id):
1288
1399
 
1289
1400
  if request.method == 'POST':
1290
1401
  part_class_form = PartClassForm(request.POST, instance=part_class, organization=organization)
1291
- if part_class_form.is_valid():
1292
- part_class_form.save()
1402
+ property_definitions_formset = PartRevisionPropertyDefinitionFormSet(
1403
+ request.POST,
1404
+ form_kwargs={'organization': organization},
1405
+ prefix='prop-def'
1406
+ )
1407
+
1408
+ if part_class_form.is_valid() and property_definitions_formset.is_valid():
1409
+ part_class = part_class_form.save()
1410
+
1411
+ # Clear current associations and re-add from formset
1412
+ part_class.property_definitions.clear()
1413
+ for form in property_definitions_formset:
1414
+ if form.cleaned_data and not form.cleaned_data.get('DELETE'):
1415
+ definition = form.cleaned_data.get('property_definition')
1416
+ if definition:
1417
+ part_class.property_definitions.add(definition)
1418
+
1293
1419
  return HttpResponseRedirect(reverse('bom:settings', kwargs={'tab_anchor': 'indabom'}))
1294
1420
 
1295
1421
  else:
1422
+ if not part_class_form.is_valid():
1423
+ messages.error(request, part_class_form.errors)
1424
+ if not property_definitions_formset.is_valid():
1425
+ messages.error(request, property_definitions_formset.errors)
1296
1426
  return TemplateResponse(request, 'bom/edit-part-class.html', locals())
1297
1427
 
1298
1428
  else:
1299
1429
  part_class_form = PartClassForm(instance=part_class, organization=organization)
1430
+ initial = [{'property_definition': pd} for pd in part_class.property_definitions.all().order_by('name')]
1431
+ property_definitions_formset = PartRevisionPropertyDefinitionFormSet(
1432
+ initial=initial,
1433
+ form_kwargs={'organization': organization},
1434
+ prefix='prop-def',
1435
+ )
1300
1436
 
1301
1437
  return TemplateResponse(request, 'bom/edit-part-class.html', locals())
1302
1438
 
@@ -1547,7 +1683,8 @@ def part_revision_new(request, part_id):
1547
1683
  used_part_revisions = all_used_in_prs.filter(configuration='W')
1548
1684
 
1549
1685
  if request.method == 'POST':
1550
- part_revision_new_form = PartRevisionNewForm(request.POST, part=part, revision=next_revision_number, assembly=latest_revision.assembly)
1686
+ part_revision_new_form = PartRevisionNewForm(request.POST, part=part, revision=next_revision_number,
1687
+ assembly=latest_revision.assembly, organization=organization)
1551
1688
  if part_revision_new_form.is_valid():
1552
1689
  new_part_revision = part_revision_new_form.save()
1553
1690
 
@@ -1579,9 +1716,9 @@ def part_revision_new(request, part_id):
1579
1716
  if latest_revision:
1580
1717
  messages.info(request, 'New revision automatically incremented to `{}` from your last revision `{}`.'.format(next_revision_number, latest_revision.revision))
1581
1718
  latest_revision.revision = next_revision_number # use updated object to populate form but don't save changes
1582
- part_revision_new_form = PartRevisionNewForm(instance=latest_revision)
1719
+ part_revision_new_form = PartRevisionNewForm(instance=latest_revision, organization=organization)
1583
1720
  else:
1584
- part_revision_new_form = PartRevisionNewForm()
1721
+ part_revision_new_form = PartRevisionNewForm(organization=organization)
1585
1722
 
1586
1723
  return TemplateResponse(request, 'bom/part-revision-new.html', locals())
1587
1724
 
@@ -1599,12 +1736,12 @@ def part_revision_edit(request, part_id, part_revision_id):
1599
1736
  action = reverse('bom:part-revision-edit', kwargs={'part_id': part_id, 'part_revision_id': part_revision_id})
1600
1737
 
1601
1738
  if request.method == 'POST':
1602
- form = PartRevisionForm(request.POST, instance=part_revision)
1739
+ form = PartRevisionForm(request.POST, instance=part_revision, organization=organization)
1603
1740
  if form.is_valid():
1604
1741
  form.save()
1605
1742
  return HttpResponseRedirect(reverse('bom:part-info', kwargs={'part_id': part_id}))
1606
1743
  else:
1607
- form = PartRevisionForm(instance=part_revision)
1744
+ form = PartRevisionForm(instance=part_revision, organization=organization)
1608
1745
 
1609
1746
  return TemplateResponse(request, 'bom/part-revision-edit.html', locals())
1610
1747
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bom
3
- Version: 1.252
3
+ Version: 1.258
4
4
  Summary: A simple Django app to manage a bill of materials.
5
5
  Author-email: Mike Kasparian <mpkasp@gmail.com>
6
6
  License: GPL-3.0-only
@@ -1,21 +1,21 @@
1
1
  bom/__init__.py,sha256=HuvSMR9cYQcppTZGD0XjUVUBtHWwWMh1yMQzk_2wTS4,41
2
- bom/admin.py,sha256=3fgD0_e5U76P1UT8CTeWbmqo3KK3PKz8ECz-5a_pXEM,4401
2
+ bom/admin.py,sha256=MmCa4X9J5aKNbQTrfyLnDdoIt9MrlS3rI1sN9EkhsIs,5892
3
3
  bom/apps.py,sha256=TJMUTSX1h2genPwCq6SN6g1fhrrSmjEXGg2zQFa_ryM,147
4
4
  bom/auth_backends.py,sha256=Xj3MCUJg3r9M4v1c8wrxC3lwpE5F8_2_HD5s9M_5Rms,1480
5
5
  bom/base_classes.py,sha256=CrWD7wlIkwYb90VoGcVOcw2WoQszRrCje-Re5d_UW1Q,1183
6
- bom/constants.py,sha256=5CFE0uvKTL91w24rqdAB6EMgpIyw0HhfmmktxF4gCgs,4296
6
+ bom/constants.py,sha256=Vs3-s1_ej8hDMlq5YC01vZXs1TECuPe9sn834UierLI,4666
7
7
  bom/context_processors.py,sha256=OxMVCqxGtRoHR7aJfTs6xANpxJQzBDUIuNTG1f_Xjoo,312
8
- bom/csv_headers.py,sha256=1VDJ7aNqYjDhf5_rfWBZqO6wsIS99oD01yXx2nNmIHQ,12620
8
+ bom/csv_headers.py,sha256=0WLvgchbTtW_9ya3UC_qL5hv7muuklf_vtoMNBFAOoc,11468
9
9
  bom/decorators.py,sha256=fCK-lxJTBp3LEdZtKMyQg5hRqxQm5RJny9eb7oyjbtE,1233
10
10
  bom/form_fields.py,sha256=tLqchl0j8izBCZnm82NMyHpQV6EuGgCjCl5lrnGR2V0,2816
11
- bom/forms.py,sha256=wmfurA8M0cxc72nLPsMo0-m6JOXzXOhFF2MSRXzZnVI,68836
12
- bom/helpers.py,sha256=ONsDM0agG9sKJWMjN4IRNlWx2HNF7T0CXM-ts0GRiAY,15031
11
+ bom/forms.py,sha256=_hsEdhyr2QDQ-Ei7ZRcv4N9s4lmbYR4xT5-NhyJ8rB4,57312
12
+ bom/helpers.py,sha256=jzwNDgD-4htdJfWWjNy8ZhVqfdgSxhNpsFn6kDpC5UU,20172
13
13
  bom/local_settings.py,sha256=yE4aupIquCWsFms44qoCrRrlIyM3sqpOkiwyj1WLxI8,820
14
- bom/models.py,sha256=GWnSNEDP5po_fo9CphwtimZTFkSrbjKCs6zg0g-LKD8,37834
14
+ bom/models.py,sha256=dzvhU68hu5Wam4RvD3e75dcsqsbVmBWVe8vi57w40hQ,38424
15
15
  bom/part_bom.py,sha256=30HYAKAEhtadiM9tk6vgCQnn7gNJeuXbzF5gXvMvKG4,8720
16
16
  bom/settings.py,sha256=aBg0PHaK9NvNZNmfnPrU4-kp2GQeeAGMB_EVvMoAmJs,8197
17
- bom/tests.py,sha256=ZqcTUYVXeWjAqzKAV6hp6SKTU0_IOTwIEboTujl7N_M,69905
18
- bom/urls.py,sha256=sGNKO8BsTO_TDPsqB-c_fqRozaNHOf9WYRaOy-7OLAE,6841
17
+ bom/tests.py,sha256=Grn2aoXR7AnoVJ9Wa_stgkofk94WS7sPcVKWxpelvY0,73980
18
+ bom/urls.py,sha256=7yjQ7ONydqZHHFHd9jWThEu_03r3LyDcVJ-BGYNy6LQ,7589
19
19
  bom/utils.py,sha256=z_2jACSkRc0hsc0mdR8tOK10KiSDeM0a6rXIpztPDuA,7302
20
20
  bom/validators.py,sha256=tiQYIblITCOwb8m1kfs_CFmFnJofCtFzqENlxBuGL7Y,872
21
21
  bom/wsgi.py,sha256=-2oAfSSVdNFCjxaKXcPp-JL_K8AhVClzls6OC_ZI1Jc,380
@@ -70,12 +70,13 @@ bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d
70
70
  bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py,sha256=l1q5BCNVYWD6Ngf9pGzYq1hQMvvshmdFlm33On63YNc,3247
71
71
  bom/migrations/0050_alter_organization_options.py,sha256=n-YGAoUdUxYdh5NY0Zpz2T4CWEOR7tDjSFFk-KZD_tw,432
72
72
  bom/migrations/0051_alter_manufacturer_organization_and_more.py,sha256=xjnkZhEgsJDsfK9leBPxxQ2oG_Qf2FdrttTx-lldmjw,1539
73
+ bom/migrations/0052_remove_partrevision_attribute_and_more.py,sha256=WxRL6J8pepMfyuATUj7blr_1LG8Lf1ZdK_kLN1F_F-o,31364
73
74
  bom/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
75
  bom/static/bom/css/dashboard.css,sha256=saLXUpnVRjsV9HNdsmQD4Eq-zBlm8R2YePhvoc1uifk,245
75
76
  bom/static/bom/css/jquery.treetable.css,sha256=H37aGBAAFP3R6v08nui9gKSdLE2VGsGsmlttrIImzfE,652
76
77
  bom/static/bom/css/materialize.min.css,sha256=OweaP_Ic6rsV-lysfyS4h-LM6sRwuO3euTYfr6M124g,141841
77
78
  bom/static/bom/css/part-info.css,sha256=xQ6zJXHLStwU76UVoYxjG-MjdQzFRwg-jANqrj_KFS0,252
78
- bom/static/bom/css/style.css,sha256=_UDH_6aa77N7tWxZNNQv6LblE0hHSLkdTxWzpKJpEwk,6326
79
+ bom/static/bom/css/style.css,sha256=NARNKKTNIE-3CU2Glcqbs8fzfedRhbRzIFSRza_bT6I,6737
79
80
  bom/static/bom/css/tablesorter-theme.materialize.css,sha256=S7DYXb4vdqdDSUouZ8aIbAxIpemhIzFfeRySdnvvSlc,7435
80
81
  bom/static/bom/css/treetable-theme.css,sha256=RxMklK-XfcF90gxekH3IULmyr7_HRA0TdNz_9Xjxuro,24013
81
82
  bom/static/bom/doc/sample_part_classes.csv,sha256=nAWhBV9KtHSejLUKD7OKKtbkfUYCeLgCwze9BPstiFo,1694
@@ -123,6 +124,7 @@ bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps,sha256=xZ8g
123
124
  bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg,sha256=Rk6WGzHe0lGJGEyWiN6lTusosfK8ubtqSdf0ZzuWLBE,4358
124
125
  bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps,sha256=WUvJDjV62btGu5W1SkKE6juGMOHnA62JJ_0p8C_eOnw,26107
125
126
  bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg,sha256=CR9QqAnt_NVL2YweEZe4fN6kQ6QQ31nZHxSmwqVs1t0,4360
127
+ bom/static/bom/js/formset-handler.js,sha256=eEFRa1Sln5Uj7P660_nLDcIHr-mri3SewB89Pr0CwPA,2389
126
128
  bom/static/bom/js/jquery-3.4.1.min.js,sha256=CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo,88145
127
129
  bom/static/bom/js/jquery.ba-floatingscrollbar.min.js,sha256=NptA5rS2zjhkcu26WQJtMr34psHYzUYRsLrSziTusgg,1271
128
130
  bom/static/bom/js/jquery.treetable.js,sha256=JEXnh_LuKYxk8CUIT1anQ4es4nfOqC0bds_NjsbMBUI,16611
@@ -144,16 +146,17 @@ bom/templates/bom/create-part.html,sha256=UjHx6rkPJl-BRt9gKs5zB3s5Y4vrImDTuD25lv
144
146
  bom/templates/bom/dashboard-menu.html,sha256=4MnFSw0x4w7R0CsSwEDFP3FuZVBFxVChIHr58l3rpSk,799
145
147
  bom/templates/bom/dashboard.html,sha256=m-jGdf4aeIcQqbdqSTwzRCIoLldiIIUQrfM-zRJgyvU,16314
146
148
  bom/templates/bom/edit-manufacturer-part.html,sha256=4WagGptcVtYCxW1zWvHGeaZSc-0qqEKDRHFyKarqIjU,3518
147
- bom/templates/bom/edit-part-class.html,sha256=WOWaxaaGZTIumHI_lTeBgPSSmBHnTlASzq03nvIulQ4,1430
149
+ bom/templates/bom/edit-part-class.html,sha256=1DV8_bQiYuxYUuqMT2SsKDI4UWnnZnEx5EU7Nw7KJlw,5757
148
150
  bom/templates/bom/edit-part.html,sha256=bGfBI3X8eb7iLy_nYDPQRP2CKyp4tNO2-vjakx-_YiM,3051
149
- bom/templates/bom/edit-user-meta.html,sha256=8M4TOPigOBX71wCRVZ4Z_qn2XVNO4aQQujSOHwJoER8,1681
151
+ bom/templates/bom/edit-quantity-of-measure.html,sha256=79ftu8klYrryj3JrSPEQ3Up5NLh2Qbf4qHp_8qZm5aM,5975
152
+ bom/templates/bom/edit-user-meta.html,sha256=Z4iMA0OErrvVNHbFjLuq7tpO5f6C9ovDpI8-zhC6oX0,3489
150
153
  bom/templates/bom/help.html,sha256=hi16fwtVqeWP3Vb3vOpLSKx0ioB1MODJ8lkh6bczfiM,83247
151
154
  bom/templates/bom/manufacturer-info.html,sha256=jR98qXONqquEeda92djQgmFfmJiC8jbsGgyXuzJY100,3742
152
155
  bom/templates/bom/manufacturers.html,sha256=3ZF8Up-IiAvR6CCmrj_92qPPh7vKrVQaEN05KKX2yrA,5550
153
156
  bom/templates/bom/nothing-to-see.html,sha256=cRspNAHlSfv7KjQwp34gANhVqQbXzfFpqtRSm6NoV9s,657
154
157
  bom/templates/bom/organization-create.html,sha256=yLrEJH8BlD-W1USk8pYAzTvr-Qw9ZM5rBGYO3n6lCu0,7982
155
- bom/templates/bom/part-info.html,sha256=lilYygmR8cQhQ5lJeYK6dj-OdIm72s1SerELHqyrPSs,25406
156
- bom/templates/bom/part-revision-display.html,sha256=t_wwzf910fhBc2vFjqoISnhX4OEr7pkfh8R-RGq_6ac,5509
158
+ bom/templates/bom/part-info.html,sha256=236TZ6yTvR5LCravYiuKgzL_CB6nXrd0_C299gvQF8U,26051
159
+ bom/templates/bom/part-revision-display.html,sha256=f5o-9cjGBz7KPp8ubSiUiFNa2tWzHqSKSe3rC7smR6A,1414
157
160
  bom/templates/bom/part-revision-edit.html,sha256=gOWiRd8Vq0z912_fI9UtBC0yYkcF_lruMQfAWN4kqw0,1624
158
161
  bom/templates/bom/part-revision-manage-bom.html,sha256=Nd1CIANnCwYU5KzijlIDfKTXjXqrDOeuwmGOk-CYyrY,5073
159
162
  bom/templates/bom/part-revision-new.html,sha256=BMgKBNmFkrsimqSeviP1Rn3huOB_0kfK-77oIyqwItw,2691
@@ -161,7 +164,7 @@ bom/templates/bom/part-revision-release.html,sha256=voG7wmYc1Cm3e_H1IasvQcPuyqnn
161
164
  bom/templates/bom/search-help.html,sha256=Wh_tXBJtz0bznk0F1C7OSdRhMe2qpOs9NMCBb2i0CFI,4398
162
165
  bom/templates/bom/seller-info.html,sha256=MACsHMYQXMWfRslXuvh9hD2z28VXzVi0DSy4yg7WQMk,3595
163
166
  bom/templates/bom/sellers.html,sha256=6ut7LwRMGUKYB4BRjiSpDBP9BGgqT7nxpNQpUVWDvkw,5412
164
- bom/templates/bom/settings.html,sha256=az0QXxrCPEDa8XRG7q3ASDe8dIP3G941qKmijrzwczw,28241
167
+ bom/templates/bom/settings.html,sha256=g7PhrtbQSf7VRK6pDTPUxUr-PjCLzrJyUErno2pDekY,36184
165
168
  bom/templates/bom/signup.html,sha256=tB_x7q3IufSNXsd9Dfh8fdWpkiWSGH2_Zgw749B1PaU,884
166
169
  bom/templates/bom/subscription_panel.html,sha256=Ute49APwiXONQW2z0AApJRaSwnwtsYt3_opn0bW5BX8,843
167
170
  bom/templates/bom/table_of_contents.html,sha256=7wXWOfmVkk5Itjax5x1PE-g5QjxqmYBr7RW8NgtGRng,1763
@@ -180,9 +183,9 @@ bom/third_party_apis/mouser.py,sha256=q2-p0k2n-LNel_QRlfak0kAXT-9hh59k_Pt51PTG09
180
183
  bom/third_party_apis/test_apis.py,sha256=2W0jtTisGTmktC7l556pn9-pZYseTQmmQfo6_4uP4Dc,679
181
184
  bom/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
185
  bom/views/json_views.py,sha256=LK3-njLZrILLqZxCuE-_sUEC2z2GBxQFRysX67-h14c,2334
183
- bom/views/views.py,sha256=IB0pgdQojvuvykopTdpM42m8EMgy8oYJ4Ui01TR30Ys,73146
184
- django_bom-1.252.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
185
- django_bom-1.252.dist-info/METADATA,sha256=JCrxqDW9rFFK-tSg056gcNzbkcVU89iuahZ1tiKCK7o,7558
186
- django_bom-1.252.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
187
- django_bom-1.252.dist-info/top_level.txt,sha256=6zytg4lnnobI96dO-ZEadPOCslrrFmf4t2Pnv-y8x0Y,4
188
- django_bom-1.252.dist-info/RECORD,,
186
+ bom/views/views.py,sha256=rYEtIPEJMu1rFSNUARcBlJUe8NgBKoHxl38VWYb8htY,80320
187
+ django_bom-1.258.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
188
+ django_bom-1.258.dist-info/METADATA,sha256=_PsObL9U6JRTrbBLHd-cqFKPLPW9e3kj4zT4lxBhxT0,7558
189
+ django_bom-1.258.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
190
+ django_bom-1.258.dist-info/top_level.txt,sha256=6zytg4lnnobI96dO-ZEadPOCslrrFmf4t2Pnv-y8x0Y,4
191
+ django_bom-1.258.dist-info/RECORD,,