worker-automate-hub 0.5.820__py3-none-any.whl → 0.5.921__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- worker_automate_hub/api/client.py +121 -10
- worker_automate_hub/api/rpa_historico_service.py +1 -0
- worker_automate_hub/tasks/jobs/abertura_livros_fiscais.py +11 -14
- worker_automate_hub/tasks/jobs/descartes.py +8 -8
- worker_automate_hub/tasks/jobs/devolucao_produtos.py +1386 -0
- worker_automate_hub/tasks/jobs/extracao_dados_nielsen.py +504 -0
- worker_automate_hub/tasks/jobs/extracao_saldo_estoque_fiscal.py +90 -11
- worker_automate_hub/tasks/jobs/fidc_gerar_nosso_numero.py +2 -2
- worker_automate_hub/tasks/jobs/fidc_remessa_cobranca_cnab240.py +24 -15
- worker_automate_hub/tasks/jobs/importacao_extratos.py +538 -0
- worker_automate_hub/tasks/jobs/importacao_extratos_748.py +800 -0
- worker_automate_hub/tasks/jobs/inclusao_pedidos_ipiranga.py +223 -0
- worker_automate_hub/tasks/jobs/inclusao_pedidos_raizen.py +187 -0
- worker_automate_hub/tasks/jobs/inclusao_pedidos_vibra.py +345 -0
- worker_automate_hub/tasks/jobs/lista_clientes_sap.py +631 -0
- worker_automate_hub/tasks/jobs/lista_devolucoes_sap.py +626 -0
- worker_automate_hub/tasks/jobs/notas_faturamento_sap.py +438 -157
- worker_automate_hub/tasks/jobs/opex_capex.py +523 -384
- worker_automate_hub/tasks/task_definitions.py +38 -2
- worker_automate_hub/utils/util.py +20 -10
- {worker_automate_hub-0.5.820.dist-info → worker_automate_hub-0.5.921.dist-info}/METADATA +2 -1
- {worker_automate_hub-0.5.820.dist-info → worker_automate_hub-0.5.921.dist-info}/RECORD +24 -15
- {worker_automate_hub-0.5.820.dist-info → worker_automate_hub-0.5.921.dist-info}/WHEEL +0 -0
- {worker_automate_hub-0.5.820.dist-info → worker_automate_hub-0.5.921.dist-info}/entry_points.txt +0 -0
|
@@ -17,7 +17,9 @@ from pywinauto_recorder.player import set_combobox
|
|
|
17
17
|
from rich.console import Console
|
|
18
18
|
import sys
|
|
19
19
|
import asyncio
|
|
20
|
-
|
|
20
|
+
from pywinauto import Desktop
|
|
21
|
+
|
|
22
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..","..","..")))
|
|
21
23
|
from worker_automate_hub.api.ahead_service import save_xml_to_downloads
|
|
22
24
|
from worker_automate_hub.api.client import (
|
|
23
25
|
get_config_by_name,
|
|
@@ -61,7 +63,11 @@ pyautogui.PAUSE = 0.5
|
|
|
61
63
|
pyautogui.FAILSAFE = False
|
|
62
64
|
console = Console()
|
|
63
65
|
|
|
66
|
+
BASE_PATH = r"assets\entrada_notas"
|
|
67
|
+
|
|
68
|
+
|
|
64
69
|
async def get_ultimo_item():
|
|
70
|
+
console.print("[ITENS] Iniciando função get_ultimo_item...", style="bold cyan")
|
|
65
71
|
send_keys("^({END})")
|
|
66
72
|
await worker_sleep(2)
|
|
67
73
|
send_keys("+{F10}")
|
|
@@ -70,133 +76,145 @@ async def get_ultimo_item():
|
|
|
70
76
|
await worker_sleep(1)
|
|
71
77
|
send_keys("{ENTER}")
|
|
72
78
|
await worker_sleep(2)
|
|
79
|
+
console.print("[ITENS] Conectando na janela 'Alteração de Item' para obter último índice...", style="cyan")
|
|
73
80
|
app = Application().connect(title="Alteração de Item")
|
|
74
81
|
main_window = app["Alteração de Item"]
|
|
75
82
|
main_window.set_focus()
|
|
76
83
|
edit = main_window.child_window(class_name="TDBIEditCode", found_index=0)
|
|
77
84
|
index_ultimo_item = int(edit.window_text())
|
|
85
|
+
console.print(f"[ITENS] Último item encontrado: {index_ultimo_item}", style="bold green")
|
|
78
86
|
try:
|
|
79
87
|
btn_cancelar = main_window.child_window(title="&Cancelar")
|
|
80
88
|
btn_cancelar.click()
|
|
81
89
|
except Exception as error:
|
|
82
90
|
btn_cancelar = main_window.child_window(title="Cancelar")
|
|
83
91
|
btn_cancelar.click()
|
|
84
|
-
console.print(f"Erro ao
|
|
92
|
+
console.print(f"[ITENS] Erro ao fechar janela get_ultimo_item: {error}", style="bold yellow")
|
|
85
93
|
await worker_sleep(1)
|
|
86
94
|
return index_ultimo_item
|
|
87
95
|
|
|
88
|
-
async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
89
|
-
"""
|
|
90
|
-
Processo que realiza entrada de notas no ERP EMSys(Linx ).
|
|
91
96
|
|
|
92
|
-
|
|
97
|
+
async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
98
|
+
numero_nota = None
|
|
93
99
|
try:
|
|
94
|
-
|
|
100
|
+
console.print("\n================ INÍCIO PROCESSO opex_capex ================\n", style="bold blue")
|
|
101
|
+
console.print(f"[TASK] Dados da task recebida: {task}", style="cyan")
|
|
102
|
+
|
|
103
|
+
console.print("[ETAPA 1] Buscando configuração de login_emsys via API...", style="bold cyan")
|
|
95
104
|
config = await get_config_by_name("login_emsys")
|
|
96
|
-
console.print(
|
|
105
|
+
console.print("[ETAPA 1] Configuração 'login_emsys' obtida com sucesso.", style="bold green")
|
|
97
106
|
|
|
98
|
-
# Seta config entrada na var nota para melhor entendimento
|
|
99
107
|
nota = task.configEntrada
|
|
108
|
+
console.print(f"[ETAPA 1] ConfigEntrada (nota): {nota}", style="cyan")
|
|
109
|
+
|
|
100
110
|
multiplicador_timeout = int(float(task.sistemas[0].timeout))
|
|
111
|
+
console.print(f"[ETAPA 1] Timeout multiplicador definido como: {multiplicador_timeout}", style="cyan")
|
|
101
112
|
set_variable("timeout_multiplicador", multiplicador_timeout)
|
|
102
113
|
|
|
103
|
-
|
|
114
|
+
console.print("[ETAPA 2] Fechando instâncias do EMSys se existirem...", style="bold cyan")
|
|
104
115
|
await kill_all_emsys()
|
|
105
116
|
data_atual = datetime.now().strftime("%d/%m/%Y")
|
|
106
|
-
print(data_atual)
|
|
107
|
-
|
|
117
|
+
console.print(f"[ETAPA 2] Data atual: {data_atual}", style="cyan")
|
|
118
|
+
|
|
119
|
+
console.print("[ETAPA 3] Preparando dados da nota para consulta na API...", style="bold cyan")
|
|
108
120
|
numero_nota = nota.get("numeroNota")
|
|
109
121
|
serie_nota = nota.get("serieNota")
|
|
110
|
-
|
|
111
|
-
filial_nota = filial_nota.split("-")[0].strip()
|
|
122
|
+
fornecedor = nota.get("fornecedorCnpj")
|
|
112
123
|
centro_custo = nota.get("centroCusto")
|
|
113
124
|
centro_custo = centro_custo.split("-")[0].strip().lstrip("0")
|
|
114
125
|
|
|
126
|
+
console.print(f"[ETAPA 3] NumeroNota={numero_nota} | Serie={serie_nota} | FornecedorCNPJ={fornecedor} | CentroCusto={centro_custo}", style="cyan")
|
|
127
|
+
|
|
115
128
|
try:
|
|
129
|
+
console.print("[ETAPA 4] Consultando dados da NF no EMSys via get_dados_nf_emsys...", style="bold cyan")
|
|
116
130
|
dados_nf = await get_dados_nf_emsys(
|
|
117
131
|
numero_nota=numero_nota,
|
|
118
132
|
serie_nota=serie_nota,
|
|
119
|
-
|
|
133
|
+
fornecedor=fornecedor
|
|
120
134
|
)
|
|
135
|
+
console.print(f"[ETAPA 4] Retorno get_dados_nf_emsys: {dados_nf}", style="cyan")
|
|
121
136
|
|
|
122
|
-
# Se a API retornou erro
|
|
123
137
|
if isinstance(dados_nf, dict) and "erro" in dados_nf:
|
|
124
|
-
console.print("Erro retornado pela API
|
|
138
|
+
console.print("[ETAPA 4] Erro retornado pela API de dados NF.", style="bold red")
|
|
139
|
+
console.print(f"[ETAPA 4] Detalhes erro API: {dados_nf['erro']}", style="red")
|
|
125
140
|
nf_chave_acesso = None
|
|
126
|
-
|
|
127
|
-
# Se retornou lista mas está vazia
|
|
128
141
|
elif isinstance(dados_nf, list) and not dados_nf:
|
|
129
|
-
console.print("Nenhum dado encontrado para a nota.")
|
|
142
|
+
console.print("[ETAPA 4] Nenhum dado encontrado para a nota na API.", style="bold yellow")
|
|
130
143
|
nf_chave_acesso = None
|
|
131
|
-
|
|
132
|
-
# Se retornou lista com dados
|
|
133
144
|
else:
|
|
134
145
|
nf_chave_acesso = dados_nf[0].get("chaveNfe")
|
|
135
|
-
console.print("Chave da NF:",
|
|
146
|
+
console.print(f"[ETAPA 4] Chave da NF obtida: {nf_chave_acesso}", style="bold green")
|
|
136
147
|
|
|
137
148
|
except Exception as e:
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
observacao = f"[ERRO ETAPA 4] Erro ao buscar nota via get_dados_nf_emsys: {e}"
|
|
150
|
+
console.print(observacao, style="bold red")
|
|
151
|
+
logger.error(observacao)
|
|
152
|
+
return RpaRetornoProcessoDTO(
|
|
153
|
+
sucesso=False,
|
|
154
|
+
retorno=observacao,
|
|
155
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
156
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
157
|
+
)
|
|
140
158
|
|
|
141
|
-
|
|
142
|
-
console.log("Realizando o download do XML..\n")
|
|
159
|
+
console.print("[ETAPA 5] Iniciando download do XML da NF...", style="bold cyan")
|
|
143
160
|
await save_xml_to_downloads(nf_chave_acesso)
|
|
161
|
+
console.print("[ETAPA 5] XML baixado com sucesso.", style="bold green")
|
|
144
162
|
|
|
163
|
+
console.print("[ETAPA 6] Consultando status da NF no EMSys via get_status_nf_emsys...", style="bold cyan")
|
|
145
164
|
status_nf_emsys = await get_status_nf_emsys(nf_chave_acesso)
|
|
165
|
+
console.print(f"[ETAPA 6] Status NF EMSys: {status_nf_emsys}", style="cyan")
|
|
146
166
|
|
|
147
167
|
empresa_codigo = dados_nf[0]["empresaCodigo"]
|
|
148
168
|
cfop = dados_nf[0]["numeroDoCfop"]
|
|
149
169
|
cfops_itens = [item["cfopProduto"] for item in dados_nf[0]["itens"]]
|
|
170
|
+
console.print(f"[ETAPA 6] EmpresaCodigo={empresa_codigo} | CFOP NF={cfop} | CFOPs Itens={cfops_itens}", style="cyan")
|
|
150
171
|
|
|
151
|
-
|
|
152
|
-
|
|
153
172
|
if status_nf_emsys.get("status") == "Lançada":
|
|
154
|
-
console.print(
|
|
155
|
-
"\\Nota fiscal já lançada, processo finalizado...", style="bold green"
|
|
156
|
-
)
|
|
173
|
+
console.print("\\Nota fiscal já lançada, processo finalizado...", style="bold green")
|
|
157
174
|
return RpaRetornoProcessoDTO(
|
|
158
175
|
sucesso=False,
|
|
159
176
|
retorno="Nota fiscal já lançada",
|
|
160
177
|
status=RpaHistoricoStatusEnum.Descartado,
|
|
161
178
|
)
|
|
162
179
|
else:
|
|
163
|
-
console.print("\\Nota fiscal não lançada, iniciando o processo...")
|
|
180
|
+
console.print("\\Nota fiscal não lançada, iniciando o processo...", style="yellow")
|
|
164
181
|
|
|
182
|
+
console.print("[ETAPA 7] Iniciando EMSys3_29.exe...", style="bold cyan")
|
|
165
183
|
app = Application(backend="win32").start("C:\\Rezende\\EMSys3\\EMSys3_29.exe")
|
|
166
184
|
warnings.filterwarnings(
|
|
167
185
|
"ignore",
|
|
168
186
|
category=UserWarning,
|
|
169
|
-
message="32-bit application should be automated
|
|
187
|
+
message="32-bit application should be automated usando 32-bit Python",
|
|
170
188
|
)
|
|
171
|
-
console.print("
|
|
172
|
-
|
|
189
|
+
console.print("[ETAPA 7] EMSys iniciando...", style="bold green")
|
|
190
|
+
|
|
191
|
+
console.print("[ETAPA 7] Realizando login no EMSys pelo login_emsys...", style="bold cyan")
|
|
192
|
+
return_login = await login_emsys(config.conConfiguracao, app, task, filial_origem=empresa_codigo)
|
|
173
193
|
|
|
174
|
-
if return_login.sucesso
|
|
194
|
+
if return_login.sucesso:
|
|
195
|
+
console.print("[ETAPA 8] Login realizado com sucesso. Acessando menu 'Nota Fiscal de Entrada'...", style="bold green")
|
|
175
196
|
type_text_into_field(
|
|
176
197
|
"Nota Fiscal de Entrada", app["TFrmMenuPrincipal"]["Edit"], True, "50"
|
|
177
198
|
)
|
|
178
199
|
pyautogui.press("enter")
|
|
179
200
|
await worker_sleep(2)
|
|
180
201
|
pyautogui.press("enter")
|
|
181
|
-
console.print(
|
|
182
|
-
f"\nPesquisa: 'Nota Fiscal de Entrada' realizada com sucesso",
|
|
183
|
-
style="bold green",
|
|
184
|
-
)
|
|
202
|
+
console.print("[ETAPA 8] Pesquisa: 'Nota Fiscal de Entrada' realizada com sucesso", style="bold green")
|
|
185
203
|
else:
|
|
186
|
-
logger.info(f"
|
|
187
|
-
console.print(f"
|
|
204
|
+
logger.info(f"[ETAPA 8] Error Message login: {return_login.retorno}")
|
|
205
|
+
console.print(f"[ETAPA 8] Error Message login: {return_login.retorno}", style="bold red")
|
|
188
206
|
return return_login
|
|
189
207
|
|
|
190
208
|
await worker_sleep(6)
|
|
191
209
|
|
|
192
|
-
|
|
193
|
-
console.print("Navegando pela Janela de Nota Fiscal de Entrada...\n")
|
|
210
|
+
console.print("[ETAPA 9] Selecionando tipo de documento: NOTA FISCAL DE ENTRADA ELETRONICA - DANFE...", style="bold cyan")
|
|
194
211
|
document_type = await select_documento_type(
|
|
195
212
|
"NOTA FISCAL DE ENTRADA ELETRONICA - DANFE"
|
|
196
213
|
)
|
|
197
|
-
if document_type.sucesso
|
|
214
|
+
if document_type.sucesso:
|
|
198
215
|
console.log(document_type.retorno, style="bold green")
|
|
199
216
|
else:
|
|
217
|
+
console.print("[ETAPA 9] Falha ao selecionar tipo de documento.", style="bold red")
|
|
200
218
|
return RpaRetornoProcessoDTO(
|
|
201
219
|
sucesso=False,
|
|
202
220
|
retorno=document_type.retorno,
|
|
@@ -206,11 +224,12 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
206
224
|
|
|
207
225
|
await worker_sleep(4)
|
|
208
226
|
|
|
209
|
-
|
|
227
|
+
console.print("[ETAPA 10] Iniciando importação da NFe (XML)...", style="bold cyan")
|
|
210
228
|
imported_nfe = await import_nfe()
|
|
211
|
-
if imported_nfe.sucesso
|
|
229
|
+
if imported_nfe.sucesso:
|
|
212
230
|
console.log(imported_nfe.retorno, style="bold green")
|
|
213
231
|
else:
|
|
232
|
+
console.print("[ETAPA 10] Falha na importação da NFe.", style="bold red")
|
|
214
233
|
return RpaRetornoProcessoDTO(
|
|
215
234
|
sucesso=False,
|
|
216
235
|
retorno=imported_nfe.retorno,
|
|
@@ -220,18 +239,21 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
220
239
|
|
|
221
240
|
await worker_sleep(5)
|
|
222
241
|
|
|
242
|
+
console.print("[ETAPA 11] Buscando XML importado no EMSys via get_xml...", style="bold cyan")
|
|
223
243
|
await get_xml(nf_chave_acesso)
|
|
244
|
+
console.print("[ETAPA 11] get_xml concluído.", style="bold green")
|
|
224
245
|
|
|
246
|
+
await worker_sleep(10)
|
|
225
247
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# VERIFICANDO A EXISTENCIA DE WARNINGS
|
|
248
|
+
console.print("[ETAPA 12] Verificando existência de pop-up 'Warning' após importação do XML...", style="bold cyan")
|
|
229
249
|
warning_pop_up = await is_window_open("Warning")
|
|
230
|
-
if warning_pop_up["IsOpened"]
|
|
250
|
+
if warning_pop_up["IsOpened"]:
|
|
251
|
+
console.print("[ETAPA 12] Pop-up Warning encontrado, tratando via warnings_after_xml_imported...", style="yellow")
|
|
231
252
|
warning_work = await warnings_after_xml_imported()
|
|
232
|
-
if warning_work.sucesso
|
|
253
|
+
if warning_work.sucesso:
|
|
233
254
|
console.log(warning_work.retorno, style="bold green")
|
|
234
255
|
else:
|
|
256
|
+
console.print("[ETAPA 12] Falha ao tratar Warning após XML.", style="bold red")
|
|
235
257
|
return RpaRetornoProcessoDTO(
|
|
236
258
|
sucesso=False,
|
|
237
259
|
retorno=warning_work.retorno,
|
|
@@ -239,9 +261,10 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
239
261
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
240
262
|
)
|
|
241
263
|
|
|
242
|
-
|
|
264
|
+
console.print("[ETAPA 13] Verificando existência de pop-up 'Erro' após importação do XML...", style="bold cyan")
|
|
243
265
|
erro_pop_up = await is_window_open("Erro")
|
|
244
|
-
if erro_pop_up["IsOpened"]
|
|
266
|
+
if erro_pop_up["IsOpened"]:
|
|
267
|
+
console.print("[ETAPA 13] Pop-up Erro encontrado, tratando via error_after_xml_imported...", style="bold red")
|
|
245
268
|
error_work = await error_after_xml_imported()
|
|
246
269
|
return RpaRetornoProcessoDTO(
|
|
247
270
|
sucesso=error_work.sucesso,
|
|
@@ -249,21 +272,16 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
249
272
|
status=error_work.status,
|
|
250
273
|
tags=error_work.tags
|
|
251
274
|
)
|
|
275
|
+
|
|
276
|
+
await worker_sleep(3)
|
|
252
277
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
)
|
|
278
|
+
console.print("[ETAPA 14] Conectando na janela 'Informações para importação da Nota Fiscal Eletrônica'...", style="bold cyan")
|
|
279
|
+
app = Application().connect(title="Informações para importação da Nota Fiscal Eletrônica")
|
|
256
280
|
main_window = app["Informações para importação da Nota Fiscal Eletrônica"]
|
|
257
281
|
|
|
258
|
-
#
|
|
259
|
-
console.print(f"
|
|
260
|
-
combo_box_natureza_operacao = main_window.child_window(
|
|
261
|
-
class_name="TDBIComboBox", found_index=0
|
|
262
|
-
)
|
|
263
|
-
combo_box_natureza_operacao.click()
|
|
282
|
+
# ================= BLOCO CFOP =================
|
|
283
|
+
console.print(f"[CFOP] Iniciando processo de seleção da Natureza de Operação (CFOP: {cfop})...", style="bold cyan")
|
|
264
284
|
|
|
265
|
-
await worker_sleep(3)
|
|
266
|
-
# Mapeamento CFOP -> (lista, código exibido no combobox)
|
|
267
285
|
cfop_map = {
|
|
268
286
|
"1556": (['5101', '5102', '5103', '5104'], "1.556"),
|
|
269
287
|
"1407": (['5401', '5403', '5404', '5405'], "1.407"),
|
|
@@ -271,51 +289,105 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
271
289
|
}
|
|
272
290
|
|
|
273
291
|
cfop_str = str(cfop)
|
|
292
|
+
cfop_key_escolhido = None
|
|
293
|
+
codigo_combo_escolhido = None
|
|
294
|
+
|
|
274
295
|
for key, (lista, codigo_combo) in cfop_map.items():
|
|
275
296
|
if cfop_str in lista:
|
|
297
|
+
cfop_key_escolhido = key
|
|
298
|
+
codigo_combo_escolhido = codigo_combo
|
|
299
|
+
break
|
|
300
|
+
|
|
301
|
+
console.print(f"[CFOP] CFOP NF: {cfop_str} | CFOP key escolhida: {cfop_key_escolhido} | Código combo: {codigo_combo_escolhido}", style="cyan")
|
|
302
|
+
|
|
303
|
+
if not cfop_key_escolhido:
|
|
304
|
+
msg = "Erro mapeado, CFOP diferente de início com 540 ou 510, necessário ação manual ou ajuste no robô..."
|
|
305
|
+
console.print(f"[CFOP] {msg}", style="bold red")
|
|
306
|
+
return RpaRetornoProcessoDTO(
|
|
307
|
+
sucesso=False,
|
|
308
|
+
retorno=msg,
|
|
309
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
310
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
max_tentativas_cfop = 3
|
|
314
|
+
selecionou_cfop = False
|
|
315
|
+
|
|
316
|
+
for tentativa in range(1, max_tentativas_cfop + 1):
|
|
317
|
+
try:
|
|
318
|
+
console.print(f"[CFOP] Tentando selecionar Natureza de Operação (tentativa {tentativa}/{max_tentativas_cfop})...", style="bold cyan")
|
|
319
|
+
|
|
320
|
+
combo_box_natureza_operacao = main_window.child_window(
|
|
321
|
+
class_name="TDBIComboBox", found_index=0
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
combo_box_natureza_operacao.set_focus()
|
|
325
|
+
combo_box_natureza_operacao.click_input()
|
|
326
|
+
await worker_sleep(1)
|
|
327
|
+
|
|
328
|
+
texto_alvo_parcial = f"{cfop_key_escolhido}-COMPRA DE MERCADORIAS SEM ESTOQUE"
|
|
329
|
+
texto_alvo_codigo = str(codigo_combo_escolhido)
|
|
330
|
+
|
|
331
|
+
console.print(f"[CFOP] Buscando opção que contenha '{texto_alvo_parcial}' e '{texto_alvo_codigo}'...", style="cyan")
|
|
332
|
+
|
|
276
333
|
for opc in combo_box_natureza_operacao.item_texts():
|
|
277
|
-
if (
|
|
278
|
-
|
|
334
|
+
if (texto_alvo_parcial in opc) and (texto_alvo_codigo in opc):
|
|
335
|
+
console.print(f"[CFOP] Opção candidata encontrada: {opc}", style="cyan")
|
|
279
336
|
combo_box_natureza_operacao.select(opc)
|
|
280
337
|
send_keys("{ENTER}")
|
|
281
|
-
|
|
282
|
-
break
|
|
338
|
+
await worker_sleep(1)
|
|
283
339
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
340
|
+
texto_final = combo_box_natureza_operacao.window_text().strip()
|
|
341
|
+
console.print(f"[CFOP] Texto final no combo: '{texto_final}'", style="cyan")
|
|
342
|
+
if texto_alvo_codigo in texto_final or cfop_key_escolhido in texto_final:
|
|
343
|
+
selecionou_cfop = True
|
|
344
|
+
console.print(f"[CFOP] Natureza de Operação selecionada com sucesso: {texto_final}", style="bold green")
|
|
345
|
+
break
|
|
346
|
+
|
|
347
|
+
if selecionou_cfop:
|
|
348
|
+
break
|
|
349
|
+
else:
|
|
350
|
+
console.print("[CFOP] Não foi possível confirmar a seleção da Natureza de Operação. Tentando novamente...", style="yellow")
|
|
351
|
+
await worker_sleep(2)
|
|
352
|
+
|
|
353
|
+
except Exception as e:
|
|
354
|
+
console.print(f"[CFOP] Erro ao selecionar Natureza de Operação na tentativa {tentativa}: {e}", style="bold red")
|
|
355
|
+
await worker_sleep(2)
|
|
356
|
+
|
|
357
|
+
if not selecionou_cfop:
|
|
358
|
+
msg = "Não foi possível selecionar a Natureza de Operação (CFOP) após múltiplas tentativas."
|
|
359
|
+
console.print(f"[CFOP] {msg}", style="bold red")
|
|
288
360
|
return RpaRetornoProcessoDTO(
|
|
289
361
|
sucesso=False,
|
|
290
|
-
retorno=
|
|
362
|
+
retorno=msg,
|
|
291
363
|
status=RpaHistoricoStatusEnum.Falha,
|
|
292
|
-
tags=[RpaTagDTO(descricao=RpaTagEnum.
|
|
364
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
293
365
|
)
|
|
294
|
-
|
|
366
|
+
|
|
367
|
+
console.print(f"[CFOP] CFOP selecionado com base em {cfop_key_escolhido}. CFOP original da NF: {cfop}", style="bold green")
|
|
368
|
+
|
|
295
369
|
await worker_sleep(3)
|
|
296
370
|
|
|
297
|
-
#
|
|
298
|
-
|
|
371
|
+
# ================= ALMOXARIFADO =================
|
|
372
|
+
console.print("[ALMOXARIFADO] Iniciando preenchimento do almoxarifado...", style="bold cyan")
|
|
373
|
+
fornecedor_nome = dados_nf[0]["fornecedorNome"]
|
|
299
374
|
empresaCodigo = dados_nf[0]["empresaCodigo"]
|
|
300
|
-
console.print(
|
|
301
|
-
|
|
302
|
-
)
|
|
375
|
+
console.print(f"[ALMOXARIFADO] Fornecedor: {fornecedor_nome} | EmpresaCodigo: {empresaCodigo}", style="cyan")
|
|
376
|
+
console.print(f"[ALMOXARIFADO] Inserindo informação do Almoxarifado para empresa_codigo={empresa_codigo}...", style="cyan")
|
|
303
377
|
try:
|
|
304
|
-
new_app = Application(backend="uia").connect(
|
|
305
|
-
title="Informações para importação da Nota Fiscal Eletrônica"
|
|
306
|
-
)
|
|
378
|
+
new_app = Application(backend="uia").connect(title="Informações para importação da Nota Fiscal Eletrônica")
|
|
307
379
|
window = new_app["Informações para importação da Nota Fiscal Eletrônica"]
|
|
308
|
-
edit = window.child_window(
|
|
309
|
-
class_name="TDBIEditCode", found_index=3, control_type="Edit"
|
|
310
|
-
)
|
|
380
|
+
edit = window.child_window(class_name="TDBIEditCode", found_index=3, control_type="Edit")
|
|
311
381
|
if empresa_codigo == '1':
|
|
312
382
|
valor_almoxarifado = empresaCodigo + "60"
|
|
313
383
|
else:
|
|
314
384
|
valor_almoxarifado = empresaCodigo + "50"
|
|
385
|
+
console.print(f"[ALMOXARIFADO] Valor a ser inserido no almoxarifado: {valor_almoxarifado}", style="cyan")
|
|
315
386
|
edit.set_edit_text(valor_almoxarifado)
|
|
316
387
|
edit.type_keys("{TAB}")
|
|
388
|
+
console.print("[ALMOXARIFADO] Almoxarifado preenchido com sucesso.", style="bold green")
|
|
317
389
|
except Exception as e:
|
|
318
|
-
console.print(f"Erro ao iterar itens de almoxarifado: {e}")
|
|
390
|
+
console.print(f"[ALMOXARIFADO] Erro ao iterar itens de almoxarifado: {e}", style="bold red")
|
|
319
391
|
return RpaRetornoProcessoDTO(
|
|
320
392
|
sucesso=False,
|
|
321
393
|
retorno=f"Erro ao iterar itens de almoxarifado: {e}",
|
|
@@ -323,14 +395,19 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
323
395
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
324
396
|
)
|
|
325
397
|
|
|
326
|
-
await worker_sleep(
|
|
327
|
-
|
|
398
|
+
await worker_sleep(3)
|
|
399
|
+
|
|
400
|
+
# ================= DESPESA =================
|
|
401
|
+
console.print("[DESPESA] Inserindo conta contábil / tipo de despesa...", style="bold cyan")
|
|
328
402
|
despesa = nota.get('contaContabil')
|
|
403
|
+
console.print(f"[DESPESA] Conta contábil original: {despesa}", style="cyan")
|
|
329
404
|
despesa = despesa.split("-")[0].strip()
|
|
405
|
+
console.print(f"[DESPESA] Conta contábil tratada (apenas código): {despesa}", style="cyan")
|
|
330
406
|
tipo_despesa_work = await tipo_despesa(despesa)
|
|
331
|
-
if tipo_despesa_work.sucesso
|
|
407
|
+
if tipo_despesa_work.sucesso:
|
|
332
408
|
console.log(tipo_despesa_work.retorno, style="bold green")
|
|
333
409
|
else:
|
|
410
|
+
console.print("[DESPESA] Falha na função tipo_despesa.", style="bold red")
|
|
334
411
|
return RpaRetornoProcessoDTO(
|
|
335
412
|
sucesso=False,
|
|
336
413
|
retorno=tipo_despesa_work.retorno,
|
|
@@ -340,16 +417,12 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
340
417
|
await worker_sleep(5)
|
|
341
418
|
|
|
342
419
|
try:
|
|
343
|
-
console.print("Verificando se existe
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
# Acessar a janela buscar
|
|
348
|
-
janela = app.window(class_name="TFrmBuscaGeralDialog")
|
|
420
|
+
console.print("[DESPESA] Verificando se existe tela de busca de tipo de despesa (TFrmBuscaGeralDialog)...", style="bold cyan")
|
|
421
|
+
app_busca = Application(backend="win32").connect(class_name="TFrmBuscaGeralDialog")
|
|
422
|
+
janela = app_busca.window(class_name="TFrmBuscaGeralDialog")
|
|
349
423
|
janela.set_focus()
|
|
350
|
-
# Clicar em canelar
|
|
351
424
|
janela.child_window(title="&Cancelar", class_name="TBitBtn").click()
|
|
352
|
-
console.print("Tipo de despesa não
|
|
425
|
+
console.print("[DESPESA] Tela de busca de tipo de despesa encontrada. Tipo de despesa não localizado.", style="yellow")
|
|
353
426
|
return RpaRetornoProcessoDTO(
|
|
354
427
|
sucesso=False,
|
|
355
428
|
retorno="Tipo de Despesa / conta contábil não localizado",
|
|
@@ -357,12 +430,18 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
357
430
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
358
431
|
)
|
|
359
432
|
except:
|
|
433
|
+
console.print("[DESPESA] Tela de busca de tipo de despesa não apareceu. Seguindo fluxo normalmente.", style="cyan")
|
|
360
434
|
pass
|
|
361
|
-
|
|
435
|
+
|
|
436
|
+
await worker_sleep(3)
|
|
437
|
+
|
|
438
|
+
# ================= ICMS HEADER =================
|
|
439
|
+
console.print("[ICMS] Ativando checkbox 'Zerar ICMS'...", style="bold cyan")
|
|
362
440
|
checkbox_zerar_icms = await zerar_icms()
|
|
363
|
-
if checkbox_zerar_icms.sucesso
|
|
441
|
+
if checkbox_zerar_icms.sucesso:
|
|
364
442
|
console.log(checkbox_zerar_icms.retorno, style="bold green")
|
|
365
443
|
else:
|
|
444
|
+
console.print("[ICMS] Falha na função zerar_icms.", style="bold red")
|
|
366
445
|
return RpaRetornoProcessoDTO(
|
|
367
446
|
sucesso=False,
|
|
368
447
|
retorno=checkbox_zerar_icms.retorno,
|
|
@@ -370,15 +449,17 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
370
449
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
371
450
|
)
|
|
372
451
|
|
|
373
|
-
|
|
374
|
-
if
|
|
452
|
+
console.print("[ICMS] Definindo código ICMS conforme CFOP mapeado...", style="bold cyan")
|
|
453
|
+
if cfop_key_escolhido == '1556':
|
|
375
454
|
codigo_icms = '33'
|
|
376
455
|
else:
|
|
377
456
|
codigo_icms = '20'
|
|
457
|
+
console.print(f"[ICMS] Código ICMS escolhido: {codigo_icms}", style="cyan")
|
|
378
458
|
cod_icms_work = await cod_icms(codigo_icms)
|
|
379
|
-
if cod_icms_work.sucesso
|
|
459
|
+
if cod_icms_work.sucesso:
|
|
380
460
|
console.log(cod_icms_work.retorno, style="bold green")
|
|
381
461
|
else:
|
|
462
|
+
console.print("[ICMS] Falha na função cod_icms.", style="bold red")
|
|
382
463
|
return RpaRetornoProcessoDTO(
|
|
383
464
|
sucesso=False,
|
|
384
465
|
retorno=cod_icms_work.retorno,
|
|
@@ -386,80 +467,81 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
386
467
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
387
468
|
)
|
|
388
469
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
)
|
|
470
|
+
await worker_sleep(3)
|
|
471
|
+
|
|
472
|
+
console.print("[CFOP] Selecionando a opção 'Manter Natureza de Operação selecionada'...", style="bold cyan")
|
|
393
473
|
checkbox = window.child_window(
|
|
394
474
|
title="Manter Natureza de Operação selecionada",
|
|
395
475
|
class_name="TDBICheckBox",
|
|
396
476
|
)
|
|
397
477
|
if not checkbox.get_toggle_state() == 1:
|
|
398
478
|
checkbox.click()
|
|
399
|
-
console.print(
|
|
400
|
-
|
|
401
|
-
)
|
|
479
|
+
console.print("[CFOP] Opção 'Manter Natureza de Operação selecionada' marcada com sucesso.", style="bold green")
|
|
480
|
+
else:
|
|
481
|
+
console.print("[CFOP] Opção 'Manter Natureza de Operação selecionada' já estava marcada.", style="cyan")
|
|
402
482
|
|
|
403
|
-
await worker_sleep(
|
|
404
|
-
console.print("Clicando em OK...
|
|
483
|
+
await worker_sleep(3)
|
|
484
|
+
console.print("[CFOP] Clicando em OK para confirmar informações da importação...", style="bold cyan")
|
|
405
485
|
|
|
406
486
|
max_attempts = 3
|
|
407
487
|
i = 0
|
|
408
488
|
while i < max_attempts:
|
|
409
|
-
console.print("
|
|
489
|
+
console.print(f"[CFOP] Tentativa {i+1}/{max_attempts} de clicar no botão OK...", style="cyan")
|
|
410
490
|
try:
|
|
411
491
|
try:
|
|
412
492
|
btn_ok = main_window.child_window(title="Ok")
|
|
413
493
|
btn_ok.click()
|
|
494
|
+
console.print("[CFOP] Clique no botão 'Ok' realizado.", style="cyan")
|
|
414
495
|
except:
|
|
415
496
|
btn_ok = main_window.child_window(title="&Ok")
|
|
416
497
|
btn_ok.click()
|
|
498
|
+
console.print("[CFOP] Clique no botão '&Ok' realizado.", style="cyan")
|
|
417
499
|
except:
|
|
418
|
-
console.print("Não foi
|
|
500
|
+
console.print("[CFOP] Não foi possível clicar no botão OK nesta tentativa.", style="yellow")
|
|
419
501
|
|
|
420
502
|
await worker_sleep(3)
|
|
421
503
|
|
|
422
|
-
console.print(
|
|
423
|
-
"Verificando a existencia da tela Informações para importação da Nota Fiscal Eletrônica...\n"
|
|
424
|
-
)
|
|
425
|
-
|
|
426
504
|
try:
|
|
427
505
|
informacao_nf_eletronica = await is_window_open(
|
|
428
506
|
"Informações para importação da Nota Fiscal Eletrônica"
|
|
429
507
|
)
|
|
430
508
|
if not informacao_nf_eletronica["IsOpened"]:
|
|
431
|
-
console.print(
|
|
432
|
-
"Tela Informações para importação da Nota Fiscal Eletrônica fechada, seguindo com o processo"
|
|
433
|
-
)
|
|
509
|
+
console.print("[CFOP] Tela de Informações para importação fechada. Prosseguindo...", style="bold green")
|
|
434
510
|
break
|
|
511
|
+
else:
|
|
512
|
+
console.print("[CFOP] Tela ainda aberta após clique em OK.", style="yellow")
|
|
435
513
|
except Exception as e:
|
|
436
|
-
console.print(
|
|
437
|
-
f"Tela Informações para importação da Nota Fiscal Eletrônica encontrada. Tentativa {i + 1}/{max_attempts}."
|
|
438
|
-
)
|
|
514
|
+
console.print(f"[CFOP] Erro ao verificar tela de informações: {e}. Tentativa {i+1}/{max_attempts}.", style="bold red")
|
|
439
515
|
|
|
440
516
|
i += 1
|
|
441
517
|
|
|
442
518
|
if i == max_attempts:
|
|
519
|
+
msg = "Número máximo de tentativas atingido, Não foi possivel finalizar os trabalhos na tela de Informações para importação da Nota Fiscal Eletrônica"
|
|
520
|
+
console.print(f"[CFOP] {msg}", style="bold red")
|
|
443
521
|
return RpaRetornoProcessoDTO(
|
|
444
522
|
sucesso=False,
|
|
445
|
-
retorno=
|
|
523
|
+
retorno=msg,
|
|
446
524
|
status=RpaHistoricoStatusEnum.Falha,
|
|
447
525
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
448
526
|
)
|
|
449
527
|
|
|
450
528
|
await worker_sleep(10)
|
|
451
529
|
|
|
530
|
+
# ================= ITENS =================
|
|
531
|
+
console.print("[ITENS] Verificando pop-up de itens não localizados / NCM...", style="bold cyan")
|
|
452
532
|
try:
|
|
453
|
-
console.print("Verificando itens não localizados ou NCM...\n")
|
|
454
533
|
itens_by_supplier = await is_window_open_by_class("TFrmAguarde", "TMessageForm")
|
|
534
|
+
console.print(f"[ITENS] Retorno is_window_open_by_class: {itens_by_supplier}", style="cyan")
|
|
455
535
|
|
|
456
|
-
if itens_by_supplier["IsOpened"]
|
|
536
|
+
if itens_by_supplier["IsOpened"]:
|
|
537
|
+
console.print("[ITENS] Pop-up de itens não localizados encontrado. Chamando itens_not_found_supplier...", style="yellow")
|
|
457
538
|
itens_by_supplier_work = await itens_not_found_supplier(nota.get("nfe"))
|
|
458
|
-
|
|
459
539
|
if not itens_by_supplier_work.sucesso:
|
|
540
|
+
console.print("[ITENS] Tratativa de itens não localizados retornou falha.", style="bold red")
|
|
460
541
|
return itens_by_supplier_work
|
|
461
542
|
|
|
462
543
|
except Exception as error:
|
|
544
|
+
console.print(f"[ITENS] Falha ao verificar POP-UP de itens não localizados: {error}", style="bold red")
|
|
463
545
|
return RpaRetornoProcessoDTO(
|
|
464
546
|
sucesso=False,
|
|
465
547
|
retorno=f"Falha ao verificar a existência de POP-UP de itens não localizados: {error}",
|
|
@@ -469,31 +551,35 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
469
551
|
|
|
470
552
|
await worker_sleep(10)
|
|
471
553
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
# Tenta localizar a imagem na tela
|
|
554
|
+
console.print("[ITENS] Localizando botão 'Itens da Nota' via imagem...", style="bold cyan")
|
|
555
|
+
imagem_itens = fr"{BASE_PATH}\itens_nota.png"
|
|
556
|
+
tentativas_img = 0
|
|
477
557
|
while True:
|
|
478
|
-
|
|
558
|
+
tentativas_img += 1
|
|
559
|
+
console.print(f"[ITENS] Tentativa {tentativas_img} de localizar itens_nota.png...", style="cyan")
|
|
560
|
+
local = pyautogui.locateCenterOnScreen(imagem_itens, confidence=0.8)
|
|
479
561
|
if local:
|
|
480
|
-
pyautogui.click(local)
|
|
481
|
-
print("Imagem encontrada e clicada!")
|
|
562
|
+
pyautogui.click(local)
|
|
563
|
+
console.print("[ITENS] Imagem 'itens_nota.png' encontrada e clicada com sucesso!", style="bold green")
|
|
482
564
|
break
|
|
483
565
|
else:
|
|
484
|
-
print("Imagem não encontrada, tentando novamente...")
|
|
566
|
+
console.print("[ITENS] Imagem 'itens_nota.png' não encontrada, tentando novamente...", style="yellow")
|
|
485
567
|
time.sleep(1)
|
|
486
568
|
|
|
487
569
|
await worker_sleep(3)
|
|
488
|
-
|
|
570
|
+
console.print("[ITENS] Clicando em 'Itens da nota' por coordenada (fallback)...", style="cyan")
|
|
489
571
|
pyautogui.click(791, 379)
|
|
490
572
|
await worker_sleep(2)
|
|
573
|
+
|
|
574
|
+
console.print("[ITENS] Obtendo índice do último item via get_ultimo_item()...", style="bold cyan")
|
|
491
575
|
index_item_atual = 0
|
|
492
576
|
index_ultimo_item = await get_ultimo_item()
|
|
493
|
-
console.print(f"Index
|
|
577
|
+
console.print(f"[ITENS] Index último item retornado: {index_ultimo_item}", style="bold green")
|
|
494
578
|
|
|
495
579
|
try:
|
|
580
|
+
console.print("[ITENS] Iniciando loop para tratar ICMS/IPI item a item...", style="bold cyan")
|
|
496
581
|
while index_item_atual < index_ultimo_item:
|
|
582
|
+
console.print(f"[ITENS] Início do processamento do item índice {index_item_atual+1}/{index_ultimo_item}...", style="cyan")
|
|
497
583
|
send_keys("^({HOME})")
|
|
498
584
|
await worker_sleep(1)
|
|
499
585
|
|
|
@@ -508,32 +594,25 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
508
594
|
send_keys("{ENTER}")
|
|
509
595
|
|
|
510
596
|
await worker_sleep(2)
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
main_window.set_focus()
|
|
597
|
+
app_alt = Application().connect(title="Alteração de Item")
|
|
598
|
+
win_alt = app_alt["Alteração de Item"]
|
|
599
|
+
win_alt.set_focus()
|
|
515
600
|
|
|
516
|
-
|
|
517
|
-
class_name="TDBIEditCode", found_index=0
|
|
518
|
-
)
|
|
601
|
+
_ = win_alt.child_window(class_name="TDBIEditCode", found_index=0)
|
|
519
602
|
index_item_atual += 1
|
|
520
|
-
console.print(f"
|
|
603
|
+
console.print(f"[ITENS] Ítem atual no final da execução da tela: {index_item_atual}", style="cyan")
|
|
521
604
|
await worker_sleep(1)
|
|
522
|
-
|
|
605
|
+
|
|
523
606
|
lista_icms_090 = ["5101", "5102", "5103", "5104"]
|
|
524
607
|
lista_icms_060 = ["5401", "5403", "5404", "5405", "6104", "6401", "6403", "6404", "6405"]
|
|
525
608
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
609
|
+
console.print("[ITENS] Conectando na janela TFrmAlteraItemNFE para ajuste ICMS/IPI...", style="cyan")
|
|
610
|
+
app_item = Application().connect(class_name="TFrmAlteraItemNFE")
|
|
611
|
+
win_item = app_item["TFrmAlteraItemNFE"]
|
|
612
|
+
win_item.set_focus()
|
|
530
613
|
|
|
614
|
+
tipo_icms = win_item.child_window(class_name="TDBIComboBox", found_index=5)
|
|
531
615
|
|
|
532
|
-
# Localiza o combobox
|
|
533
|
-
|
|
534
|
-
tipo_icms = main_window.child_window(class_name="TDBIComboBox", found_index=5)
|
|
535
|
-
|
|
536
|
-
# Define o texto da opção desejada
|
|
537
616
|
if cfop in lista_icms_090:
|
|
538
617
|
opcao_desejada = "090 - ICMS NACIONAL OUTRAS"
|
|
539
618
|
elif cfop in lista_icms_060:
|
|
@@ -541,262 +620,320 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
541
620
|
else:
|
|
542
621
|
opcao_desejada = None
|
|
543
622
|
|
|
544
|
-
|
|
623
|
+
console.print(f"[ITENS] CFOP item={cfop} | Opção ICMS desejada: {opcao_desejada}", style="cyan")
|
|
624
|
+
|
|
545
625
|
if opcao_desejada:
|
|
546
626
|
try:
|
|
547
627
|
tipo_icms.select(opcao_desejada)
|
|
548
628
|
send_keys("{ENTER}")
|
|
629
|
+
console.print(f"[ITENS] Tipo ICMS '{opcao_desejada}' selecionado com sucesso.", style="bold green")
|
|
549
630
|
except Exception as e:
|
|
550
|
-
print(f"Erro ao selecionar opção: {e}")
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
631
|
+
console.print(f"[ITENS] Erro ao selecionar opção ICMS no combobox: {e}", style="bold red")
|
|
632
|
+
|
|
633
|
+
combo_ipi = win_item.child_window(class_name="TDBIComboBox", found_index=4)
|
|
634
|
+
console.print("[ITENS] Selecionando IPI 0% no combobox de IPI...", style="cyan")
|
|
635
|
+
combo_ipi.select("IPI 0%")
|
|
636
|
+
console.print("[ITENS] IPI 0% selecionado com sucesso.", style="bold green")
|
|
556
637
|
|
|
557
|
-
|
|
558
|
-
|
|
638
|
+
console.print("[ITENS] Clicando em 'Alterar' para confirmar mudanças do item...", style="cyan")
|
|
639
|
+
win_item.child_window(class_name="TDBIBitBtn", found_index=3).click()
|
|
640
|
+
else:
|
|
641
|
+
console.print("[ITENS] Nenhuma opção ICMS mapeada para este CFOP de item. Item será mantido como está.", style="yellow")
|
|
642
|
+
|
|
559
643
|
await worker_sleep(5)
|
|
560
644
|
except Exception as e:
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
645
|
+
console.print(f"[ITENS] Erro geral ao trabalhar nas alterações dos itens: {e}", style="bold red")
|
|
646
|
+
return RpaRetornoProcessoDTO(
|
|
647
|
+
sucesso=False,
|
|
648
|
+
retorno=f"Erro aotrabalhar nas alterações dos itens: {e}",
|
|
649
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
650
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
console.print("[ITENS] Finalizado o tratamento de todos os itens. Verificando pop-up de confirmação TMessageForm...", style="bold cyan")
|
|
654
|
+
try:
|
|
655
|
+
app_msg = Application().connect(class_name="TMessageForm")
|
|
656
|
+
win_msg = app_msg["TMessageForm"]
|
|
657
|
+
btn_ok = win_msg.child_window(title="&Yes", class_name="TButton")
|
|
658
|
+
btn_ok.click_input()
|
|
659
|
+
console.print("[ITENS] Pop-up TMessageForm confirmado com &Yes.", style="bold green")
|
|
660
|
+
except:
|
|
661
|
+
console.print("[ITENS] Nenhum pop-up TMessageForm de confirmação encontrado. Seguindo...", style="cyan")
|
|
662
|
+
pass
|
|
566
663
|
await worker_sleep(10)
|
|
567
664
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
665
|
+
# ===================== PAGAMENTOS =====================
|
|
666
|
+
console.print("[PAGAMENTOS] Navegando pela janela de Nota Fiscal de Entrada (TFrmNotaFiscalEntrada)...", style="bold cyan")
|
|
667
|
+
app_nf = Application().connect(class_name="TFrmNotaFiscalEntrada")
|
|
668
|
+
nf_window = app_nf["TFrmNotaFiscalEntrada"]
|
|
571
669
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
imagem = "assets\\entrada_notas\\pagamentos.png"
|
|
670
|
+
console.print("[PAGAMENTOS] Localizando aba 'Pagamentos' via imagem pagamentos.png...", style="bold cyan")
|
|
671
|
+
img_pag = fr"{BASE_PATH}\pagamentos.png"
|
|
575
672
|
|
|
576
|
-
|
|
673
|
+
tentativas_pag = 0
|
|
577
674
|
while True:
|
|
578
|
-
|
|
675
|
+
tentativas_pag += 1
|
|
676
|
+
console.print(f"[PAGAMENTOS] Tentativa {tentativas_pag} de localizar 'pagamentos.png'...", style="cyan")
|
|
677
|
+
local = pyautogui.locateCenterOnScreen(img_pag, confidence=0.9)
|
|
579
678
|
if local:
|
|
580
|
-
pyautogui.click(local)
|
|
581
|
-
print("Imagem encontrada e clicada!")
|
|
679
|
+
pyautogui.click(local)
|
|
680
|
+
console.print("[PAGAMENTOS] Imagem 'pagamentos.png' encontrada e clicada com sucesso!", style="bold green")
|
|
582
681
|
break
|
|
583
682
|
else:
|
|
584
|
-
print("Imagem não encontrada, tentando novamente...")
|
|
683
|
+
console.print("[PAGAMENTOS] Imagem 'pagamentos.png' não encontrada, tentando novamente...", style="yellow")
|
|
585
684
|
time.sleep(1)
|
|
586
685
|
|
|
587
686
|
await worker_sleep(3)
|
|
588
687
|
|
|
589
|
-
|
|
590
|
-
panel_TTabSheet = panel_TPage.child_window(class_name="TPageControl")
|
|
591
|
-
|
|
592
|
-
panel_TabPagamento = panel_TTabSheet.child_window(title="Pagamento")
|
|
593
|
-
|
|
594
|
-
# Combo alvo (ajuste found_index se precisar)
|
|
595
|
-
tipo_cobranca = panel_TTabSheet.child_window(class_name="TDBIComboBox", found_index=0)
|
|
596
|
-
|
|
597
|
-
# Ordem de preferência
|
|
688
|
+
console.print("[PAGAMENTOS] Localizando combobox de Tipo de Cobrança na janela principal...", style="bold cyan")
|
|
598
689
|
opcoes = [
|
|
599
690
|
"BANCO DO BRASIL BOLETO FIDC",
|
|
600
691
|
"BANCO DO BRASIL BOLETO",
|
|
601
692
|
"BOLETO",
|
|
602
693
|
]
|
|
694
|
+
console.print(f"[PAGAMENTOS] Ordem de preferência tipo de cobrança: {opcoes}", style="cyan")
|
|
695
|
+
|
|
696
|
+
tipo_cobranca = None
|
|
697
|
+
try:
|
|
698
|
+
# primeiro chute: found_index=0 na janela principal
|
|
699
|
+
tipo_cobranca = nf_window.child_window(class_name="TDBIComboBox", found_index=0)
|
|
700
|
+
console.print("[PAGAMENTOS] Combobox de cobrança encontrado via found_index=0 na janela principal.", style="cyan")
|
|
701
|
+
except Exception as e:
|
|
702
|
+
console.print(f"[PAGAMENTOS] Falha ao localizar combobox de cobrança por found_index=0: {e}", style="yellow")
|
|
703
|
+
tipo_cobranca = None
|
|
704
|
+
|
|
705
|
+
if not tipo_cobranca:
|
|
706
|
+
console.print("[PAGAMENTOS] Tentando localizar combobox correto de cobrança analisando todos os TDBIComboBox...", style="cyan")
|
|
707
|
+
try:
|
|
708
|
+
candidatos = nf_window.descendants(class_name="TDBIComboBox")
|
|
709
|
+
except Exception as e:
|
|
710
|
+
console.print(f"[PAGAMENTOS] Erro ao obter descendants TDBIComboBox: {e}", style="bold red")
|
|
711
|
+
candidatos = []
|
|
712
|
+
|
|
713
|
+
for i, combo in enumerate(candidatos):
|
|
714
|
+
try:
|
|
715
|
+
itens_combo = [t.strip() for t in combo.item_texts() if str(t).strip()]
|
|
716
|
+
console.print(f"[PAGAMENTOS] Combo {i} itens encontrados: {itens_combo}", style="cyan")
|
|
717
|
+
texto_unico = " | ".join(itens_combo).lower()
|
|
718
|
+
if any(op.lower() in texto_unico for op in opcoes):
|
|
719
|
+
tipo_cobranca = combo
|
|
720
|
+
console.print(f"[PAGAMENTOS] Combo {i} escolhido como Tipo de Cobrança (contém alguma opção esperada).", style="bold green")
|
|
721
|
+
break
|
|
722
|
+
except Exception as e:
|
|
723
|
+
console.print(f"[PAGAMENTOS] Erro ao ler itens do combo {i}: {e}", style="yellow")
|
|
603
724
|
|
|
604
|
-
|
|
725
|
+
if not tipo_cobranca:
|
|
726
|
+
raise RuntimeError("Não foi possível localizar o combobox de Tipo de Cobrança na janela de Nota Fiscal de Entrada.")
|
|
727
|
+
|
|
728
|
+
# 1) Tenta select direto
|
|
605
729
|
selecionado = None
|
|
606
730
|
for alvo in opcoes:
|
|
607
731
|
try:
|
|
608
732
|
tipo_cobranca.select(alvo)
|
|
609
733
|
if tipo_cobranca.window_text().strip().lower() == alvo.lower():
|
|
610
734
|
selecionado = alvo
|
|
735
|
+
console.print(f"[PAGAMENTOS] Tipo de cobrança selecionado diretamente via .select(): {alvo}", style="bold green")
|
|
611
736
|
break
|
|
612
737
|
except Exception:
|
|
738
|
+
console.print(f"[PAGAMENTOS] Falha ao selecionar opção '{alvo}' via .select(). Tentando próximas opções...", style="yellow")
|
|
613
739
|
pass
|
|
614
740
|
|
|
615
|
-
# 2)
|
|
741
|
+
# 2) Fallback: HOME + DOWN lendo texto
|
|
616
742
|
if not selecionado:
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
itens = []
|
|
638
|
-
|
|
639
|
-
idx_alvo = -1
|
|
640
|
-
alvo_escolhido = None
|
|
641
|
-
for alvo in opcoes:
|
|
642
|
-
for i, t in enumerate(itens):
|
|
643
|
-
if t.lower() == alvo.lower():
|
|
644
|
-
idx_alvo = i
|
|
645
|
-
alvo_escolhido = alvo
|
|
646
|
-
break
|
|
647
|
-
if idx_alvo >= 0:
|
|
743
|
+
console.print("[PAGAMENTOS] Tentando selecionar tipo de cobrança navegando com setas (HOME + DOWN)...", style="bold cyan")
|
|
744
|
+
try:
|
|
745
|
+
tipo_cobranca.set_focus()
|
|
746
|
+
tipo_cobranca.click_input()
|
|
747
|
+
except Exception as e:
|
|
748
|
+
console.print(f"[PAGAMENTOS] Erro ao focar/clicar no combobox de cobrança: {e}", style="yellow")
|
|
749
|
+
|
|
750
|
+
send_keys('{HOME}')
|
|
751
|
+
vistos = set()
|
|
752
|
+
for _ in range(80):
|
|
753
|
+
atual = tipo_cobranca.window_text().strip()
|
|
754
|
+
atual_lower = atual.lower()
|
|
755
|
+
console.print(f"[PAGAMENTOS] Opção atualmente exibida no combo: '{atual}'", style="cyan")
|
|
756
|
+
|
|
757
|
+
match = False
|
|
758
|
+
for o in opcoes:
|
|
759
|
+
o_lower = o.lower()
|
|
760
|
+
if o_lower == atual_lower or o_lower in atual_lower:
|
|
761
|
+
match = True
|
|
762
|
+
selecionado = atual
|
|
648
763
|
break
|
|
649
764
|
|
|
650
|
-
if
|
|
651
|
-
try:
|
|
652
|
-
lista.select(idx_alvo)
|
|
653
|
-
except Exception:
|
|
654
|
-
# fallback por teclas sem digitar texto do item
|
|
655
|
-
send_keys('{HOME}')
|
|
656
|
-
for _ in range(idx_alvo):
|
|
657
|
-
send_keys('{DOWN}')
|
|
765
|
+
if match:
|
|
658
766
|
send_keys('{ENTER}')
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
except PywTimeout:
|
|
662
|
-
pass
|
|
663
|
-
if tipo_cobranca.window_text().strip().lower() == alvo_escolhido.lower():
|
|
664
|
-
selecionado = alvo_escolhido
|
|
665
|
-
else:
|
|
666
|
-
# fallback só com setas (sem digitar): vai ao topo e desce checando
|
|
667
|
-
send_keys('{HOME}')
|
|
668
|
-
vistos = set()
|
|
669
|
-
for _ in range(60):
|
|
670
|
-
atual = tipo_cobranca.window_text().strip()
|
|
671
|
-
if atual.lower() in (o.lower() for o in opcoes):
|
|
672
|
-
send_keys('{ENTER}')
|
|
673
|
-
selecionado = atual
|
|
674
|
-
break
|
|
675
|
-
if atual.lower() in vistos:
|
|
676
|
-
# deu a volta
|
|
677
|
-
send_keys('{ESC}')
|
|
678
|
-
break
|
|
679
|
-
vistos.add(atual.lower())
|
|
680
|
-
send_keys('{DOWN}')
|
|
767
|
+
console.print(f"[PAGAMENTOS] Tipo de cobrança selecionado via navegação por setas: '{selecionado}'", style="bold green")
|
|
768
|
+
break
|
|
681
769
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
770
|
+
if atual_lower in vistos:
|
|
771
|
+
console.print("[PAGAMENTOS] Deu a volta na lista de tipos de cobrança. Abortando navegação.", style="yellow")
|
|
772
|
+
break
|
|
685
773
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
dt_vencimento_nota = nota.get("dataVencimento") # vem como '2025-09-26'
|
|
689
|
-
data_atual = datetime.now().date()
|
|
774
|
+
vistos.add(atual_lower)
|
|
775
|
+
send_keys('{DOWN}')
|
|
690
776
|
|
|
691
|
-
|
|
692
|
-
|
|
777
|
+
erro_tipo = tipo_cobranca.window_text().strip()
|
|
778
|
+
erro_tipo_lower = erro_tipo.lower()
|
|
693
779
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
780
|
+
valido = False
|
|
781
|
+
for o in opcoes:
|
|
782
|
+
o_lower = o.lower()
|
|
783
|
+
if o_lower == erro_tipo_lower or o_lower in erro_tipo_lower:
|
|
784
|
+
valido = True
|
|
785
|
+
break
|
|
786
|
+
|
|
787
|
+
if not selecionado or not valido:
|
|
788
|
+
console.print(
|
|
789
|
+
f"[PAGAMENTOS] Não foi possível confirmar uma opção válida de cobrança. Ficou: '{erro_tipo}'",
|
|
790
|
+
style="bold red"
|
|
791
|
+
)
|
|
792
|
+
raise RuntimeError(f"Não consegui selecionar uma opção válida. Ficou: '{erro_tipo}'")
|
|
793
|
+
|
|
794
|
+
console.print(f"[PAGAMENTOS] Tipo de cobrança final selecionado: {erro_tipo}", style="bold green")
|
|
795
|
+
|
|
796
|
+
# ========= DATA DE VENCIMENTO =========
|
|
797
|
+
console.print("[PAGAMENTOS] Calculando e ajustando data de vencimento da parcela...", style="bold cyan")
|
|
798
|
+
dt_vencimento_nota = nota.get("dataVencimento")
|
|
799
|
+
data_atual_date = datetime.now().date()
|
|
800
|
+
console.print(f"[PAGAMENTOS] Data vencimento original (configEntrada): {dt_vencimento_nota}", style="cyan")
|
|
801
|
+
|
|
802
|
+
data_vencimento = datetime.strptime(dt_vencimento_nota, "%Y-%m-%d").date()
|
|
697
803
|
|
|
698
|
-
|
|
699
|
-
|
|
804
|
+
if data_vencimento <= data_atual_date:
|
|
805
|
+
console.print("[PAGAMENTOS] Data de vencimento original é hoje ou já passou. Ajustando para próximo dia útil...", style="yellow")
|
|
806
|
+
data_vencimento = data_atual_date + timedelta(days=1)
|
|
807
|
+
while data_vencimento.weekday() >= 5:
|
|
700
808
|
data_vencimento += timedelta(days=1)
|
|
701
809
|
|
|
702
|
-
# Converter para string (formato brasileiro dd/mm/yyyy)
|
|
703
810
|
data_vencimento_str = data_vencimento.strftime("%d/%m/%Y")
|
|
704
|
-
print("
|
|
705
|
-
|
|
706
|
-
# Inserir no campo
|
|
707
|
-
data_venc = panel_TTabSheet.child_window(
|
|
708
|
-
class_name="TDBIEditDate", found_index=0
|
|
709
|
-
)
|
|
811
|
+
console.print(f"[PAGAMENTOS] Nova data de vencimento calculada: {data_vencimento_str}", style="bold green")
|
|
710
812
|
|
|
813
|
+
console.print("[PAGAMENTOS] Inserindo data de vencimento no campo TDBIEditDate (found_index=0)...", style="cyan")
|
|
814
|
+
data_venc = nf_window.child_window(class_name="TDBIEditDate", found_index=0)
|
|
711
815
|
data_venc.set_edit_text(data_vencimento_str)
|
|
712
816
|
|
|
713
|
-
console.print(
|
|
817
|
+
console.print("[PAGAMENTOS] Incluindo registro de parcela (delete + inclui novamente)...", style="bold cyan")
|
|
818
|
+
|
|
819
|
+
try:
|
|
820
|
+
console.print("[PAGAMENTOS] Excluindo parcela existente (se houver)...", style="cyan")
|
|
821
|
+
nf_window.child_window(class_name="TDBIBitBtn", found_index=0).click_input()
|
|
822
|
+
await worker_sleep(3)
|
|
823
|
+
app_del = Application().connect(class_name="TMessageForm")
|
|
824
|
+
main_del = app_del["TMessageForm"]
|
|
825
|
+
btn_ok = main_del.child_window(title="&Yes", class_name="TButton")
|
|
826
|
+
btn_ok.click_input()
|
|
827
|
+
console.print("[PAGAMENTOS] Parcela antiga excluída com sucesso.", style="bold green")
|
|
828
|
+
await worker_sleep(3)
|
|
829
|
+
|
|
830
|
+
valor = nf_window.child_window(class_name="TDBIEditNumber", found_index=7)
|
|
831
|
+
valor_encontrado = valor.window_text()
|
|
832
|
+
console.print(f"[PAGAMENTOS] Valor da parcela lido (antes de tratar ponto): {valor_encontrado}", style="cyan")
|
|
833
|
+
valor_encontrado = valor_encontrado.replace(".","")
|
|
834
|
+
console.print(f"[PAGAMENTOS] Valor da parcela após remover '.': {valor_encontrado}", style="cyan")
|
|
835
|
+
|
|
836
|
+
await worker_sleep(3)
|
|
837
|
+
|
|
838
|
+
inserir_valor = nf_window.child_window(class_name="TDBIEditNumber", found_index=3)
|
|
839
|
+
console.print("[PAGAMENTOS] Inserindo valor tratado no campo index 3...", style="cyan")
|
|
840
|
+
inserir_valor.set_focus()
|
|
841
|
+
send_keys("^a{DEL}")
|
|
842
|
+
send_keys(valor_encontrado)
|
|
843
|
+
|
|
844
|
+
console.print("[PAGAMENTOS] Incluindo nova parcela...", style="cyan")
|
|
845
|
+
nf_window.child_window(class_name="TDBIBitBtn", found_index=1).click_input()
|
|
846
|
+
console.print("[PAGAMENTOS] Parcela incluída com sucesso.", style="bold green")
|
|
847
|
+
except Exception as e:
|
|
848
|
+
console.print(f"[PAGAMENTOS] Erro ao excluir/incluir parcela de pagamento: {e}. Prosseguindo com fallback de inclusão de registro.", style="yellow")
|
|
849
|
+
|
|
850
|
+
console.print("[PAGAMENTOS] Tentando incluir registro via imagem IncluirRegistro.png...", style="bold cyan")
|
|
714
851
|
try:
|
|
715
|
-
inserir_registro = pyautogui.locateOnScreen("
|
|
716
|
-
# inserir_registro = pyautogui.locateOnScreen(r"C:\Users\automatehub\Documents\GitHub\worker-automate-hub\assets\entrada_notas\IncluirRegistro.png", confidence=0.8)
|
|
852
|
+
inserir_registro = pyautogui.locateOnScreen(fr"{BASE_PATH}\IncluirRegistro.png", confidence=0.8)
|
|
717
853
|
pyautogui.click(inserir_registro)
|
|
854
|
+
console.print("[PAGAMENTOS] Botão de 'Incluir Registro' clicado via imagem com sucesso.", style="bold green")
|
|
718
855
|
except Exception as e:
|
|
719
856
|
console.print(
|
|
720
|
-
f"Não foi possivel incluir o registro utilizando reconhecimento de imagem, Error: {e}...\n tentando inserir via posição
|
|
857
|
+
f"[PAGAMENTOS] Não foi possivel incluir o registro utilizando reconhecimento de imagem, Error: {e}...\n tentando inserir via posição...",
|
|
858
|
+
style="yellow"
|
|
721
859
|
)
|
|
722
860
|
await incluir_registro()
|
|
861
|
+
console.print("[PAGAMENTOS] Fallback incluir_registro() executado.", style="cyan")
|
|
723
862
|
|
|
724
863
|
await worker_sleep(10)
|
|
725
|
-
|
|
726
|
-
console.print(
|
|
727
|
-
"Verificando a existencia de POP-UP de Itens que Ultrapassam a Variação Máxima de Custo ...\n"
|
|
728
|
-
)
|
|
729
|
-
itens_variacao_maxima = await is_window_open_by_class(
|
|
730
|
-
"TFrmTelaSelecao", "TFrmTelaSelecao"
|
|
731
|
-
)
|
|
732
|
-
if itens_variacao_maxima["IsOpened"] == True:
|
|
733
|
-
app = Application().connect(class_name="TFrmTelaSelecao")
|
|
734
|
-
main_window = app["TFrmTelaSelecao"]
|
|
735
|
-
send_keys("%o")
|
|
736
864
|
|
|
737
|
-
|
|
738
|
-
console.print(
|
|
739
|
-
"Verificando a existencia de Warning informando que a Soma dos pagamentos não bate com o valor da nota. ...\n"
|
|
740
|
-
)
|
|
741
|
-
app = Application().connect(class_name="TFrmNotaFiscalEntrada")
|
|
742
|
-
main_window = app["TFrmNotaFiscalEntrada"]
|
|
865
|
+
# ================= RATEIO / FINALIZAÇÃO =================
|
|
866
|
+
console.print("[RATEIO] Tratando pop-ups e aguardando tela de Rateio da Despesa...", style="bold cyan")
|
|
743
867
|
|
|
744
868
|
try:
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
)
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
status=RpaHistoricoStatusEnum.Falha,
|
|
759
|
-
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
760
|
-
)
|
|
761
|
-
else:
|
|
762
|
-
console.print(
|
|
763
|
-
"Warning informando que a Soma dos pagamentos não bate com o valor da nota não existe ...\n"
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
max_attempts = 7
|
|
767
|
-
i = 0
|
|
768
|
-
aguarde_rateio_despesa = True
|
|
769
|
-
|
|
770
|
-
while i < max_attempts:
|
|
771
|
-
await worker_sleep(3)
|
|
869
|
+
console.print("[RATEIO] Verificando POP-UP 'Itens que Ultrapassam a Variação Máxima de Custo'...", style="cyan")
|
|
870
|
+
itens_variacao_maxima = await is_window_open_by_class("TFrmTelaSelecao", "TFrmTelaSelecao")
|
|
871
|
+
console.print(f"[RATEIO] Retorno is_window_open_by_class para TFrmTelaSelecao: {itens_variacao_maxima}", style="cyan")
|
|
872
|
+
|
|
873
|
+
if itens_variacao_maxima.get("IsOpened"):
|
|
874
|
+
console.print("[RATEIO] Pop-up encontrado. Confirmando (ALT+O)...", style="yellow")
|
|
875
|
+
app_sel = Application().connect(class_name="TFrmTelaSelecao")
|
|
876
|
+
win_sel = app_sel["TFrmTelaSelecao"]
|
|
877
|
+
win_sel.set_focus()
|
|
878
|
+
send_keys("%o")
|
|
879
|
+
console.print("[RATEIO] POP-UP tratado com sucesso.", style="bold green")
|
|
880
|
+
except Exception as error:
|
|
881
|
+
console.print(f"[RATEIO] Falha ao verificar POP-UP de variação máxima: {error}", style="bold red")
|
|
772
882
|
|
|
773
|
-
|
|
883
|
+
await worker_sleep(2)
|
|
774
884
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
885
|
+
console.print("[RATEIO] Verificando se a tela de 'Rateio da Despesa' já está aberta...", style="bold cyan")
|
|
886
|
+
rateio_aberto = False
|
|
887
|
+
try:
|
|
888
|
+
rateio_win = Desktop(backend="uia").window(title_re=".*Rateio.*")
|
|
889
|
+
rateio_aberto = rateio_win.exists(timeout=1)
|
|
890
|
+
console.print(f"[RATEIO] Tela de rateio aberta? {rateio_aberto}", style="cyan")
|
|
891
|
+
except Exception as e:
|
|
892
|
+
console.print(f"[RATEIO] Erro ao verificar tela de rateio: {e}", style="yellow")
|
|
893
|
+
rateio_aberto = False
|
|
782
894
|
|
|
783
|
-
|
|
784
|
-
|
|
895
|
+
if not rateio_aberto:
|
|
896
|
+
console.print("[RATEIO] Tela de rateio não aberta. Verificando Warning de soma pagamentos x valor da nota...", style="cyan")
|
|
897
|
+
try:
|
|
898
|
+
warning_app = Application().connect(title="Warning")
|
|
899
|
+
warning_pop_up_pagamentos = warning_app["Warning"]
|
|
900
|
+
existe_warning_pagamentos = warning_pop_up_pagamentos.exists(timeout=1)
|
|
901
|
+
except Exception:
|
|
902
|
+
existe_warning_pagamentos = False
|
|
785
903
|
|
|
786
|
-
|
|
904
|
+
if existe_warning_pagamentos:
|
|
905
|
+
console.print("[RATEIO] Warning encontrado: soma dos pagamentos não bate com o valor da nota.", style="bold red")
|
|
906
|
+
return RpaRetornoProcessoDTO(
|
|
907
|
+
sucesso=False,
|
|
908
|
+
retorno="A soma dos pagamentos não bate com o valor da nota.",
|
|
909
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
910
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
911
|
+
)
|
|
912
|
+
else:
|
|
913
|
+
console.print("[RATEIO] Warning de soma dos pagamentos não encontrado. Seguindo com o processo...", style="bold green")
|
|
914
|
+
else:
|
|
915
|
+
console.print("[RATEIO] Tela de Rateio da Despesa já está aberta. Ignorando validação de Warning de pagamentos.", style="cyan")
|
|
787
916
|
|
|
788
|
-
|
|
917
|
+
console.print("[RATEIO] Aguardando a tela 'Rateio da Despesa'...", style="bold cyan")
|
|
918
|
+
try:
|
|
919
|
+
rateio_win = Desktop(backend="uia").window(title_re=".*Rateio.*")
|
|
920
|
+
rateio_win.wait("exists enabled visible ready", timeout=30)
|
|
921
|
+
console.print("[RATEIO] Tela 'Rateio da Despesa' encontrada. Prosseguindo com o rateio...", style="bold green")
|
|
922
|
+
except Exception as e:
|
|
923
|
+
console.print(f"[RATEIO] Erro ao aguardar tela de Rateio: {e}", style="bold red")
|
|
789
924
|
return RpaRetornoProcessoDTO(
|
|
790
925
|
sucesso=False,
|
|
791
|
-
retorno=
|
|
926
|
+
retorno="Número máximo de tentativas atingido. A tela para Rateio da Despesa não foi encontrada.",
|
|
792
927
|
status=RpaHistoricoStatusEnum.Falha,
|
|
793
928
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
794
929
|
)
|
|
795
930
|
|
|
931
|
+
console.print("[RATEIO] Chamando função rateio_despesa()...", style="bold cyan")
|
|
796
932
|
despesa_rateio_work = await rateio_despesa(empresaCodigo)
|
|
797
|
-
if despesa_rateio_work.sucesso
|
|
933
|
+
if despesa_rateio_work.sucesso:
|
|
798
934
|
console.log(despesa_rateio_work.retorno, style="bold green")
|
|
799
935
|
else:
|
|
936
|
+
console.print("[RATEIO] Falha ao executar rateio_despesa.", style="bold red")
|
|
800
937
|
return RpaRetornoProcessoDTO(
|
|
801
938
|
sucesso=False,
|
|
802
939
|
retorno=despesa_rateio_work.retorno,
|
|
@@ -804,86 +941,80 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
804
941
|
tags=despesa_rateio_work.tags
|
|
805
942
|
)
|
|
806
943
|
|
|
807
|
-
|
|
944
|
+
console.print("[FINALIZAÇÃO] Aguardando warnings finais e validação da nota lançada...", style="bold cyan")
|
|
808
945
|
await worker_sleep(15)
|
|
809
946
|
warning_pop_up = await is_window_open("Warning")
|
|
810
|
-
if warning_pop_up["IsOpened"]
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
console.print(f"Obtendo texto do Warning...\n")
|
|
816
|
-
console.print(f"Tirando print da janela do warning para realização do OCR...\n")
|
|
947
|
+
if warning_pop_up["IsOpened"]:
|
|
948
|
+
console.print("[FINALIZAÇÃO] Pop-up 'Warning' encontrado no fim do fluxo. Capturando mensagem com OCR...", style="yellow")
|
|
949
|
+
app_w = Application().connect(title="Warning")
|
|
950
|
+
win_w = app_w["Warning"]
|
|
951
|
+
win_w.set_focus()
|
|
817
952
|
|
|
818
|
-
window_rect =
|
|
953
|
+
window_rect = win_w.rectangle()
|
|
819
954
|
screenshot = pyautogui.screenshot(
|
|
820
|
-
region=(
|
|
821
|
-
window_rect.left,
|
|
822
|
-
window_rect.top,
|
|
823
|
-
window_rect.width(),
|
|
824
|
-
window_rect.height(),
|
|
825
|
-
)
|
|
955
|
+
region=(window_rect.left, window_rect.top, window_rect.width(), window_rect.height())
|
|
826
956
|
)
|
|
827
957
|
username = getpass.getuser()
|
|
828
|
-
path_to_png = f"C:\\Users\\{username}\\Downloads\\warning_popup_{nota.get(
|
|
958
|
+
path_to_png = f"C:\\Users\\{username}\\Downloads\\warning_popup_{nota.get('nfe')}.png"
|
|
829
959
|
screenshot.save(path_to_png)
|
|
830
|
-
console.print(f"Print salvo em {path_to_png}
|
|
960
|
+
console.print(f"[FINALIZAÇÃO] Print do Warning salvo em {path_to_png}", style="cyan")
|
|
831
961
|
|
|
832
|
-
console.print(
|
|
833
|
-
f"Preparando a imagem para maior resolução e assertividade no OCR...\n"
|
|
834
|
-
)
|
|
835
962
|
image = Image.open(path_to_png)
|
|
836
963
|
image = image.convert("L")
|
|
837
964
|
enhancer = ImageEnhance.Contrast(image)
|
|
838
965
|
image = enhancer.enhance(2.0)
|
|
839
966
|
image.save(path_to_png)
|
|
840
|
-
console.print(
|
|
841
|
-
console.print(f"Realizando OCR...\n")
|
|
967
|
+
console.print("[FINALIZAÇÃO] Imagem preparada. Iniciando OCR...", style="cyan")
|
|
842
968
|
captured_text = pytesseract.image_to_string(Image.open(path_to_png))
|
|
843
|
-
console.print(
|
|
844
|
-
f"Texto Full capturado {captured_text}...\n"
|
|
845
|
-
)
|
|
969
|
+
console.print(f"[FINALIZAÇÃO] Texto capturado do Warning: {captured_text}", style="bold green")
|
|
846
970
|
os.remove(path_to_png)
|
|
971
|
+
console.print("[FINALIZAÇÃO] Arquivo de imagem do Warning removido.", style="cyan")
|
|
972
|
+
|
|
847
973
|
if 'movimento não permitido' in captured_text.lower():
|
|
974
|
+
console.print("[FINALIZAÇÃO] Warning mapeado: movimento não permitido (livro fechado).", style="bold red")
|
|
848
975
|
return RpaRetornoProcessoDTO(
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
976
|
+
sucesso=False,
|
|
977
|
+
retorno=f"Filial: {empresaCodigo} está com o livro fechado ou encerrado, verificar com o setor fiscal",
|
|
978
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
979
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
853
980
|
)
|
|
854
981
|
else:
|
|
982
|
+
console.print("[FINALIZAÇÃO] Warning não mapeado. Retornando como erro técnico com mensagem completa do OCR.", style="bold red")
|
|
855
983
|
return RpaRetornoProcessoDTO(
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
984
|
+
sucesso=False,
|
|
985
|
+
retorno=f"Warning não mapeado para seguimento do robo, mensagem: {captured_text}",
|
|
986
|
+
status=RpaHistoricoStatusEnum.Falha,
|
|
987
|
+
tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
|
|
860
988
|
)
|
|
861
989
|
|
|
862
990
|
await worker_sleep(3)
|
|
863
|
-
|
|
991
|
+
|
|
992
|
+
console.print("[FINALIZAÇÃO] Verificando se a nota foi lançada via check_nota_importada...", style="bold cyan")
|
|
864
993
|
nf_imported = await check_nota_importada(dados_nf[0].get("chaveNfe"))
|
|
865
|
-
|
|
994
|
+
console.print(f"[FINALIZAÇÃO] Retorno check_nota_importada: sucesso={nf_imported.sucesso} | retorno={nf_imported.retorno}", style="cyan")
|
|
995
|
+
if nf_imported.sucesso:
|
|
866
996
|
await worker_sleep(3)
|
|
867
|
-
console.print("
|
|
868
|
-
|
|
869
|
-
status_nf_emsys = await get_status_nf_emsys(
|
|
997
|
+
console.print("[FINALIZAÇÃO] Validando status da NF no EMSys via get_status_nf_emsys...", style="bold cyan")
|
|
998
|
+
nf_chave_int = int(dados_nf[0].get("chaveNfe"))
|
|
999
|
+
status_nf_emsys = await get_status_nf_emsys(nf_chave_int)
|
|
1000
|
+
console.print(f"[FINALIZAÇÃO] Status NF EMSys pós-lançamento: {status_nf_emsys}", style="cyan")
|
|
870
1001
|
if status_nf_emsys.get("status") == "Lançada":
|
|
871
|
-
console.print("\
|
|
1002
|
+
console.print("\n[FINALIZAÇÃO] Nota lançada com sucesso, processo finalizado...", style="bold green")
|
|
872
1003
|
return RpaRetornoProcessoDTO(
|
|
873
1004
|
sucesso=True,
|
|
874
1005
|
retorno="Nota Lançada com sucesso!",
|
|
875
1006
|
status=RpaHistoricoStatusEnum.Sucesso,
|
|
876
1007
|
)
|
|
877
1008
|
else:
|
|
878
|
-
console.print("
|
|
1009
|
+
console.print("[FINALIZAÇÃO] Pop-up nota incluída encontrado, porém status retornou diferente de 'Lançada'.", style="bold red")
|
|
879
1010
|
return RpaRetornoProcessoDTO(
|
|
880
1011
|
sucesso=False,
|
|
881
|
-
retorno=f"Pop-up nota incluida encontrada, porém nota encontrada como 'já lançada' trazendo as seguintes informações: {nf_imported.retorno}
|
|
1012
|
+
retorno=f"Pop-up nota incluida encontrada, porém nota encontrada como 'já lançada' trazendo as seguintes informações: {nf_imported.retorno}",
|
|
882
1013
|
status=RpaHistoricoStatusEnum.Falha,
|
|
883
1014
|
tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
|
|
884
1015
|
)
|
|
885
1016
|
else:
|
|
886
|
-
console.print("
|
|
1017
|
+
console.print("[FINALIZAÇÃO] check_nota_importada retornou falha. Nota não confirmada como lançada.", style="bold red")
|
|
887
1018
|
return RpaRetornoProcessoDTO(
|
|
888
1019
|
sucesso=False,
|
|
889
1020
|
retorno=f"Erro ao lançar nota, erro: {nf_imported.retorno}",
|
|
@@ -892,7 +1023,7 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
892
1023
|
)
|
|
893
1024
|
|
|
894
1025
|
except Exception as ex:
|
|
895
|
-
observacao = f"Erro Processo Entrada de Notas: {str(ex)}"
|
|
1026
|
+
observacao = f"[ERRO GERAL] Erro Processo Entrada de Notas: {str(ex)}"
|
|
896
1027
|
logger.error(observacao)
|
|
897
1028
|
console.print(observacao, style="bold red")
|
|
898
1029
|
return RpaRetornoProcessoDTO(
|
|
@@ -903,5 +1034,13 @@ async def opex_capex(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
|
|
|
903
1034
|
)
|
|
904
1035
|
|
|
905
1036
|
finally:
|
|
906
|
-
|
|
907
|
-
|
|
1037
|
+
console.print("[FINALLY] Iniciando limpeza de XML (delete_xml)...", style="bold cyan")
|
|
1038
|
+
try:
|
|
1039
|
+
if numero_nota:
|
|
1040
|
+
await delete_xml(numero_nota)
|
|
1041
|
+
console.print(f"[FINALLY] XML da nota {numero_nota} deletado com sucesso.", style="bold green")
|
|
1042
|
+
else:
|
|
1043
|
+
console.print("[FINALLY] numero_nota é None, não foi possível chamar delete_xml com parâmetro válido.", style="yellow")
|
|
1044
|
+
except Exception as e:
|
|
1045
|
+
console.print(f"[FINALLY] Falha ao deletar XML da nota {numero_nota}: {e}", style="bold red")
|
|
1046
|
+
console.print("\n================ FIM PROCESSO opex_capex ================\n", style="bold blue")
|