1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-08-05 06:57:27 +02:00

bom.py now generates bom.csv to allow costed BOMs to be made using a spreadsheet.

This commit is contained in:
Chris Palmer
2021-06-04 17:47:29 +01:00
parent ae934d47c7
commit a782d43e67
3 changed files with 60 additions and 0 deletions

View File

@@ -277,6 +277,15 @@ The top level assembly instructions and assembly contents could also be differen
If the top level module is just a shell wrapper that simply includes one other assembly, with no additional parts, then it is removed from the build instructions and If the top level module is just a shell wrapper that simply includes one other assembly, with no additional parts, then it is removed from the build instructions and
the assembly it calls becomes the top level. This allows a different project description for each target but only one set of top level instructions without repeating them. the assembly it calls becomes the top level. This allows a different project description for each target but only one set of top level instructions without repeating them.
### Costed BOMs
A costed bill of materials can be made by opening the generated file `bom/bom.csv` in a spreadsheet program using a single quote as the string delimiter and comma as the field separator.
That gets a list of part descriptions and quantities to which prices can be added to get the total cost and perhaps a URL of where to buy each part.
If a Python file called `parts.py` is found then `bom.py` will attempt to call functions for each part to get a price and URL.
Any functions not found are printed, so you can see the format expected.
The function are passed the quantity to allow them to calculate volume discounts, etc.
### Other libraries ### Other libraries
The build scripts need to be able to locate the source files where the modules to generate the STL files and assemblies reside. They will search all the scad files The build scripts need to be able to locate the source files where the modules to generate the STL files and assemblies reside. They will search all the scad files

View File

@@ -0,0 +1,16 @@
'Ferrule for 1.5mm^2 wire - not shown', 3
'Wire blue 30/0.25mm strands, length 150mm - not shown', 2
'Wire brown 30/0.25mm strands, length 150mm - not shown', 2
'Wire green & yellow 30/0.25mm strands, length 150mm - not shown', 2
'IEC inlet for ATX', 1
'Heatfit insert M3', 2
'4mm shielded jack socket blue', 2
'4mm shielded jack socket brown', 1
'4mm shielded jack socket green', 2
'Mains socket 13A', 1
'Nut M3 x 2.4mm nyloc', 6
'Screw M3 cs cap x 12mm', 2
'Screw M3 cs cap x 20mm', 2
'Screw M3 dome x 10mm', 4
'Heatshrink sleeving ID 3.2mm x 15mm - not shown', 8
'Washer M3 x 7mm x 0.5mm', 10
1 'Ferrule for 1.5mm^2 wire - not shown', 3
2 'Wire blue 30/0.25mm strands, length 150mm - not shown', 2
3 'Wire brown 30/0.25mm strands, length 150mm - not shown', 2
4 'Wire green & yellow 30/0.25mm strands, length 150mm - not shown', 2
5 'IEC inlet for ATX', 1
6 'Heatfit insert M3', 2
7 '4mm shielded jack socket blue', 2
8 '4mm shielded jack socket brown', 1
9 '4mm shielded jack socket green', 2
10 'Mains socket 13A', 1
11 'Nut M3 x 2.4mm nyloc', 6
12 'Screw M3 cs cap x 12mm', 2
13 'Screw M3 cs cap x 20mm', 2
14 'Screw M3 dome x 10mm', 4
15 'Heatshrink sleeving ID 3.2mm x 15mm - not shown', 8
16 'Washer M3 x 7mm x 0.5mm', 10

View File

@@ -31,6 +31,12 @@ from set_config import *
import json import json
import re import re
try:
import parts
got_parts_py = True
except:
got_parts_py = False
def find_scad_file(mname): def find_scad_file(mname):
for filename in os.listdir(source_dir): for filename in os.listdir(source_dir):
if filename[-5:] == ".scad": if filename[-5:] == ".scad":
@@ -129,6 +135,33 @@ class BOM:
return ass return ass
return ass.replace("assembly", "assemblies") return ass.replace("assembly", "assemblies")
def print_CSV(self, file = None):
i = 0
for part in sorted(self.vitamins):
i += 1
if ': ' in part:
part_no, description = part.split(': ')
else:
part_no, description = "", part
qty = self.vitamins[part].count
if got_parts_py:
match = re.match(r'^.*\((.*?)[,\)].*$', part_no)
if match and not match.group(1).startswith('"'):
part_no = part_no.replace('(' + match.group(1), '_' + match.group(1) + '(').replace('(, ', '(')
func = 'parts.' + part_no.replace('(', '(%d, ' % qty).replace(', )', ')')
func = func.replace('true', 'True').replace('false', 'False').replace('undef', 'None')
try:
price, url = eval(func)
print("'%s',%3d,%.2f,'=B%d*C%d',%s" % (description, qty, price, i, i, url), file=file)
except:
if part_no:
print("%s not found in parts.py" % func)
print("'%s',%3d" % (description, qty), file=file)
else:
print("'%s',%3d" % (description, qty), file=file)
if got_parts_py:
print(",'=SUM(B1:B%d)',,'=SUM(D1:D%d)'" %(i, i), file=file)
def print_bom(self, breakdown, file = None): def print_bom(self, breakdown, file = None):
if self.vitamins: if self.vitamins:
print("Vitamins:", file=file) print("Vitamins:", file=file)
@@ -265,6 +298,8 @@ def boms(target = None):
main.print_bom(True, open(bom_dir + "/bom.txt","wt")) main.print_bom(True, open(bom_dir + "/bom.txt","wt"))
main.print_CSV(open(bom_dir + "/bom.csv","wt"))
for ass in main.assemblies: for ass in main.assemblies:
with open(bom_dir + "/" + ass + ".txt", "wt") as f: with open(bom_dir + "/" + ass + ".txt", "wt") as f:
bom = main.assemblies[ass] bom = main.assemblies[ass]