django-bom 1.228__tar.gz → 1.255__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.

Potentially problematic release.


This version of django-bom might be problematic. Click here for more details.

Files changed (204) hide show
  1. {django-bom-1.228/django_bom.egg-info → django_bom-1.255}/PKG-INFO +27 -20
  2. {django-bom-1.228 → django_bom-1.255}/README.md +7 -8
  3. {django-bom-1.228 → django_bom-1.255}/bom/admin.py +27 -14
  4. django_bom-1.255/bom/auth_backends.py +47 -0
  5. {django-bom-1.228 → django_bom-1.255}/bom/constants.py +2 -0
  6. {django-bom-1.228 → django_bom-1.255}/bom/csv_headers.py +1 -0
  7. {django-bom-1.228 → django_bom-1.255}/bom/forms.py +11 -28
  8. {django-bom-1.228 → django_bom-1.255}/bom/helpers.py +2 -1
  9. django_bom-1.255/bom/local_settings.py +35 -0
  10. django_bom-1.255/bom/migrations/0046_alter_sellerpart_unique_together.py +17 -0
  11. django_bom-1.255/bom/migrations/0047_sellerpart_seller_part_number.py +18 -0
  12. django_bom-1.255/bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py +1017 -0
  13. django_bom-1.255/bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py +99 -0
  14. django_bom-1.255/bom/migrations/0050_alter_organization_options.py +17 -0
  15. django_bom-1.255/bom/migrations/0051_alter_manufacturer_organization_and_more.py +41 -0
  16. {django-bom-1.228 → django_bom-1.255}/bom/models.py +112 -94
  17. {django-bom-1.228 → django_bom-1.255}/bom/part_bom.py +1 -0
  18. django_bom-1.255/bom/settings.py +262 -0
  19. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/style.css +96 -5
  20. django_bom-1.255/bom/static/bom/doc/test_full_bom.csv +37 -0
  21. django_bom-1.255/bom/templates/bom/account-delete.html +23 -0
  22. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/add-manufacturer-part.html +2 -5
  23. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/add-sellerpart.html +9 -5
  24. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/base-menu.html +10 -1
  25. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-action-table.html +2 -2
  26. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-form-modal.html +3 -2
  27. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-form.html +1 -5
  28. django_bom-1.255/bom/templates/bom/bom-modal-add-users.html +49 -0
  29. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-signup.html +0 -4
  30. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/components/bom-flat.html +2 -2
  31. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/components/bom-indented.html +3 -3
  32. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/components/manufacturer-part-list.html +6 -2
  33. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/components/seller-part-list.html +2 -1
  34. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/create-part.html +2 -5
  35. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/dashboard.html +6 -3
  36. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/edit-manufacturer-part.html +2 -5
  37. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/edit-part-class.html +2 -5
  38. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/edit-part.html +2 -6
  39. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/edit-user-meta.html +2 -5
  40. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/help.html +2 -9
  41. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/manufacturer-info.html +1 -2
  42. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/manufacturers.html +3 -2
  43. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/organization-create.html +8 -8
  44. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-info.html +3 -4
  45. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-revision-edit.html +2 -5
  46. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-revision-manage-bom.html +1 -2
  47. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-revision-new.html +2 -5
  48. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-revision-release.html +0 -7
  49. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/search-help.html +0 -4
  50. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/seller-info.html +1 -2
  51. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/sellers.html +3 -2
  52. django_bom-1.255/bom/templates/bom/settings.html +465 -0
  53. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/signup.html +1 -1
  54. django_bom-1.255/bom/templates/bom/subscription_panel.html +16 -0
  55. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/upload-bom.html +0 -1
  56. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/upload-parts-help.html +3 -6
  57. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/upload-parts.html +0 -4
  58. {django-bom-1.228 → django_bom-1.255}/bom/tests.py +11 -6
  59. {django-bom-1.228 → django_bom-1.255}/bom/third_party_apis/mouser.py +1 -0
  60. {django-bom-1.228 → django_bom-1.255}/bom/urls.py +14 -8
  61. {django-bom-1.228 → django_bom-1.255}/bom/views/json_views.py +2 -2
  62. {django-bom-1.228 → django_bom-1.255}/bom/views/views.py +35 -14
  63. {django-bom-1.228 → django_bom-1.255/django_bom.egg-info}/PKG-INFO +27 -20
  64. {django-bom-1.228 → django_bom-1.255}/django_bom.egg-info/SOURCES.txt +11 -5
  65. django_bom-1.255/django_bom.egg-info/requires.txt +6 -0
  66. django_bom-1.255/pyproject.toml +70 -0
  67. django_bom-1.255/setup.cfg +4 -0
  68. django-bom-1.228/bom/local_settings.py +0 -41
  69. django-bom-1.228/bom/settings.py +0 -225
  70. django-bom-1.228/bom/static/.DS_Store +0 -0
  71. django-bom-1.228/bom/static/bom/.DS_Store +0 -0
  72. django-bom-1.228/bom/static/bom/doc/test_full_bom.csv +0 -36
  73. django-bom-1.228/bom/static/bom/img/.DS_Store +0 -0
  74. django-bom-1.228/bom/templates/bom/settings.html +0 -395
  75. django-bom-1.228/django_bom.egg-info/requires.txt +0 -5
  76. django-bom-1.228/setup.cfg +0 -25
  77. django-bom-1.228/setup.py +0 -43
  78. {django-bom-1.228 → django_bom-1.255}/LICENSE +0 -0
  79. {django-bom-1.228 → django_bom-1.255}/MANIFEST.in +0 -0
  80. {django-bom-1.228 → django_bom-1.255}/bom/__init__.py +0 -0
  81. {django-bom-1.228 → django_bom-1.255}/bom/apps.py +0 -0
  82. {django-bom-1.228 → django_bom-1.255}/bom/base_classes.py +0 -0
  83. {django-bom-1.228 → django_bom-1.255}/bom/context_processors.py +0 -0
  84. {django-bom-1.228 → django_bom-1.255}/bom/decorators.py +0 -0
  85. {django-bom-1.228 → django_bom-1.255}/bom/form_fields.py +0 -0
  86. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0001_initial.py +0 -0
  87. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0002_auto_20180908_2151.py +0 -0
  88. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0003_sellerpart_data_source.py +0 -0
  89. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0004_auto_20180911_0011.py +0 -0
  90. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0005_auto_20181007_1934.py +0 -0
  91. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0006_auto_20181007_1949.py +0 -0
  92. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0007_auto_20181009_0256.py +0 -0
  93. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0008_auto_20181030_0427.py +0 -0
  94. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0009_subpart_reference.py +0 -0
  95. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0010_auto_20181202_0733.py +0 -0
  96. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0011_auto_20181202_2113.py +0 -0
  97. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0012_partchangehistory.py +0 -0
  98. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0013_auto_20190222_1631.py +0 -0
  99. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0014_auto_20190223_2353.py +0 -0
  100. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0015_auto_20190303_1915.py +0 -0
  101. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0016_auto_20190405_2308.py +0 -0
  102. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0017_auto_20190616_1912.py +0 -0
  103. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0018_auto_20190616_2143.py +0 -0
  104. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0019_auto_20190624_1246.py +0 -0
  105. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0020_auto_20190627_0207.py +0 -0
  106. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0021_auto_20190627_0428.py +0 -0
  107. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0022_auto_20190811_2140.py +0 -0
  108. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0023_auto_20191205_2351.py +0 -0
  109. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0024_auto_20191214_1342.py +0 -0
  110. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0025_auto_20191221_1907.py +0 -0
  111. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0026_auto_20191222_2258.py +0 -0
  112. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0027_auto_20191222_2347.py +0 -0
  113. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0028_partrevision_displayable_synopsis.py +0 -0
  114. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0029_auto_20191231_1630.py +0 -0
  115. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0030_auto_20200101_2253.py +0 -0
  116. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0031_auto_20200104_1352.py +0 -0
  117. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0032_auto_20200126_1806.py +0 -0
  118. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0033_auto_20200203_0618.py +0 -0
  119. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0034_auto_20200222_0359.py +0 -0
  120. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0035_auto_20200303_0111.py +0 -0
  121. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0036_auto_20200303_0538.py +0 -0
  122. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0037_auto_20200405_1642.py +0 -0
  123. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0038_auto_20200422_0504.py +0 -0
  124. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0039_auto_20200929_2315.py +0 -0
  125. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0040_alter_organization_currency.py +0 -0
  126. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0041_organization_subscription_quantity.py +0 -0
  127. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0042_auto_20210720_2137.py +0 -0
  128. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0043_auto_20211123_0157.py +0 -0
  129. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0044_auto_20220831_1241.py +0 -0
  130. {django-bom-1.228 → django_bom-1.255}/bom/migrations/0045_sellerpart_link.py +0 -0
  131. {django-bom-1.228 → django_bom-1.255}/bom/migrations/__init__.py +0 -0
  132. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/dashboard.css +0 -0
  133. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/jquery.treetable.css +0 -0
  134. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/materialize.min.css +0 -0
  135. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/part-info.css +0 -0
  136. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/tablesorter-theme.materialize.css +0 -0
  137. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/css/treetable-theme.css +0 -0
  138. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/doc/sample_part_classes.csv +0 -0
  139. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/doc/test_bom.csv +0 -0
  140. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/doc/test_bom_5_intelligent.csv +0 -0
  141. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/doc/test_new_parts.csv +0 -0
  142. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/doc/test_new_parts_5_intelligent.csv +0 -0
  143. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/_ionicons_svg_md-arrow-dropdown.svg +0 -0
  144. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/_ionicons_svg_md-arrow-dropright.svg +0 -0
  145. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/favicon.ico +0 -0
  146. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_disabled_web.png +0 -0
  147. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_focus_web.png +0 -0
  148. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_normal_web.png +0 -0
  149. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_dark_pressed_web.png +0 -0
  150. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_light_disabled_web.png +0 -0
  151. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_light_focus_web.png +0 -0
  152. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_light_normal_web.png +0 -0
  153. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/1x/btn_google_signin_light_pressed_web.png +0 -0
  154. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_disabled_web@2x.png +0 -0
  155. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_focus_web@2x.png +0 -0
  156. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_normal_web@2x.png +0 -0
  157. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_dark_pressed_web@2x.png +0 -0
  158. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_light_disabled_web@2x.png +0 -0
  159. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_light_focus_web@2x.png +0 -0
  160. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_light_normal_web@2x.png +0 -0
  161. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/2x/btn_google_signin_light_pressed_web@2x.png +0 -0
  162. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.eps +0 -0
  163. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.svg +0 -0
  164. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.eps +0 -0
  165. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.svg +0 -0
  166. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.eps +0 -0
  167. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.svg +0 -0
  168. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.eps +0 -0
  169. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.svg +0 -0
  170. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.eps +0 -0
  171. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.svg +0 -0
  172. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.eps +0 -0
  173. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.svg +0 -0
  174. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps +0 -0
  175. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg +0 -0
  176. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps +0 -0
  177. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg +0 -0
  178. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/google_drive_logo.svg +0 -0
  179. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/indabom.png +0 -0
  180. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/mouser.png +0 -0
  181. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/img/octopart_blue.svg +0 -0
  182. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/js/jquery-3.4.1.min.js +0 -0
  183. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/js/jquery.ba-floatingscrollbar.min.js +0 -0
  184. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/js/jquery.treetable.js +0 -0
  185. {django-bom-1.228 → django_bom-1.255}/bom/static/bom/js/materialize.min.js +0 -0
  186. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/base.html +0 -0
  187. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-action-btn.html +0 -0
  188. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-base-menu.html +0 -0
  189. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/bom-base.html +0 -0
  190. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/dashboard-menu.html +0 -0
  191. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/nothing-to-see.html +0 -0
  192. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/part-revision-display.html +0 -0
  193. {django-bom-1.228 → django_bom-1.255}/bom/templates/bom/table_of_contents.html +0 -0
  194. {django-bom-1.228 → django_bom-1.255}/bom/templates/registration/login.html +0 -0
  195. {django-bom-1.228 → django_bom-1.255}/bom/third_party_apis/__init__.py +0 -0
  196. {django-bom-1.228 → django_bom-1.255}/bom/third_party_apis/base_api.py +0 -0
  197. {django-bom-1.228 → django_bom-1.255}/bom/third_party_apis/google_drive.py +0 -0
  198. {django-bom-1.228 → django_bom-1.255}/bom/third_party_apis/test_apis.py +0 -0
  199. {django-bom-1.228 → django_bom-1.255}/bom/utils.py +0 -0
  200. {django-bom-1.228 → django_bom-1.255}/bom/validators.py +0 -0
  201. {django-bom-1.228 → django_bom-1.255}/bom/views/__init__.py +0 -0
  202. {django-bom-1.228 → django_bom-1.255}/bom/wsgi.py +0 -0
  203. {django-bom-1.228 → django_bom-1.255}/django_bom.egg-info/dependency_links.txt +0 -0
  204. {django-bom-1.228 → django_bom-1.255}/django_bom.egg-info/top_level.txt +0 -0
@@ -1,24 +1,34 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: django-bom
3
- Version: 1.228
3
+ Version: 1.255
4
4
  Summary: A simple Django app to manage a bill of materials.
5
- Home-page: https://www.indabom.com/
6
- Author: Mike Kasparian
7
- Author-email: mpkasp@gmail.com
8
- License: GPL 3.0 License
9
- Platform: UNKNOWN
5
+ Author-email: Mike Kasparian <mpkasp@gmail.com>
6
+ License: GPL-3.0-only
7
+ Project-URL: Homepage, https://www.indabom.com/
10
8
  Classifier: Environment :: Web Environment
11
9
  Classifier: Framework :: Django
12
- Classifier: Framework :: Django :: 3.1
10
+ Classifier: Framework :: Django :: 5
13
11
  Classifier: Intended Audience :: Developers
14
- Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15
13
  Classifier: Operating System :: OS Independent
16
14
  Classifier: Programming Language :: Python
17
- Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3 :: Only
18
20
  Classifier: Topic :: Internet :: WWW/HTTP
19
21
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
22
+ Requires-Python: >=3.10
20
23
  Description-Content-Type: text/markdown
21
24
  License-File: LICENSE
25
+ Requires-Dist: Django<5.3,>=5.2
26
+ Requires-Dist: social-auth-app-django<6,>=5
27
+ Requires-Dist: social-auth-core<6,>=4
28
+ Requires-Dist: google-api-python-client>=2
29
+ Requires-Dist: django-materializecss-form
30
+ Requires-Dist: django-money<5,>=3
31
+ Dynamic: license-file
22
32
 
23
33
  # BOM
24
34
  ![](https://github.com/mpkasp/django-bom/workflows/Django%20CI/badge.svg)
@@ -41,16 +51,15 @@ If you already have a django project, you can skip to [Add Django Bom To Your Ap
41
51
  * [Installation pitfalls](#installation-pitfalls)
42
52
 
43
53
  ## Start From Scratch: Add to a new Django project
44
- 1. To start from scratch we recommend setting up a virtual environment
54
+ 1. To start from scratch, install your pipenv using Python 3.12
45
55
  ```
46
- virtualenv -p python3 mysite
47
- cd mysite
48
- source bin/activate
56
+ pipenv --python 3.12
57
+ pipenv shell
49
58
  ```
50
59
 
51
60
  2. From here install django, and set up your project.
52
61
  ```
53
- pip install django
62
+ pipenv install django
54
63
  django-admin startproject mysite
55
64
  cd mysite
56
65
  python manage.py migrate
@@ -60,7 +69,7 @@ python manage.py createsuperuser # make a user for your development environment
60
69
  3. Continue on to [Add Django Bom To Your App](#add-django-bom-to-your-app).
61
70
 
62
71
  ## Add Django Bom To Your App
63
- django-bom is a [reusable django application](https://docs.djangoproject.com/en/1.11/intro/reusable-apps/). If you don't already have a django project, you can follow some quick steps below to get up and running, or read about creating your first django app [here](https://docs.djangoproject.com/en/1.11/intro/tutorial01/). Note that django-bom currently supports python 2.7.
72
+ django-bom is a [reusable django application](https://docs.djangoproject.com/en/1.11/intro/reusable-apps/). If you don't already have a django project, you can follow some quick steps below to get up and running, or read about creating your first django app [here](https://docs.djangoproject.com/en/1.11/intro/tutorial01/).
64
73
 
65
74
  ```
66
75
  pip install django-bom
@@ -110,7 +119,7 @@ TEMPLATES = [
110
119
  and
111
120
 
112
121
  ```
113
- BOM_CONFIG = {}
122
+ BOM_CONFIG = {'standalone_mode': False}
114
123
  ```
115
124
 
116
125
  4. Run `python manage.py migrate` to create the bom models.
@@ -132,7 +141,7 @@ source bin/activate
132
141
  2. From here install django, and set up your project.
133
142
  ```
134
143
  git clone https://github.com/mpkasp/django-bom.git
135
- pip install -r requirements.txt
144
+ pipenv install
136
145
  python manage.py migrate
137
146
  cp bom/local_settings.py.example bom/local_settings.py
138
147
  python manage.py runserver
@@ -195,5 +204,3 @@ You may get an error during your `pip install -r requirements.txt` related to sq
195
204
 
196
205
  #### Cryptography
197
206
  Sometimes you'll have issues installing cryptography, if this is the case you may just need to set up some environment variables. This [stackoverflow](https://stackoverflow.com/questions/46288737/error-while-installing-sqlite-using-pip-on-python-2-7-13) may help.
198
-
199
-
@@ -19,16 +19,15 @@ If you already have a django project, you can skip to [Add Django Bom To Your Ap
19
19
  * [Installation pitfalls](#installation-pitfalls)
20
20
 
21
21
  ## Start From Scratch: Add to a new Django project
22
- 1. To start from scratch we recommend setting up a virtual environment
22
+ 1. To start from scratch, install your pipenv using Python 3.12
23
23
  ```
24
- virtualenv -p python3 mysite
25
- cd mysite
26
- source bin/activate
24
+ pipenv --python 3.12
25
+ pipenv shell
27
26
  ```
28
27
 
29
28
  2. From here install django, and set up your project.
30
29
  ```
31
- pip install django
30
+ pipenv install django
32
31
  django-admin startproject mysite
33
32
  cd mysite
34
33
  python manage.py migrate
@@ -38,7 +37,7 @@ python manage.py createsuperuser # make a user for your development environment
38
37
  3. Continue on to [Add Django Bom To Your App](#add-django-bom-to-your-app).
39
38
 
40
39
  ## Add Django Bom To Your App
41
- django-bom is a [reusable django application](https://docs.djangoproject.com/en/1.11/intro/reusable-apps/). If you don't already have a django project, you can follow some quick steps below to get up and running, or read about creating your first django app [here](https://docs.djangoproject.com/en/1.11/intro/tutorial01/). Note that django-bom currently supports python 2.7.
40
+ django-bom is a [reusable django application](https://docs.djangoproject.com/en/1.11/intro/reusable-apps/). If you don't already have a django project, you can follow some quick steps below to get up and running, or read about creating your first django app [here](https://docs.djangoproject.com/en/1.11/intro/tutorial01/).
42
41
 
43
42
  ```
44
43
  pip install django-bom
@@ -88,7 +87,7 @@ TEMPLATES = [
88
87
  and
89
88
 
90
89
  ```
91
- BOM_CONFIG = {}
90
+ BOM_CONFIG = {'standalone_mode': False}
92
91
  ```
93
92
 
94
93
  4. Run `python manage.py migrate` to create the bom models.
@@ -110,7 +109,7 @@ source bin/activate
110
109
  2. From here install django, and set up your project.
111
110
  ```
112
111
  git clone https://github.com/mpkasp/django-bom.git
113
- pip install -r requirements.txt
112
+ pipenv install
114
113
  python manage.py migrate
115
114
  cp bom/local_settings.py.example bom/local_settings.py
116
115
  python manage.py runserver
@@ -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,27 @@ from .models import (
6
7
  Assembly,
7
8
  Manufacturer,
8
9
  ManufacturerPart,
9
- Organization,
10
10
  Part,
11
11
  PartClass,
12
12
  PartRevision,
13
13
  Seller,
14
14
  SellerPart,
15
15
  Subpart,
16
- UserMeta,
16
+ get_organization_model,
17
+ get_user_meta_model
17
18
  )
18
19
 
19
-
20
20
  User = get_user_model()
21
+ UserMeta = get_user_meta_model()
22
+ Organization = get_organization_model()
21
23
 
22
24
  class UserMetaInline(admin.TabularInline):
23
25
  model = UserMeta
26
+ verbose_name = 'BOM User Meta'
24
27
  raw_id_fields = ('organization',)
25
28
  can_delete = False
26
29
 
27
30
 
28
- class UserAdmin(UserAdmin):
29
- inlines = (UserMetaInline,)
30
-
31
-
32
31
  class OrganizationAdmin(admin.ModelAdmin):
33
32
  list_display = ('name',)
34
33
 
@@ -52,6 +51,7 @@ class SellerPartAdmin(admin.ModelAdmin):
52
51
  list_display = (
53
52
  'manufacturer_part',
54
53
  'seller',
54
+ 'seller_part_number',
55
55
  'minimum_order_quantity',
56
56
  'minimum_pack_quantity',
57
57
  'unit_cost',
@@ -141,14 +141,27 @@ class AssemblyAdmin(admin.ModelAdmin):
141
141
  ]
142
142
 
143
143
 
144
- # Try to unregister User model
145
- try:
146
- admin.site.unregister(User)
147
- except admin.sites.NotRegistered:
148
- pass
144
+ if settings.BOM_USER_META_MODEL == 'bom.UserMeta':
145
+ current_user_admin = admin.site._registry.get(User)
146
+
147
+ if current_user_admin:
148
+ user_admin_class = current_user_admin.__class__
149
+ existing_inlines = list(user_admin_class.inlines or [])
150
+ if UserMetaInline not in existing_inlines:
151
+ existing_inlines.append(UserMetaInline)
152
+ user_admin_class.inlines = existing_inlines
153
+ else:
154
+ class BomUserAdmin(UserAdmin):
155
+ inlines = [UserMetaInline]
156
+
157
+
158
+ admin.site.register(User, BomUserAdmin)
159
+
160
+ if settings.BOM_ORGANIZATION_MODEL == 'bom.Organization':
161
+ from .models import Organization
162
+
163
+ admin.site.register(Organization, OrganizationAdmin)
149
164
 
150
- admin.site.register(User, UserAdmin)
151
- admin.site.register(Organization, OrganizationAdmin)
152
165
  admin.site.register(Seller, SellerAdmin)
153
166
  admin.site.register(SellerPart, SellerPartAdmin)
154
167
  admin.site.register(ManufacturerPart, ManufacturerPartAdmin)
@@ -0,0 +1,47 @@
1
+ from typing import Optional
2
+
3
+ from . import constants
4
+ from .models import get_organization_model
5
+
6
+ Organization = get_organization_model()
7
+
8
+
9
+ class OrganizationPermissionBackend:
10
+ """
11
+ Object-level permission backend for django-bom.
12
+
13
+ - Uses Django's has_perm(user, perm, obj) to evaluate permissions tied to an Organization.
14
+ - Superusers are granted all permissions.
15
+ - For `bom.manage_members`: User must be owner or admin within the organization.
16
+ """
17
+
18
+ def authenticate(self, request, **credentials): # pragma: no cover - not used for auth
19
+ return None
20
+
21
+ def has_perm(self, user_obj, perm: str, obj: Optional[object] = None):
22
+ # Only handle our specific object-level permission. Let other backends process others.
23
+ if not user_obj or not user_obj.is_authenticated:
24
+ return False
25
+
26
+ if user_obj.is_superuser:
27
+ return True
28
+
29
+ if perm != 'bom.manage_members':
30
+ return None
31
+
32
+ if obj is None or not isinstance(obj, Organization):
33
+ return False
34
+
35
+ profile = user_obj.bom_profile()
36
+ if not profile or profile.organization_id != obj.id:
37
+ return False
38
+
39
+ if obj.subscription != constants.SUBSCRIPTION_TYPE_PRO:
40
+ return False
41
+
42
+ is_owner = obj.owner_id == user_obj.id
43
+ is_admin = getattr(profile, 'role', None) == constants.ROLE_TYPE_ADMIN
44
+ if not (is_owner or is_admin):
45
+ return False
46
+
47
+ return True
@@ -92,6 +92,8 @@ PACKAGE_TYPES = (
92
92
  ('QFT', 'QFT'),
93
93
  ('PLCC', 'PLCC'),
94
94
  ('VGA', 'VGA'),
95
+ ('BGA', 'BGA'),
96
+ ('CSP', 'CSP'),
95
97
  ('Other', 'Other'),
96
98
  )
97
99
 
@@ -172,6 +172,7 @@ class ManufacturerPartCSVHeaders(CSVHeaders):
172
172
  class SellerPartCSVHeaders(CSVHeaders):
173
173
  all_headers_defns = [
174
174
  CSVHeader('seller', name_options=['part_seller', 'part_seller_name', ]),
175
+ CSVHeader('seller_part_number', name_options=['seller_pn', 'spn', 'pn', 'part_seller_part_number', 'seller_part_number', ]),
175
176
  CSVHeader('unit_cost', name_options=['seller_part_unit_cost', 'unit_cost', 'part_cost', ]),
176
177
  CSVHeader('minimum_order_quantity', name_options=['minimum_order_quantity', 'moq', 'part_moq', ]),
177
178
  CSVHeader('nre_cost', name_options=['part_nre', 'part_nre_cost', 'nre', 'nre_cost', ]),
@@ -1,41 +1,27 @@
1
1
  import codecs
2
2
  import csv
3
3
  import logging
4
- from typing import Type, TypeVar
5
4
 
6
5
  from django import forms
7
6
  from django.contrib.auth.forms import UserCreationForm
8
7
  from django.core.exceptions import ValidationError
9
- from django.core.validators import MaxLengthValidator, MaxValueValidator, MinLengthValidator, MinValueValidator
8
+ from django.core.validators import MaxLengthValidator, MinLengthValidator
10
9
  from django.db import IntegrityError
11
10
  from django.forms.models import model_to_dict
12
11
  from django.utils.translation import gettext_lazy as _
13
-
14
12
  from djmoney.money import Money
15
13
 
16
14
  from .constants import (
17
- CONFIGURATION_TYPES,
18
15
  CURRENT_UNITS,
19
16
  DISTANCE_UNITS,
20
17
  FREQUENCY_UNITS,
21
18
  INTERFACE_TYPES,
22
19
  MEMORY_UNITS,
23
- NUMBER_CLASS_CODE_LEN_DEFAULT,
24
- NUMBER_CLASS_CODE_LEN_MAX,
25
- NUMBER_CLASS_CODE_LEN_MIN,
26
- NUMBER_ITEM_LEN_DEFAULT,
27
- NUMBER_ITEM_LEN_MAX,
28
- NUMBER_ITEM_LEN_MIN,
29
20
  NUMBER_SCHEME_INTELLIGENT,
30
21
  NUMBER_SCHEME_SEMI_INTELLIGENT,
31
- NUMBER_VARIATION_LEN_DEFAULT,
32
- NUMBER_VARIATION_LEN_MAX,
33
- NUMBER_VARIATION_LEN_MIN,
34
22
  PACKAGE_TYPES,
35
23
  POWER_UNITS,
36
24
  ROLE_TYPE_VIEWER,
37
- ROLE_TYPES,
38
- SUBSCRIPTION_TYPES,
39
25
  TEMPERATURE_UNITS,
40
26
  VALUE_UNITS,
41
27
  VOLTAGE_UNITS,
@@ -43,11 +29,9 @@ from .constants import (
43
29
  WEIGHT_UNITS,
44
30
  )
45
31
  from .csv_headers import (
46
- BOMFlatCSVHeaders,
47
32
  BOMIndentedCSVHeaders,
48
33
  CSVHeaderError,
49
34
  PartClassesCSVHeaders,
50
- PartsListCSVHeaders,
51
35
  )
52
36
  from .form_fields import AutocompleteTextInput
53
37
  from .models import (
@@ -55,7 +39,6 @@ from .models import (
55
39
  AssemblySubparts,
56
40
  Manufacturer,
57
41
  ManufacturerPart,
58
- Organization,
59
42
  Part,
60
43
  PartClass,
61
44
  PartRevision,
@@ -63,20 +46,18 @@ from .models import (
63
46
  SellerPart,
64
47
  Subpart,
65
48
  User,
66
- UserMeta,
49
+ get_user_meta_model,
50
+ get_organization_model,
67
51
  )
68
52
  from .utils import (
69
- check_references_for_duplicates,
70
- get_from_dict,
71
53
  listify_string,
72
- prep_for_sorting_nicely,
73
54
  stringify_list,
74
55
  )
75
- from .validators import alphanumeric, decimal, numeric
76
-
56
+ from .validators import alphanumeric
77
57
 
78
58
  logger = logging.getLogger(__name__)
79
-
59
+ Organization = get_organization_model()
60
+ UserMeta = get_user_meta_model()
80
61
 
81
62
  class UserModelChoiceField(forms.ModelChoiceField):
82
63
  def label_from_instance(self, user):
@@ -205,7 +186,8 @@ class OrganizationCreateForm(forms.ModelForm):
205
186
  class OrganizationForm(forms.ModelForm):
206
187
  class Meta:
207
188
  model = Organization
208
- exclude = ['owner', 'subscription', 'subscription_quantity', 'google_drive_parent', 'number_scheme', ]
189
+ # exclude = ['owner', 'subscription', 'subscription_quantity', 'google_drive_parent', 'number_scheme', ]
190
+ fields = ['name', 'number_class_code_len', 'number_item_len', 'number_variation_len', ]
209
191
  labels = {
210
192
  "name": "Organization Name",
211
193
  "number_class_code_len": "Number Class Code Length (C)",
@@ -230,7 +212,7 @@ class OrganizationFormEditSettings(OrganizationForm):
230
212
 
231
213
  class Meta:
232
214
  model = Organization
233
- exclude = ['subscription', 'subscription_quantity', 'google_drive_parent', 'number_scheme', 'number_item_len', 'number_class_code_len', 'number_variation_len', 'owner', ]
215
+ fields = ['name', 'owner', 'currency']
234
216
  labels = {
235
217
  "name": "Organization Name",
236
218
  }
@@ -571,6 +553,7 @@ class PartCSVForm(forms.Form):
571
553
  value = csv_headers.get_val_from_row(part_data, 'value')
572
554
  value_units = csv_headers.get_val_from_row(part_data, 'value_units')
573
555
  seller_name = csv_headers.get_val_from_row(part_data, 'seller')
556
+ seller_part_number = csv_headers.get_val_from_row(part_data, 'seller_part_number')
574
557
  unit_cost = csv_headers.get_val_from_row(part_data, 'unit_cost')
575
558
  nre_cost = csv_headers.get_val_from_row(part_data, 'part_nre_cost')
576
559
  moq = csv_headers.get_val_from_row(part_data, 'moq')
@@ -746,7 +729,7 @@ class PartCSVForm(forms.Form):
746
729
 
747
730
  if seller_name and unit_cost and nre_cost:
748
731
  seller, created = Seller.objects.get_or_create(name__iexact=seller_name, organization=self.organization, defaults={'name': seller_name})
749
- seller_part, created = SellerPart.objects.get_or_create(manufacturer_part=manufacturer_part, seller=seller, unit_cost=unit_cost, nre_cost=nre_cost, minimum_order_quantity=moq, minimum_pack_quantity=mpq)
732
+ seller_part, created = SellerPart.objects.get_or_create(manufacturer_part=manufacturer_part, seller=seller, seller_part_number=seller_part_number, unit_cost=unit_cost, nre_cost=nre_cost, minimum_order_quantity=moq, minimum_pack_quantity=mpq)
750
733
 
751
734
  self.successes.append("Part {0} on row {1} created.".format(part.full_part_number(), row_count))
752
735
  else:
@@ -191,7 +191,8 @@ def create_some_fake_parts(organization):
191
191
 
192
192
  (s1, s2, s3) = create_some_fake_sellers(organization=organization)
193
193
 
194
- create_a_fake_seller_part(s1, mp1, moq=1, mpq=1, unit_cost=0, lead_time_days=None, nre_cost=0,)
194
+ create_a_fake_seller_part(s1, mp1, moq=0, mpq=1, unit_cost=0, lead_time_days=None, nre_cost=0,)
195
+ create_a_fake_seller_part(s1, mp1, moq=1, mpq=2, unit_cost=10, lead_time_days=None, nre_cost=0, )
195
196
  create_a_fake_seller_part(s1, mp1, moq=1, mpq=1, unit_cost=1.2, lead_time_days=20, nre_cost=500)
196
197
  create_a_fake_seller_part(s2, mp1, moq=1000, mpq=5000, unit_cost=0.1005, lead_time_days=7, nre_cost=0)
197
198
  create_a_fake_seller_part(s2, mp2, moq=200, mpq=200, unit_cost=0.5, lead_time_days=47, nre_cost=1)
@@ -0,0 +1,35 @@
1
+ from pathlib import Path
2
+
3
+ BASE_DIR = Path(__file__).resolve().parent.parent
4
+
5
+ # SECURITY WARNING: keep the secret key used in production secret!
6
+ SECRET_KEY = 'supersecretkey'
7
+
8
+ # SECURITY WARNING: don't run with debug turned on in production!
9
+ DEBUG = True
10
+
11
+ ALLOWED_HOSTS = ['*']
12
+
13
+ BOM_CONFIG = {
14
+ 'mouser_api_key': 'secretkey',
15
+ 'admin_dashboard': {
16
+ 'enable_autocomplete': False,
17
+ 'page_size': 50,
18
+ }
19
+ }
20
+
21
+ # google GoogleOAuth
22
+ SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'secretkey'
23
+ SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'secretkey'
24
+
25
+ # Database
26
+ # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
27
+
28
+ DATABASES = {
29
+ 'default': {
30
+ 'ENGINE': 'django.db.backends.sqlite3',
31
+ 'NAME': BASE_DIR / 'db.sqlite3',
32
+ }
33
+ }
34
+
35
+ FIXER_ACCESS_KEY = 'secretkey from fixer.io' # for exchange rate conversions
@@ -0,0 +1,17 @@
1
+ # Generated by Django 3.2.16 on 2023-01-29 21:57
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('bom', '0045_sellerpart_link'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterUniqueTogether(
14
+ name='sellerpart',
15
+ unique_together=set(),
16
+ ),
17
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 3.2.16 on 2023-03-07 17:07
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('bom', '0046_alter_sellerpart_unique_together'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='sellerpart',
15
+ name='seller_part_number',
16
+ field=models.CharField(blank=True, default='', max_length=64, null=True),
17
+ ),
18
+ ]