django-bom 1.237__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.
Files changed (183) hide show
  1. bom/__init__.py +1 -0
  2. bom/admin.py +161 -0
  3. bom/apps.py +8 -0
  4. bom/base_classes.py +31 -0
  5. bom/constants.py +210 -0
  6. bom/context_processors.py +9 -0
  7. bom/csv_headers.py +274 -0
  8. bom/decorators.py +32 -0
  9. bom/form_fields.py +59 -0
  10. bom/forms.py +1400 -0
  11. bom/helpers.py +292 -0
  12. bom/local_settings.py +35 -0
  13. bom/migrations/0001_initial.py +135 -0
  14. bom/migrations/0002_auto_20180908_2151.py +24 -0
  15. bom/migrations/0003_sellerpart_data_source.py +18 -0
  16. bom/migrations/0004_auto_20180911_0011.py +18 -0
  17. bom/migrations/0005_auto_20181007_1934.py +56 -0
  18. bom/migrations/0006_auto_20181007_1949.py +41 -0
  19. bom/migrations/0007_auto_20181009_0256.py +19 -0
  20. bom/migrations/0008_auto_20181030_0427.py +19 -0
  21. bom/migrations/0009_subpart_reference.py +18 -0
  22. bom/migrations/0010_auto_20181202_0733.py +23 -0
  23. bom/migrations/0011_auto_20181202_2113.py +22 -0
  24. bom/migrations/0012_partchangehistory.py +30 -0
  25. bom/migrations/0013_auto_20190222_1631.py +19 -0
  26. bom/migrations/0014_auto_20190223_2353.py +18 -0
  27. bom/migrations/0015_auto_20190303_1915.py +136 -0
  28. bom/migrations/0016_auto_20190405_2308.py +58 -0
  29. bom/migrations/0017_auto_20190616_1912.py +19 -0
  30. bom/migrations/0018_auto_20190616_2143.py +24 -0
  31. bom/migrations/0019_auto_20190624_1246.py +45 -0
  32. bom/migrations/0020_auto_20190627_0207.py +38 -0
  33. bom/migrations/0021_auto_20190627_0428.py +23 -0
  34. bom/migrations/0022_auto_20190811_2140.py +35 -0
  35. bom/migrations/0023_auto_20191205_2351.py +255 -0
  36. bom/migrations/0024_auto_20191214_1342.py +89 -0
  37. bom/migrations/0025_auto_20191221_1907.py +38 -0
  38. bom/migrations/0026_auto_20191222_2258.py +22 -0
  39. bom/migrations/0027_auto_20191222_2347.py +17 -0
  40. bom/migrations/0028_partrevision_displayable_synopsis.py +74 -0
  41. bom/migrations/0029_auto_20191231_1630.py +23 -0
  42. bom/migrations/0030_auto_20200101_2253.py +22 -0
  43. bom/migrations/0031_auto_20200104_1352.py +38 -0
  44. bom/migrations/0032_auto_20200126_1806.py +27 -0
  45. bom/migrations/0033_auto_20200203_0618.py +29 -0
  46. bom/migrations/0034_auto_20200222_0359.py +30 -0
  47. bom/migrations/0035_auto_20200303_0111.py +34 -0
  48. bom/migrations/0036_auto_20200303_0538.py +17 -0
  49. bom/migrations/0037_auto_20200405_1642.py +44 -0
  50. bom/migrations/0038_auto_20200422_0504.py +19 -0
  51. bom/migrations/0039_auto_20200929_2315.py +41 -0
  52. bom/migrations/0040_alter_organization_currency.py +19 -0
  53. bom/migrations/0041_organization_subscription_quantity.py +18 -0
  54. bom/migrations/0042_auto_20210720_2137.py +23 -0
  55. bom/migrations/0043_auto_20211123_0157.py +24 -0
  56. bom/migrations/0044_auto_20220831_1241.py +23 -0
  57. bom/migrations/0045_sellerpart_link.py +18 -0
  58. bom/migrations/0046_alter_sellerpart_unique_together.py +17 -0
  59. bom/migrations/0047_sellerpart_seller_part_number.py +18 -0
  60. bom/migrations/0048_rename_part_organization_number_class_bom_part_organiz_b333d6_idx_and_more.py +1017 -0
  61. bom/migrations/0049_alter_assembly_id_alter_assemblysubparts_id_and_more.py +99 -0
  62. bom/migrations/__init__.py +0 -0
  63. bom/models.py +757 -0
  64. bom/part_bom.py +192 -0
  65. bom/settings.py +264 -0
  66. bom/static/bom/css/dashboard.css +17 -0
  67. bom/static/bom/css/jquery.treetable.css +28 -0
  68. bom/static/bom/css/materialize.min.css +13 -0
  69. bom/static/bom/css/part-info.css +15 -0
  70. bom/static/bom/css/style.css +319 -0
  71. bom/static/bom/css/tablesorter-theme.materialize.css +176 -0
  72. bom/static/bom/css/treetable-theme.css +42 -0
  73. bom/static/bom/doc/sample_part_classes.csv +38 -0
  74. bom/static/bom/doc/test_bom.csv +6 -0
  75. bom/static/bom/doc/test_bom_5_intelligent.csv +4 -0
  76. bom/static/bom/doc/test_full_bom.csv +37 -0
  77. bom/static/bom/doc/test_new_parts.csv +5 -0
  78. bom/static/bom/doc/test_new_parts_5_intelligent.csv +5 -0
  79. bom/static/bom/img/_ionicons_svg_md-arrow-dropdown.svg +1 -0
  80. bom/static/bom/img/_ionicons_svg_md-arrow-dropright.svg +1 -0
  81. bom/static/bom/img/favicon.ico +0 -0
  82. bom/static/bom/img/google/web/1x/btn_google_signin_dark_disabled_web.png +0 -0
  83. bom/static/bom/img/google/web/1x/btn_google_signin_dark_focus_web.png +0 -0
  84. bom/static/bom/img/google/web/1x/btn_google_signin_dark_normal_web.png +0 -0
  85. bom/static/bom/img/google/web/1x/btn_google_signin_dark_pressed_web.png +0 -0
  86. bom/static/bom/img/google/web/1x/btn_google_signin_light_disabled_web.png +0 -0
  87. bom/static/bom/img/google/web/1x/btn_google_signin_light_focus_web.png +0 -0
  88. bom/static/bom/img/google/web/1x/btn_google_signin_light_normal_web.png +0 -0
  89. bom/static/bom/img/google/web/1x/btn_google_signin_light_pressed_web.png +0 -0
  90. bom/static/bom/img/google/web/2x/btn_google_signin_dark_disabled_web@2x.png +0 -0
  91. bom/static/bom/img/google/web/2x/btn_google_signin_dark_focus_web@2x.png +0 -0
  92. bom/static/bom/img/google/web/2x/btn_google_signin_dark_normal_web@2x.png +0 -0
  93. bom/static/bom/img/google/web/2x/btn_google_signin_dark_pressed_web@2x.png +0 -0
  94. bom/static/bom/img/google/web/2x/btn_google_signin_light_disabled_web@2x.png +0 -0
  95. bom/static/bom/img/google/web/2x/btn_google_signin_light_focus_web@2x.png +0 -0
  96. bom/static/bom/img/google/web/2x/btn_google_signin_light_normal_web@2x.png +0 -0
  97. bom/static/bom/img/google/web/2x/btn_google_signin_light_pressed_web@2x.png +0 -0
  98. bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.eps +814 -0
  99. bom/static/bom/img/google/web/vector/btn_google_dark_disabled_ios.svg +24 -0
  100. bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.eps +1866 -0
  101. bom/static/bom/img/google/web/vector/btn_google_dark_focus_ios.svg +51 -0
  102. bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.eps +1031 -0
  103. bom/static/bom/img/google/web/vector/btn_google_dark_normal_ios.svg +50 -0
  104. bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.eps +1031 -0
  105. bom/static/bom/img/google/web/vector/btn_google_dark_pressed_ios.svg +50 -0
  106. bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.eps +814 -0
  107. bom/static/bom/img/google/web/vector/btn_google_light_disabled_ios.svg +24 -0
  108. bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.eps +1837 -0
  109. bom/static/bom/img/google/web/vector/btn_google_light_focus_ios.svg +44 -0
  110. bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.eps +1002 -0
  111. bom/static/bom/img/google/web/vector/btn_google_light_normal_ios.svg +43 -0
  112. bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.eps +1002 -0
  113. bom/static/bom/img/google/web/vector/btn_google_light_pressed_ios.svg +43 -0
  114. bom/static/bom/img/google_drive_logo.svg +1 -0
  115. bom/static/bom/img/indabom.png +0 -0
  116. bom/static/bom/img/mouser.png +0 -0
  117. bom/static/bom/img/octopart_blue.svg +19 -0
  118. bom/static/bom/js/jquery-3.4.1.min.js +2 -0
  119. bom/static/bom/js/jquery.ba-floatingscrollbar.min.js +10 -0
  120. bom/static/bom/js/jquery.treetable.js +629 -0
  121. bom/static/bom/js/materialize.min.js +6 -0
  122. bom/templates/bom/account-delete.html +23 -0
  123. bom/templates/bom/add-manufacturer-part.html +66 -0
  124. bom/templates/bom/add-sellerpart.html +93 -0
  125. bom/templates/bom/base-menu.html +16 -0
  126. bom/templates/bom/base.html +129 -0
  127. bom/templates/bom/bom-action-btn.html +23 -0
  128. bom/templates/bom/bom-action-table.html +57 -0
  129. bom/templates/bom/bom-base-menu.html +6 -0
  130. bom/templates/bom/bom-base.html +24 -0
  131. bom/templates/bom/bom-form-modal.html +36 -0
  132. bom/templates/bom/bom-form.html +30 -0
  133. bom/templates/bom/bom-signup.html +12 -0
  134. bom/templates/bom/components/bom-flat.html +131 -0
  135. bom/templates/bom/components/bom-indented.html +237 -0
  136. bom/templates/bom/components/manufacturer-part-list.html +270 -0
  137. bom/templates/bom/components/seller-part-list.html +62 -0
  138. bom/templates/bom/create-part.html +65 -0
  139. bom/templates/bom/dashboard-menu.html +15 -0
  140. bom/templates/bom/dashboard.html +303 -0
  141. bom/templates/bom/edit-manufacturer-part.html +72 -0
  142. bom/templates/bom/edit-part-class.html +33 -0
  143. bom/templates/bom/edit-part.html +67 -0
  144. bom/templates/bom/edit-user-meta.html +38 -0
  145. bom/templates/bom/help.html +1356 -0
  146. bom/templates/bom/manufacturer-info.html +82 -0
  147. bom/templates/bom/manufacturers.html +97 -0
  148. bom/templates/bom/nothing-to-see.html +15 -0
  149. bom/templates/bom/organization-create.html +132 -0
  150. bom/templates/bom/part-info.html +439 -0
  151. bom/templates/bom/part-revision-display.html +184 -0
  152. bom/templates/bom/part-revision-edit.html +39 -0
  153. bom/templates/bom/part-revision-manage-bom.html +115 -0
  154. bom/templates/bom/part-revision-new.html +57 -0
  155. bom/templates/bom/part-revision-release.html +41 -0
  156. bom/templates/bom/search-help.html +101 -0
  157. bom/templates/bom/seller-info.html +82 -0
  158. bom/templates/bom/sellers.html +97 -0
  159. bom/templates/bom/settings.html +408 -0
  160. bom/templates/bom/signup.html +28 -0
  161. bom/templates/bom/table_of_contents.html +47 -0
  162. bom/templates/bom/upload-bom.html +111 -0
  163. bom/templates/bom/upload-parts-help.html +103 -0
  164. bom/templates/bom/upload-parts.html +50 -0
  165. bom/templates/registration/login.html +39 -0
  166. bom/tests.py +1506 -0
  167. bom/third_party_apis/__init__.py +0 -0
  168. bom/third_party_apis/base_api.py +51 -0
  169. bom/third_party_apis/google_drive.py +166 -0
  170. bom/third_party_apis/mouser.py +132 -0
  171. bom/third_party_apis/test_apis.py +24 -0
  172. bom/urls.py +94 -0
  173. bom/utils.py +228 -0
  174. bom/validators.py +23 -0
  175. bom/views/__init__.py +0 -0
  176. bom/views/json_views.py +55 -0
  177. bom/views/views.py +1620 -0
  178. bom/wsgi.py +16 -0
  179. django_bom-1.237.dist-info/METADATA +206 -0
  180. django_bom-1.237.dist-info/RECORD +183 -0
  181. django_bom-1.237.dist-info/WHEEL +5 -0
  182. django_bom-1.237.dist-info/licenses/LICENSE +674 -0
  183. django_bom-1.237.dist-info/top_level.txt +1 -0
@@ -0,0 +1,408 @@
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="row container-app">
10
+ <div class="col s12">
11
+ <ul id="tabs" class="tabs tabs-fixed-width">
12
+ <li class="tab"><a id="user-tab" href="#user">User</a></li>
13
+ <li class="tab"><a id="indabom-tab" href="#indabom">IndaBOM</a></li>
14
+ <li class="tab"><a id="organization-tab" href="#organization">Organization</a></li>
15
+ </ul>
16
+ </div>
17
+
18
+ <div id="user" class="col s12">
19
+ <h3>User Info</h3>
20
+ <form name="seller" action="{% url 'bom:settings' tab_anchor=USER_TAB %}" method="post" class="col s12">
21
+ {% csrf_token %}
22
+ <div class="row">
23
+ <div class="col s12">
24
+ <p>Your role is: <b>{{ user.bom_profile.get_role_display }}</b></p>
25
+ <p>Your username is: <b>{{ user.username }}</b></p>
26
+ <p>To request a change in role please contact <a href="mailto:{{ organization.owner.email }}">{{ organization.owner.email }}</a> for assistance.</p>
27
+ </div>
28
+ </div>
29
+ <div class="row">
30
+ {{ user_form.first_name|materializecss:'s12 m4' }}
31
+ {{ user_form.last_name|materializecss:'s12 m4' }}
32
+ {{ user_form.email|materializecss:'s12 m4' }}
33
+ </div>
34
+ <div class="row">
35
+ <div class="col s12 right-align">
36
+ <button class="waves-effect waves-light btn btn-primary" type="submit" name="submit-edit-user">
37
+ Save
38
+ </button>
39
+ </div>
40
+ </div>
41
+ </form>
42
+
43
+ <div class="row">
44
+ <div class="col s12">
45
+ <div class="card-panel">
46
+ <h5 class="text-error">Danger Zone</h5>
47
+ <p>Deleting your account is permanent. If you are the organization owner, your organization will also be deleted unless you transfer ownership before proceeding.</p>
48
+ <a href="{% url 'account-delete' %}" class="btn btn-warning">Delete My Account</a>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ <div id="indabom" class="col s12">
55
+ {% if profile.role == 'A' %}
56
+ {% if organization.number_scheme == 'S' %}
57
+ {% if part_classes.count > 0 %}
58
+ <h3>Edit Part Classes</h3>
59
+ <a href="{% url 'bom:help' %}#part-numbering" target="_blank">What is a part class?</a>
60
+ <form name="seller" action="{% url 'bom:settings' tab_anchor=INDABOM_TAB %}" method="post" enctype="multipart/form-data">
61
+ {% csrf_token %}
62
+ {% if part_classes.count > 0 %}
63
+ <div class="row" style="margin-bottom: 0;">
64
+ <div class="input-field col s8 m4">
65
+ <select name="part-class-action">
66
+ <option value="" disabled selected>Choose your action</option>
67
+ <option value="submit-part-class-enable-mouser">Enable Mouser</option>
68
+ <option value="submit-part-class-disable-mouser">Disable Mouser</option>
69
+ <option value="submit-part-class-delete">Delete</option>
70
+ </select>
71
+ <label>Action</label>
72
+ </div>
73
+ <div class="col s2 m2">
74
+ <div class="input-field">
75
+ <button class="waves-effect waves-light btn btn-primary" type="submit">Go
76
+ </button>
77
+ </div>
78
+ </div>
79
+ <div class="col s2 m6 right-align">
80
+ <div class="input-field">
81
+ <button class="waves-effect btn-flat btn-icon-round tooltipped" type="submit" name="submit-part-class-export" data-tooltip="Export part classes."><i
82
+ class="material-icons">file_download</i></button>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <table class="striped tight">
87
+ <thead>
88
+ <tr>
89
+ <th class="text-normal"><label><input type="checkbox" id="part-class-select-all"><span></span></label></th>
90
+ <th class="text-normal">Code</th>
91
+ <th class="text-normal">Name</th>
92
+ <th class="text-normal">Description</th>
93
+ <th class="text-normal"><img height="18" style="padding: 4px 4px 0 4px;" alt="Mouser" title="Via Mouser.com" src="{% static 'bom/img/mouser.png' %}">Mouser
94
+ Sourcing
95
+ </th>
96
+ <th class="text-normal">Options</th>
97
+ </tr>
98
+ </thead>
99
+ <tbody>
100
+ {% for part_class in part_classes %}
101
+ <tr>
102
+ <td>
103
+ <label><input type="checkbox" class="filled-in checkbox-array" name="actions" value="{{ part_class.id }}"><span></span></label>
104
+ </td>
105
+ <td class="text-normal">{{ part_class.code }}</td>
106
+ <td class="text-normal">{{ part_class.name }}</td>
107
+ <td class="text-normal">{{ part_class.comment }}</td>
108
+ <td class="text-normal">{% if part_class.mouser_enabled %}
109
+ <img height="24" style="padding: 4px 4px 0 4px;" alt="Mouser" title="Via Mouser.com" src="{% static 'bom/img/mouser.png' %}">{% endif %}</td>
110
+ <td>
111
+ <a class="waves-effect btn-flat"
112
+ href="{% url 'bom:part-class-edit' part_class_id=part_class.id %}"><i
113
+ class="material-icons left">edit</i>Edit</a>
114
+ </td>
115
+ </tr>
116
+ {% endfor %}
117
+ </tbody>
118
+ </table>
119
+ {% else %}
120
+ <p>No part classes have been defined yet.</p>
121
+ {% endif %}
122
+ </form>
123
+ {% endif %}
124
+ <div class="row" style="padding-top: 16px;">
125
+ <div class="col s12 right-align">
126
+ {% if part_classes.count == 0 %}
127
+ <a href="{% url 'bom:help' %}#part-numbering" target="_blank">What is a part class?</a>
128
+ <p>You may also use <a href="{% static 'bom/doc/sample_part_classes.csv' %}">this sample CSV file</a>.</p>
129
+ {% endif %}
130
+ {% 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>.' %}
131
+ {% 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' %}
132
+ </div>
133
+ </div>
134
+ <h3 id="indabom-part-number">Part Number</h3>
135
+ <form name="seller" action="{% url 'bom:settings' tab_anchor=INDABOM_TAB %}" method="post" enctype="multipart/form-data">
136
+ {% csrf_token %}
137
+ <p>You may only increase the number of digits for each component of the part number: the part class code (C), part item number (N), and the part variation (V).</p>
138
+ <p>Your organization's current configuration is <b>{{ organization.number_cs }}-{{ organization.number_ns }}{% if organization.number_vs %}-
139
+ {{ organization.number_vs }}{% endif %}</b></p>
140
+ <div class="row">
141
+ {{ organization_number_len_form|materializecss:'s4 m2' }}
142
+ <div class="col s12 m6 input-field">
143
+ <button class="waves-effect waves-light btn btn-primary" type="submit"
144
+ name="submit-number-item-len"
145
+ onclick="return confirm('Are you sure you want to change the number of digits?')">Save
146
+ </button>
147
+ </div>
148
+ </div>
149
+ </form>
150
+ {% endif %}
151
+ <h3>Change Organization Number Scheme</h3>
152
+ <p>Your organization's number scheme is currently: <b>{{ organization.get_number_scheme_display }}</b></p>
153
+ <ul class="browser-default">
154
+ {% if organization.number_scheme == 'S' or organization_parts_count == 0 %}
155
+ <li style="padding-bottom: 16px;"><b>Semi-intelligent</b> e.g. CCC-NNNN-YY<br>Consists of 3 components: a 3-digit part class, a N-digit part number, and a 2-digit variation.
156
+ IndaBOM
157
+ part numbers are designed to be simple to assign and simple to subsequently write, type, or speak. You define the part classes in your organization, and how long your
158
+ N-digit
159
+ part number is below.
160
+ </li>
161
+ {% endif %}
162
+ {% if organization.number_scheme == 'I' or organization_parts_count == 0 %}
163
+ <li><b>Intelligent</b> You control your numbers.<br>Intelligent part numbering on IndaBOM allows the user to assign any part number to a part. The part number contains
164
+ descriptive details embedded within that provides noteworthy information about the part. For example, a capacitor may be named C0402X5R33PF to indicate that it is a
165
+ capacitor of size "0402", using a X5R dialectric, and is 33pF.
166
+ </li>
167
+ {% endif %}
168
+ </ul>
169
+ <p style="font-size: 15px;">You can read more about the options <a href="{% url 'bom:help' %}#part-numbering" target="_blank">here</a>.</p>
170
+ {% if organization_parts_count > 0 %}
171
+ <p><b>You've already created {{ organization_parts_count }} part{{ organization_parts_count|pluralize }}.</b> Since changing your organization number scheme requires changing your
172
+ parts numbers, please manually delete your parts then come back here to change your organization number scheme. Alternatively we can
173
+ help delete your parts if you reach out to info@indabom.com.</p>
174
+ {% else %}
175
+ <form name="number-scheme" action="{% url 'bom:settings' tab_anchor=INDABOM_TAB %}" method="post" class="col s12">
176
+ {% csrf_token %}
177
+ <button type="submit" name="change-number-scheme" class="waves-effect waves-light btn red lighten-1">Change Scheme to {% if organization.number_scheme == 'S' %}
178
+ Intelligent{% else %}Semi-Intelligent{% endif %}</button>
179
+ </form>
180
+ {% endif %}
181
+ {% else %}
182
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
183
+ {% endif %}
184
+ </div>
185
+
186
+ <div id="organization" class="col s12">
187
+ {% if user.bom_profile.role == 'A' %}
188
+ <h3>Organization</h3>
189
+ <div class="row">
190
+ <div class="col s12">
191
+ <form name="seller" action="{% url 'bom:settings' tab_anchor=ORGANIZATION_TAB %}" method="post" class="col s12" enctype="multipart/form-data">
192
+ {% csrf_token %}
193
+ <div class="row">
194
+ {{ organization_form|materializecss:'s12 m4' }}
195
+ </div>
196
+ <div class="row">
197
+ <div class="col s12 right-align">
198
+ <button class="waves-effect waves-light btn btn-primary" type="submit"
199
+ name="submit-edit-organization"
200
+ onclick="return confirm('Are you sure you want to change the organization information?')">Save
201
+ </button>
202
+ </div>
203
+ </div>
204
+ </form>
205
+ </div>
206
+ </div>
207
+ <div class="row">
208
+ <div class="col s12">
209
+ <h3>Users</h3>
210
+ {% if users_in_organization.count > 0 %}
211
+ <form name="seller" action="{% url 'bom:settings' tab_anchor=ORGANIZATION_TAB %}" method="post" class="col s12" enctype="multipart/form-data">
212
+ {% csrf_token %}
213
+ <table>
214
+ <thead>
215
+ <tr>
216
+ <th class="text-normal"><label><input type="checkbox" id="user-select-all"><span></span></label></th>
217
+ <th class="text-normal">Role</th>
218
+ <th class="text-normal">User Name</th>
219
+ <th class="text-normal">Full Name</th>
220
+ <th class="text-normal">Email</th>
221
+ <th class="text-normal"></th>
222
+ </tr>
223
+ </thead>
224
+ <tbody>
225
+ {% for org_user in users_in_organization %}
226
+ <tr>
227
+ <td>
228
+ <label><input type="checkbox" class="filled-in" name="remove_user_meta_id_{{ org_user.bom_profile.id }}"><span/></label>
229
+ </td>
230
+ <td class="text-normal">{{ org_user.bom_profile.get_role_display }}</td>
231
+ <td class="text-normal">{{ org_user.username }}</td>
232
+ <td class="text-normal">{{ org_user.first_name }} {{ org_user.last_name }}</td>
233
+ <td class="text-normal"><a href="mailto:{{ user.email }}">{{ org_user.email }}</a></td>
234
+ <td>
235
+ <a class="waves-effect btn-flat"
236
+ href="{% url 'bom:user-meta-edit' user_meta_id=org_user.bom_profile.id %}"><i
237
+ class="material-icons left">edit</i>Edit</a>
238
+ </td>
239
+ </tr>
240
+ {% endfor %}
241
+ </tbody>
242
+ </table>
243
+ <div class="row" style="padding-top: 16px;">
244
+ <div class="col s6">
245
+ <button class="waves-effect waves-light btn red lighten-1" type="submit" name="submit-remove-user"
246
+ onclick="return confirm('Are you sure you want to remove the selected users from {{ organization }}?')">Remove Selected
247
+ </button>
248
+ </div>
249
+ <div class="col s6 right-align">
250
+ {% include 'bom/bom-form-modal.html' with modal_title='Add User' form=user_add_form action=user_add_form_action name='submit-add-user' modal_description='Adding users to your organization is a paid feature, but is free for a limited time while we are still developing the tool. Contact <a href="mailto:info@indabom.com">info@indabom.com</a> if you are interested.' %}
251
+ </div>
252
+ </div>
253
+ </form>
254
+ {% else %}
255
+ <div class="row" style="padding-left: .75rem;">
256
+ <div class="col s12">
257
+ <p>There are no additional users in this organization: {{ organization }}.</p>
258
+ {% if organization.subscription == 'F' %}
259
+ {% include 'bom/bom-form-modal.html' with modal_title='Add User' name='submit-add-user-free' modal_description='Adding users to your organization is a paid feature, but is free for a limited time while we are still developing the tool. Contact <a href="mailto:info@indabom.com">info@indabom.com</a> if you are interested.' %}
260
+ {% else %}
261
+ {% if organization.subscription_quantity == 0 or users_in_organization.count < organization.subscription_quantity %}
262
+ {% include 'bom/bom-form-modal.html' with modal_title='Add User' form=user_add_form action=user_add_form_action name='submit-add-user' modal_description='Add a user to your organization.' %}
263
+ {% else %}
264
+ <p>You've added the maximum number of users to this organization. Update your subscription to add more.</p>
265
+ {% endif %}
266
+ {% endif %}
267
+ </div>
268
+ </div>
269
+ {% endif %}
270
+ </div>
271
+ </div>
272
+ <div class="row">
273
+ <div class="col s12">
274
+ <h3>Part File Storage with Google Drive <img title="Via Google Drive" style="height: 2.5rem; padding-bottom: 8px; vertical-align: middle;"
275
+ src="{% static 'bom/img/google_drive_logo.svg' %}"></h3>
276
+ {% if not google_authentication %}
277
+ <p>Connect your Google account to access Google Drive features.
278
+ {% if not organization.google_drive_parent %}Organization owners can enable file storage using Google Drive. {% if organization.owner == user %} Since you are the
279
+ owner, you are able to enable
280
+ file storage!{% else %}Contact your organization owner to enable.{% endif %}{% endif %}<p>
281
+ <p>When you connect, we will create a folder called <b>IndaBOM Part Files</b> in your root of Google drive (and can be moved anywhere in your drive). To add files to a
282
+ part,
283
+ navigate to the part in IndaBOM, and on the part's <b>Specifications</b> tab, click the <img title="Via Google Drive" style="width: 16px; vertical-align: middle;"
284
+ src="{% static 'bom/img/google_drive_logo.svg' %}">&nbsp;Google Drive link.
285
+ This will create a folder for your part in your root IndaBOM directory, or take you there if it already exists.
286
+ <p>
287
+ <p>You'll be able to access the files directly through Google Drive, and through IndaBOM.</p>
288
+ {% else %}
289
+ <p>You're connected with Google and can access Google Drive features.</p>
290
+ {% endif %}
291
+ <ul>
292
+ {% if google_authentication %}
293
+ <p>Logged in to Google as: {{ google_authentication.uid }}
294
+ <form action="{% url 'social:disconnect' 'google-oauth2' %}" method="post">
295
+ {% csrf_token %}
296
+ <button class="waves-effect waves-light btn btn-primary" type="submit">Disconnect
297
+ </button>
298
+ </form>
299
+ {% else %}
300
+ <a href="{% url "social:begin" "google-oauth2" %}">
301
+ <img title="Google sign-in." src="{% static 'bom/img/google/web/1x/btn_google_signin_dark_normal_web.png' %}">
302
+ </a>
303
+ {% endif %}
304
+ </ul>
305
+ </div>
306
+ </div>
307
+ <div class="row">
308
+ <div class="col s12">
309
+ <h3>Automagic Sourcing via Mouser <img title="Sourcing via Mouser.com" style="height: 2.5rem; padding-bottom: 8px; vertical-align: middle;"
310
+ src="{% static 'bom/img/mouser.png' %}">
311
+ </h3>
312
+ <p>No connection required. To enable sourcing via mouser, select which part classes you'd like enabled on the Settings INDABOM tab. Once enabled, sourcing information will
313
+ appear on
314
+ part detail pages in which there are parts sourced via Mouser.</p>
315
+ </div>
316
+ </div>
317
+ {% endif %}
318
+ {% if profile.organization %}
319
+ <div class="row">
320
+ <div class="col s12">
321
+ <h3>Leave Your Organization</h3>
322
+ <p>Warning, the only way back in to {{ organization.name }} is if you are invited by an organization administrator.</p>
323
+ <form name="leave-organization" action="{% url 'bom:settings' tab_anchor=ORGANIZATION_TAB %}" method="post" class="col s12" enctype="multipart/form-data">
324
+ {% csrf_token %}
325
+ <button class="waves-effect waves-light btn red lighten-1" type="submit" name="submit-leave-organization">Leave Organization</button>
326
+ </form>
327
+ </div>
328
+ </div>
329
+ {% else %}
330
+ <div class="row">
331
+ <div class="col s12">
332
+ <h3>You're not part of any organization!</h3>
333
+ <p>To create your organization, start <a href="{% url 'bom:home' %}">here</a>.</p>
334
+ </div>
335
+ </div>
336
+ {% endif %}
337
+ </div>
338
+ </div>
339
+
340
+ {% endblock %}
341
+
342
+ {% block bom-script %}
343
+
344
+ <!-- Handle if there's an anchor, select tab -->
345
+ <script type='text/javascript'>
346
+ var tabsElem = document.querySelector('.tabs');
347
+
348
+ {% if tab_anchor %}
349
+ $('#{{ tab_anchor }}-tab').addClass('active');
350
+ {% endif %}
351
+
352
+ var tabs = M.Tabs.init(tabsElem);
353
+ </script>
354
+
355
+ <script type='text/javascript'>
356
+ function user_checkbox_clear_all() {
357
+ $("input[type='checkbox']:checked").prop("checked", false)
358
+ }
359
+ </script>
360
+
361
+ <script type='text/javascript'>
362
+ $(document).ready(function () {
363
+ const selectAllId = '#part-class-select-all';
364
+ $(selectAllId).change(function () {
365
+ var table = $(selectAllId).closest('table');
366
+ if ($(selectAllId).is(":checked")) {
367
+ $("input[type='checkbox']:not(:checked)", table).prop("checked", true)
368
+ } else {
369
+ $("input[type='checkbox']:checked", table).prop("checked", false)
370
+ }
371
+ });
372
+ });
373
+
374
+ $(document).ready(function () {
375
+ const selectAllId = '#user-select-all';
376
+ $(selectAllId).change(function () {
377
+ var table = $(selectAllId).closest('table');
378
+ if ($(selectAllId).is(":checked")) {
379
+ $("input[type='checkbox']:not(:checked)", table).prop("checked", true)
380
+ } else {
381
+ $("input[type='checkbox']:checked", table).prop("checked", false)
382
+ }
383
+ });
384
+ });
385
+ </script>
386
+
387
+ <script>
388
+ $(document).ready(function () {
389
+ let $checkbox = $('.checkbox-array');
390
+ let lastChecked = null;
391
+
392
+ $checkbox.click(function (e) {
393
+ if (!lastChecked) {
394
+ lastChecked = this;
395
+ return;
396
+ }
397
+
398
+ if (e.shiftKey) {
399
+ const start = $checkbox.index(this);
400
+ const end = $checkbox.index(lastChecked);
401
+ $checkbox.slice(Math.min(start, end), Math.max(start, end) + 1).prop('checked', lastChecked.checked);
402
+ }
403
+ lastChecked = this;
404
+ });
405
+ });
406
+ </script>
407
+
408
+ {% endblock bom-script %}
@@ -0,0 +1,28 @@
1
+ {% extends 'bom/base.html' %}
2
+
3
+ {% load materializecss %}
4
+
5
+ {% block title %}Sign Up For BOM{% endblock %}
6
+ {% block head-title %}Sign Up{% endblock %}
7
+
8
+ {% block content %}
9
+ {% load static %}
10
+ <div class="container">
11
+ <div class="section center">
12
+ <h5 class="">Sign up for BOM</h5>
13
+ </div>
14
+ <div class="section center">
15
+ <form method="post">
16
+ {% csrf_token %}
17
+ <div class="row">
18
+ <div class="col m6 push-m3 s12">
19
+ {{ form|materializecss }}
20
+ <div class="center">
21
+ <button class="waves-effect waves-light btn btn-primary" style="min-width:150px" type="submit">Sign Up</button>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </form>
26
+ </div>
27
+ </div>
28
+ {% endblock %}
@@ -0,0 +1,47 @@
1
+ {% load static %}
2
+
3
+ {% block script %}
4
+ <script>
5
+ document.addEventListener('DOMContentLoaded', function() {
6
+ htmlTableOfContents();
7
+ } );
8
+
9
+ function htmlTableOfContents(documentRef) {
10
+ var documentRef = documentRef || document;
11
+ var toc = documentRef.getElementById("toc");
12
+ // Use headings inside <article> only:
13
+ // var headings = [].slice.call(documentRef.body.querySelectorAll('article h1, article h2, article h3, article h4, article h5, article h6'));
14
+ {#var headings = [].slice.call(documentRef.body.querySelectorAll('h1, h2, h3, h4, h5, h6'));#}
15
+ var article = document.querySelector("article");
16
+ var headings = article ? [].slice.call(article.querySelectorAll( "h1, h2, h3, h4, h5, h6")) : [];
17
+ headings.forEach(function (heading, index) {
18
+ var ref = "toc" + index;
19
+ var h_parent = heading.parentElement;
20
+ if (h_parent.hasAttribute("id"))
21
+ ref = h_parent.getAttribute( "id" );
22
+ else
23
+ ref = heading.textContent.replace(/\s+/g, '-').toLowerCase();
24
+ h_parent.setAttribute("id", ref);
25
+
26
+ var link = documentRef.createElement("a");
27
+ link.setAttribute("href", "#" + ref);
28
+ link.textContent = heading.textContent;
29
+
30
+ var div = documentRef.createElement("li");
31
+ div.setAttribute("class", `${heading.tagName.toLowerCase()} scrollspy`);
32
+ div.appendChild(link);
33
+ toc.appendChild(div);
34
+ });
35
+ }
36
+
37
+ try {
38
+ module.exports = htmlTableOfContents;
39
+ } catch (e) {
40
+ // module.exports is not defined
41
+ }
42
+
43
+ $(document).ready(function(){
44
+ $('.scrollspy').scrollSpy();
45
+ });
46
+ </script>
47
+ {% endblock %}
@@ -0,0 +1,111 @@
1
+ {% extends 'bom/bom-base.html' %}
2
+
3
+ {% load static %}
4
+ {% load materializecss %}
5
+
6
+ {% block head-title %}{{ title }}{% endblock %}
7
+
8
+ {% block main %}
9
+ {{ add_subpart_form.media }}
10
+ {% endblock %}
11
+
12
+ {% block bom-menu %}
13
+ {% endblock %}
14
+
15
+ {% block content %}
16
+ <div class="container-app">
17
+ {% if profile.role == 'A' %}
18
+ <div class="upload-bom">
19
+ <p>Click here to download <a href="{% static 'bom/doc/test_bom_5_intelligent.csv' %}">a sample CSV file for uploading intelligent
20
+ parts</a> and here is <a href="{% static 'bom/doc/test_bom.csv' %}">a sample CSV file for uploading semi-intelligent parts</a>. Uploading uses
21
+ an append or create strategy, for example, if a part, part revision, or part class already exists, it will be overwritten; and
22
+ if a part, part revision, or part class <b>does not</b> exist, it will be created.</p>
23
+ <p>For details on CSV file requirements, see the help docs <a href="{% url 'bom:help' %}#uploading-parts" target="_blank">here <i class="material-icons" style="font-size: 1em;">open_in_new</i></a>.</p>
24
+
25
+ <form action="{% url 'bom:upload-bom' %}" method="post" enctype="multipart/form-data">
26
+ {% csrf_token %}
27
+ <div class="row">
28
+ <div class="col s9 file-field input-field">
29
+ <div class="green lighten-1 btn">
30
+ <span>File</span>
31
+ {{ bom_csv_form.file }}
32
+ </div>
33
+ <div class="file-path-wrapper">
34
+ <input class="file-path validate" type="text" placeholder="Upload a file.">
35
+ {{ bom_csv_form.file.errors }}
36
+ </div>
37
+ </div>
38
+ <div class="col s1 input-field">
39
+ <input class="green lighten-1 btn" type="submit" value="Upload"/>
40
+ </div>
41
+ </div>
42
+ {# <div class="row">#}
43
+ {# {{ upload_bom_form.create_part_classes|materializecss:'m3 s12' }}#}
44
+ {# <div class="col m6 s12">#}
45
+ {# If a part is uploaded with a part class that doesn't exist, the upload will fail. Check this box to instead, try to create the part class.#}
46
+ {# </div>#}
47
+ {# </div>#}
48
+ <div class="row">
49
+ {{ upload_bom_form.parent_part_number|materializecss:'m3 s12' }}
50
+ <div class="col m6 s12 input-field">
51
+ <b>{{upload_bom_form.parent_part_number.label}}</b> <i>Optional.</i> Upload this BOM to a parent assembly by specifying the parent part number. Level 1 will upload as the first child of this part.
52
+ {% if parent_part %}
53
+ <br><h6><a href="{% url 'bom:part-info' part_id=parent_part.id %}">Go to {{ parent_part_number }}</a></h6>
54
+ {% endif %}
55
+ </div>
56
+ </div>
57
+ </form>
58
+ <div class="row">
59
+ <div class="col s6">
60
+ <a href="{% url 'bom:upload-bom' %}" class="waves-effect waves-light btn-flat grey-text lighten-1" style="margin-left: -16px;">Cancel</a>
61
+ </div>
62
+ </div>
63
+ <br>
64
+ </div>
65
+ {% else %}
66
+ {% include 'bom/nothing-to-see.html' with required_privilege='Admin' %}
67
+ {% endif %}
68
+ </div>
69
+ {% endblock %}
70
+
71
+ {% block bom-script %}
72
+ <!-- Tree Table -->
73
+ <script src="{% static 'bom/js/jquery.treetable.js' %}"></script>
74
+ <script>
75
+ $("#indented-bom").treetable({
76
+ expandable: true,
77
+ indent: 2,
78
+ initialState: 'collapsed',
79
+ onInitialized: function () {
80
+ $("#indented-bom").treetable("reveal", {{ part_revision.id }});
81
+ }
82
+ });
83
+ </script>
84
+
85
+ <!-- Floating Horizontal Scrollbar -->
86
+ <script type="text/javascript" src="{% static 'bom/js/jquery.ba-floatingscrollbar.min.js' %}"></script>
87
+ <script>
88
+ $(function () {
89
+ $('.responsive-table-wrapper').floatingScrollbar();
90
+ });
91
+ </script>
92
+
93
+ <!-- Handle if there's an anchor, select tab -->
94
+ <script type='text/javascript'>
95
+ // For dropdown menu
96
+ $(document).ready(function () {
97
+ $('.dropdown-trigger').dropdown({
98
+ inDuration: 300,
99
+ outDuration: 225,
100
+ constrainWidth: false, // Does not change width of dropdown to that of the activator
101
+ hover: false, // Activate on hover
102
+ gutter: 0, // Spacing from edge
103
+ belowOrigin: false, // Displays dropdown below the button
104
+ alignment: 'left', // Displays dropdown with edge aligned to the left of button
105
+ stopPropagation: false // Stops event propagation
106
+ }
107
+ );
108
+
109
+ });
110
+ </script>
111
+ {% endblock %}