django-bom 1.248__tar.gz → 1.252__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 (194) hide show
  1. {django_bom-1.248/django_bom.egg-info → django_bom-1.252}/PKG-INFO +1 -1
  2. {django_bom-1.248 → django_bom-1.252}/bom/admin.py +4 -2
  3. {django_bom-1.248 → django_bom-1.252}/bom/auth_backends.py +3 -1
  4. {django_bom-1.248 → django_bom-1.252}/bom/forms.py +4 -3
  5. django_bom-1.252/bom/migrations/0051_alter_manufacturer_organization_and_more.py +41 -0
  6. {django_bom-1.248 → django_bom-1.252}/bom/models.py +62 -19
  7. {django_bom-1.248 → django_bom-1.252}/bom/settings.py +2 -0
  8. {django_bom-1.248 → django_bom-1.252}/bom/views/json_views.py +2 -2
  9. {django_bom-1.248 → django_bom-1.252}/bom/views/views.py +10 -3
  10. {django_bom-1.248 → django_bom-1.252/django_bom.egg-info}/PKG-INFO +1 -1
  11. {django_bom-1.248 → django_bom-1.252}/django_bom.egg-info/SOURCES.txt +1 -0
  12. {django_bom-1.248 → django_bom-1.252}/pyproject.toml +1 -1
  13. {django_bom-1.248 → django_bom-1.252}/LICENSE +0 -0
  14. {django_bom-1.248 → django_bom-1.252}/MANIFEST.in +0 -0
  15. {django_bom-1.248 → django_bom-1.252}/README.md +0 -0
  16. {django_bom-1.248 → django_bom-1.252}/bom/__init__.py +0 -0
  17. {django_bom-1.248 → django_bom-1.252}/bom/apps.py +0 -0
  18. {django_bom-1.248 → django_bom-1.252}/bom/base_classes.py +0 -0
  19. {django_bom-1.248 → django_bom-1.252}/bom/constants.py +0 -0
  20. {django_bom-1.248 → django_bom-1.252}/bom/context_processors.py +0 -0
  21. {django_bom-1.248 → django_bom-1.252}/bom/csv_headers.py +0 -0
  22. {django_bom-1.248 → django_bom-1.252}/bom/decorators.py +0 -0
  23. {django_bom-1.248 → django_bom-1.252}/bom/form_fields.py +0 -0
  24. {django_bom-1.248 → django_bom-1.252}/bom/helpers.py +0 -0
  25. {django_bom-1.248 → django_bom-1.252}/bom/local_settings.py +0 -0
  26. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0001_initial.py +0 -0
  27. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0002_auto_20180908_2151.py +0 -0
  28. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0003_sellerpart_data_source.py +0 -0
  29. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0004_auto_20180911_0011.py +0 -0
  30. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0005_auto_20181007_1934.py +0 -0
  31. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0006_auto_20181007_1949.py +0 -0
  32. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0007_auto_20181009_0256.py +0 -0
  33. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0008_auto_20181030_0427.py +0 -0
  34. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0009_subpart_reference.py +0 -0
  35. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0010_auto_20181202_0733.py +0 -0
  36. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0011_auto_20181202_2113.py +0 -0
  37. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0012_partchangehistory.py +0 -0
  38. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0013_auto_20190222_1631.py +0 -0
  39. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0014_auto_20190223_2353.py +0 -0
  40. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0015_auto_20190303_1915.py +0 -0
  41. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0016_auto_20190405_2308.py +0 -0
  42. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0017_auto_20190616_1912.py +0 -0
  43. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0018_auto_20190616_2143.py +0 -0
  44. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0019_auto_20190624_1246.py +0 -0
  45. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0020_auto_20190627_0207.py +0 -0
  46. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0021_auto_20190627_0428.py +0 -0
  47. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0022_auto_20190811_2140.py +0 -0
  48. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0023_auto_20191205_2351.py +0 -0
  49. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0024_auto_20191214_1342.py +0 -0
  50. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0025_auto_20191221_1907.py +0 -0
  51. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0026_auto_20191222_2258.py +0 -0
  52. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0027_auto_20191222_2347.py +0 -0
  53. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0028_partrevision_displayable_synopsis.py +0 -0
  54. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0029_auto_20191231_1630.py +0 -0
  55. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0030_auto_20200101_2253.py +0 -0
  56. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0031_auto_20200104_1352.py +0 -0
  57. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0032_auto_20200126_1806.py +0 -0
  58. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0033_auto_20200203_0618.py +0 -0
  59. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0034_auto_20200222_0359.py +0 -0
  60. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0035_auto_20200303_0111.py +0 -0
  61. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0036_auto_20200303_0538.py +0 -0
  62. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0037_auto_20200405_1642.py +0 -0
  63. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0038_auto_20200422_0504.py +0 -0
  64. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0039_auto_20200929_2315.py +0 -0
  65. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0040_alter_organization_currency.py +0 -0
  66. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0041_organization_subscription_quantity.py +0 -0
  67. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0042_auto_20210720_2137.py +0 -0
  68. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0043_auto_20211123_0157.py +0 -0
  69. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0044_auto_20220831_1241.py +0 -0
  70. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0045_sellerpart_link.py +0 -0
  71. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0046_alter_sellerpart_unique_together.py +0 -0
  72. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0047_sellerpart_seller_part_number.py +0 -0
  73. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py +0 -0
  74. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py +0 -0
  75. {django_bom-1.248 → django_bom-1.252}/bom/migrations/0050_alter_organization_options.py +0 -0
  76. {django_bom-1.248 → django_bom-1.252}/bom/migrations/__init__.py +0 -0
  77. {django_bom-1.248 → django_bom-1.252}/bom/part_bom.py +0 -0
  78. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/dashboard.css +0 -0
  79. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/jquery.treetable.css +0 -0
  80. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/materialize.min.css +0 -0
  81. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/part-info.css +0 -0
  82. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/style.css +0 -0
  83. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/tablesorter-theme.materialize.css +0 -0
  84. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/css/treetable-theme.css +0 -0
  85. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/sample_part_classes.csv +0 -0
  86. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/test_bom.csv +0 -0
  87. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/test_bom_5_intelligent.csv +0 -0
  88. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/test_full_bom.csv +0 -0
  89. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/test_new_parts.csv +0 -0
  90. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/doc/test_new_parts_5_intelligent.csv +0 -0
  91. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/_ionicons_svg_md-arrow-dropdown.svg +0 -0
  92. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/_ionicons_svg_md-arrow-dropright.svg +0 -0
  93. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/favicon.ico +0 -0
  94. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_disabled_web.png +0 -0
  95. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_focus_web.png +0 -0
  96. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_normal_web.png +0 -0
  97. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_pressed_web.png +0 -0
  98. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_light_disabled_web.png +0 -0
  99. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_light_focus_web.png +0 -0
  100. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_light_normal_web.png +0 -0
  101. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/1x/btn_google_signin_light_pressed_web.png +0 -0
  102. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_disabled_web@2x.png +0 -0
  103. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_focus_web@2x.png +0 -0
  104. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_normal_web@2x.png +0 -0
  105. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_pressed_web@2x.png +0 -0
  106. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_light_disabled_web@2x.png +0 -0
  107. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_light_focus_web@2x.png +0 -0
  108. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_light_normal_web@2x.png +0 -0
  109. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/2x/btn_google_signin_light_pressed_web@2x.png +0 -0
  110. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.eps +0 -0
  111. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.svg +0 -0
  112. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.eps +0 -0
  113. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.svg +0 -0
  114. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.eps +0 -0
  115. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.svg +0 -0
  116. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.eps +0 -0
  117. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.svg +0 -0
  118. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.eps +0 -0
  119. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.svg +0 -0
  120. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.eps +0 -0
  121. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.svg +0 -0
  122. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps +0 -0
  123. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg +0 -0
  124. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps +0 -0
  125. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg +0 -0
  126. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/google_drive_logo.svg +0 -0
  127. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/indabom.png +0 -0
  128. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/mouser.png +0 -0
  129. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/img/octopart_blue.svg +0 -0
  130. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/js/jquery-3.4.1.min.js +0 -0
  131. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/js/jquery.ba-floatingscrollbar.min.js +0 -0
  132. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/js/jquery.treetable.js +0 -0
  133. {django_bom-1.248 → django_bom-1.252}/bom/static/bom/js/materialize.min.js +0 -0
  134. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/account-delete.html +0 -0
  135. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/add-manufacturer-part.html +0 -0
  136. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/add-sellerpart.html +0 -0
  137. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/base-menu.html +0 -0
  138. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/base.html +0 -0
  139. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-action-btn.html +0 -0
  140. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-action-table.html +0 -0
  141. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-base-menu.html +0 -0
  142. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-base.html +0 -0
  143. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-form-modal.html +0 -0
  144. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-form.html +0 -0
  145. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-modal-add-users.html +0 -0
  146. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/bom-signup.html +0 -0
  147. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/components/bom-flat.html +0 -0
  148. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/components/bom-indented.html +0 -0
  149. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/components/manufacturer-part-list.html +0 -0
  150. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/components/seller-part-list.html +0 -0
  151. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/create-part.html +0 -0
  152. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/dashboard-menu.html +0 -0
  153. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/dashboard.html +0 -0
  154. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/edit-manufacturer-part.html +0 -0
  155. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/edit-part-class.html +0 -0
  156. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/edit-part.html +0 -0
  157. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/edit-user-meta.html +0 -0
  158. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/help.html +0 -0
  159. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/manufacturer-info.html +0 -0
  160. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/manufacturers.html +0 -0
  161. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/nothing-to-see.html +0 -0
  162. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/organization-create.html +0 -0
  163. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-info.html +0 -0
  164. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-revision-display.html +0 -0
  165. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-revision-edit.html +0 -0
  166. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-revision-manage-bom.html +0 -0
  167. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-revision-new.html +0 -0
  168. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/part-revision-release.html +0 -0
  169. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/search-help.html +0 -0
  170. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/seller-info.html +0 -0
  171. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/sellers.html +0 -0
  172. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/settings.html +0 -0
  173. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/signup.html +0 -0
  174. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/subscription_panel.html +0 -0
  175. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/table_of_contents.html +0 -0
  176. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/upload-bom.html +0 -0
  177. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/upload-parts-help.html +0 -0
  178. {django_bom-1.248 → django_bom-1.252}/bom/templates/bom/upload-parts.html +0 -0
  179. {django_bom-1.248 → django_bom-1.252}/bom/templates/registration/login.html +0 -0
  180. {django_bom-1.248 → django_bom-1.252}/bom/tests.py +0 -0
  181. {django_bom-1.248 → django_bom-1.252}/bom/third_party_apis/__init__.py +0 -0
  182. {django_bom-1.248 → django_bom-1.252}/bom/third_party_apis/base_api.py +0 -0
  183. {django_bom-1.248 → django_bom-1.252}/bom/third_party_apis/google_drive.py +0 -0
  184. {django_bom-1.248 → django_bom-1.252}/bom/third_party_apis/mouser.py +0 -0
  185. {django_bom-1.248 → django_bom-1.252}/bom/third_party_apis/test_apis.py +0 -0
  186. {django_bom-1.248 → django_bom-1.252}/bom/urls.py +0 -0
  187. {django_bom-1.248 → django_bom-1.252}/bom/utils.py +0 -0
  188. {django_bom-1.248 → django_bom-1.252}/bom/validators.py +0 -0
  189. {django_bom-1.248 → django_bom-1.252}/bom/views/__init__.py +0 -0
  190. {django_bom-1.248 → django_bom-1.252}/bom/wsgi.py +0 -0
  191. {django_bom-1.248 → django_bom-1.252}/django_bom.egg-info/dependency_links.txt +0 -0
  192. {django_bom-1.248 → django_bom-1.252}/django_bom.egg-info/requires.txt +0 -0
  193. {django_bom-1.248 → django_bom-1.252}/django_bom.egg-info/top_level.txt +0 -0
  194. {django_bom-1.248 → django_bom-1.252}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bom
3
- Version: 1.248
3
+ Version: 1.252
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
@@ -6,17 +6,19 @@ from .models import (
6
6
  Assembly,
7
7
  Manufacturer,
8
8
  ManufacturerPart,
9
- Organization,
10
9
  Part,
11
10
  PartClass,
12
11
  PartRevision,
13
12
  Seller,
14
13
  SellerPart,
15
14
  Subpart,
16
- UserMeta,
15
+ get_organization_model,
16
+ get_user_meta_model
17
17
  )
18
18
 
19
19
  User = get_user_model()
20
+ UserMeta = get_user_meta_model()
21
+ Organization = get_organization_model()
20
22
 
21
23
  class UserMetaInline(admin.TabularInline):
22
24
  model = UserMeta
@@ -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:
@@ -39,7 +39,6 @@ from .models import (
39
39
  AssemblySubparts,
40
40
  Manufacturer,
41
41
  ManufacturerPart,
42
- Organization,
43
42
  Part,
44
43
  PartClass,
45
44
  PartRevision,
@@ -47,7 +46,8 @@ from .models import (
47
46
  SellerPart,
48
47
  Subpart,
49
48
  User,
50
- UserMeta,
49
+ get_user_meta_model,
50
+ get_organization_model,
51
51
  )
52
52
  from .utils import (
53
53
  listify_string,
@@ -56,7 +56,8 @@ from .utils import (
56
56
  from .validators import alphanumeric
57
57
 
58
58
  logger = logging.getLogger(__name__)
59
-
59
+ Organization = get_organization_model()
60
+ UserMeta = get_user_meta_model()
60
61
 
61
62
  class UserModelChoiceField(forms.ModelChoiceField):
62
63
  def label_from_instance(self, user):
@@ -0,0 +1,41 @@
1
+ # Generated by Django 5.2.8 on 2026-01-04 00:59
2
+
3
+ import django.db.models.deletion
4
+ from django.conf import settings
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('bom', '0050_alter_organization_options'),
12
+ migrations.swappable_dependency(settings.BOM_ORGANIZATION_MODEL),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.AlterField(
17
+ model_name='manufacturer',
18
+ name='organization',
19
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.BOM_ORGANIZATION_MODEL),
20
+ ),
21
+ migrations.AlterField(
22
+ model_name='part',
23
+ name='organization',
24
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.BOM_ORGANIZATION_MODEL),
25
+ ),
26
+ migrations.AlterField(
27
+ model_name='partclass',
28
+ name='organization',
29
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.BOM_ORGANIZATION_MODEL),
30
+ ),
31
+ migrations.AlterField(
32
+ model_name='seller',
33
+ name='organization',
34
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.BOM_ORGANIZATION_MODEL),
35
+ ),
36
+ migrations.AlterField(
37
+ model_name='usermeta',
38
+ name='organization',
39
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.BOM_ORGANIZATION_MODEL),
40
+ ),
41
+ ]
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
2
2
 
3
3
  import logging
4
4
 
5
+ from django.apps import apps
5
6
  from django.conf import settings
6
7
  from django.contrib.auth import get_user_model
7
8
  from django.core.cache import cache
@@ -23,32 +24,54 @@ logger = logging.getLogger(__name__)
23
24
  User = get_user_model()
24
25
 
25
26
 
27
+ def get_user_meta_model():
28
+ from django.apps import apps
29
+ from django.conf import settings
30
+ return apps.get_model(settings.BOM_USER_META_MODEL)
31
+
32
+
33
+ def get_organization_model():
34
+ from django.apps import apps
35
+ from django.conf import settings
36
+ return apps.get_model(settings.BOM_ORGANIZATION_MODEL)
37
+
38
+
39
+ def _user_meta(self, organization=None):
40
+ from django.apps import apps
41
+ from django.conf import settings
42
+ UserMetaModel = apps.get_model(settings.BOM_USER_META_MODEL)
43
+ meta, created = UserMetaModel.objects.get_or_create(
44
+ user=self,
45
+ defaults={'organization': organization}
46
+ )
47
+ return meta
48
+
49
+
26
50
  class OrganizationScopedModel(models.Model):
27
- organization = models.ForeignKey('Organization', on_delete=models.CASCADE, db_index=True)
51
+ organization = models.ForeignKey(settings.BOM_ORGANIZATION_MODEL, on_delete=models.CASCADE, db_index=True)
28
52
 
29
53
  class Meta:
30
54
  abstract = True
31
55
 
32
56
 
33
- class Organization(models.Model):
57
+ class AbstractOrganization(models.Model):
34
58
  name = models.CharField(max_length=255, default=None)
35
- subscription = models.CharField(max_length=1, choices=SUBSCRIPTION_TYPES)
36
- subscription_quantity = models.IntegerField(default=0)
37
59
  owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
38
60
  number_scheme = models.CharField(max_length=1, choices=NUMBER_SCHEMES, default=NUMBER_SCHEME_SEMI_INTELLIGENT)
39
61
  number_class_code_len = models.PositiveIntegerField(default=NUMBER_CLASS_CODE_LEN_DEFAULT,
40
- validators=[MinValueValidator(NUMBER_CLASS_CODE_LEN_MIN), MaxValueValidator(NUMBER_CLASS_CODE_LEN_MAX)])
62
+ validators=[MinValueValidator(NUMBER_CLASS_CODE_LEN_MIN),
63
+ MaxValueValidator(NUMBER_CLASS_CODE_LEN_MAX)])
41
64
  number_item_len = models.PositiveIntegerField(default=NUMBER_ITEM_LEN_DEFAULT,
42
- validators=[MinValueValidator(NUMBER_ITEM_LEN_MIN), MaxValueValidator(NUMBER_ITEM_LEN_MAX)])
65
+ validators=[MinValueValidator(NUMBER_ITEM_LEN_MIN),
66
+ MaxValueValidator(NUMBER_ITEM_LEN_MAX)])
43
67
  number_variation_len = models.PositiveIntegerField(default=NUMBER_VARIATION_LEN_DEFAULT,
44
- validators=[MinValueValidator(NUMBER_VARIATION_LEN_MIN), MaxValueValidator(NUMBER_VARIATION_LEN_MAX)])
68
+ validators=[MinValueValidator(NUMBER_VARIATION_LEN_MIN),
69
+ MaxValueValidator(NUMBER_VARIATION_LEN_MAX)])
45
70
  google_drive_parent = models.CharField(max_length=128, blank=True, default=None, null=True)
46
71
  currency = CurrencyField(max_length=3, choices=CURRENCY_CHOICES, default='USD')
47
72
 
48
- class Meta:
49
- permissions = (
50
- ("manage_members", "Can manage organization members"),
51
- )
73
+ subscription = models.CharField(max_length=1, choices=SUBSCRIPTION_TYPES)
74
+ subscription_quantity = models.IntegerField(default=0)
52
75
 
53
76
  def number_cs(self):
54
77
  return "C" * self.number_class_code_len
@@ -76,13 +99,25 @@ class Organization(models.Model):
76
99
  return self.owner.email
77
100
 
78
101
  def save(self, *args, **kwargs):
79
- super(Organization, self).save()
80
- SellerPart.objects.filter(seller__organization=self).update(unit_cost_currency=self.currency, nre_cost_currency=self.currency)
102
+ super(AbstractOrganization, self).save()
103
+ SellerPart.objects.filter(seller__organization=self).update(unit_cost_currency=self.currency,
104
+ nre_cost_currency=self.currency)
81
105
 
106
+ class Meta:
107
+ abstract = True
108
+
109
+
110
+ class Organization(AbstractOrganization):
111
+ class Meta:
112
+ swappable = 'BOM_ORGANIZATION_MODEL'
113
+ permissions = (
114
+ ("manage_members", "Can manage organization members"),
115
+ )
82
116
 
83
- class UserMeta(models.Model):
117
+
118
+ class AbstractUserMeta(models.Model):
84
119
  user = models.OneToOneField(settings.AUTH_USER_MODEL, db_index=True, on_delete=models.CASCADE)
85
- organization = models.ForeignKey(Organization, blank=True, null=True, on_delete=models.CASCADE)
120
+ organization = models.ForeignKey(settings.BOM_ORGANIZATION_MODEL, blank=True, null=True, on_delete=models.CASCADE)
86
121
  role = models.CharField(max_length=1, choices=ROLE_TYPES)
87
122
 
88
123
  def get_or_create_organization(self):
@@ -92,7 +127,9 @@ class UserMeta(models.Model):
92
127
  else:
93
128
  org_name = self.user.first_name + ' ' + self.user.last_name
94
129
 
95
- organization, created = Organization.objects.get_or_create(owner=self.user, defaults={'name': org_name, 'subscription': 'F'})
130
+ OrganizationModel = apps.get_model(settings.BOM_ORGANIZATION_MODEL)
131
+ organization, created = OrganizationModel.objects.get_or_create(owner=self.user, defaults={'name': org_name,
132
+ 'subscription': 'F'})
96
133
 
97
134
  self.organization = organization
98
135
  self.role = 'A'
@@ -109,10 +146,13 @@ class UserMeta(models.Model):
109
146
  def is_organization_owner(self) -> bool:
110
147
  return self.organization.owner == self.user if self.organization else False
111
148
 
112
- def _user_meta(self, organization=None):
113
- return UserMeta.objects.get_or_create(user=self, defaults={'organization': organization})[0]
149
+ class Meta:
150
+ abstract = True
114
151
 
115
- User.add_to_class('bom_profile', _user_meta)
152
+
153
+ class UserMeta(AbstractUserMeta):
154
+ class Meta:
155
+ swappable = 'BOM_USER_META_MODEL'
116
156
 
117
157
 
118
158
  class PartClass(OrganizationScopedModel):
@@ -730,3 +770,6 @@ class SellerPart(models.Model, AsDictModel):
730
770
 
731
771
  def __str__(self):
732
772
  return u'%s' % (self.manufacturer_part.part.full_part_number() + ' ' + self.seller.name)
773
+
774
+
775
+ User.add_to_class('bom_profile', _user_meta)
@@ -23,6 +23,8 @@ BOM_CONFIG_DEFAULT = {
23
23
  'page_size': 50,
24
24
  }
25
25
  }
26
+ BOM_ORGANIZATION_MODEL = 'bom.Organization'
27
+ BOM_USER_META_MODEL = 'bom.UserMeta'
26
28
 
27
29
  # Apply custom settings over defaults
28
30
  bom_config_new = BOM_CONFIG_DEFAULT.copy()
@@ -5,9 +5,9 @@ from django.shortcuts import get_object_or_404
5
5
  from django.utils.decorators import method_decorator
6
6
  from django.views import View
7
7
 
8
- from bom.models import Part, PartClass, Subpart, SellerPart, Organization, Manufacturer, ManufacturerPart, User, UserMeta, PartRevision, Assembly, AssemblySubparts
9
- from bom.third_party_apis.mouser import Mouser
8
+ from bom.models import PartRevision
10
9
  from bom.third_party_apis.base_api import BaseApiError
10
+ from bom.third_party_apis.mouser import Mouser
11
11
 
12
12
 
13
13
  class BomJsonResponse(View):
@@ -69,11 +69,12 @@ from bom.models import (
69
69
  SellerPart,
70
70
  Subpart,
71
71
  User,
72
- UserMeta,
72
+ get_user_meta_model
73
73
  )
74
74
  from bom.utils import check_references_for_duplicates, listify_string, prep_for_sorting_nicely
75
75
 
76
76
  logger = logging.getLogger(__name__)
77
+ UserMeta = get_user_meta_model()
77
78
  BOM_LOGIN_URL = getattr(settings, "BOM_LOGIN_URL", None) or settings.LOGIN_URL
78
79
 
79
80
  def form_error_messages(form_errors) -> [str]:
@@ -403,7 +404,10 @@ def bom_settings(request, tab_anchor=None):
403
404
  for field, errors in user_add_form.errors.items():
404
405
  for error in errors:
405
406
  messages.error(request, f"{field.capitalize()}: {error}")
406
-
407
+ users_in_organization.all()
408
+ users_in_organization_count = users_in_organization.count()
409
+ has_member_capacity = users_in_organization_count < organization.subscription_quantity
410
+ seats_available = max(organization.subscription_quantity - users_in_organization_count, 0)
407
411
  elif 'clear-add-user' in request.POST:
408
412
  tab_anchor = ORGANIZATION_TAB
409
413
  user_add_form = UserAddForm()
@@ -423,7 +427,10 @@ def bom_settings(request, tab_anchor=None):
423
427
  user_meta.save()
424
428
  except UserMeta.DoesNotExist:
425
429
  messages.error(request, "No user found with given id {}.".format(user_meta_id))
426
-
430
+ users_in_organization.all()
431
+ users_in_organization_count = users_in_organization.count()
432
+ has_member_capacity = users_in_organization_count < organization.subscription_quantity
433
+ seats_available = max(organization.subscription_quantity - users_in_organization_count, 0)
427
434
  elif 'submit-edit-organization' in request.POST:
428
435
  tab_anchor = ORGANIZATION_TAB
429
436
  organization_form = OrganizationFormEditSettings(request.POST, instance=organization, user=user)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bom
3
- Version: 1.248
3
+ Version: 1.252
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
@@ -73,6 +73,7 @@ bom/migrations/0047_sellerpart_seller_part_number.py
73
73
  bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py
74
74
  bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py
75
75
  bom/migrations/0050_alter_organization_options.py
76
+ bom/migrations/0051_alter_manufacturer_organization_and_more.py
76
77
  bom/migrations/__init__.py
77
78
  bom/static/bom/css/dashboard.css
78
79
  bom/static/bom/css/jquery.treetable.css
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "django-bom"
10
- version = "1.248"
10
+ version = "1.252"
11
11
  description = "A simple Django app to manage a bill of materials."
12
12
  readme = {file = "README.md", content-type = "text/markdown"}
13
13
  requires-python = ">=3.10"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes