Initial commit
This commit is contained in:
196
fusion_claims/scripts/import_adp_mobility_manual.py
Normal file
196
fusion_claims/scripts/import_adp_mobility_manual.py
Normal file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
ADP Mobility Manual CSV to JSON Converter
|
||||
|
||||
This script reads the ADP Mobility Manual CSV file, cleans the data,
|
||||
and outputs a JSON file that can be imported into Odoo's fusion.adp.device.code model.
|
||||
|
||||
Usage:
|
||||
python import_adp_mobility_manual.py input.csv output.json
|
||||
|
||||
Or run without arguments to use default paths.
|
||||
|
||||
Copyright 2024-2025 Nexa Systems Inc.
|
||||
License OPL-1 (Odoo Proprietary License v1.0)
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def clean_text(text):
|
||||
"""Clean text from weird characters, normalize encoding."""
|
||||
if not text:
|
||||
return ''
|
||||
# Convert to string if not already
|
||||
text = str(text)
|
||||
# Replace curly quotes with straight quotes
|
||||
text = text.replace('"', '"').replace('"', '"')
|
||||
text = text.replace(''', "'").replace(''', "'")
|
||||
# Replace various dashes with standard hyphen
|
||||
text = text.replace('–', '-').replace('—', '-')
|
||||
# Remove non-printable characters except newlines
|
||||
text = ''.join(char if char.isprintable() or char in '\n\r\t' else ' ' for char in text)
|
||||
# Normalize multiple spaces
|
||||
text = re.sub(r'\s+', ' ', text)
|
||||
# Strip leading/trailing whitespace
|
||||
return text.strip()
|
||||
|
||||
|
||||
def parse_price(price_str):
|
||||
"""Parse price string like '$64.00' or '$2,578.00' to float."""
|
||||
if not price_str:
|
||||
return 0.0
|
||||
# Remove currency symbols, commas, spaces, quotes
|
||||
price_str = str(price_str).strip()
|
||||
price_str = re.sub(r'[\$,"\'\s]', '', price_str)
|
||||
try:
|
||||
return float(price_str)
|
||||
except ValueError:
|
||||
return 0.0
|
||||
|
||||
|
||||
def convert_csv_to_json(input_path, output_path):
|
||||
"""Convert ADP Mobility Manual CSV to JSON format."""
|
||||
data = []
|
||||
errors = []
|
||||
skipped = 0
|
||||
|
||||
# Try different encodings
|
||||
encodings = ['utf-8-sig', 'utf-8', 'latin-1', 'cp1252']
|
||||
content = None
|
||||
|
||||
for encoding in encodings:
|
||||
try:
|
||||
with open(input_path, 'r', encoding=encoding) as f:
|
||||
content = f.read()
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
if content is None:
|
||||
print(f"Error: Could not read file with any known encoding")
|
||||
return None
|
||||
|
||||
# Parse CSV
|
||||
reader = csv.DictReader(content.splitlines())
|
||||
|
||||
for idx, row in enumerate(reader, start=2): # Start at 2 (header is line 1)
|
||||
try:
|
||||
# Get device code - skip if empty
|
||||
device_code = clean_text(row.get('Device Code', ''))
|
||||
if not device_code:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
# Get device type
|
||||
device_type = clean_text(row.get('Device Type', ''))
|
||||
if not device_type:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
# Get manufacturer
|
||||
manufacturer = clean_text(row.get('Manufacturer', ''))
|
||||
|
||||
# Get device description - clean it
|
||||
device_description = clean_text(row.get('Device Description', ''))
|
||||
|
||||
# Parse quantity
|
||||
qty_str = row.get('Qty', '1') or '1'
|
||||
try:
|
||||
quantity = int(qty_str)
|
||||
except ValueError:
|
||||
quantity = 1
|
||||
|
||||
# Parse price (handle both ' Approved Price ' with spaces and 'Approved Price')
|
||||
price = 0.0
|
||||
for key in row.keys():
|
||||
if 'price' in key.lower() and 'approved' in key.lower():
|
||||
price = parse_price(row.get(key, ''))
|
||||
break
|
||||
|
||||
# Parse serial requirement
|
||||
serial_str = clean_text(row.get('Serial', 'No')).upper()
|
||||
sn_required = serial_str in ('YES', 'Y', 'TRUE', '1')
|
||||
|
||||
data.append({
|
||||
'Device Type': device_type,
|
||||
'Manufacturer': manufacturer,
|
||||
'Device Description': device_description,
|
||||
'Device Code': device_code,
|
||||
'Quantity': quantity,
|
||||
'ADP Price': price,
|
||||
'SN Required': 'Yes' if sn_required else 'No',
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
errors.append(f"Row {idx}: {str(e)}")
|
||||
|
||||
# Write JSON output
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Print summary
|
||||
print(f"\n{'='*60}")
|
||||
print(f"ADP Mobility Manual Import Summary")
|
||||
print(f"{'='*60}")
|
||||
print(f"Input file: {input_path}")
|
||||
print(f"Output file: {output_path}")
|
||||
print(f"Records processed: {len(data)}")
|
||||
print(f"Records skipped: {skipped}")
|
||||
print(f"Errors: {len(errors)}")
|
||||
|
||||
if errors:
|
||||
print(f"\nFirst 10 errors:")
|
||||
for err in errors[:10]:
|
||||
print(f" - {err}")
|
||||
|
||||
# Print device type summary
|
||||
device_types = {}
|
||||
for item in data:
|
||||
dt = item['Device Type']
|
||||
device_types[dt] = device_types.get(dt, 0) + 1
|
||||
|
||||
print(f"\nDevice Types ({len(device_types)} unique):")
|
||||
for dt in sorted(device_types.keys())[:20]:
|
||||
print(f" - {dt}: {device_types[dt]} devices")
|
||||
if len(device_types) > 20:
|
||||
print(f" ... and {len(device_types) - 20} more")
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"JSON file ready for import into Odoo!")
|
||||
print(f"Use: Sales > Configuration > ADP Device Codes > Import")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def main():
|
||||
# Default paths
|
||||
default_input = r"C:\Users\gur_p\Downloads\ADP-Mobility-Manual.csv"
|
||||
default_output = r"C:\Users\gur_p\Downloads\ADP-Mobility-Manual-cleaned.json"
|
||||
|
||||
if len(sys.argv) >= 3:
|
||||
input_path = sys.argv[1]
|
||||
output_path = sys.argv[2]
|
||||
elif len(sys.argv) == 2:
|
||||
input_path = sys.argv[1]
|
||||
output_path = os.path.splitext(input_path)[0] + '-cleaned.json'
|
||||
else:
|
||||
input_path = default_input
|
||||
output_path = default_output
|
||||
|
||||
if not os.path.exists(input_path):
|
||||
print(f"Error: Input file not found: {input_path}")
|
||||
print(f"\nUsage: python {sys.argv[0]} input.csv [output.json]")
|
||||
sys.exit(1)
|
||||
|
||||
convert_csv_to_json(input_path, output_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user