diff --git a/scripts/site_imports/wjf/run.py b/scripts/site_imports/wjf/run.py index 6a6b9a0..3f0f206 100644 --- a/scripts/site_imports/wjf/run.py +++ b/scripts/site_imports/wjf/run.py @@ -50,8 +50,10 @@ def _upsert(h, path, payload, unique_field, idfield, list_path=None): # --- classic machinetype routing (per the resolved import decisions) --------- +# measuringtools are the physical instruments (the CMM/gauge machine types). A +# PC that DRIVES one (pctype CMM/Genspect/Keyence/Wax) is still a computer, not a +# measuring tool - routing by pctype wrongly swept ~105 PCs into measuringtools. MEASURING_MTYPES = {3, 5, 8, 23, 47, 48} # CMM, Wax, Eddy, Measuring, Inspection, Spline -MEASURING_PCTYPES = {5, 6, 7, 8} # PC subtypes: CMM, Wax/Trace, Keyence, Genspect COMPUTER_MTYPES = {33, 20} # PC, Server NETWORK_MTYPES = {16, 17, 18, 19, 46} # Access, IDF, Camera, Switch, Firewall SKIP_MTYPES = {15, 44} # Printer (printers table), USB (cmmc source) @@ -79,9 +81,7 @@ def _route(machinetypeid, pctypeid, islocationonly=False): if machinetypeid in MEASURING_MTYPES: return 'measuringtool' if machinetypeid in COMPUTER_MTYPES: - if machinetypeid == 33 and pctypeid in MEASURING_PCTYPES: - return 'measuringtool' - return 'computer' + return 'computer' # a metrology PC is still a PC (it CONTROLS a tool) return 'machine' # includes the 134 untyped (machinetypeid=1) shop machines @@ -349,6 +349,52 @@ def stage_printers(h): return {'printers': made} +# classic pctype -> the measuring instrument that PC drives +METROLOGY_PCTYPE_TOOL = {5: 'CMM', 6: 'Form Tracer', 7: 'Vision System', 8: 'Genspect'} + + +def stage_metrology(h): + """Metrology PCs (CMM/Genspect/Keyence/Wax) are computers that CONTROL an + instrument. Classic has no separate tool row, so synthesize a measuring-tool + asset per metrology PC and a Controls relationship (PC -> tool), mirroring + what the runtime collector does. Runs after the asset hub (needs the PC's + assetid from the crosswalk).""" + controls_id = _upsert(h, '/api/assets/relationshiptypes', + {'relationshiptype': 'Controls'}, 'relationshiptype', + 'relationshiptypeid', '/api/assets/relationshiptypes') + made = linked = 0 + for m in h.source.rows('shopdb_src', + 'SELECT machineid, alias, hostname, machinenumber, businessunitid, ' + 'mapleft, maptop, pctypeid FROM machines ' + 'WHERE machinetypeid=33 AND pctypeid IN (5,6,7,8) ' + 'AND (islocationonly IS NULL OR islocationonly=0)'): + pc_assetid = h.ids.get('asset', m['machineid']) + if not pc_assetid: + continue # PC not imported (dup-skipped etc.) + toolname = METROLOGY_PCTYPE_TOOL[m['pctypeid']] + typeid = _upsert(h, '/api/measuringtools/types', {'name': toolname}, + 'name', 'measuringtooltypeid', '/api/measuringtools/types') + pcname = (m['alias'] or m['hostname'] or m['machinenumber'] or '').strip() + status, data = h.post('/api/measuringtools', { + 'assetnumber': f"MT-{m['machineid']}", + 'name': (f"{pcname} {toolname}").strip() or toolname, + 'measuringtooltypeid': typeid, + 'businessunitid': h.ids.get('businessunit', m['businessunitid']), + 'mapx': m['mapleft'], 'mapy': m['maptop']}) + if status not in (200, 201): + continue + tool_assetid = _id_of(data, 'assetid') + made += 1 + if tool_assetid and controls_id: + h.ids.put('metrologytool', m['machineid'], tool_assetid) + st, _ = h.post('/api/assets/relationships', { + 'sourceassetid': pc_assetid, 'targetassetid': tool_assetid, + 'relationshiptypeid': controls_id}) + if st in (200, 201): + linked += 1 + return {'measuringtools_synth': made, 'controls_links': linked} + + def stage_communications(h): """Fold each asset's primary IP from the source communications table. There is no bulk-communications endpoint, so this is one of the plan's documented @@ -722,6 +768,7 @@ STAGES = { 'assets': stage_assets, 'locations': stage_locations, 'printers': stage_printers, + 'metrology': stage_metrology, 'communications': stage_communications, 'applications': stage_applications, 'warranties': stage_warranties, @@ -739,7 +786,7 @@ def main(): parser.add_argument( '--stages', default='reference,employees,catalog,assets,locations,printers,' - 'communications,applications,warranties,notifications,' + 'metrology,communications,applications,warranties,notifications,' 'knowledgebase,relationships,subnets,usb,verify', help='comma list of stages to run') args = parser.parse_args()