django-bom 1.252__tar.gz → 1.257__tar.gz

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.
Files changed (201) hide show
  1. {django_bom-1.252/django_bom.egg-info → django_bom-1.257}/PKG-INFO +1 -1
  2. {django_bom-1.252 → django_bom-1.257}/bom/admin.py +52 -12
  3. {django_bom-1.252 → django_bom-1.257}/bom/constants.py +7 -0
  4. {django_bom-1.252 → django_bom-1.257}/bom/csv_headers.py +22 -44
  5. django_bom-1.257/bom/forms.py +1328 -0
  6. {django_bom-1.252 → django_bom-1.257}/bom/helpers.py +79 -4
  7. django_bom-1.257/bom/migrations/0052_remove_partrevision_attribute_and_more.py +576 -0
  8. {django_bom-1.252 → django_bom-1.257}/bom/models.py +191 -80
  9. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/style.css +19 -0
  10. django_bom-1.257/bom/static/bom/js/formset-handler.js +65 -0
  11. django_bom-1.257/bom/templates/bom/edit-part-class.html +120 -0
  12. django_bom-1.257/bom/templates/bom/edit-quantity-of-measure.html +119 -0
  13. django_bom-1.257/bom/templates/bom/edit-user-meta.html +70 -0
  14. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/part-info.html +10 -1
  15. django_bom-1.257/bom/templates/bom/part-revision-display.html +47 -0
  16. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/settings.html +138 -11
  17. {django_bom-1.252 → django_bom-1.257}/bom/tests.py +117 -31
  18. {django_bom-1.252 → django_bom-1.257}/bom/urls.py +6 -0
  19. {django_bom-1.252 → django_bom-1.257}/bom/views/views.py +179 -42
  20. {django_bom-1.252 → django_bom-1.257/django_bom.egg-info}/PKG-INFO +1 -1
  21. {django_bom-1.252 → django_bom-1.257}/django_bom.egg-info/SOURCES.txt +3 -0
  22. {django_bom-1.252 → django_bom-1.257}/pyproject.toml +1 -1
  23. django_bom-1.252/bom/forms.py +0 -1381
  24. django_bom-1.252/bom/templates/bom/edit-part-class.html +0 -33
  25. django_bom-1.252/bom/templates/bom/edit-user-meta.html +0 -38
  26. django_bom-1.252/bom/templates/bom/part-revision-display.html +0 -184
  27. {django_bom-1.252 → django_bom-1.257}/LICENSE +0 -0
  28. {django_bom-1.252 → django_bom-1.257}/MANIFEST.in +0 -0
  29. {django_bom-1.252 → django_bom-1.257}/README.md +0 -0
  30. {django_bom-1.252 → django_bom-1.257}/bom/__init__.py +0 -0
  31. {django_bom-1.252 → django_bom-1.257}/bom/apps.py +0 -0
  32. {django_bom-1.252 → django_bom-1.257}/bom/auth_backends.py +0 -0
  33. {django_bom-1.252 → django_bom-1.257}/bom/base_classes.py +0 -0
  34. {django_bom-1.252 → django_bom-1.257}/bom/context_processors.py +0 -0
  35. {django_bom-1.252 → django_bom-1.257}/bom/decorators.py +0 -0
  36. {django_bom-1.252 → django_bom-1.257}/bom/form_fields.py +0 -0
  37. {django_bom-1.252 → django_bom-1.257}/bom/local_settings.py +0 -0
  38. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0001_initial.py +0 -0
  39. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0002_auto_20180908_2151.py +0 -0
  40. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0003_sellerpart_data_source.py +0 -0
  41. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0004_auto_20180911_0011.py +0 -0
  42. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0005_auto_20181007_1934.py +0 -0
  43. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0006_auto_20181007_1949.py +0 -0
  44. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0007_auto_20181009_0256.py +0 -0
  45. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0008_auto_20181030_0427.py +0 -0
  46. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0009_subpart_reference.py +0 -0
  47. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0010_auto_20181202_0733.py +0 -0
  48. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0011_auto_20181202_2113.py +0 -0
  49. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0012_partchangehistory.py +0 -0
  50. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0013_auto_20190222_1631.py +0 -0
  51. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0014_auto_20190223_2353.py +0 -0
  52. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0015_auto_20190303_1915.py +0 -0
  53. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0016_auto_20190405_2308.py +0 -0
  54. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0017_auto_20190616_1912.py +0 -0
  55. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0018_auto_20190616_2143.py +0 -0
  56. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0019_auto_20190624_1246.py +0 -0
  57. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0020_auto_20190627_0207.py +0 -0
  58. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0021_auto_20190627_0428.py +0 -0
  59. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0022_auto_20190811_2140.py +0 -0
  60. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0023_auto_20191205_2351.py +0 -0
  61. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0024_auto_20191214_1342.py +0 -0
  62. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0025_auto_20191221_1907.py +0 -0
  63. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0026_auto_20191222_2258.py +0 -0
  64. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0027_auto_20191222_2347.py +0 -0
  65. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0028_partrevision_displayable_synopsis.py +0 -0
  66. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0029_auto_20191231_1630.py +0 -0
  67. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0030_auto_20200101_2253.py +0 -0
  68. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0031_auto_20200104_1352.py +0 -0
  69. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0032_auto_20200126_1806.py +0 -0
  70. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0033_auto_20200203_0618.py +0 -0
  71. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0034_auto_20200222_0359.py +0 -0
  72. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0035_auto_20200303_0111.py +0 -0
  73. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0036_auto_20200303_0538.py +0 -0
  74. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0037_auto_20200405_1642.py +0 -0
  75. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0038_auto_20200422_0504.py +0 -0
  76. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0039_auto_20200929_2315.py +0 -0
  77. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0040_alter_organization_currency.py +0 -0
  78. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0041_organization_subscription_quantity.py +0 -0
  79. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0042_auto_20210720_2137.py +0 -0
  80. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0043_auto_20211123_0157.py +0 -0
  81. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0044_auto_20220831_1241.py +0 -0
  82. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0045_sellerpart_link.py +0 -0
  83. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0046_alter_sellerpart_unique_together.py +0 -0
  84. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0047_sellerpart_seller_part_number.py +0 -0
  85. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py +0 -0
  86. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py +0 -0
  87. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0050_alter_organization_options.py +0 -0
  88. {django_bom-1.252 → django_bom-1.257}/bom/migrations/0051_alter_manufacturer_organization_and_more.py +0 -0
  89. {django_bom-1.252 → django_bom-1.257}/bom/migrations/__init__.py +0 -0
  90. {django_bom-1.252 → django_bom-1.257}/bom/part_bom.py +0 -0
  91. {django_bom-1.252 → django_bom-1.257}/bom/settings.py +0 -0
  92. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/dashboard.css +0 -0
  93. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/jquery.treetable.css +0 -0
  94. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/materialize.min.css +0 -0
  95. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/part-info.css +0 -0
  96. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/tablesorter-theme.materialize.css +0 -0
  97. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/css/treetable-theme.css +0 -0
  98. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/sample_part_classes.csv +0 -0
  99. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/test_bom.csv +0 -0
  100. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/test_bom_5_intelligent.csv +0 -0
  101. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/test_full_bom.csv +0 -0
  102. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/test_new_parts.csv +0 -0
  103. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/doc/test_new_parts_5_intelligent.csv +0 -0
  104. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/_ionicons_svg_md-arrow-dropdown.svg +0 -0
  105. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/_ionicons_svg_md-arrow-dropright.svg +0 -0
  106. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/favicon.ico +0 -0
  107. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_disabled_web.png +0 -0
  108. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_focus_web.png +0 -0
  109. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_normal_web.png +0 -0
  110. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_pressed_web.png +0 -0
  111. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_light_disabled_web.png +0 -0
  112. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_light_focus_web.png +0 -0
  113. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_light_normal_web.png +0 -0
  114. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/1x/btn_google_signin_light_pressed_web.png +0 -0
  115. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_disabled_web@2x.png +0 -0
  116. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_focus_web@2x.png +0 -0
  117. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_normal_web@2x.png +0 -0
  118. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_pressed_web@2x.png +0 -0
  119. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_light_disabled_web@2x.png +0 -0
  120. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_light_focus_web@2x.png +0 -0
  121. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_light_normal_web@2x.png +0 -0
  122. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/2x/btn_google_signin_light_pressed_web@2x.png +0 -0
  123. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.eps +0 -0
  124. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.svg +0 -0
  125. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.eps +0 -0
  126. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.svg +0 -0
  127. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.eps +0 -0
  128. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.svg +0 -0
  129. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.eps +0 -0
  130. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.svg +0 -0
  131. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.eps +0 -0
  132. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.svg +0 -0
  133. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.eps +0 -0
  134. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.svg +0 -0
  135. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps +0 -0
  136. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg +0 -0
  137. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps +0 -0
  138. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg +0 -0
  139. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/google_drive_logo.svg +0 -0
  140. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/indabom.png +0 -0
  141. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/mouser.png +0 -0
  142. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/img/octopart_blue.svg +0 -0
  143. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/js/jquery-3.4.1.min.js +0 -0
  144. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/js/jquery.ba-floatingscrollbar.min.js +0 -0
  145. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/js/jquery.treetable.js +0 -0
  146. {django_bom-1.252 → django_bom-1.257}/bom/static/bom/js/materialize.min.js +0 -0
  147. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/account-delete.html +0 -0
  148. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/add-manufacturer-part.html +0 -0
  149. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/add-sellerpart.html +0 -0
  150. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/base-menu.html +0 -0
  151. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/base.html +0 -0
  152. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-action-btn.html +0 -0
  153. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-action-table.html +0 -0
  154. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-base-menu.html +0 -0
  155. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-base.html +0 -0
  156. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-form-modal.html +0 -0
  157. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-form.html +0 -0
  158. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-modal-add-users.html +0 -0
  159. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/bom-signup.html +0 -0
  160. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/components/bom-flat.html +0 -0
  161. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/components/bom-indented.html +0 -0
  162. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/components/manufacturer-part-list.html +0 -0
  163. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/components/seller-part-list.html +0 -0
  164. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/create-part.html +0 -0
  165. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/dashboard-menu.html +0 -0
  166. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/dashboard.html +0 -0
  167. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/edit-manufacturer-part.html +0 -0
  168. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/edit-part.html +0 -0
  169. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/help.html +0 -0
  170. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/manufacturer-info.html +0 -0
  171. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/manufacturers.html +0 -0
  172. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/nothing-to-see.html +0 -0
  173. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/organization-create.html +0 -0
  174. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/part-revision-edit.html +0 -0
  175. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/part-revision-manage-bom.html +0 -0
  176. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/part-revision-new.html +0 -0
  177. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/part-revision-release.html +0 -0
  178. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/search-help.html +0 -0
  179. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/seller-info.html +0 -0
  180. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/sellers.html +0 -0
  181. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/signup.html +0 -0
  182. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/subscription_panel.html +0 -0
  183. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/table_of_contents.html +0 -0
  184. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/upload-bom.html +0 -0
  185. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/upload-parts-help.html +0 -0
  186. {django_bom-1.252 → django_bom-1.257}/bom/templates/bom/upload-parts.html +0 -0
  187. {django_bom-1.252 → django_bom-1.257}/bom/templates/registration/login.html +0 -0
  188. {django_bom-1.252 → django_bom-1.257}/bom/third_party_apis/__init__.py +0 -0
  189. {django_bom-1.252 → django_bom-1.257}/bom/third_party_apis/base_api.py +0 -0
  190. {django_bom-1.252 → django_bom-1.257}/bom/third_party_apis/google_drive.py +0 -0
  191. {django_bom-1.252 → django_bom-1.257}/bom/third_party_apis/mouser.py +0 -0
  192. {django_bom-1.252 → django_bom-1.257}/bom/third_party_apis/test_apis.py +0 -0
  193. {django_bom-1.252 → django_bom-1.257}/bom/utils.py +0 -0
  194. {django_bom-1.252 → django_bom-1.257}/bom/validators.py +0 -0
  195. {django_bom-1.252 → django_bom-1.257}/bom/views/__init__.py +0 -0
  196. {django_bom-1.252 → django_bom-1.257}/bom/views/json_views.py +0 -0
  197. {django_bom-1.252 → django_bom-1.257}/bom/wsgi.py +0 -0
  198. {django_bom-1.252 → django_bom-1.257}/django_bom.egg-info/dependency_links.txt +0 -0
  199. {django_bom-1.252 → django_bom-1.257}/django_bom.egg-info/requires.txt +0 -0
  200. {django_bom-1.252 → django_bom-1.257}/django_bom.egg-info/top_level.txt +0 -0
  201. {django_bom-1.252 → django_bom-1.257}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bom
3
- Version: 1.252
3
+ Version: 1.257
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,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
@@ -9,9 +10,13 @@ from .models import (
9
10
  Part,
10
11
  PartClass,
11
12
  PartRevision,
13
+ PartRevisionProperty,
14
+ PartRevisionPropertyDefinition,
12
15
  Seller,
13
16
  SellerPart,
14
17
  Subpart,
18
+ UnitDefinition,
19
+ QuantityOfMeasure,
15
20
  get_organization_model,
16
21
  get_user_meta_model
17
22
  )
@@ -86,7 +91,10 @@ class PartClassAdmin(admin.ModelAdmin):
86
91
 
87
92
  class PartRevisionAdminInline(admin.TabularInline):
88
93
  model = PartRevision
94
+ extra = 0
89
95
  raw_id_fields = ('assembly',)
96
+ readonly_fields = ('timestamp',)
97
+ show_change_link = True
90
98
 
91
99
 
92
100
  class PartAdmin(admin.ModelAdmin):
@@ -96,8 +104,10 @@ class PartAdmin(admin.ModelAdmin):
96
104
  'organization',
97
105
  'get_full_part_number',
98
106
  )
107
+ list_filter = ('organization', 'number_class',)
99
108
  raw_id_fields = ('number_class', 'primary_manufacturer_part',)
100
109
  inlines = [
110
+ PartRevisionAdminInline,
101
111
  ManufacturerPartAdminInline,
102
112
  ]
103
113
 
@@ -108,10 +118,22 @@ class PartAdmin(admin.ModelAdmin):
108
118
  get_full_part_number.admin_order_field = 'number_class__part_number'
109
119
 
110
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
+
111
132
  class PartRevisionAdmin(admin.ModelAdmin):
112
133
  list_display = ('part', 'revision', 'description', 'get_assembly_size', 'timestamp',)
113
134
  raw_id_fields = ('assembly',)
114
135
  readonly_fields = ('timestamp',)
136
+ inlines = [PartRevisionPropertyInline]
115
137
 
116
138
  def get_assembly_size(self, obj):
117
139
  return None if obj.assembly is None else obj.assembly.subparts.count()
@@ -140,22 +162,37 @@ class AssemblyAdmin(admin.ModelAdmin):
140
162
  ]
141
163
 
142
164
 
143
- current_admin = admin.site._registry.get(User)
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
+
144
188
 
145
- if current_admin:
146
- admin_class = current_admin.__class__
147
- inlines = list(admin_class.inlines or [])
148
- if UserMetaInline not in inlines:
149
- inlines.append(UserMetaInline)
150
- admin_class.inlines = inlines
151
- else:
152
- class BomUserAdmin(UserAdmin):
153
- inlines = [UserMetaInline]
189
+ admin.site.register(User, BomUserAdmin)
154
190
 
191
+ if settings.BOM_ORGANIZATION_MODEL == 'bom.Organization':
192
+ from .models import Organization
155
193
 
156
- admin.site.register(User, BomUserAdmin)
194
+ admin.site.register(Organization, OrganizationAdmin)
157
195
 
158
- admin.site.register(Organization, OrganizationAdmin)
159
196
  admin.site.register(Seller, SellerAdmin)
160
197
  admin.site.register(SellerPart, SellerPartAdmin)
161
198
  admin.site.register(ManufacturerPart, ManufacturerPartAdmin)
@@ -165,3 +202,6 @@ admin.site.register(PartRevision, PartRevisionAdmin)
165
202
  admin.site.register(Manufacturer, ManufacturerAdmin)
166
203
  admin.site.register(Assembly, AssemblyAdmin)
167
204
  admin.site.register(Subpart, SubpartAdmin)
205
+ admin.site.register(UnitDefinition, UnitDefinitionAdmin)
206
+ admin.site.register(PartRevisionPropertyDefinition, PartRevisionPropertyDefinitionAdmin)
207
+ admin.site.register(QuantityOfMeasure, QuantityOfMeasureAdmin)
@@ -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'),
@@ -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', ]),