diff --git a/inventory-template.md b/inventory-template.md new file mode 100644 index 0000000..5d19c3e --- /dev/null +++ b/inventory-template.md @@ -0,0 +1,37 @@ +# [SHOP NAME] Inventory Template + +## Equipment + +| Item | Model/Part Number | Serial Number | Purchase Date | Purchase Price | Current Value | Location | Condition | Notes | +|------|-------------------|---------------|---------------|----------------|---------------|----------|-----------|-------| +| Example Equipment | ABC-123 | SN001234 | 2024-01-15 | $1,200.00 | $800.00 | Shelf A1 | Good | Warranty expires 2026 | + +## Tools + +| Item | Model/Part Number | Serial Number | Purchase Date | Purchase Price | Current Value | Location | Condition | Notes | +|------|-------------------|---------------|---------------|----------------|---------------|----------|-----------|-------| +| Example Tool | DEF-456 | SN005678 | 2024-02-10 | $300.00 | $250.00 | Toolbox B | Excellent | | + +## Supplies + +| Item | Model/Part Number | Quantity | Unit Cost | Total Value | Location | Expiration Date | Notes | +|------|-------------------|----------|-----------|-------------|----------|-----------------|-------| +| Example Supply | GHI-789 | 50 | $5.00 | $250.00 | Cabinet C | 2025-12-31 | | + +## Consumables + +| Item | Model/Part Number | Quantity | Unit Cost | Total Value | Location | Expiration Date | Notes | +|------|-------------------|----------|-----------|-------------|----------|-----------------|-------| +| Example Consumable | JKL-012 | 100 | $2.50 | $250.00 | Storage D | 2025-06-30 | | + +--- + +**Total Equipment Value:** $X,XXX.XX +**Total Tool Value:** $X,XXX.XX +**Total Supply Value:** $X,XXX.XX +**Total Consumables Value:** $X,XXX.XX + +**Grand Total:** $X,XXX.XX + +**Last Updated:** [DATE] +**Updated By:** [NAME] \ No newline at end of file diff --git a/markdown-to-tsv.py b/markdown-to-tsv.py new file mode 100644 index 0000000..97af598 --- /dev/null +++ b/markdown-to-tsv.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +""" +Convert markdown inventory files to TSV format for asset database import. +Processes markdown tables and extracts inventory data. +""" + +import re +import csv +import sys +import os +from pathlib import Path +import argparse +from datetime import datetime + +def parse_markdown_table(content, section_name): + """Parse a markdown table and return rows as dictionaries.""" + items = [] + + # Find the section + section_pattern = rf'## {section_name}\s*\n' + section_match = re.search(section_pattern, content, re.IGNORECASE) + + if not section_match: + return items + + # Extract content from this section until next section or end + start_pos = section_match.end() + next_section = re.search(r'\n## ', content[start_pos:]) + + if next_section: + section_content = content[start_pos:start_pos + next_section.start()] + else: + section_content = content[start_pos:] + + # Find table + table_pattern = r'\|([^|]+\|)+\s*\n\|[-\s|:]+\|\s*\n((?:\|[^|]*\|.*\n?)*)' + table_match = re.search(table_pattern, section_content) + + if not table_match: + return items + + # Parse header + header_line = table_match.group(0).split('\n')[0] + headers = [h.strip() for h in header_line.split('|')[1:-1]] + + # Parse data rows + data_section = table_match.group(2) + for line in data_section.strip().split('\n'): + if line.strip() and '|' in line: + values = [v.strip() for v in line.split('|')[1:-1]] + if values and values[0]: # Skip empty rows + item = dict(zip(headers, values)) + item['Category'] = section_name + items.append(item) + + return items + +def extract_shop_name(content): + """Extract shop name from markdown title.""" + title_match = re.search(r'^#\s*(.+)', content, re.MULTILINE) + if title_match: + return title_match.group(1).strip() + return "Unknown Shop" + +def process_markdown_file(file_path): + """Process a single markdown file and extract all inventory items.""" + try: + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + shop_name = extract_shop_name(content) + all_items = [] + + # Process each section + sections = ['Equipment', 'Tools', 'Supplies', 'Consumables'] + for section in sections: + items = parse_markdown_table(content, section) + for item in items: + item['Shop'] = shop_name + item['Source_File'] = os.path.basename(file_path) + all_items.append(item) + + return all_items + + except Exception as e: + print(f"Error processing {file_path}: {e}", file=sys.stderr) + return [] + +def write_tsv(items, output_file): + """Write items to TSV file.""" + if not items: + print("No items to write.") + return + + # Get all unique fields + all_fields = set() + for item in items: + all_fields.update(item.keys()) + + # Standard field order + standard_fields = ['Shop', 'Category', 'Item', 'Model/Part Number', 'Serial Number', + 'Purchase Date', 'Purchase Price', 'Current Value', 'Location', + 'Condition', 'Quantity', 'Unit Cost', 'Total Value', 'Expiration Date', + 'Notes', 'Source_File'] + + # Arrange fields with standard ones first + fieldnames = [f for f in standard_fields if f in all_fields] + fieldnames.extend([f for f in all_fields if f not in standard_fields]) + + with open(output_file, 'w', newline='', encoding='utf-8') as f: + writer = csv.DictWriter(f, fieldnames=fieldnames, delimiter='\t') + writer.writeheader() + writer.writerows(items) + +def main(): + parser = argparse.ArgumentParser(description='Convert markdown inventory to TSV') + parser.add_argument('input', nargs='*', help='Input markdown files or directories') + parser.add_argument('-o', '--output', default='inventory.tsv', help='Output TSV file') + parser.add_argument('-r', '--recursive', action='store_true', help='Process directories recursively') + + args = parser.parse_args() + + if not args.input: + # Default to current directory src folder + args.input = ['src/'] + + all_items = [] + + for input_path in args.input: + path = Path(input_path) + + if path.is_file() and path.suffix == '.md': + all_items.extend(process_markdown_file(path)) + elif path.is_dir(): + pattern = '**/*.md' if args.recursive else '*.md' + for md_file in path.glob(pattern): + if 'inventory' in md_file.name.lower() or 'equipment' in md_file.name.lower() or 'tools' in md_file.name.lower(): + all_items.extend(process_markdown_file(md_file)) + + if all_items: + write_tsv(all_items, args.output) + print(f"Processed {len(all_items)} items and wrote to {args.output}") + else: + print("No inventory items found in the specified files.") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/sample-inventory.md b/sample-inventory.md new file mode 100644 index 0000000..02a4f72 --- /dev/null +++ b/sample-inventory.md @@ -0,0 +1,29 @@ +# Sample Clean Fabrication Shop Inventory + +## Equipment + +| Item | Model/Part Number | Serial Number | Purchase Date | Purchase Price | Current Value | Location | Condition | Notes | +|------|-------------------|---------------|---------------|----------------|---------------|----------|-----------|-------| +| Soldering Station | Hakko FX-888D | SN123456 | 2023-03-15 | $149.99 | $120.00 | Bench A | Excellent | Under warranty | +| Hot Air Station | Quick 861DW | SN789012 | 2023-05-22 | $89.99 | $75.00 | Bench B | Good | | + +## Tools + +| Item | Model/Part Number | Serial Number | Purchase Date | Purchase Price | Current Value | Location | Condition | Notes | +|------|-------------------|---------------|---------------|----------------|---------------|----------|-----------|-------| +| Digital Multimeter | Fluke 87V | SN345678 | 2023-01-10 | $389.99 | $350.00 | Toolbox 1 | Excellent | Calibrated 2024 | +| Oscilloscope | Rigol DS1054Z | SN901234 | 2023-04-12 | $349.99 | $300.00 | Bench C | Good | | + +## Supplies + +| Item | Model/Part Number | Quantity | Unit Cost | Total Value | Location | Expiration Date | Notes | +|------|-------------------|----------|-----------|-------------|----------|-----------------|-------| +| Solder Wire | Kester 63/37 | 5 | $24.99 | $124.95 | Cabinet A | | 1lb spools | +| Flux Paste | Kester 186 | 3 | $12.99 | $38.97 | Cabinet A | 2025-12-31 | | + +## Consumables + +| Item | Model/Part Number | Quantity | Unit Cost | Total Value | Location | Expiration Date | Notes | +|------|-------------------|----------|-----------|-------------|----------|-----------------|-------| +| Solder Wick | Chemtronics 80-3-5 | 10 | $4.99 | $49.90 | Drawer B | | | +| Isopropyl Alcohol | 99% IPA | 2 | $8.99 | $17.98 | Chemical Cabinet | | 1L bottles | \ No newline at end of file