worker-automate-hub 0.5.606__py3-none-any.whl → 0.5.608__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.
@@ -0,0 +1,1346 @@
1
+ import asyncio
2
+ import getpass
3
+ import warnings
4
+ import os
5
+ import re
6
+ import uuid
7
+ import time
8
+ import win32clipboard
9
+ import difflib
10
+
11
+ import pyautogui
12
+ import pytesseract
13
+ from datetime import datetime, timedelta
14
+ from pywinauto.application import Application
15
+ from PIL import Image, ImageEnhance, ImageFilter
16
+ from pywinauto.keyboard import send_keys
17
+ import win32clipboard
18
+ from pywinauto_recorder.player import set_combobox
19
+ from rich.console import Console
20
+ from worker_automate_hub.api.ahead_service import save_xml_to_downloads
21
+ from worker_automate_hub.api.client import (
22
+ get_config_by_name,
23
+ get_status_nf_emsys,
24
+ )
25
+ from worker_automate_hub.models.dto.rpa_historico_request_dto import (
26
+ RpaHistoricoStatusEnum,
27
+ RpaRetornoProcessoDTO,
28
+ RpaTagDTO,
29
+ RpaTagEnum,
30
+ )
31
+ from worker_automate_hub.models.dto.rpa_processo_entrada_dto import (
32
+ RpaProcessoEntradaDTO,
33
+ )
34
+ from worker_automate_hub.utils.logger import logger
35
+ from worker_automate_hub.utils.util import (
36
+ delete_xml,
37
+ error_after_xml_imported,
38
+ get_xml,
39
+ carregamento_import_xml,
40
+ import_nfe,
41
+ is_window_open,
42
+ is_window_open_by_class,
43
+ itens_not_found_supplier,
44
+ kill_all_emsys,
45
+ login_emsys,
46
+ select_documento_type,
47
+ set_variable,
48
+ type_text_into_field,
49
+ warnings_after_xml_imported,
50
+ worker_sleep,
51
+ check_nota_importada,
52
+ )
53
+ from worker_automate_hub.utils.utils_nfe_entrada import EMSys
54
+
55
+ pyautogui.PAUSE = 0.5
56
+ pyautogui.FAILSAFE = False
57
+ console = Console()
58
+
59
+ emsys = EMSys()
60
+
61
+
62
+ async def entrada_de_notas_9000(task: RpaProcessoEntradaDTO) -> RpaRetornoProcessoDTO:
63
+ """
64
+ Processo que relazia entrada de notas no ERP EMSys(Linx).
65
+
66
+ """
67
+ try:
68
+ # Get config from BOF
69
+ config = await get_config_by_name("login_emsys")
70
+ console.print(task)
71
+
72
+ # Seta config entrada na var nota para melhor entendimento
73
+ nota = task.configEntrada
74
+ multiplicador_timeout = int(float(task.sistemas[0].timeout))
75
+ set_variable("timeout_multiplicador", multiplicador_timeout)
76
+
77
+ # Fecha a instancia do emsys - caso esteja aberta
78
+ await kill_all_emsys()
79
+
80
+ # Download XML
81
+ console.log("Realizando o download do XML..\n")
82
+ await save_xml_to_downloads(nota["nfe"])
83
+
84
+ app = Application(backend="win32").start("C:\\Rezende\\EMSys3\\EMSys3.exe")
85
+ warnings.filterwarnings(
86
+ "ignore",
87
+ category=UserWarning,
88
+ message="32-bit application should be automated using 32-bit Python",
89
+ )
90
+ console.print("\nEMSys iniciando...", style="bold green")
91
+ return_login = await login_emsys(config.conConfiguracao, app, task)
92
+
93
+ if return_login.sucesso == True:
94
+ type_text_into_field(
95
+ "Nota Fiscal de Entrada", app["TFrmMenuPrincipal"]["Edit"], True, "50"
96
+ )
97
+ pyautogui.press("enter")
98
+ await worker_sleep(2)
99
+ pyautogui.press("enter")
100
+ console.print(
101
+ f"\nPesquisa: 'Nota Fiscal de Entrada' realizada com sucesso",
102
+ style="bold green",
103
+ )
104
+ else:
105
+ logger.info(f"\nError Message: {return_login.retorno}")
106
+ console.print(f"\nError Message: {return_login.retorno}", style="bold red")
107
+ return return_login
108
+
109
+ await worker_sleep(6)
110
+
111
+ # Procura campo documento
112
+ console.print("Navegando pela Janela de Nota Fiscal de Entrada...\n")
113
+ document_type = await select_documento_type(
114
+ "NOTA FISCAL DE ENTRADA ELETRONICA - DANFE"
115
+ )
116
+ if document_type.sucesso == True:
117
+ console.log(document_type.retorno, style="bold green")
118
+ else:
119
+ return RpaRetornoProcessoDTO(
120
+ sucesso=False,
121
+ retorno=document_type.retorno,
122
+ status=RpaHistoricoStatusEnum.Falha, tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
123
+ )
124
+
125
+ await worker_sleep(4)
126
+
127
+ # Clica em 'Importar-Nfe'
128
+ imported_nfe = await import_nfe()
129
+ if imported_nfe.sucesso == True:
130
+ console.log(imported_nfe.retorno, style="bold green")
131
+ else:
132
+ return RpaRetornoProcessoDTO(
133
+ sucesso=False,
134
+ retorno=imported_nfe.retorno,
135
+ status=RpaHistoricoStatusEnum.Falha, tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
136
+ )
137
+
138
+ await worker_sleep(5)
139
+
140
+ await get_xml(nota.get("nfe"))
141
+ await worker_sleep(3)
142
+
143
+ # VERIFICANDO A EXISTENCIA DE WARNINGS
144
+ warning_pop_up = await is_window_open("Warning")
145
+ if warning_pop_up["IsOpened"] == True:
146
+ warning_work = await warnings_after_xml_imported()
147
+ if warning_work.sucesso == True:
148
+ console.log(warning_work.retorno, style="bold green")
149
+ else:
150
+ return RpaRetornoProcessoDTO(
151
+ sucesso=False,
152
+ retorno=warning_work.retorno,
153
+ status=RpaHistoricoStatusEnum.Falha,
154
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
155
+ )
156
+
157
+ # VERIFICANDO A EXISTENCIA DE ERRO
158
+ erro_pop_up = await is_window_open("Erro")
159
+ if erro_pop_up["IsOpened"] == True:
160
+ error_work_message = await error_after_xml_imported()
161
+ return RpaRetornoProcessoDTO(
162
+ sucesso=error_work_message.sucesso,
163
+ retorno=error_work_message.retorno,
164
+ status=error_work_message.status,
165
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
166
+ )
167
+
168
+ app = Application().connect(
169
+ title="Informações para importação da Nota Fiscal Eletrônica"
170
+ )
171
+ main_window = app["Informações para importação da Nota Fiscal Eletrônica"]
172
+
173
+
174
+ # INTERAGINDO COM A DATA DE ENTRADA
175
+ await worker_sleep(2)
176
+ try:
177
+ recebimento_fisico = nota.get("recebimentoFisico", None)
178
+ if recebimento_fisico:
179
+ recebimento_fisico = nota["recebimentoFisico"].split(" ")
180
+ pyautogui.write(recebimento_fisico[0])
181
+ await worker_sleep(2)
182
+ except:
183
+ console.print(
184
+ f"A chave recebimentoFisico não está presente na config de entrada...\n"
185
+ )
186
+
187
+ # INTERAGINDO COM A NATUREZA DA OPERACAO
188
+ cfop = int(nota.get("cfop"))
189
+ console.print(f"Inserindo a informação da CFOP, caso se aplique {cfop} ...\n")
190
+ if cfop == 5655 or cfop == 5656:
191
+ combo_box_natureza_operacao = main_window.child_window(
192
+ class_name="TDBIComboBox", found_index=0
193
+ )
194
+ combo_box_natureza_operacao.click()
195
+
196
+ await worker_sleep(3)
197
+ try:
198
+ set_combobox("||List", "1652-COMPRA DE MERCADORIAS- 1.652")
199
+ except:
200
+ console.log("Não foi possivel selecionar o tipo de documento via set combobox, realizando a alteração utilizando pyautogui write")
201
+ pyautogui.write("1102")
202
+ await worker_sleep(2)
203
+ pyautogui.hotkey("enter")
204
+ await worker_sleep(2)
205
+ pyautogui.write("1652-COMPRA DE MERCADORIAS- 1.652")
206
+ await worker_sleep(2)
207
+
208
+ elif cfop == 6655:
209
+ combo_box_natureza_operacao = main_window.child_window(
210
+ class_name="TDBIComboBox", found_index=0
211
+ )
212
+ combo_box_natureza_operacao.click()
213
+
214
+ await worker_sleep(3)
215
+ try:
216
+ set_combobox("||List", "2652-COMPRA DE MERCADORIAS- 2.652")
217
+ except:
218
+ console.log("Não foi possivel selecionar o tipo de documento via set combobox, realizando a alteração utilizando pyautogui write")
219
+ pyautogui.write("1102")
220
+ await worker_sleep(2)
221
+ pyautogui.hotkey("enter")
222
+ await worker_sleep(2)
223
+ pyautogui.write("2652-COMPRA DE MERCADORIAS- 2.652")
224
+ await worker_sleep(2)
225
+ else:
226
+ console.print(
227
+ "Erro mapeado, CFOP diferente de 5655 ou 6655, necessario ação manual ou ajuste no robo...\n"
228
+ )
229
+ return RpaRetornoProcessoDTO(
230
+ sucesso=False,
231
+ retorno="Erro mapeado, CFOP diferente de 5655 ou 6655, necessario ação manual ou ajuste no robo",
232
+ status=RpaHistoricoStatusEnum.Falha,
233
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
234
+ )
235
+
236
+
237
+ combo_box_natureza_operacao = main_window.child_window(class_name="TDBIComboBox", found_index=0)
238
+ if "2652-COMPRA DE MERCADORIAS- 2.652" in combo_box_natureza_operacao.window_text() or "1652-COMPRA DE MERCADORIAS- 1.652" in combo_box_natureza_operacao.window_text():
239
+ console.log("CFOP informado com sucesso")
240
+ else:
241
+ return RpaRetornoProcessoDTO(
242
+ sucesso=False,
243
+ retorno="Não foi possivel selecionar o CFOP",
244
+ status=RpaHistoricoStatusEnum.Falha,
245
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
246
+ )
247
+
248
+ await worker_sleep(3)
249
+ try:
250
+ console.print(f"Trabalhando com itens com multiplas referencias.\n")
251
+ itens_nao_semelhantes = []
252
+ # TRABALHANDO COM ITENS QUE POSSUEM MULTIPLAS REFERÊNCIAS
253
+ while True:
254
+ await worker_sleep(3)
255
+ console.print(
256
+ f"Verificando a existencia de fornecedor com múltiplas referencias...\n"
257
+ )
258
+ itens_by_supplier = await is_window_open_by_class(
259
+ "TFrmSelecionaItensFornecedor", "TFrmSelecionaItensFornecedor"
260
+ )
261
+ if itens_by_supplier["IsOpened"] == True:
262
+ new_app = Application(backend="uia").connect(
263
+ class_name="TFrmSelecionaItensFornecedor"
264
+ )
265
+ window = new_app["TFrmSelecionaItensFornecedor"]
266
+ window.set_focus()
267
+ await worker_sleep(2)
268
+
269
+ console.print(f"Obtendo item com multiplas referências...\n")
270
+ console.print(f"Tirando print da janela para realização do OCR...\n")
271
+
272
+ text_captured = False
273
+ count_while = 0
274
+ max_attempts = 3
275
+ item_da_nota = ''
276
+
277
+ while count_while < max_attempts:
278
+ window_rect = window.rectangle()
279
+ console.print(f"Area que sera utulizada para o screenshot {window_rect}...\n")
280
+ screenshot = window.capture_as_image()
281
+
282
+ username = getpass.getuser()
283
+ short_uuid = str(uuid.uuid4()).replace('-', '')[:6]
284
+ path_to_png = f"C:\\Users\\{username}\\Downloads\\{short_uuid}.png"
285
+ screenshot.save(path_to_png)
286
+ while not os.path.exists(path_to_png) or os.path.getsize(path_to_png) == 0:
287
+ time.sleep(0.1)
288
+ console.print(f"Print salvo em {path_to_png}...\n")
289
+
290
+ await worker_sleep(2)
291
+ console.print("Preparando a imagem para maior resolução e assertividade no OCR...\n")
292
+ image = Image.open(path_to_png)
293
+ image = image.convert("L")
294
+ enhancer = ImageEnhance.Contrast(image)
295
+ image = enhancer.enhance(2.0)
296
+ image.save(path_to_png)
297
+ console.print("Imagem preparada com sucesso...\n")
298
+
299
+ console.print(f"Imagem antes do OCR: {image}\n")
300
+ console.print(f"Dimensões da imagem: {image.size}\n")
301
+
302
+ console.print("Realizando OCR...\n")
303
+ captured_text = pytesseract.image_to_string(image)
304
+ console.print(f"Texto Full capturado {captured_text}, tentando obter o item da nota...\n")
305
+
306
+ match = re.search(r"Item da Nota:\s*(.*)\s*", captured_text)
307
+ if os.path.exists(path_to_png):
308
+ os.remove(path_to_png)
309
+ console.print(f"Imagem apagada com sucesso do diretorio {path_to_png}... \n")
310
+ else:
311
+ console.print(f"Imagem não encontrada para realização do OCR... \n")
312
+
313
+ console.print(f"Texto extraido do RegEx: {match}... \n")
314
+ if match:
315
+ item_da_nota = match.group(1).strip()
316
+ console.print(f"Item da Nota capturado: {item_da_nota}... \n")
317
+ text_captured = True
318
+ break
319
+ else:
320
+ if match:
321
+ item_da_nota = match.group(1).strip()
322
+ console.print(f"Item da Nota capturado: {item_da_nota}... \n")
323
+ text_captured = True
324
+ break
325
+ else:
326
+ match = re.search(r"Item da (Nota|Nata|N0ta)\s*(.*)\s*", captured_text)
327
+ if match:
328
+ item_da_nota = match.group(1).strip()
329
+ console.print(f"Item da Nota capturado: {item_da_nota}... \n")
330
+ text_captured = True
331
+ break
332
+ else:
333
+ console.print(f"Tentativa {count_while + 1} de {max_attempts} falhou. Tentando novamente...\n")
334
+ count_while += 1
335
+
336
+ if not text_captured:
337
+ return RpaRetornoProcessoDTO(
338
+ sucesso=False,
339
+ retorno="Quantidade de tentativa atingida (3), não foi possivel capturar o item da nota com multiplas referencias para andamento no processo",
340
+ status=RpaHistoricoStatusEnum.Falha,
341
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
342
+ )
343
+
344
+ console.print(
345
+ f"Interagindo com os multiplos itens e detectando qual ira ser selecionado para andamento no processo... \n"
346
+ )
347
+ copied_codes_list = []
348
+ count = 0
349
+ last_copied = None
350
+
351
+ while True:
352
+ if count == 0:
353
+ send_keys("^({HOME})")
354
+ else:
355
+ send_keys("{DOWN 1}")
356
+
357
+ send_keys("^c")
358
+ win32clipboard.OpenClipboard()
359
+ window_message = win32clipboard.GetClipboardData().strip()
360
+ win32clipboard.CloseClipboard()
361
+
362
+ console.print(f"Linha copiada: {window_message}... \n")
363
+
364
+ if last_copied is not None and window_message == last_copied:
365
+ break
366
+
367
+ copied_codes_list.append(
368
+ {"linha": count, "conteudo": window_message}
369
+ )
370
+
371
+ last_copied = window_message
372
+ count = +1
373
+
374
+ console.print(f"Valores copiados {copied_codes_list}... \n")
375
+
376
+ extracted_items = {}
377
+
378
+ for entry in copied_codes_list:
379
+ content = entry["conteudo"]
380
+ lines = content.split("\r\n")
381
+ for line in lines:
382
+ items = line.split("\t")
383
+ if len(items) >= 3:
384
+ cod_item = items[0].strip()
385
+ descricao = items[1].strip()
386
+ cod_barra = items[2].strip()
387
+
388
+ extracted_items[cod_item] = {
389
+ "Descrição": descricao,
390
+ "Código de Barra": cod_barra,
391
+ "Linha": entry["linha"],
392
+ }
393
+
394
+ best_match = None
395
+ highest_ratio = 0.0
396
+
397
+ for cod_item, info in extracted_items.items():
398
+ descricao = info["Descrição"]
399
+ similarity_ratio = difflib.SequenceMatcher(
400
+ None, item_da_nota, descricao
401
+ ).ratio()
402
+
403
+ if similarity_ratio > highest_ratio:
404
+ highest_ratio = similarity_ratio
405
+ best_match = {
406
+ "Cod Item": cod_item,
407
+ "Descrição": descricao,
408
+ "Código de Barra": info["Código de Barra"],
409
+ "Linha": info["Linha"],
410
+ "Similaridade": similarity_ratio,
411
+ }
412
+
413
+ if best_match and highest_ratio > 0.7:
414
+ console.print(
415
+ f"Melhor semelhança encontrada {best_match}, selecionando... \n"
416
+ )
417
+ send_keys("^({HOME})")
418
+ send_keys("{DOWN " + str(best_match["Linha"]) + "}")
419
+ send_keys("%o")
420
+ await worker_sleep(2)
421
+ else:
422
+ itens_nao_semelhantes.append(
423
+ {"item": item_da_nota, "match": best_match}
424
+ )
425
+ send_keys("%o")
426
+ else:
427
+ console.print(
428
+ "Não possui a tela de fornecedor com múltiplas referencias, seguindo com o processo...\n"
429
+ )
430
+ break
431
+
432
+ if len(itens_nao_semelhantes) > 0:
433
+ return RpaRetornoProcessoDTO(
434
+ sucesso=False,
435
+ retorno=f"Não foi possivel encontrar o item mais proximo ao item da nota com multiplas referencias {itens_nao_semelhantes}",
436
+ status=RpaHistoricoStatusEnum.Falha,
437
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
438
+ )
439
+ except Exception as error:
440
+ console.print("Erro durante a trativa de multiplas referencias, erro : {error}")
441
+
442
+ await worker_sleep(3)
443
+ # INTERAGINDO COM O CAMPO ALMOXARIFADO
444
+ filialEmpresaOrigem = nota.get("filialEmpresaOrigem")
445
+ console.print(
446
+ f"Inserindo a informação do Almoxarifado {filialEmpresaOrigem} ...\n"
447
+ )
448
+ try:
449
+ new_app = Application(backend="uia").connect(
450
+ title="Informações para importação da Nota Fiscal Eletrônica"
451
+ )
452
+ window = new_app["Informações para importação da Nota Fiscal Eletrônica"]
453
+ edit = window.child_window(
454
+ class_name="TDBIEditCode", found_index=3, control_type="Edit"
455
+ )
456
+ valor_almoxarifado = filialEmpresaOrigem + "50"
457
+ edit.set_edit_text(valor_almoxarifado)
458
+ edit.type_keys("{TAB}")
459
+ except Exception as e:
460
+ console.print(f"Erro ao iterar itens de almoxarifado: {e}")
461
+ return RpaRetornoProcessoDTO(
462
+ sucesso=False,
463
+ retorno=f"Erro ao iterar itens de almoxarifado: {e}",
464
+ status=RpaHistoricoStatusEnum.Falha,
465
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
466
+ )
467
+
468
+ await worker_sleep(1)
469
+ console.print("Clicando em OK... \n")
470
+
471
+ max_attempts = 6
472
+ i = 0
473
+ while i < max_attempts:
474
+ console.print("Clicando no botão de OK...\n")
475
+ try:
476
+ try:
477
+ btn_ok = main_window.child_window(title="Ok")
478
+ btn_ok.click()
479
+ except:
480
+ btn_ok = main_window.child_window(title="&Ok")
481
+ btn_ok.click()
482
+ except:
483
+ console.print("Não foi possivel clicar no Botão OK... \n")
484
+
485
+ await worker_sleep(3)
486
+
487
+ console.print(
488
+ "Verificando a existencia da tela Informações para importação da Nota Fiscal Eletrônica...\n"
489
+ )
490
+
491
+ try:
492
+ informacao_nf_eletronica = await is_window_open(
493
+ "Informações para importação da Nota Fiscal Eletrônica"
494
+ )
495
+ if informacao_nf_eletronica["IsOpened"] == False:
496
+ console.print(
497
+ "Tela Informações para importação da Nota Fiscal Eletrônica fechada, seguindo com o processo"
498
+ )
499
+ break
500
+ except Exception as e:
501
+ console.print(
502
+ f"Tela Informações para importação da Nota Fiscal Eletrônica encontrada. Tentativa {i + 1}/{max_attempts}."
503
+ )
504
+
505
+ i += 1
506
+
507
+ if i == max_attempts:
508
+ return RpaRetornoProcessoDTO(
509
+ sucesso=False,
510
+ retorno=f"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",
511
+ status=RpaHistoricoStatusEnum.Falha,
512
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
513
+ )
514
+
515
+ await worker_sleep(2)
516
+ waiting_for_delay = await carregamento_import_xml()
517
+ if waiting_for_delay.sucesso:
518
+ console.print(waiting_for_delay.retorno)
519
+ else:
520
+ return RpaRetornoProcessoDTO(
521
+ sucesso=False,
522
+ retorno=waiting_for_delay.retorno,
523
+ status=RpaHistoricoStatusEnum.Falha,
524
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
525
+ )
526
+
527
+ try:
528
+ console.print("Verificando itens não localizados ou NCM...\n")
529
+ itens_by_supplier = await is_window_open_by_class("TFrmAguarde", "TMessageForm")
530
+
531
+ if itens_by_supplier["IsOpened"] == True:
532
+ itens_by_supplier_work = await itens_not_found_supplier(nota.get("nfe"))
533
+
534
+ if not itens_by_supplier_work.sucesso:
535
+ return itens_by_supplier_work
536
+
537
+ except Exception as error:
538
+ return RpaRetornoProcessoDTO(
539
+ sucesso=False,
540
+ retorno=f"Falha ao verificar a existência de POP-UP de itens não localizados: {error}",
541
+ status=RpaHistoricoStatusEnum.Falha,
542
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
543
+ )
544
+
545
+ console.print("Navegando pela Janela de Nota Fiscal de Entrada...\n")
546
+ app = Application().connect(class_name="TFrmNotaFiscalEntrada")
547
+ main_window = app["TFrmNotaFiscalEntrada"]
548
+
549
+ main_window.set_focus()
550
+ await worker_sleep(1)
551
+ console.print("Acessando os itens da nota... \n")
552
+ panel_TPage = main_window.child_window(class_name="TPage", title="Formulario")
553
+ panel_TTabSheet = panel_TPage.child_window(class_name="TcxCustomInnerTreeView")
554
+ panel_TTabSheet.wait("visible")
555
+ panel_TTabSheet.click()
556
+ send_keys("{DOWN " + ("5") + "}")
557
+
558
+ # CONFIRMANDO SE A ABA DE ITENS FOI ACESSADA COM SUCESSO
559
+ try:
560
+ panel_TPage = main_window.child_window(class_name="TPage", title="Formulario")
561
+ panel_TPage.wait("visible")
562
+ panel_TTabSheet = panel_TPage.child_window(class_name="TTabSheet")
563
+ title_n_serie = panel_TPage.child_window(title="N° Série")
564
+
565
+ console.print("Verificando se os itens foram abertos com sucesso... \n")
566
+ if not title_n_serie:
567
+ console.print(f"Não foi possivel acessar a aba de 'Itens da nota...\n")
568
+ return RpaRetornoProcessoDTO(
569
+ sucesso=False,
570
+ retorno="Não foi possivel acessar a aba de 'Itens da nota'",
571
+ status=RpaHistoricoStatusEnum.Falha,
572
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
573
+ )
574
+ except Exception as e:
575
+ return RpaRetornoProcessoDTO(
576
+ sucesso=False,
577
+ retorno=f"Não foi possivel acessar a aba de 'Itens da nota', erro: {e}",
578
+ status=RpaHistoricoStatusEnum.Falha,
579
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
580
+ )
581
+
582
+ await worker_sleep(2)
583
+
584
+ # Verifica se existe alocacões na task
585
+
586
+ console.print("Verificando se existe alocações na task")
587
+
588
+ list_distribuicao_obs = []
589
+ alocacoes = task.configEntrada.get("alocacoes", [])
590
+
591
+ if isinstance(alocacoes, list) and alocacoes:
592
+ for alocacao in alocacoes:
593
+ codigo_filial = alocacao.get("codigo")
594
+ valor = alocacao.get("qtdAlocada")
595
+ console.print(f"Código Filial: {codigo_filial} | Quantidade Alocada: {valor}")
596
+ tanque = f"{codigo_filial} - ({valor})"
597
+ list_distribuicao_obs.append(tanque)
598
+ else:
599
+ console.print("Não há alocações na task de entrada.")
600
+
601
+ console.print("Verificando campo observações")
602
+ observacoes_nota = nota.get("observacoes")
603
+ pattern = rf"(\b{filialEmpresaOrigem}\d+)\s*-\s*TANQUE\s+(\d+)\s*[/-]\s*(\w+\s*\w*)\s*\((.*?)\)"
604
+
605
+ resultados_itens_ahead = re.findall(pattern, observacoes_nota)
606
+
607
+ list_distribuicao_obs = []
608
+ for codigo_filial, numero_tanque, tipo_combustivel, valor in resultados_itens_ahead:
609
+ tanque =f"{codigo_filial} - {numero_tanque} - {tipo_combustivel} ({valor})"
610
+ list_distribuicao_obs.append(tanque)
611
+
612
+
613
+ if len(list_distribuicao_obs) > 0:
614
+ console.print(f'Distribuição observação a serem processados: {list_distribuicao_obs}')
615
+ index_tanque = 0
616
+ list_tanques_distribuidos = []
617
+ send_keys("{TAB 2}", pause=0.1)
618
+
619
+ try:
620
+ for info_distribuicao_obs in list_distribuicao_obs:
621
+ await worker_sleep(2)
622
+ console.print(f"Tanque a ser distribuido: {info_distribuicao_obs}... \n")
623
+ send_keys("^({HOME})")
624
+ await worker_sleep(1)
625
+ send_keys("{DOWN " + str(index_tanque) + "}", pause=0.1)
626
+ await worker_sleep(1)
627
+ send_keys("+{F10}")
628
+ await worker_sleep(1)
629
+ send_keys("{DOWN 6}")
630
+ await worker_sleep(1)
631
+ send_keys("{ENTER}")
632
+ await worker_sleep(4)
633
+
634
+
635
+ max_attempts = 5
636
+ i = 0
637
+ while i < max_attempts:
638
+ distribuir_item_window = await is_window_open("Distribui Item Tanque")
639
+ if distribuir_item_window["IsOpened"] == True:
640
+ app = Application().connect(title="Distribui Item Tanque")
641
+ main_window = app["Distribui Item Tanque"]
642
+
643
+ main_window.set_focus()
644
+ break
645
+ else:
646
+ await worker_sleep(3)
647
+ i = i + 1
648
+
649
+ if i >= max_attempts:
650
+ return RpaRetornoProcessoDTO(
651
+ sucesso=False,
652
+ retorno=f"Erro ao trabalhar nas alterações dos item de tanque, tela de Distribui item tanque não foi encontrada",
653
+ status=RpaHistoricoStatusEnum.Falha,
654
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
655
+ )
656
+
657
+ try:
658
+ panel_grid = main_window.child_window(class_name="TcxGridSite")
659
+ except:
660
+ panel_grid = main_window.child_window(class_name="TcxGrid")
661
+
662
+ grid_rect = panel_grid.rectangle()
663
+ center_x = (grid_rect.left + grid_rect.right) // 2
664
+ center_y = (grid_rect.top + grid_rect.bottom) // 2
665
+
666
+ pyautogui.click(center_x, center_y)
667
+ await worker_sleep(1)
668
+ send_keys("^({HOME})")
669
+ await worker_sleep(1)
670
+ send_keys("{LEFT 3}")
671
+
672
+ distribuiu_algo = False
673
+ distribuicao_atual = []
674
+ last_line_almoxarifado_emsys = 'x'
675
+ max_distribuicao = 0
676
+
677
+ while max_distribuicao <= 20:
678
+ console.print(f"Tentativa: {max_distribuicao}... \n")
679
+ await worker_sleep(1)
680
+ with pyautogui.hold('ctrl'):
681
+ pyautogui.press('c')
682
+
683
+ await worker_sleep(1)
684
+
685
+ with pyautogui.hold('ctrl'):
686
+ pyautogui.press('c')
687
+
688
+ win32clipboard.OpenClipboard()
689
+ line_almoxarifado_emsys = win32clipboard.GetClipboardData().strip()
690
+ win32clipboard.CloseClipboard()
691
+ console.print(f"Linha atual copiada do Emsys: {line_almoxarifado_emsys}\nUltima Linha copiada: {last_line_almoxarifado_emsys}")
692
+
693
+ if bool(line_almoxarifado_emsys):
694
+ if last_line_almoxarifado_emsys == line_almoxarifado_emsys:
695
+ break
696
+ else:
697
+ last_line_almoxarifado_emsys = line_almoxarifado_emsys
698
+
699
+ codigo_almoxarifado_emsys = line_almoxarifado_emsys.split('\n')[1].split('\t')[0].strip()
700
+
701
+ for second_info_distribuicao_obs in list_distribuicao_obs:
702
+ codigo_almoxarifado_obs = second_info_distribuicao_obs.split('-')[0].strip()
703
+ console.print(
704
+ f"Código almoxarifado emsys: {codigo_almoxarifado_emsys}\nCodigo almoxarifado obs: {codigo_almoxarifado_obs}",
705
+ None)
706
+ if codigo_almoxarifado_obs == codigo_almoxarifado_emsys and not second_info_distribuicao_obs in list_tanques_distribuidos:
707
+ console.print("Entrou no IF para distribuir tanques.")
708
+ console.print(
709
+ f"Linha atual copiada do Emsys: {line_almoxarifado_emsys}\nUltima Linha copiada: {last_line_almoxarifado_emsys}")
710
+ quantidade_combustivel = re.findall(r'\((.*?)\)', second_info_distribuicao_obs)[0].replace('.', '')
711
+
712
+ send_keys("{LEFT 3}")
713
+ await worker_sleep(1)
714
+ send_keys("{RIGHT 3}")
715
+
716
+ pyautogui.press('enter')
717
+ await worker_sleep(1)
718
+ pyautogui.write(quantidade_combustivel)
719
+ pyautogui.press('enter')
720
+ list_tanques_distribuidos.append(second_info_distribuicao_obs)
721
+ distribuicao_atual.append(f"Valor do tipo de combustivel:{codigo_almoxarifado_emsys} nas observações é {quantidade_combustivel}")
722
+ distribuiu_algo = True
723
+
724
+ max_distribuicao = max_distribuicao + 1
725
+ pyautogui.press('down')
726
+ await worker_sleep(1)
727
+
728
+ index_tanque = index_tanque + 1
729
+ console.print(f"Index Tanque: {index_tanque}")
730
+
731
+ if distribuiu_algo:
732
+ console.print(f"Extraindo informação da Janela de Distribuir Itens para realização do OCR...\n")
733
+
734
+ max_attempts = 3
735
+ attempts = 0
736
+ captured_text = None
737
+ resultado = None
738
+ while attempts < max_attempts:
739
+ main_window.set_focus()
740
+ window_rect = main_window.rectangle()
741
+ screenshot = pyautogui.screenshot(
742
+ region=(
743
+ window_rect.left,
744
+ window_rect.top,
745
+ window_rect.width(),
746
+ window_rect.height(),
747
+ )
748
+ )
749
+ username = getpass.getuser()
750
+ path_to_png = f"C:\\Users\\{username}\\Downloads\\distribuir_iten_{nota.get("nfe")}.png"
751
+ screenshot.save(path_to_png)
752
+ console.print(f"Print salvo em {path_to_png}...\n")
753
+
754
+ console.print(
755
+ f"Preparando a imagem para maior resolução e assertividade no OCR...\n"
756
+ )
757
+ image = Image.open(path_to_png)
758
+ image = image.filter(ImageFilter.SHARPEN)
759
+ image = image.convert("L")
760
+ enhancer = ImageEnhance.Contrast(image)
761
+ image = enhancer.enhance(2.0)
762
+ image.save(path_to_png)
763
+ console.print(f"Imagem preparada com sucesso...\n")
764
+ console.print(f"Realizando OCR...\n")
765
+ await worker_sleep(1)
766
+ captured_text = pytesseract.image_to_string(Image.open(path_to_png))
767
+ console.print(f"Texto Full capturado {captured_text}...\n")
768
+ os.remove(path_to_png)
769
+
770
+ pattern_qtd_restante = r"Quantidade restante:\s([\d,]+)"
771
+ resultado = re.search(pattern_qtd_restante, captured_text)
772
+ if resultado:
773
+ break
774
+ else:
775
+ await worker_sleep(2)
776
+ console.print(f"Não conseguiu encontrar a quantidade restante, tentando cortar a imagem...\n")
777
+ width, height = image.size
778
+ box = (0, height - 100, width, height)
779
+ cropped_image = image.crop(box)
780
+
781
+ cropped_image = cropped_image.convert("L")
782
+ cropped_image = cropped_image.filter(ImageFilter.SHARPEN)
783
+ enhancer = ImageEnhance.Contrast(cropped_image)
784
+ cropped_image = enhancer.enhance(2.0)
785
+
786
+ captured_text = pytesseract.image_to_string(cropped_image)
787
+ console.print(f"Texto Full capturado {captured_text}...\n")
788
+
789
+ resultado = re.search(pattern_qtd_restante, captured_text)
790
+ if resultado:
791
+ break
792
+
793
+ await worker_sleep(2)
794
+ attempts += 1
795
+
796
+ try:
797
+ if resultado:
798
+ quantidade_restante = int(resultado.group(1).replace(",", ""))
799
+
800
+ if quantidade_restante > 0:
801
+ return RpaRetornoProcessoDTO(
802
+ sucesso=False,
803
+ retorno=f"A distribuição informada diverge do que está na nota, {', '.join(distribuicao_atual)} e o valor da quantidade restante é de {str(quantidade_restante)}.",
804
+ status=RpaHistoricoStatusEnum.Falha,
805
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
806
+ )
807
+ else:
808
+ console.print(f"A quantidade restante é igual ou menor que 0, seguindo... \n")
809
+ else:
810
+ return RpaRetornoProcessoDTO(
811
+ sucesso=False,
812
+ retorno=f"Não foi possivel obter o resultado da quantidade restante, texto extraido: {captured_text}",
813
+ status=RpaHistoricoStatusEnum.Falha,
814
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
815
+ )
816
+ except Exception as e:
817
+ return RpaRetornoProcessoDTO(
818
+ sucesso=False,
819
+ retorno=f"Erro {e}, Não foi possivel obter o resultado da quantidade restante",
820
+ status=RpaHistoricoStatusEnum.Falha,
821
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
822
+ )
823
+
824
+ console.print(f"Algum Item foi distribuido, clicando em OK para salvar")
825
+ main_window.set_focus()
826
+ await worker_sleep(1)
827
+ btn_ok = main_window.child_window(
828
+ class_name="TBitBtn", found_index=1
829
+ )
830
+ btn_ok.click()
831
+ await worker_sleep(5)
832
+
833
+ max_attempts = 5
834
+ i = 0
835
+ while i < max_attempts:
836
+ distribuir_item_window = await is_window_open("Distribui Item Tanque")
837
+ if distribuir_item_window["IsOpened"] == True:
838
+ try:
839
+ btn_ok.click()
840
+ except:
841
+ console.print(f"Tela de distribuir item deve ter sido encerrada")
842
+ finally:
843
+ i = i + 1
844
+ await worker_sleep(2)
845
+ else:
846
+ console.print(f"Tela de distribuir item do tanque finalizado com sucesso")
847
+ await worker_sleep(5)
848
+ break
849
+
850
+ if i >= max_attempts:
851
+ return RpaRetornoProcessoDTO(
852
+ sucesso=False,
853
+ retorno=f"Tela de distribuir item não foi encerrada",
854
+ status=RpaHistoricoStatusEnum.Falha,
855
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
856
+ )
857
+ else:
858
+ console.print(f"Nenhum item foi distribuido, clicando em Cancelar")
859
+ btn_cancelar = main_window.child_window(
860
+ class_name="TBitBtn", found_index=0
861
+ )
862
+ btn_cancelar.click()
863
+
864
+ max_attempts = 5
865
+ i = 0
866
+ while i < max_attempts:
867
+ distribuir_item_window = await is_window_open("Distribui Item Tanque")
868
+ if distribuir_item_window["IsOpened"] == True:
869
+ try:
870
+ btn_cancelar.click()
871
+ except:
872
+ console.print(f"Tela de distribuir item deve ter sido encerrada")
873
+ finally:
874
+ i = i + 1
875
+ await worker_sleep(2)
876
+ else:
877
+ console.print(f"Tela de distribuir item do tanque finalizado com sucesso")
878
+ await worker_sleep(5)
879
+ break
880
+
881
+ if i >= max_attempts:
882
+ return RpaRetornoProcessoDTO(
883
+ sucesso=False,
884
+ retorno=f"Tela de distribuir item não foi encerrada",
885
+ status=RpaHistoricoStatusEnum.Falha,
886
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
887
+ )
888
+ except Exception as e:
889
+ return RpaRetornoProcessoDTO(
890
+ sucesso=False,
891
+ retorno=f"Erro ao trabalhar nas alterações dos itens: {e}",
892
+ status=RpaHistoricoStatusEnum.Falha,
893
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
894
+ )
895
+
896
+ else:
897
+ console.print("Nenhum item com necessidade de ser alterado... \n")
898
+
899
+ await worker_sleep(5)
900
+
901
+ try:
902
+ console.print("Verificando itens não localizados ou NCM...\n")
903
+ itens_by_supplier = await is_window_open_by_class("TFrmAguarde", "TMessageForm")
904
+
905
+ if itens_by_supplier["IsOpened"] == True:
906
+ itens_by_supplier_work = await itens_not_found_supplier(nota.get("nfe"))
907
+
908
+ if not itens_by_supplier_work.sucesso:
909
+ return itens_by_supplier_work
910
+
911
+ except Exception as error:
912
+ return RpaRetornoProcessoDTO(
913
+ sucesso=False,
914
+ retorno=f"Falha ao verificar a existência de POP-UP de itens não localizados: {error}",
915
+ status=RpaHistoricoStatusEnum.Falha,
916
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
917
+ )
918
+
919
+ console.print("Navegando pela Janela de Nota Fiscal de Entrada...\n")
920
+ app = Application().connect(class_name="TFrmNotaFiscalEntrada")
921
+ main_window = app["TFrmNotaFiscalEntrada"]
922
+
923
+ main_window.set_focus()
924
+ console.log("Seleciona Pagamento", style="bold yellow")
925
+ try:
926
+ pyautogui.click(623, 374)
927
+ await worker_sleep(1)
928
+ send_keys("{DOWN " + ("4") + "}")
929
+ except Exception as e:
930
+ panel_TPage = main_window.child_window(class_name="TPage", title="Formulario")
931
+ panel_TTabSheet = panel_TPage.child_window(class_name="TcxCustomInnerTreeView")
932
+ panel_TTabSheet.wait("visible")
933
+ panel_TTabSheet.click()
934
+ send_keys("{DOWN " + ("2") + "}")
935
+
936
+ await worker_sleep(6)
937
+ try:
938
+ panel_TPage = main_window.child_window(class_name="TPage", title="Formulario")
939
+ panel_TTabSheet = panel_TPage.child_window(class_name="TPageControl")
940
+
941
+ panel_TabPagamento = panel_TTabSheet.child_window(class_name="TTabSheet")
942
+ panel_TabParcelamento = panel_TTabSheet.child_window(title="Parcelamento")
943
+
944
+ tipo_cobranca = panel_TabParcelamento.child_window(
945
+ class_name="TDBIComboBox", found_index=0
946
+ )
947
+
948
+ console.print("Verificando o tipo de cobrança selecionado... \n")
949
+ tipo_selecionado = tipo_cobranca.window_text()
950
+ if "boleto" in tipo_selecionado.lower() or 'carteira' in tipo_selecionado.lower():
951
+ console.print(f"Tipo de cobrança corretamente selecionado {tipo_selecionado}... \n")
952
+ else:
953
+ console.print(f"Tipo de cobrança não foi selecionado corretamente, interagindo com o campo para selecionar o campo corretamente... \n")
954
+ tipo_cobranca.click()
955
+ try:
956
+ set_combobox("||List", "BANCO DO BRASIL BOLETO")
957
+ except:
958
+ set_combobox("||List", "CARTEIRA")
959
+ except Exception as e:
960
+ return RpaRetornoProcessoDTO(
961
+ sucesso=False,
962
+ retorno=f"Não foi possivel acessar a aba de 'Pagamento', {e}",
963
+ status=RpaHistoricoStatusEnum.Falha,
964
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
965
+ )
966
+ try:
967
+ await worker_sleep(2)
968
+ tab_valores = panel_TabPagamento.child_window(title="Valores")
969
+ valores_restantes = tab_valores.child_window(
970
+ class_name="TDBIEditNumber", found_index=1
971
+ )
972
+
973
+ valores_informado = tab_valores.child_window(
974
+ class_name="TDBIEditNumber", found_index=2
975
+ )
976
+
977
+ valores_informado_text = valores_informado.window_text()
978
+ valores_restantes_text = valores_restantes.window_text()
979
+
980
+ valores_informado_text_transform = valores_informado_text.replace('.', '')
981
+ valores_informado_text_transform = valores_informado_text_transform.replace(",",".")
982
+
983
+ console.print(f"Pagamento informado valor:{valores_informado_text}... \n")
984
+ if float(valores_informado_text_transform) <= 0.0:
985
+ #if '0,00' in valores_informado_text and len(valores_informado_text) <= 4:
986
+ console.print(f"Pagamento não informado, registrando... \n")
987
+ dt_emissao = nota.get("dataEmissao")
988
+ dt_emissao = datetime.strptime(dt_emissao, "%d/%m/%Y")
989
+ pattern = r"(\d{2}/\d{2}/\d{4})"
990
+ match = re.search(pattern, nota.get("recebimentoFisico"))
991
+ recebimento_fisico = match.group(1) if match else None
992
+ recebimento_fisico = datetime.strptime(recebimento_fisico, "%d/%m/%Y")
993
+
994
+ #se a data do aceite no Ahead ultrapassar dois dias após a emissão da nota, deve-se colocar o vencimento para a mesma data do “Receb. Físico”/Aceite.
995
+ if ((recebimento_fisico >= dt_emissao + timedelta(days=2)) and ("vibra" in nota.get("nomeFornecedor").lower() or "ipiranga" in nota.get("nomeFornecedor").lower() or "raizen" in nota.get("nomeFornecedor").lower() or "charru" in nota.get("nomeFornecedor").lower())):
996
+ recebimento_fisico = recebimento_fisico.strftime("%d/%m/%Y")
997
+ console.print(f"Informando a data de vencimento, {recebimento_fisico}... \n")
998
+ vencimento = panel_TabParcelamento.child_window(
999
+ class_name="TDBIEditDate"
1000
+ )
1001
+ vencimento.set_edit_text(recebimento_fisico)
1002
+ elif "sim dis" in nota.get("nomeFornecedor").lower():
1003
+ vencimento = panel_TabParcelamento.child_window(
1004
+ class_name="TDBIEditDate"
1005
+ )
1006
+ data_vencimento = nota.get("dataVencimento")
1007
+ vencimento.set_edit_text(data_vencimento)
1008
+ else:
1009
+ #Senão adicionar 1 dia a emissao
1010
+ dt_emissao = nota.get("dataEmissao")
1011
+ dt_emissao = datetime.strptime(dt_emissao, "%d/%m/%Y")
1012
+ dt_emissao = dt_emissao + timedelta(days=1)
1013
+ dt_emissao = dt_emissao.strftime("%d/%m/%Y")
1014
+ vencimento = panel_TabParcelamento.child_window(
1015
+ class_name="TDBIEditDate"
1016
+ )
1017
+ vencimento.set_edit_text(dt_emissao)
1018
+
1019
+ await worker_sleep(2)
1020
+ console.print(f"Inserindo o valor {valores_restantes_text}... \n")
1021
+ valor = panel_TabParcelamento.child_window(
1022
+ class_name="TDBIEditNumber", found_index=3
1023
+ )
1024
+ valor.set_edit_text(valores_restantes_text)
1025
+ await worker_sleep(2)
1026
+ console.print(f"Adicionando o pagamento... \n")
1027
+ btn_add = panel_TabParcelamento.child_window(
1028
+ class_name="TDBIBitBtn", found_index=1
1029
+ )
1030
+ btn_add.click()
1031
+
1032
+ await worker_sleep(4)
1033
+ console.print(f"Verificando se o pagamento foi adicionado com sucesso... \n")
1034
+ valores_informado = tab_valores.child_window(
1035
+ class_name="TDBIEditNumber", found_index=2
1036
+ )
1037
+ valores_informado_text = valores_informado.window_text()
1038
+ if '0,00' in valores_informado_text and len(valores_informado_text) == 3:
1039
+ return RpaRetornoProcessoDTO(
1040
+ sucesso=False,
1041
+ retorno=f"Erro ao adicionar o pagamento, valor informado {valores_informado_text}.",
1042
+ status=RpaHistoricoStatusEnum.Falha,
1043
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1044
+ )
1045
+ console.print(f"Processo de incluir pagamento realizado com sucesso... \n")
1046
+ else:
1047
+ data_vencimento = ""
1048
+ if "vibra" in nota.get("nomeFornecedor").lower() or "ipiranga" in nota.get("nomeFornecedor").lower() or "raizen" in nota.get("nomeFornecedor").lower() or "charru" in nota.get("nomeFornecedor").lower():
1049
+ dt_emissao = nota.get("dataEmissao")
1050
+ dt_emissao = datetime.strptime(dt_emissao, "%d/%m/%Y")
1051
+ pattern = r"(\d{2}/\d{2}/\d{4})"
1052
+ match = re.search(pattern, nota.get("recebimentoFisico"))
1053
+ recebimento_fisico = match.group(1) if match else None
1054
+ recebimento_fisico = datetime.strptime(recebimento_fisico, "%d/%m/%Y")
1055
+ if recebimento_fisico >= dt_emissao + timedelta(days=2):
1056
+ recebimento_fisico = recebimento_fisico.strftime("%d/%m/%Y")
1057
+ console.print(f"Informando a data de vencimento, {recebimento_fisico}... \n")
1058
+ data_vencimento = recebimento_fisico
1059
+ else:
1060
+ dt_emissao = dt_emissao + timedelta(days=1)
1061
+ dt_emissao = dt_emissao.strftime("%d/%m/%Y")
1062
+ data_vencimento = dt_emissao
1063
+ else:
1064
+ data_vencimento = nota.get("dataVencimento")
1065
+
1066
+ await worker_sleep(2)
1067
+ console.print(f"Removendo registro de parcelamento do pagamento... \n")
1068
+ btn_remove = panel_TabParcelamento.child_window(
1069
+ class_name="TDBIBitBtn", found_index=0
1070
+ )
1071
+ btn_remove.click()
1072
+ await worker_sleep(3)
1073
+ confirm_pop_up = await is_window_open_by_class("TMessageForm","TMessageForm")
1074
+ if confirm_pop_up["IsOpened"] == True:
1075
+ app_confirm = Application().connect(
1076
+ class_name="TMessageForm"
1077
+ )
1078
+ main_window_confirm = app_confirm["TMessageForm"]
1079
+
1080
+ btn_yes = main_window_confirm["&Yes"]
1081
+ if btn_yes.exists():
1082
+ try:
1083
+ btn_yes.click()
1084
+ await worker_sleep(3)
1085
+ console.print("O botão Yes de remover parcelamento foi clicado com sucesso.", style="green")
1086
+ except:
1087
+ console.print("Falha ao clicar no botão Yes de faturar.", style="red")
1088
+ else:
1089
+ pyautogui.click(915, 562)
1090
+ else:
1091
+ return RpaRetornoProcessoDTO(
1092
+ sucesso=False,
1093
+ retorno=f"Pop de confirmação de remover parcelamento não foi encontrado.",
1094
+ status=RpaHistoricoStatusEnum.Falha,
1095
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1096
+ )
1097
+ await worker_sleep(3)
1098
+ confirm_pop_up = await is_window_open_by_class("TMessageForm","TMessageForm")
1099
+ if confirm_pop_up["IsOpened"] == True:
1100
+ return RpaRetornoProcessoDTO(
1101
+ sucesso=False,
1102
+ retorno=f"Erro ao adicionar remover o parcelamento do pagamento.",
1103
+ status=RpaHistoricoStatusEnum.Falha,
1104
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1105
+ )
1106
+
1107
+ await worker_sleep(2)
1108
+ console.print(f"Parcelamento de pagamento excluido, adicionando o novo... \n")
1109
+ console.print(f"Inserindo a data de vencimento {data_vencimento} \n")
1110
+ vencimento = panel_TabParcelamento.child_window(
1111
+ class_name="TDBIEditDate"
1112
+ )
1113
+ vencimento.set_edit_text(data_vencimento)
1114
+ await worker_sleep(2)
1115
+ app = Application().connect(class_name="TFrmNotaFiscalEntrada")
1116
+ main_window = app["TFrmNotaFiscalEntrada"]
1117
+
1118
+ main_window.set_focus()
1119
+ panel_TPage = main_window.child_window(class_name="TPage", title="Formulario")
1120
+ panel_TTabSheet = panel_TPage.child_window(class_name="TPageControl")
1121
+
1122
+ panel_TabPagamento = panel_TTabSheet.child_window(class_name="TTabSheet")
1123
+ panel_TabParcelamento = panel_TTabSheet.child_window(title="Parcelamento")
1124
+
1125
+ tab_valores = panel_TabPagamento.child_window(title="Valores")
1126
+ valores_restantes = tab_valores.child_window(
1127
+ class_name="TDBIEditNumber", found_index=1
1128
+ )
1129
+
1130
+ valores_informado = tab_valores.child_window(
1131
+ class_name="TDBIEditNumber", found_index=2
1132
+ )
1133
+
1134
+
1135
+ valores_informado_text = valores_informado.window_text()
1136
+ valores_restantes_text = valores_restantes.window_text()
1137
+
1138
+ console.print(f"Valor informado: {valores_informado_text} \n")
1139
+ console.print(f"Valor restante: {valores_restantes_text} \n")
1140
+
1141
+
1142
+ console.print(f"Inserindo o valor {valores_restantes_text}... \n")
1143
+ valor = panel_TabParcelamento.child_window(
1144
+ class_name="TDBIEditNumber", found_index=3
1145
+ )
1146
+ valor.set_edit_text(valores_restantes_text)
1147
+ await worker_sleep(5)
1148
+ console.print(f"Adicionando o pagamento... \n")
1149
+ btn_add = panel_TabParcelamento.child_window(
1150
+ class_name="TDBIBitBtn", found_index=1
1151
+ )
1152
+ btn_add.click()
1153
+
1154
+ await worker_sleep(4)
1155
+ console.print(f"Verificando se o pagamento foi adicionado com sucesso... \n")
1156
+ valores_informado = tab_valores.child_window(
1157
+ class_name="TDBIEditNumber", found_index=2
1158
+ )
1159
+ valores_informado_text = valores_informado.window_text()
1160
+ if '0,00' in valores_informado_text and len(valores_informado_text) == 3:
1161
+ return RpaRetornoProcessoDTO(
1162
+ sucesso=False,
1163
+ retorno=f"Erro ao adicionar o pagamento, valor informado {valores_informado_text}.",
1164
+ status=RpaHistoricoStatusEnum.Falha,
1165
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1166
+ )
1167
+ console.print(f"Processo de incluir pagamento realizado com sucesso... \n")
1168
+ except Exception as e:
1169
+ return RpaRetornoProcessoDTO(
1170
+ sucesso=False,
1171
+ retorno=f"Erro ao adicionar o pagamento {e}.",
1172
+ status=RpaHistoricoStatusEnum.Falha,
1173
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1174
+ )
1175
+
1176
+
1177
+ # Inclui registro
1178
+ console.print(f"Incluindo registro...\n")
1179
+ try:
1180
+ ASSETS_PATH = "assets"
1181
+ inserir_registro = pyautogui.locateOnScreen(
1182
+ ASSETS_PATH + "\\entrada_notas\\IncluirRegistro.png", confidence=0.8
1183
+ )
1184
+ pyautogui.click(inserir_registro)
1185
+ except Exception as e:
1186
+ console.print(
1187
+ f"Não foi possivel incluir o registro utilizando reconhecimento de imagem, Error: {e}...\n tentando inserir via posição...\n"
1188
+ )
1189
+ try:
1190
+ retorno = await emsys.incluir_registro(chave_nfe=nota.get("nfe"))
1191
+ if retorno.sucesso == True:
1192
+ return RpaRetornoProcessoDTO(
1193
+ sucesso=error_work.sucesso,
1194
+ retorno=error_work.retorno,
1195
+ status=error_work.status,
1196
+ )
1197
+ except:
1198
+ console.print("A Nota fiscal ainda não foi incluída, continuando o processo...")
1199
+
1200
+
1201
+ await worker_sleep(5)
1202
+ console.print(
1203
+ "Verificando a existencia de POP-UP de Itens que Ultrapassam a Variação Máxima de Custo ...\n"
1204
+ )
1205
+ itens_variacao_maxima = await is_window_open_by_class(
1206
+ "TFrmTelaSelecao", "TFrmTelaSelecao"
1207
+ )
1208
+ if itens_variacao_maxima["IsOpened"] == True:
1209
+ app = Application().connect(class_name="TFrmTelaSelecao")
1210
+ main_window = app["TFrmTelaSelecao"]
1211
+ send_keys("%o")
1212
+
1213
+
1214
+ # Verificando se possui pop-up de Warning
1215
+ await worker_sleep(6)
1216
+ warning_pop_up = await is_window_open("Warning")
1217
+ if warning_pop_up["IsOpened"] == True:
1218
+ app = Application().connect(title="Warning")
1219
+ main_window = app["Warning"]
1220
+ main_window.set_focus()
1221
+
1222
+ console.print(f"Obtendo texto do Warning...\n")
1223
+ console.print(f"Tirando print da janela do warning para realização do OCR...\n")
1224
+
1225
+ window_rect = main_window.rectangle()
1226
+ screenshot = pyautogui.screenshot(
1227
+ region=(
1228
+ window_rect.left,
1229
+ window_rect.top,
1230
+ window_rect.width(),
1231
+ window_rect.height(),
1232
+ )
1233
+ )
1234
+ username = getpass.getuser()
1235
+ path_to_png = f"C:\\Users\\{username}\\Downloads\\warning_popup_{nota.get("nfe")}.png"
1236
+ screenshot.save(path_to_png)
1237
+ console.print(f"Print salvo em {path_to_png}...\n")
1238
+
1239
+ console.print(
1240
+ f"Preparando a imagem para maior resolução e assertividade no OCR...\n"
1241
+ )
1242
+ image = Image.open(path_to_png)
1243
+ image = image.convert("L")
1244
+ enhancer = ImageEnhance.Contrast(image)
1245
+ image = enhancer.enhance(2.0)
1246
+ image.save(path_to_png)
1247
+ console.print(f"Imagem preparada com sucesso...\n")
1248
+ console.print(f"Realizando OCR...\n")
1249
+ captured_text = pytesseract.image_to_string(Image.open(path_to_png))
1250
+ console.print(
1251
+ f"Texto Full capturado {captured_text}...\n"
1252
+ )
1253
+ os.remove(path_to_png)
1254
+ if 'movimento não permitido' in captured_text.lower():
1255
+ return RpaRetornoProcessoDTO(
1256
+ sucesso=False,
1257
+ retorno=f"Filial: {filialEmpresaOrigem} está com o livro fechado ou encerrado, verificar com o setor fiscal",
1258
+ status=RpaHistoricoStatusEnum.Falha,
1259
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
1260
+ )
1261
+ elif 'informe o tipo de' in captured_text.lower():
1262
+ return RpaRetornoProcessoDTO(
1263
+ sucesso=False,
1264
+ retorno=f"Mensagem do Warning, Informe o tipo cobraça ",
1265
+ status=RpaHistoricoStatusEnum.Falha,
1266
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1267
+ )
1268
+ else:
1269
+ return RpaRetornoProcessoDTO(
1270
+ sucesso=False,
1271
+ retorno=f"Warning não mapeado para seguimento do robo, mensagem: {captured_text}",
1272
+ status=RpaHistoricoStatusEnum.Falha,
1273
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1274
+ )
1275
+
1276
+
1277
+ # VERIFICANDO A EXISTENCIA DE ERRO
1278
+ erro_pop_up = await is_window_open("Erro")
1279
+ if erro_pop_up["IsOpened"] == True:
1280
+ await worker_sleep(6)
1281
+ error_work = await error_after_xml_imported()
1282
+ return RpaRetornoProcessoDTO(
1283
+ sucesso=False,
1284
+ retorno=error_work.retorno,
1285
+ status=RpaHistoricoStatusEnum.Falha,
1286
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1287
+ )
1288
+
1289
+ await worker_sleep(8)
1290
+ nf_chave_acesso = int(nota.get("nfe"))
1291
+ status_nf_emsys = await get_status_nf_emsys(nf_chave_acesso)
1292
+ if status_nf_emsys.get("status") == "Lançada":
1293
+ console.print("\nNota lançada com sucesso, processo finalizado...", style="bold green")
1294
+ return RpaRetornoProcessoDTO(
1295
+ sucesso=True,
1296
+ retorno="Nota Lançada com sucesso!",
1297
+ status=RpaHistoricoStatusEnum.Sucesso,
1298
+ )
1299
+ else:
1300
+ console.print("Dupla confirmação lançamento da nota fiscal")
1301
+ # Verifica se a info 'Nota fiscal incluida' está na tela
1302
+ nf_imported = await check_nota_importada(nota.get("nfe"))
1303
+ if nf_imported.sucesso == True:
1304
+ await worker_sleep(12)
1305
+ console.print("\nVerifica se a nota ja foi lançada...")
1306
+ status_nf_emsys = await get_status_nf_emsys(nf_chave_acesso)
1307
+ if status_nf_emsys.get("status") == "Lançada":
1308
+ console.print("\nNota lançada com sucesso, processo finalizado...", style="bold green")
1309
+ return RpaRetornoProcessoDTO(
1310
+ sucesso=True,
1311
+ retorno="Nota Lançada com sucesso!",
1312
+ status=RpaHistoricoStatusEnum.Sucesso,
1313
+ )
1314
+ else:
1315
+ console.print("Erro ao lançar nota", style="bold red")
1316
+ return RpaRetornoProcessoDTO(
1317
+ sucesso=False,
1318
+ retorno=f"Pop-up nota incluida encontrada, porém nota encontrada como 'já lançada' trazendo as seguintes informações: {nf_imported.retorno} - {error_work}",
1319
+ status=RpaHistoricoStatusEnum.Falha,
1320
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Negocio)]
1321
+ )
1322
+ else:
1323
+ console.print("Erro ao lançar nota", style="bold red")
1324
+ return RpaRetornoProcessoDTO(
1325
+ sucesso=False,
1326
+ retorno=f"Erro ao lançar nota, erro: {nf_imported.retorno}",
1327
+ status=RpaHistoricoStatusEnum.Falha,
1328
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1329
+ )
1330
+
1331
+ except Exception as ex:
1332
+ observacao = f"Erro Processo Entrada de Notas: {str(ex)}"
1333
+ logger.error(observacao)
1334
+ console.print(observacao, style="bold red")
1335
+
1336
+ return RpaRetornoProcessoDTO(
1337
+ sucesso=False,
1338
+ retorno=observacao,
1339
+ status=RpaHistoricoStatusEnum.Falha,
1340
+ tags=[RpaTagDTO(descricao=RpaTagEnum.Tecnico)]
1341
+ )
1342
+
1343
+ finally:
1344
+ # Deleta o xml
1345
+ await delete_xml(nota["nfe"])
1346
+