"""Recheck installed wall tubes and persist the viewer's containment receipt. This does not change any bar coordinate, count or approval. """ import argparse import copy import json import os from pathlib import Path import sys import tempfile import time root = Path(__file__).resolve().parents[1] sys.path.insert(0, str(root/'src/backend' if (root/'src/backend').is_dir() else root)) def run(job_id, apply=False): import server server.require_modeling_rules() if len(job_id) != 24 or any(c not in '0123456789abcdef' for c in job_id): raise ValueError('invalid job') path = Path('/tmp/drawing-model-studio-8097-jobs')/(job_id+'.json') raw = path.read_bytes(); job = json.loads(raw); original = job['result'] if job.get('status') == 'running': raise ValueError('running job') plan = copy.deepcopy(original) hosts = {c['id']: c for c in plan['concrete_components']} reports = [] for group in plan['rebar_groups']: assembly = group.get('cad_cycle_assembly', {}) if not assembly.get('wall_station_sources'): continue paths = group['instance_paths_m']; owners = group['occurrence_instance_ids'] if (len(paths) != len(owners) or len(paths) != group['count'] or len(assembly['occurrences']) != len(paths) or not group['fabrication_measurement']['fixed_length_pass']): raise ValueError('path and occurrence evidence differ') outside = sum(server.tube_path_outside_component_union([bar], group['diameter_mm'], [hosts[k] for k in owner.split('+')])[0] for bar, owner in zip(paths, owners)) if outside: raise ValueError('wall tube leaves its host: '+group['id']) assembly.update(containment_checked=True, tested_path_count=len(paths)) group['section_projection_check'] = dict(pass_=True, tube_outside_samples=0, scope='rechecked physical host tube samples; not engineering approval') group['section_projection_check']['pass'] = group['section_projection_check'].pop('pass_') if group['count'] != group['schedule_count']: group['installation_line_review'] = True group['engineering_review_required'] = True reports.append(dict(id=group['id'], count=group['count'], outside_samples=0, schedule_count=group['schedule_count'], material_count_matched=group['count']==group['schedule_count'])) if apply and reports: assert plan['concrete_components'] == original['concrete_components'] assert [g['instance_paths_m'] for g in plan['rebar_groups']] == [g['instance_paths_m'] for g in original['rebar_groups']] preview = plan.get('drawingEvidence', {}).get('preview_geometry') if isinstance(preview, dict): preview['rebar_groups'] = copy.deepcopy(plan['rebar_groups']) plan['geometryRevision'] = 'inner-wall-visibility-'+str(time.time_ns()) plan['innerWallVisibilityAudit'] = dict(reports=reports, geometry_changed=False, full_model_approved=False) job['result'] = plan if path.read_bytes() != raw: raise ValueError('job changed') path.with_name(path.stem+'.before-wall-visibility-'+str(time.time_ns())+'.json').write_bytes(raw) with tempfile.NamedTemporaryFile(mode='w', dir=path.parent, delete=False, encoding='utf8') as output: json.dump(job, output, ensure_ascii=False, allow_nan=False); temporary = output.name os.replace(temporary, path) print(json.dumps(dict(job=job_id, reports=reports, applied=apply), ensure_ascii=False), flush=True) if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('jobs', nargs='+'); parser.add_argument('--apply', action='store_true') args = parser.parse_args() for job_id in args.jobs: run(job_id, args.apply)