55use App \Enums \DocumentPhase ;
66use App \Enums \DocumentStatus ;
77use App \Enums \DocumentType ;
8+ use App \Enums \InstrumentType ;
89use App \Models \Document ;
910use App \Models \DocumentImage ;
11+ use App \Models \Formalization ;
12+ use App \Models \Project ;
13+ use App \Services \InstrumentSequenceService ;
1014use Illuminate \Support \Collection ;
1115
1216class DocumentService
@@ -19,6 +23,7 @@ class DocumentService
1923 public function __construct (
2024 private readonly DocumentTypeRegistry $ registry ,
2125 private readonly DocumentPlaceholderResolver $ placeholderResolver ,
26+ private readonly InstrumentSequenceService $ sequenceService
2227 ) {}
2328
2429 public function create (array $ data , int $ createdBy ): Document
@@ -28,6 +33,9 @@ public function create(array $data, int $createdBy): Document
2833 DocumentPhase::from ($ data ['phase ' ]),
2934 );
3035
36+ // Gera número do termo e substitui a tag se for um TC
37+ $ data ['body ' ] = $ this ->resolveTermNumberAndReplacePlaceholder ($ data ['project_id ' ] ?? null , $ data ['type ' ], $ data ['body ' ]);
38+
3139 $ document = Document::create ([
3240 'notice_id ' => $ data ['notice_id ' ],
3341 'project_id ' => $ data ['project_id ' ] ?? null ,
@@ -47,8 +55,14 @@ public function create(array $data, int $createdBy): Document
4755
4856 public function update (Document $ document , array $ data ): Document
4957 {
58+ // Se houver atualização de conteúdo, garante que a tag (se inserida) vire número novamente
59+ $ body = $ data ['body ' ] ?? $ document ->body ;
60+ $ typeValue = $ document ->type instanceof DocumentType ? $ document ->type ->value : $ document ->type ;
61+
62+ $ data ['body ' ] = $ this ->resolveTermNumberAndReplacePlaceholder ($ document ->project_id , $ typeValue , $ body );
63+
5064 $ document ->update ([
51- 'body ' => $ data ['body ' ] ?? $ document -> body ,
65+ 'body ' => $ data ['body ' ],
5266 'status ' => $ data ['status ' ] ?? $ document ->status ,
5367 ]);
5468
@@ -59,6 +73,48 @@ public function update(Document $document, array $data): Document
5973 return $ this ->placeholderResolver ->prepare ($ document ->fresh ());
6074 }
6175
76+ /**
77+ * Resolve o número do termo (gerando atomicamente, se necessário)
78+ * e substitui a placeholder no corpo do documento.
79+ */
80+ private function resolveTermNumberAndReplacePlaceholder (?int $ projectId , string $ documentType , string $ bodyContent ): string
81+ {
82+ // Só aplicamos a lógica se for o Termo de Execução Cultural (TC) e se tivermos um projeto.
83+ if ($ documentType !== DocumentType::TC ->value || ! $ projectId ) {
84+ return $ bodyContent ;
85+ }
86+
87+ $ project = Project::with (['notice ' ])->find ($ projectId );
88+
89+ if (! $ project || ! $ project ->notice || ! $ project ->notice ->instrument_type ) {
90+ return $ bodyContent ; // Não é possível gerar sem o tipo de instrumento do edital
91+ }
92+
93+ // Recupera ou cria a Formalização vinculada ao Projeto
94+ $ formalization = Formalization::firstOrCreate ([
95+ 'project_id ' => $ project ->id ,
96+ ]);
97+
98+ $ termNumber = $ formalization ->term_number ;
99+
100+ // Se a Formalização ainda não tiver o número, nós o geramos de forma atômica
101+ if (! $ termNumber ) {
102+ // Assumimos que 'instrument_type' no Notice pode ser instanciado no nosso Enum.
103+ $ instrumentType = InstrumentType::tryFrom ($ project ->notice ->instrument_type )
104+ ?? InstrumentType::fromName ($ project ->notice ->instrument_type ); // Ajuste conforme salva no Notice
105+
106+ $ termNumber = $ this ->sequenceService ->generateNextTermNumber ($ instrumentType );
107+
108+ // Salva o número recém gerado
109+ $ formalization ->update ([
110+ 'term_number ' => $ termNumber ,
111+ ]);
112+ }
113+
114+ // Substitui a tag customizada pelo número do termo (ex: "418/2026")
115+ return str_replace ('[numero_termo] ' , $ termNumber , $ bodyContent );
116+ }
117+
62118 public function getByContext (
63119 ?int $ noticeId = null ,
64120 ?int $ projectId = null ,
0 commit comments