from pathlib import Path import json, shutil R=Path(__file__).resolve().parent.parent; P=R/'storage/app/private/investmoz-v2/portal-audit' plan=json.loads((P/'internal-designation-plan.json').read_text()); S=Path(plan['source']) assert S.parent==P and S.name.startswith('onboarding-qa-internal-') and plan['target']['port']==55441 service=(R/'tools/portal-internal-designation-service.php').read_text(encoding='utf-8') service=service.replace("DB::table('organizations')->where('source_system','portal-operator-master')->whereNull('deleted_at')", "DB::table('organizations')->whereIn('id', DB::table('audit_events')->where('source_system','portal-profiles-v1')->where('action','operator_organization_registered')->selectRaw(\"after_data->>'organization_id'\"))->whereNull('deleted_at')") service=service.replace("$e['organization']===$payload", "$e['organization']==$payload") service=service.replace("array_intersect_key($known,$payload)===$payload", "array_intersect_key($known,$payload)==$payload") service=service.replace("$d['designation']===$payload", "$d['designation']==$payload") service=service.replace("$id=$r->id;\n DB::table", "$id=$r->id;\n $before=['name'=>$r->name,'external_id'=>$r->external_id,'source_system'=>$r->source_system,'version_no'=>$r->version_no];\n abort_unless(in_array($r->name,$names,true) || $r->name===str_replace(' Lda',', Lda',$v['name']),409,'Denominação divergente exige reconciliação expressa.');\n DB::table") service=service.replace("['external_id'=>$v['nuit'],'updated_at'=>now()", "['name'=>$v['name'],'external_id'=>$v['nuit'],'updated_at'=>now()") service=service.replace(" // Preserve its name/provenance. A spelling difference needs explicit reconciliation.\n abort_unless($r->name===$v['name'],409,'Conservar denominação anterior até reconciliar expressamente.');", " // Reconcile only the explicit comma alias; preserve previous values in audit.") service=service.replace("'organization'=>$payload,'source_reference'", "'organization'=>$payload,'previous_master_values'=>$before??null,'source_reference'") service=service.replace(" $e=DB::table('audit_events')", " $subject=User::whereKey($v['user_id'])->lockForUpdate()->firstOrFail();\n abort_unless($subject->hasVerifiedEmail() && $subject->two_factor_secret!==null && $subject->two_factor_confirmed_at!==null && $this->organization($v['operator_organization_id'])!==null,422,'Conta ou organização já não reúne as condições da atribuição.');\n $e=DB::table('audit_events')") (S/'app/Services/PortalInternalDesignation.php').write_text(service,encoding='utf-8') ui=S/'resources/js/pages/profiles/administration.tsx'; t=ui.read_text(encoding='utf-8') t=t.replace("import { profileJson }", "import { createOperationKey } from '@/lib/operation-key';\nimport { profileJson }") t=t.replace("function Grant({", (R/'tools/portal-internal-designation-ui.tsx').read_text(encoding='utf-8')+'\nfunction Grant({',1) t=t.replace('Promotor exige pedido documental independente. Superutilizador é', 'Promotor externo usa o pedido documental. Funções internas usam a designação da proprietária. Superutilizador é') t=t.replace(' securityRequests,\n}:', ' securityRequests,\n operatorOrganizations,\n}:') t=t.replace(' actorId: number;\n types:', ' operatorOrganizations: OperatorOrganization[];\n actorId: number;\n types:') t=t.replace(' \n \n