django-bom 1.262__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (191) hide show
  1. bom/__init__.py +1 -0
  2. bom/admin.py +207 -0
  3. bom/apps.py +8 -0
  4. bom/auth_backends.py +47 -0
  5. bom/base_classes.py +31 -0
  6. bom/constants.py +217 -0
  7. bom/context_processors.py +9 -0
  8. bom/csv_headers.py +252 -0
  9. bom/decorators.py +32 -0
  10. bom/form_fields.py +59 -0
  11. bom/forms.py +1328 -0
  12. bom/helpers.py +367 -0
  13. bom/local_settings.py +35 -0
  14. bom/migrations/0001_initial.py +135 -0
  15. bom/migrations/0002_auto_20180908_2151.py +24 -0
  16. bom/migrations/0003_sellerpart_data_source.py +18 -0
  17. bom/migrations/0004_auto_20180911_0011.py +18 -0
  18. bom/migrations/0005_auto_20181007_1934.py +56 -0
  19. bom/migrations/0006_auto_20181007_1949.py +41 -0
  20. bom/migrations/0007_auto_20181009_0256.py +19 -0
  21. bom/migrations/0008_auto_20181030_0427.py +19 -0
  22. bom/migrations/0009_subpart_reference.py +18 -0
  23. bom/migrations/0010_auto_20181202_0733.py +23 -0
  24. bom/migrations/0011_auto_20181202_2113.py +22 -0
  25. bom/migrations/0012_partchangehistory.py +30 -0
  26. bom/migrations/0013_auto_20190222_1631.py +19 -0
  27. bom/migrations/0014_auto_20190223_2353.py +18 -0
  28. bom/migrations/0015_auto_20190303_1915.py +136 -0
  29. bom/migrations/0016_auto_20190405_2308.py +58 -0
  30. bom/migrations/0017_auto_20190616_1912.py +19 -0
  31. bom/migrations/0018_auto_20190616_2143.py +24 -0
  32. bom/migrations/0019_auto_20190624_1246.py +45 -0
  33. bom/migrations/0020_auto_20190627_0207.py +38 -0
  34. bom/migrations/0021_auto_20190627_0428.py +23 -0
  35. bom/migrations/0022_auto_20190811_2140.py +35 -0
  36. bom/migrations/0023_auto_20191205_2351.py +255 -0
  37. bom/migrations/0024_auto_20191214_1342.py +89 -0
  38. bom/migrations/0025_auto_20191221_1907.py +38 -0
  39. bom/migrations/0026_auto_20191222_2258.py +22 -0
  40. bom/migrations/0027_auto_20191222_2347.py +17 -0
  41. bom/migrations/0028_partrevision_displayable_synopsis.py +74 -0
  42. bom/migrations/0029_auto_20191231_1630.py +23 -0
  43. bom/migrations/0030_auto_20200101_2253.py +22 -0
  44. bom/migrations/0031_auto_20200104_1352.py +38 -0
  45. bom/migrations/0032_auto_20200126_1806.py +27 -0
  46. bom/migrations/0033_auto_20200203_0618.py +29 -0
  47. bom/migrations/0034_auto_20200222_0359.py +30 -0
  48. bom/migrations/0035_auto_20200303_0111.py +34 -0
  49. bom/migrations/0036_auto_20200303_0538.py +17 -0
  50. bom/migrations/0037_auto_20200405_1642.py +44 -0
  51. bom/migrations/0038_auto_20200422_0504.py +19 -0
  52. bom/migrations/0039_auto_20200929_2315.py +41 -0
  53. bom/migrations/0040_alter_organization_currency.py +19 -0
  54. bom/migrations/0041_organization_subscription_quantity.py +18 -0
  55. bom/migrations/0042_auto_20210720_2137.py +23 -0
  56. bom/migrations/0043_auto_20211123_0157.py +24 -0
  57. bom/migrations/0044_auto_20220831_1241.py +23 -0
  58. bom/migrations/0045_sellerpart_link.py +18 -0
  59. bom/migrations/0046_alter_sellerpart_unique_together.py +17 -0
  60. bom/migrations/0047_sellerpart_seller_part_number.py +18 -0
  61. bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py +1017 -0
  62. bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py +99 -0
  63. bom/migrations/0050_alter_organization_options.py +17 -0
  64. bom/migrations/0051_alter_manufacturer_organization_and_more.py +41 -0
  65. bom/migrations/0052_remove_partrevision_attribute_and_more.py +584 -0
  66. bom/migrations/__init__.py +0 -0
  67. bom/models.py +886 -0
  68. bom/part_bom.py +192 -0
  69. bom/settings.py +262 -0
  70. bom/static/bom/css/dashboard.css +17 -0
  71. bom/static/bom/css/jquery.treetable.css +28 -0
  72. bom/static/bom/css/materialize.min.css +13 -0
  73. bom/static/bom/css/part-info.css +15 -0
  74. bom/static/bom/css/style.css +482 -0
  75. bom/static/bom/css/tablesorter-theme.materialize.css +176 -0
  76. bom/static/bom/css/treetable-theme.css +42 -0
  77. bom/static/bom/doc/sample_part_classes.csv +38 -0
  78. bom/static/bom/doc/test_bom.csv +6 -0
  79. bom/static/bom/doc/test_bom_5_intelligent.csv +4 -0
  80. bom/static/bom/doc/test_full_bom.csv +37 -0
  81. bom/static/bom/doc/test_new_parts.csv +5 -0
  82. bom/static/bom/doc/test_new_parts_5_intelligent.csv +5 -0
  83. bom/static/bom/img/_ionicons_svg_md-arrow-dropdown.svg +1 -0
  84. bom/static/bom/img/_ionicons_svg_md-arrow-dropright.svg +1 -0
  85. bom/static/bom/img/favicon.ico +0 -0
  86. bom/static/bom/img/google/web/1x/btn_google_signin_dark_disabled_web.png +0 -0
  87. bom/static/bom/img/google/web/1x/btn_google_signin_dark_focus_web.png +0 -0
  88. bom/static/bom/img/google/web/1x/btn_google_signin_dark_normal_web.png +0 -0
  89. bom/static/bom/img/google/web/1x/btn_google_signin_dark_pressed_web.png +0 -0
  90. bom/static/bom/img/google/web/1x/btn_google_signin_light_disabled_web.png +0 -0
  91. bom/static/bom/img/google/web/1x/btn_google_signin_light_focus_web.png +0 -0
  92. bom/static/bom/img/google/web/1x/btn_google_signin_light_normal_web.png +0 -0
  93. bom/static/bom/img/google/web/1x/btn_google_signin_light_pressed_web.png +0 -0
  94. bom/static/bom/img/google/web/2x/btn_google_signin_dark_disabled_web@2x.png +0 -0
  95. bom/static/bom/img/google/web/2x/btn_google_signin_dark_focus_web@2x.png +0 -0
  96. bom/static/bom/img/google/web/2x/btn_google_signin_dark_normal_web@2x.png +0 -0
  97. bom/static/bom/img/google/web/2x/btn_google_signin_dark_pressed_web@2x.png +0 -0
  98. bom/static/bom/img/google/web/2x/btn_google_signin_light_disabled_web@2x.png +0 -0
  99. bom/static/bom/img/google/web/2x/btn_google_signin_light_focus_web@2x.png +0 -0
  100. bom/static/bom/img/google/web/2x/btn_google_signin_light_normal_web@2x.png +0 -0
  101. bom/static/bom/img/google/web/2x/btn_google_signin_light_pressed_web@2x.png +0 -0
  102. bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.eps +814 -0
  103. bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.svg +24 -0
  104. bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.eps +1866 -0
  105. bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.svg +51 -0
  106. bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.eps +1031 -0
  107. bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.svg +50 -0
  108. bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.eps +1031 -0
  109. bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.svg +50 -0
  110. bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.eps +814 -0
  111. bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.svg +24 -0
  112. bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.eps +1837 -0
  113. bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.svg +44 -0
  114. bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps +1002 -0
  115. bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg +43 -0
  116. bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps +1002 -0
  117. bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg +43 -0
  118. bom/static/bom/img/google_drive_logo.svg +1 -0
  119. bom/static/bom/img/indabom.png +0 -0
  120. bom/static/bom/img/mouser.png +0 -0
  121. bom/static/bom/img/octopart_blue.svg +19 -0
  122. bom/static/bom/js/formset-handler.js +65 -0
  123. bom/static/bom/js/jquery-3.4.1.min.js +2 -0
  124. bom/static/bom/js/jquery.ba-floatingscrollbar.min.js +10 -0
  125. bom/static/bom/js/jquery.treetable.js +629 -0
  126. bom/static/bom/js/materialize.min.js +6 -0
  127. bom/templates/bom/account-delete.html +23 -0
  128. bom/templates/bom/add-manufacturer-part.html +66 -0
  129. bom/templates/bom/add-sellerpart.html +93 -0
  130. bom/templates/bom/base-menu.html +16 -0
  131. bom/templates/bom/base.html +129 -0
  132. bom/templates/bom/bom-action-btn.html +23 -0
  133. bom/templates/bom/bom-action-table.html +57 -0
  134. bom/templates/bom/bom-base-menu.html +6 -0
  135. bom/templates/bom/bom-base.html +24 -0
  136. bom/templates/bom/bom-form-modal.html +36 -0
  137. bom/templates/bom/bom-form.html +30 -0
  138. bom/templates/bom/bom-modal-add-users.html +49 -0
  139. bom/templates/bom/bom-signup.html +12 -0
  140. bom/templates/bom/components/bom-flat.html +131 -0
  141. bom/templates/bom/components/bom-indented.html +237 -0
  142. bom/templates/bom/components/manufacturer-part-list.html +270 -0
  143. bom/templates/bom/components/seller-part-list.html +62 -0
  144. bom/templates/bom/create-part.html +65 -0
  145. bom/templates/bom/dashboard-menu.html +15 -0
  146. bom/templates/bom/dashboard.html +303 -0
  147. bom/templates/bom/edit-manufacturer-part.html +72 -0
  148. bom/templates/bom/edit-part-class.html +120 -0
  149. bom/templates/bom/edit-part.html +67 -0
  150. bom/templates/bom/edit-quantity-of-measure.html +119 -0
  151. bom/templates/bom/edit-user-meta.html +70 -0
  152. bom/templates/bom/help.html +1356 -0
  153. bom/templates/bom/manufacturer-info.html +82 -0
  154. bom/templates/bom/manufacturers.html +97 -0
  155. bom/templates/bom/nothing-to-see.html +15 -0
  156. bom/templates/bom/organization-create.html +135 -0
  157. bom/templates/bom/part-info.html +448 -0
  158. bom/templates/bom/part-revision-display.html +50 -0
  159. bom/templates/bom/part-revision-edit.html +39 -0
  160. bom/templates/bom/part-revision-manage-bom.html +115 -0
  161. bom/templates/bom/part-revision-new.html +57 -0
  162. bom/templates/bom/part-revision-release.html +41 -0
  163. bom/templates/bom/search-help.html +101 -0
  164. bom/templates/bom/seller-info.html +82 -0
  165. bom/templates/bom/sellers.html +97 -0
  166. bom/templates/bom/settings.html +734 -0
  167. bom/templates/bom/signup.html +28 -0
  168. bom/templates/bom/subscription_panel.html +16 -0
  169. bom/templates/bom/table_of_contents.html +47 -0
  170. bom/templates/bom/upload-bom.html +111 -0
  171. bom/templates/bom/upload-parts-help.html +103 -0
  172. bom/templates/bom/upload-parts.html +50 -0
  173. bom/templates/registration/login.html +39 -0
  174. bom/tests.py +1592 -0
  175. bom/third_party_apis/__init__.py +0 -0
  176. bom/third_party_apis/base_api.py +51 -0
  177. bom/third_party_apis/google_drive.py +166 -0
  178. bom/third_party_apis/mouser.py +132 -0
  179. bom/third_party_apis/test_apis.py +24 -0
  180. bom/urls.py +100 -0
  181. bom/utils.py +228 -0
  182. bom/validators.py +23 -0
  183. bom/views/__init__.py +0 -0
  184. bom/views/json_views.py +55 -0
  185. bom/views/views.py +1773 -0
  186. bom/wsgi.py +16 -0
  187. django_bom-1.262.dist-info/METADATA +206 -0
  188. django_bom-1.262.dist-info/RECORD +191 -0
  189. django_bom-1.262.dist-info/WHEEL +5 -0
  190. django_bom-1.262.dist-info/licenses/LICENSE +674 -0
  191. django_bom-1.262.dist-info/top_level.txt +1 -0
@@ -0,0 +1,734 @@
1
+ {% extends 'bom/bom-base.html' %}
2
+
3
+ {% load materializecss %}
4
+ {% load static %}
5
+
6
+ {% block head-title %}{{ title }}{% endblock %}
7
+
8
+ {% block content %}
9
+ <div class="container-app settings-grid row">
10
+ <div class="col s12 m3 l2 settings-nav">
11
+ <div class="collection">
12
+ <a href="#user" class="collection-item primary-color" id="user-nav">
13
+ <i class="material-icons">person</i>User
14
+ </a>
15
+ <a href="#organization" class="collection-item" id="organization-nav">
16
+ <i class="material-icons">business</i>Organization
17
+ </a>
18
+ <a href="#users" class="collection-item" id="users-nav">
19
+ <i class="material-icons">group</i>Organization Users
20
+ </a>
21
+ <a href="#part-classes" class="collection-item" id="part-classes-nav">
22
+ <i class="material-icons">category</i>Part Classes
23
+ </a>
24
+ <a href="#property-definitions" class="collection-item" id="property-definitions-nav">
25
+ <i class="material-icons">list_alt</i>Property Definitions
26
+ </a>
27
+ <a href="#units" class="collection-item" id="units-nav">
28
+ <i class="material-icons">straighten</i>Units & Quantities
29
+ </a>
30
+ <a href="#part-number" class="collection-item" id="part-number-nav">
31
+ <i class="material-icons">format_list_numbered</i>Part Numbers
32
+ </a>
33
+ <a href="#integrations" class="collection-item" id="integrations-nav">
34
+ <i class="material-icons">integration_instructions</i>Integrations
35
+ </a>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="col s12 m9 l10 settings-content">
40
+ <div id="user" class="settings-section">
41
+ <div class="section">
42
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">person</i>User</h4>
43
+ <form name="seller" action="{% url 'bom:settings' tab_anchor='user' %}" method="post">
44
+ {% csrf_token %}
45
+ <div class="row">
46
+ <div class="col s12">
47
+ <p>Your role is: <b>{{ user.bom_profile.get_role_display }}</b></p>
48
+ <p>Your username is: <b>{{ user.username }}</b></p>
49
+ <p>To request a change in role please contact <a
50
+ href="mailto:{{ organization.owner.email }}">{{ organization.owner.email }}</a>
51
+ for
52
+ assistance.</p>
53
+ </div>
54
+ </div>
55
+ <div class="row">
56
+ {{ user_form.first_name|materializecss:'s12 l6' }}
57
+ {{ user_form.last_name|materializecss:'s12 l6' }}
58
+ {{ user_form.email|materializecss:'s12' }}
59
+ </div>
60
+ <div class="row">
61
+ <div class="col s12 right-align">
62
+ <button class="waves-effect waves-light btn btn-primary" type="submit"
63
+ name="submit-edit-user">
64
+ Save
65
+ </button>
66
+ </div>
67
+ </div>
68
+ </form>
69
+ </div>
70
+
71
+ <div class="section" style="padding: 16px; border-radius: 6px;">
72
+ <h4 class="section-title red-text text-darken-2" style="margin-top:0;"><i
73
+ class="material-icons red-text text-darken-2">warning</i>Danger Zone</h4>
74
+ <p>Deleting your account is permanent. If you are the organization owner, your organization will
75
+ also be
76
+ deleted unless you transfer ownership before proceeding.</p>
77
+ <div class="right-align" style="margin-top: 8px;">
78
+ <a href="{% url 'account-delete' %}" class="btn red lighten-1">Delete My Account</a>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <div id="organization" class="settings-section">
84
+ {% if user.bom_profile.role == 'A' %}
85
+ <div class="section">
86
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">business</i>Organization
87
+ </h4>
88
+ <form name="seller" action="{% url 'bom:settings' tab_anchor='organization' %}" method="post"
89
+ enctype="multipart/form-data">
90
+ {% csrf_token %}
91
+ <div class="row">
92
+ {{ organization_form|materializecss:'s12' }}
93
+ </div>
94
+ <div class="row">
95
+ <div class="col s12 right-align">
96
+ <button class="waves-effect waves-light btn btn-primary" type="submit"
97
+ name="submit-edit-organization"
98
+ onclick="return confirm('Are you sure you want to change the organization information?')">
99
+ Save
100
+ </button>
101
+ </div>
102
+ </div>
103
+ </form>
104
+ </div>
105
+
106
+ {% include 'bom/subscription_panel.html' %}
107
+
108
+ <div class="section">
109
+ <h4 class="section-title"><i class="material-icons red-text text-darken-1">exit_to_app</i>Leave
110
+ Your Organization</h4>
111
+ <p>Warning, the only way back in to {{ organization.name }} is if you are invited by an
112
+ organization administrator.</p>
113
+ <form name="leave-organization" action="{% url 'bom:settings' tab_anchor='organization' %}"
114
+ method="post" enctype="multipart/form-data">
115
+ {% csrf_token %}
116
+ <div class="right-align">
117
+ <button class="waves-effect waves-light btn red lighten-1" type="submit"
118
+ name="submit-leave-organization">
119
+ <i class="material-icons left">exit_to_app</i>Leave Organization
120
+ </button>
121
+ </div>
122
+ </form>
123
+ </div>
124
+ {% else %}
125
+ <div class="section">
126
+ <h4 class="section-title">Organization</h4>
127
+ <p>You are a member of <b>{{ organization.name }}</b>.</p>
128
+ <div class="section">
129
+ <h4 class="section-title"><i class="material-icons red-text text-darken-1">exit_to_app</i>Leave
130
+ Your Organization</h4>
131
+ <p>Warning, the only way back in to {{ organization.name }} is if you are invited by an
132
+ organization administrator.</p>
133
+ <form name="leave-organization" action="{% url 'bom:settings' tab_anchor='organization' %}"
134
+ method="post" enctype="multipart/form-data">
135
+ {% csrf_token %}
136
+ <div class="right-align">
137
+ <button class="waves-effect waves-light btn red lighten-1" type="submit"
138
+ name="submit-leave-organization">
139
+ <i class="material-icons left">exit_to_app</i>Leave Organization
140
+ </button>
141
+ </div>
142
+ </form>
143
+ </div>
144
+ </div>
145
+ {% endif %}
146
+ </div>
147
+
148
+ <div id="users" class="settings-section">
149
+ {% if user.bom_profile.role == 'A' %}
150
+ <div class="section">
151
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">group</i>Users</h4>
152
+ <form name="seller" action="{% url 'bom:settings' tab_anchor='organization' %}" method="post"
153
+ enctype="multipart/form-data">
154
+ {% csrf_token %}
155
+ <table>
156
+ <thead>
157
+ <tr>
158
+ <th class="text-normal"><label><input type="checkbox"
159
+ id="user-select-all"><span></span></label>
160
+ </th>
161
+ <th class="text-normal">Role</th>
162
+ <th class="text-normal">User Name</th>
163
+ <th class="text-normal">Full Name</th>
164
+ <th class="text-normal">Email</th>
165
+ <th class="text-normal"></th>
166
+ </tr>
167
+ </thead>
168
+ <tbody>
169
+ {% for org_user in users_in_organization %}
170
+ <tr>
171
+ <td>
172
+ {% if org_user != organization.owner %}
173
+ <label><input type="checkbox" class="filled-in"
174
+ name="remove_user_meta_id_{{ org_user.bom_profile.id }}"><span/></label>{% endif %}
175
+ </td>
176
+ <td class="text-normal">{% if org_user == organization.owner %}Owner{% else %}
177
+ {{ org_user.bom_profile.get_role_display }}{% endif %}</td>
178
+ <td class="text-normal">{{ org_user.username }}</td>
179
+ <td class="text-normal">{{ org_user.first_name }} {{ org_user.last_name }}</td>
180
+ <td class="text-normal"><a
181
+ href="mailto:{{ user.email }}">{{ org_user.email }}</a>
182
+ </td>
183
+ <td class="table-action right-align">
184
+ <a href="{% url 'bom:user-meta-edit' user_meta_id=org_user.bom_profile.id %}"><i
185
+ class="material-icons left">edit</i>Edit</a>
186
+ </td>
187
+ </tr>
188
+ {% empty %}
189
+ <tr>
190
+ <td colspan="5" style="font-style: italic;">There are no additional users in
191
+ this
192
+ organization.
193
+ </td>
194
+ </tr>
195
+ {% endfor %}
196
+ </tbody>
197
+ </table>
198
+ <div class="row" style="padding-top: 16px;">
199
+ <div class="col s6">
200
+ <button class="waves-effect waves-light btn red lighten-1" type="submit"
201
+ name="submit-remove-user"
202
+ onclick="return confirm('Are you sure you want to remove the selected users from {{ organization }}?')">
203
+ Remove Selected
204
+ </button>
205
+ </div>
206
+ <div class="col s6 right-align">
207
+ {% include 'bom/bom-modal-add-users.html' with modal_title='Add User' form=user_add_form action=user_add_form_action name='submit-add-user' %}
208
+ </div>
209
+ </div>
210
+ </form>
211
+ </div>
212
+ {% else %}
213
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
214
+ {% endif %}
215
+ </div>
216
+
217
+ <div id="part-classes" class="settings-section">
218
+ {% if profile.role == 'A' %}
219
+ <div class="section">
220
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">category</i>Part
221
+ Classes</h4>
222
+ <form name="seller" action="{% url 'bom:settings' tab_anchor='indabom' %}" method="post"
223
+ enctype="multipart/form-data">
224
+ {% csrf_token %}
225
+ {% if part_classes.count > 0 %}
226
+ <div class="row" style="margin-bottom: 0;">
227
+ <div class="input-field col s8 l4">
228
+ <select name="part-class-action">
229
+ <option value="" disabled selected>Choose your action</option>
230
+ <option value="submit-part-class-enable-mouser">Enable Mouser</option>
231
+ <option value="submit-part-class-disable-mouser">Disable Mouser</option>
232
+ <option value="submit-part-class-delete">Delete</option>
233
+ </select>
234
+ <label>Action</label>
235
+ </div>
236
+ <div class="col s2 l2">
237
+ <div class="input-field">
238
+ <button class="waves-effect waves-light btn btn-primary" type="submit">Go
239
+ </button>
240
+ </div>
241
+ </div>
242
+ <div class="col s2 l6 right-align">
243
+ <div class="input-field">
244
+ <button class="waves-effect btn-flat btn-icon-round tooltipped"
245
+ type="submit" name="submit-part-class-export"
246
+ data-tooltip="Export part classes."><i class="material-icons">file_download</i>
247
+ </button>
248
+ </div>
249
+ </div>
250
+ </div>
251
+ <table class="striped tight">
252
+ <thead>
253
+ <tr>
254
+ <th class="text-normal"><label><input type="checkbox" id="part-class-select-all"><span></span></label></th>
255
+ <th class="text-normal">Code</th>
256
+ <th class="text-normal">Name</th>
257
+ <th class="text-normal">Description</th>
258
+ <th class="text-normal"><img height="18" style="padding: 4px 4px 0 4px;"
259
+ alt="Mouser" title="Via Mouser.com"
260
+ src="{% static 'bom/img/mouser.png' %}">Mouser
261
+ Sourcing
262
+ </th>
263
+ <th class="text-normal">Options</th>
264
+ </tr>
265
+ </thead>
266
+ <tbody>
267
+ {% for part_class in part_classes %}
268
+ <tr>
269
+ <td>
270
+ <label><input type="checkbox" class="filled-in checkbox-array" name="actions" value="{{ part_class.id }}"><span></span></label>
271
+ </td>
272
+ <td class="text-normal">{{ part_class.code }}</td>
273
+ <td class="text-normal">{{ part_class.name }}</td>
274
+ <td class="text-normal">{{ part_class.comment }}</td>
275
+ <td class="text-normal">{% if part_class.mouser_enabled %}
276
+ <img height="24" style="padding: 4px 4px 0 4px;" alt="Mouser"
277
+ title="Via Mouser.com"
278
+ src="{% static 'bom/img/mouser.png' %}">{% endif %}</td>
279
+ <td>
280
+ <a class="table-action"
281
+ href="{% url 'bom:part-class-edit' part_class_id=part_class.id %}"><i
282
+ class="material-icons left">edit</i>Edit</a>
283
+ </td>
284
+ </tr>
285
+ {% endfor %}
286
+ </tbody>
287
+ </table>
288
+ {% else %}
289
+ <p>No part classes have been defined yet. <a href="{% url 'bom:help' %}#part-numbering"
290
+ target="_blank">What is a part class?</a>
291
+ </p>
292
+ <p>To get started, add your first part class, or upload some here. To help, here is <a
293
+ href="{% static 'bom/doc/sample_part_classes.csv' %}">a sample
294
+ CSV file</a>.</p>
295
+ {% endif %}
296
+ </form>
297
+ <div class="right-align" style="margin-top: 16px;">
298
+ {% include 'bom/bom-form-modal.html' with modal_title='Upload Part Classes' form=part_class_csv_form action=part_class_form_action name='submit-part-class-upload' modal_description='To batch add part classes, upload a csv that contains columns with the headers<b>`name`</b> and <b>`code`</b>. You may optionally specify a description or comment by including a column with the header <b>`description`</b> or <b>`comment`</b>.' %}
299
+ {% include 'bom/bom-form-modal.html' with modal_title='Add Part Class' form=part_class_form action=part_class_form_action name='submit-part-class-create' %}
300
+ </div>
301
+ </div>
302
+ {% else %}
303
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
304
+ {% endif %}
305
+ </div>
306
+
307
+ <div id="property-definitions" class="settings-section">
308
+ {% if profile.role == 'A' %}
309
+ <div class="section">
310
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">list_alt</i>Property
311
+ Definitions</h4>
312
+ <p>Define part properties (e.g. Capacitance, Length, Sheen), their data type, and their
313
+ associated quantity of measure.</p>
314
+ {% if property_definitions.count > 0 %}
315
+ <table class="striped tight">
316
+ <thead>
317
+ <tr>
318
+ <th class="text-normal">Name</th>
319
+ <th class="text-normal">Type</th>
320
+ <th class="text-normal">Required</th>
321
+ <th class="text-normal">Quantity of Measure</th>
322
+ <th class="text-normal">Options</th>
323
+ </tr>
324
+ </thead>
325
+ <tbody>
326
+ {% for prop in property_definitions %}
327
+ <tr>
328
+ <td class="text-normal">{{ prop.name }}</td>
329
+ <td class="text-normal">{{ prop.get_type_display }}</td>
330
+ <td class="text-normal">{% if prop.required %}Yes{% else %}No{% endif %}</td>
331
+ <td class="text-normal">{{ prop.quantity_of_measure.name|default:"-" }}</td>
332
+ <td>
333
+ {% if prop.organization == organization %}
334
+ <a class="table-action"
335
+ href="{% url 'bom:property-definition-edit' property_definition_id=prop.id %}"><i
336
+ class="material-icons left">edit</i>Edit</a>
337
+ <a class="table-action red-text"
338
+ href="{% url 'bom:property-definition-delete' property_definition_id=prop.id %}"
339
+ onclick="return confirm('Are you sure you want to delete this property definition?')"><i
340
+ class="material-icons left">delete</i></a>
341
+ {% else %}
342
+ <span class="table-action tooltipped grey-text d-flex-inline align-center"
343
+ data-position="top"
344
+ data-tooltip="System Default: Cannot be modified">
345
+ <i class="material-icons left" style="font-size: 1.2rem;">lock</i> System
346
+ </span>
347
+ {% endif %}
348
+ </td>
349
+ </tr>
350
+ {% endfor %}
351
+ </tbody>
352
+ </table>
353
+ {% else %}
354
+ <p>No global property definitions defined.</p>
355
+ {% endif %}
356
+ <div class="right-align" style="margin-top: 16px;">
357
+ <a href="{% url 'bom:property-definition-add' %}"
358
+ class="waves-effect waves-light btn btn-primary">
359
+ <i class="material-icons left">add</i>Add Property Definition
360
+ </a>
361
+ </div>
362
+ </div>
363
+ {% else %}
364
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
365
+ {% endif %}
366
+ </div>
367
+
368
+ <div id="units" class="settings-section">
369
+ {% if profile.role == 'A' %}
370
+ <div class="section">
371
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">straighten</i>Units
372
+ & Quantities</h4>
373
+ <p>Define quantities of measure (e.g. Length, Resistance) and their associated units (e.g. m,
374
+ mm, Ohm, kOhm).</p>
375
+ {% if quantities_of_measure.count > 0 %}
376
+ <table class="striped tight">
377
+ <thead>
378
+ <tr>
379
+ <th class="text-normal">Quantity</th>
380
+ <th class="text-normal">Units</th>
381
+ <th class="text-normal">Options</th>
382
+ </tr>
383
+ </thead>
384
+ <tbody>
385
+ {% for qom in quantities_of_measure %}
386
+ <tr>
387
+ <td class="text-normal">{{ qom.name }}</td>
388
+ <td class="text-normal">
389
+ {% for unit in qom.units.all|slice:":3" %}
390
+ {{ unit.symbol }}{% if not forloop.last %}, {% endif %}
391
+ {% endfor %}
392
+
393
+ {% if qom.units.count > 3 %}
394
+ <span class="grey-text text-darken-1 tooltipped"
395
+ data-tooltip="
396
+
397
+
398
+
399
+
400
+
401
+
402
+
403
+
404
+
405
+
406
+
407
+
408
+
409
+
410
+
411
+
412
+
413
+
414
+
415
+
416
+
417
+
418
+
419
+
420
+
421
+ {% for unit in qom.units.all %}{{ unit.name }}{% if not forloop.last %}, {% endif %}{% endfor %}">
422
+ (+{{ qom.units.count|add:"-3" }} more)
423
+ </span>
424
+ {% endif %}
425
+ </td>
426
+ <td>
427
+ {% if qom.organization == organization %}
428
+ <a class="table-action"
429
+ href="{% url 'bom:quantity-of-measure-edit' quantity_of_measure_id=qom.id %}"><i
430
+ class="material-icons left">edit</i>Edit</a>
431
+ <a class="table-action red-text"
432
+ href="{% url 'bom:quantity-of-measure-delete' quantity_of_measure_id=qom.id %}"
433
+ onclick="return confirm('Are you sure you want to delete this quantity of measure and all its units?')"><i
434
+ class="material-icons left">delete</i></a>
435
+ {% else %}
436
+ <span class="table-action tooltipped grey-text d-flex-inline align-center"
437
+ data-position="top"
438
+ data-tooltip="System Default: Cannot be modified">
439
+ <i class="material-icons left" style="font-size: 1.2rem;">lock</i> System
440
+ </span>
441
+ {% endif %}
442
+ </td>
443
+ </tr>
444
+ {% endfor %}
445
+ </tbody>
446
+ </table>
447
+ {% else %}
448
+ <p>No quantities of measure defined.</p>
449
+ {% endif %}
450
+ <div class="right-align" style="margin-top: 16px;">
451
+ <a href="{% url 'bom:quantity-of-measure-add' %}"
452
+ class="waves-effect waves-light btn btn-primary">
453
+ <i class="material-icons left">add</i>Add Quantity of Measure
454
+ </a>
455
+ </div>
456
+ </div>
457
+ {% else %}
458
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
459
+ {% endif %}
460
+ </div>
461
+
462
+ <div id="part-number" class="settings-section">
463
+ {% if profile.role == 'A' %}
464
+ <div class="section">
465
+ <h4 class="section-title" id="indabom-part-number-header"><i
466
+ class="material-icons teal-text text-darken-1">format_list_numbered</i>Part Number</h4>
467
+ {% if organization.number_scheme == 'S' %}
468
+ <form name="seller" action="{% url 'bom:settings' tab_anchor='indabom' %}" method="post"
469
+ enctype="multipart/form-data">
470
+ {% csrf_token %}
471
+ <p>You may only increase the number of digits for each component of the part number: the
472
+ part class code (C), part item number (N), and the part variation (V).</p>
473
+ <p>Your organization's current configuration is
474
+ <b>{{ organization.number_cs }}-{{ organization.number_ns }}
475
+ {% if organization.number_vs %}-{{ organization.number_vs }}{% endif %}</b></p>
476
+ <div class="row">
477
+ {{ organization_number_len_form|materializecss:'s4 l2' }}
478
+ <div class="col s12 l6 input-field right-align">
479
+ <button class="waves-effect waves-light btn btn-primary" type="submit"
480
+ name="submit-number-item-len"
481
+ onclick="return confirm('Are you sure you want to change the number of digits?')">
482
+ Save
483
+ </button>
484
+ </div>
485
+ </div>
486
+ </form>
487
+ <div class="divider"></div>
488
+ {% endif %}
489
+
490
+ <div class="section">
491
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">swap_horiz</i>Change
492
+ Organization Number Scheme</h4>
493
+ <p>Your organization's number scheme is currently:
494
+ <b>{{ organization.get_number_scheme_display }}</b></p>
495
+ <ul class="browser-default">
496
+ {% if organization.number_scheme == 'S' or organization_parts_count == 0 %}
497
+ <li style="padding-bottom: 16px;"><b>Semi-intelligent</b> e.g. CCC-NNNN-YY<br>Consists
498
+ of 3
499
+ components: a 3-digit part class, a N-digit part number, and a 2-digit
500
+ variation.
501
+ IndaBOM part numbers are designed to be simple to assign and simple to
502
+ subsequently
503
+ write, type, or speak. You define the part classes in your organization, and how
504
+ long
505
+ your N-digit part number is below.
506
+ </li>
507
+ {% endif %}
508
+ {% if organization.number_scheme == 'I' or organization_parts_count == 0 %}
509
+ <li><b>Intelligent</b> You control your numbers.<br>Intelligent part numbering on
510
+ IndaBOM
511
+ allows the user to assign any part number to a part. The part number contains
512
+ descriptive details embedded within that provides noteworthy information about
513
+ the part.
514
+ For example, a capacitor may be named C0402X5R33PF to indicate that it is a
515
+ capacitor of
516
+ size "0402", using a X5R dialectric, and is 33pF.
517
+ </li>
518
+ {% endif %}
519
+ </ul>
520
+ <p style="font-size: 15px;">You can read more about the options <a
521
+ href="{% url 'bom:help' %}#part-numbering" target="_blank">here</a>.</p>
522
+ {% if organization_parts_count > 0 %}
523
+ <p><b>You've already created {{ organization_parts_count }}
524
+ part{{ organization_parts_count|pluralize }}.</b> Since changing your organization
525
+ number
526
+ scheme requires changing your parts numbers, please manually delete your parts then
527
+ come
528
+ back here to change your organization number scheme. Alternatively we can help
529
+ delete your
530
+ parts if you reach out to info@indabom.com.</p>
531
+ {% else %}
532
+ <form name="number-scheme" action="{% url 'bom:settings' tab_anchor='indabom' %}"
533
+ method="post">
534
+ {% csrf_token %}
535
+ <button type="submit" name="change-number-scheme"
536
+ class="waves-effect waves-light btn red lighten-1">Change Scheme to
537
+ {% if organization.number_scheme == 'S' %}Intelligent{% else %}
538
+ Semi-Intelligent{% endif %}</button>
539
+ </form>
540
+ {% endif %}
541
+ </div>
542
+ </div>
543
+ {% else %}
544
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
545
+ {% endif %}
546
+ </div>
547
+
548
+ <div id="integrations" class="settings-section">
549
+ {% if user.bom_profile.role == 'A' %}
550
+ <div class="section">
551
+ <h4 class="section-title"><i class="material-icons teal-text text-darken-1">integration_instructions</i>Integrations
552
+ </h4>
553
+ <div class="section">
554
+ <h5 class="section-title"><img style="height: 1em; margin-right: 4px;"
555
+ title="Via Google Drive"
556
+ src="{% static 'bom/img/google_drive_logo.svg' %}">Part File
557
+ Storage with Google Drive</h5>
558
+ {% if not google_authentication %}
559
+ <p>Connect your Google account to access Google Drive features.
560
+ {% if not organization.google_drive_parent %}Organization owners can enable file
561
+ storage
562
+ using Google Drive. {% if organization.owner == user %}Since you are the owner,
563
+ you are
564
+ able to enable file storage!{% else %}Contact your organization owner to enable.
565
+ {% endif %}{% endif %}</p>
566
+ <p>When you connect, we will create a folder called <b>IndaBOM Part Files</b> in your
567
+ root of
568
+ Google Drive (and it can be moved anywhere in your drive). To add files to a part,
569
+ navigate
570
+ to the part in IndaBOM, and on the part's <b>Specifications</b> tab, click the <img
571
+ title="Via Google Drive" style="width: 16px; vertical-align: middle;"
572
+ src="{% static 'bom/img/google_drive_logo.svg' %}"> Google Drive link. This
573
+ will
574
+ create a folder for your part in your root IndaBOM directory, or take you there if
575
+ it
576
+ already exists.</p>
577
+ <p>You'll be able to access the files directly through Google Drive, and through
578
+ IndaBOM.</p>
579
+ {% else %}
580
+ <p>You're connected with Google and can access Google Drive features.</p>
581
+ {% endif %}
582
+ <div>
583
+ {% if google_authentication %}
584
+ <p>Logged in to Google as: {{ google_authentication.uid }}</p>
585
+ <div class="right-align">
586
+ <form action="{% url 'social:disconnect' 'google-oauth2' %}" method="post">
587
+ {% csrf_token %}
588
+ <button class="waves-effect waves-light btn btn-primary" type="submit">
589
+ Disconnect
590
+ </button>
591
+ </form>
592
+ </div>
593
+ {% else %}
594
+ <p>To get started, sign in with Google:</p>
595
+ <div class="right-align">
596
+ <a href="{% url "social:begin" "google-oauth2" %}">
597
+ <img title="Google sign-in."
598
+ src="{% static 'bom/img/google/web/1x/btn_google_signin_dark_normal_web.png' %}">
599
+ </a>
600
+ </div>
601
+ {% endif %}
602
+ </div>
603
+ </div>
604
+ <div class="section">
605
+ <h5 class="section-title"><img style="height: 1em; margin-right: 4px;"
606
+ title="Sourcing via Mouser.com"
607
+ src="{% static 'bom/img/mouser.png' %}">Automagic Sourcing
608
+ via Mouser</h5>
609
+ <p>Currently under construction.</p>
610
+ </div>
611
+ </div>
612
+ {% else %}
613
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
614
+ {% endif %}
615
+ </div>
616
+ </div>
617
+ </div>
618
+ {% endblock %}
619
+
620
+ {% block bom-script %}
621
+ <style>
622
+ .settings-section {
623
+ display: none;
624
+ }
625
+
626
+ .settings-section.active {
627
+ display: block;
628
+ }
629
+ </style>
630
+
631
+ <!-- Handle navigation -->
632
+ <script type='text/javascript'>
633
+ $(document).ready(function () {
634
+ function showSection(sectionId) {
635
+ if (!sectionId) sectionId = '#user';
636
+ if (!sectionId.startsWith('#')) sectionId = '#' + sectionId;
637
+
638
+ $('.settings-section').removeClass('active');
639
+ $(sectionId).addClass('active');
640
+
641
+ $('.settings-nav .collection-item').removeClass('active');
642
+ $('.settings-nav .collection-item[href="' + sectionId + '"]').addClass('active');
643
+
644
+ // Update URL without jumping
645
+ if (window.location.hash !== sectionId) {
646
+ history.pushState(null, null, sectionId);
647
+ }
648
+ }
649
+
650
+ $('.settings-nav .collection-item').on('click', function (e) {
651
+ e.preventDefault();
652
+ var sectionId = $(this).attr('href');
653
+ showSection(sectionId);
654
+ });
655
+
656
+ // Initial section based on hash or tab_anchor
657
+ var initialSection = window.location.hash;
658
+ {% if tab_anchor %}
659
+ if (!initialSection) {
660
+ {% if tab_anchor == 'indabom' %}
661
+ initialSection = '#part-classes';
662
+ {% elif tab_anchor == 'organization' %}
663
+ initialSection = '#organization';
664
+ {% elif tab_anchor == 'user' %}
665
+ initialSection = '#user';
666
+ {% else %}
667
+ initialSection = '#{{ tab_anchor }}';
668
+ {% endif %}
669
+ }
670
+ {% endif %}
671
+
672
+ showSection(initialSection);
673
+
674
+ // Handle back/forward buttons
675
+ window.onpopstate = function () {
676
+ showSection(window.location.hash);
677
+ };
678
+ });
679
+ </script>
680
+
681
+ <script type='text/javascript'>
682
+ function user_checkbox_clear_all() {
683
+ $("input[type='checkbox']:checked").prop("checked", false)
684
+ }
685
+ </script>
686
+
687
+ <script type='text/javascript'>
688
+ $(document).ready(function () {
689
+ const selectAllId = '#part-class-select-all';
690
+ $(selectAllId).change(function () {
691
+ var table = $(selectAllId).closest('table');
692
+ if ($(selectAllId).is(":checked")) {
693
+ $("input[type='checkbox']:not(:checked)", table).prop("checked", true)
694
+ } else {
695
+ $("input[type='checkbox']:checked", table).prop("checked", false)
696
+ }
697
+ });
698
+ });
699
+
700
+ $(document).ready(function () {
701
+ const selectAllId = '#user-select-all';
702
+ $(selectAllId).change(function () {
703
+ var table = $(selectAllId).closest('table');
704
+ if ($(selectAllId).is(":checked")) {
705
+ $("input[type='checkbox']:not(:checked)", table).prop("checked", true)
706
+ } else {
707
+ $("input[type='checkbox']:checked", table).prop("checked", false)
708
+ }
709
+ });
710
+ });
711
+ </script>
712
+
713
+ <script>
714
+ $(document).ready(function () {
715
+ let $checkbox = $('.checkbox-array');
716
+ let lastChecked = null;
717
+
718
+ $checkbox.click(function (e) {
719
+ if (!lastChecked) {
720
+ lastChecked = this;
721
+ return;
722
+ }
723
+
724
+ if (e.shiftKey) {
725
+ const start = $checkbox.index(this);
726
+ const end = $checkbox.index(lastChecked);
727
+ $checkbox.slice(Math.min(start, end), Math.max(start, end) + 1).prop('checked', lastChecked.checked);
728
+ }
729
+ lastChecked = this;
730
+ });
731
+ });
732
+ </script>
733
+
734
+ {% endblock bom-script %}