§
    Ò¡’jŽ   ã                  óô   — d dl mZ d dlZd dlmc mZ d dlZd dl	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZmZmZ  G d„ dej        ¦  «        Zedk    r ej        ¦   «          dS dS )é    )ÚannotationsN)ÚDecimal)ÚPath)Ú
TestClient)Úget_current_user)ÚErpDatabaseClient)Ú
create_app)ÚGeometricBreakdownEngine)ÚGroundTruthLoaderÚGroundTruthRowÚQSDrillEvaluatorÚQSRuleSynthesizerc                  óJ   — e Zd ZdZdd„Zdd„Zdd„Zdd„Zdd„Zdd	„Z	dd
„Z
dS )ÚTestAIQuynhTrainingAcademyuf   Kiá»ƒm thá»­ há»‡ thá»‘ng bÃ i táº­p tá»± trá»‹ vÃ  kiá»ƒm chuáº©n AI Quá»³nh QS (HÄ�-2026 Benchmark).ÚreturnÚNonec                ó¬   — t          ¦   «         | _        t          | j        ¦  «        | _        t	          ¦   «         | _        t          d¦  «        | _        d S )NuK   HÄ�-2026/NVH Ä�áº¡i Tháº¯ng-2026/TK-DT/NVH ThÃ´n Ä�áº¡i Tháº¯ng_TD2_8.7.xls)r	   Úappr   Úclientr   Ú	db_clientr   Útest_excel_path)Úselfs    ú:C:\Projects\DSCons\tests\test_ai_quynh_training_academy.pyÚsetUpz TestAIQuynhTrainingAcademy.setUp   sF   € Ý‘<”<ˆŒÝ  ¤Ñ*Ô*ˆŒÝ*Ñ,Ô,ˆŒÝ#ØYñ 
ô  
ˆÔÐÐó    c                óP  — i | j         _        	 | j                             ¦   «         5 }|                     ¦   «         5 }|                     d¦  «         |                     ¦   «          ddd¦  «         n# 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS # t          $ r Y dS w xY w)uU   Rule 12 Teardown: Thu dá»�n sáº¡ch sáº½ toÃ n bá»™ dá»¯ liá»‡u kiá»ƒm thá»­ trong DB.us   DELETE FROM erp_learned_rules WHERE rule_title LIKE 'Tá»± Há»�c [TEST-%' OR rule_title LIKE 'Tá»± Há»�c [DA-NVH-%';N)r   Údependency_overridesr   Úget_connectionÚcursorÚexecuteÚcommitÚ	Exception)r   ÚconnÚcurs      r   ÚtearDownz#TestAIQuynhTrainingAcademy.tearDown"   s5  € à(*ˆŒÔ%ð	Ø”×.Ò.Ñ0Ô0ð "°DØ—[’[‘]”]ð " cØ—K’Kð Nñô ð ð —K’K‘M”M�Mð	"ð "ð "ñ "ô "ð "ð "ð "ð "ð "ð "øøøð "ð "ð "ð "ð"ð "ð "ñ "ô "ð "ð "ð "ð "ð "ð "ð "øøøð "ð "ð "ð "ð "ð "øõ ð 	ð 	ð 	ØˆDˆDð	øøøsW   ŽB §B
¼*A2Á&B
Á2A6	Á6B
Á9A6	Á:B
Á=B Â
BÂB ÂBÂB Â
B%Â$B%c                ó"  — | j                              ¦   «         s|                      d| j         › d�¦  «         t          j        | j         ¦  «        }|                      t          |¦  «        d¦  «         |d         }|                      |j        d¦  «         |                      |j	        d¦  «         |                      |j
        t          d¦  «        ¦  «         |                      |j        ¦  «         |                      d|j        ¦  «         d	S )
uH   Kiá»ƒm thá»­ náº¡p dá»¯ liá»‡u dá»± toÃ¡n tháº­t tá»« há»“ sÆ¡ HÄ�-2026.zExcel file z
 not foundé2   r   Ú1Úm3ú0.0ú=N)r   ÚexistsÚskipTestr   Úload_ground_truth_from_excelÚassertGreaterÚlenÚassertEqualÚsttÚunitÚquantityr   ÚassertIsNotNoneÚformula_breakdownÚassertIn)r   ÚitemsÚfirsts      r   Ú1test_ground_truth_loader_extracts_real_excel_datazLTestAIQuynhTrainingAcademy.test_ground_truth_loader_extracts_real_excel_data/   s÷   € àÔ#×*Ò*Ñ,Ô,ð 	JØ�MŠMÐH¨Ô(<ÐHÐHÐHÑIÔIÐIå!Ô>¸tÔ?SÑTÔTˆØ×Ò�3˜u™:œ: rÑ*Ô*Ð*ð �a”ˆØ×Ò˜œ CÑ(Ô(Ð(Ø×Ò˜œ TÑ*Ô*Ð*Ø×Ò˜5œ>­7°5©>¬>Ñ:Ô:Ð:Ø×Ò˜UÔ4Ñ5Ô5Ð5Ø�Š�c˜5Ô2Ñ3Ô3Ð3Ð3Ð3r   c           	     óü  — t          j        ddddddd¬¦  «        }|                      |d         d	¦  «         |                      d
|d         ¦  «         |                      |d         t          d¦  «        ¦  «         t          j        dddddd¬¦  «        }|                      |d         d¦  «         |                      d|d         ¦  «         t          j        dddd¬¦  «        }|                      |d         d¦  «         |                      |d         d¦  «         t          j        dddd¬¦  «        }|                      |d         d¦  «         |                      |d         t          d¦  «        ¦  «         dS ) u]   Kiá»ƒm thá»­ Ä‘á»™ng cÆ¡ giáº£i toÃ¡n hÃ¬nh há»�c vÃ  sinh cÃ´ng thá»©c phÃ¢n rÃ£ chi tiáº¿t.g       @g      à?é   g      Ð?gš™™™™™¹?é   )ÚlengthÚwidthÚbase_heightÚpile_count_per_footingÚpile_side_or_diaÚpile_embed_depthÚcountÚ	norm_codeúAF.11111u   cá»�cr6   r4   r*   g      $@g      ð?gš™™™™™É?)r>   Úwidth_innerÚheight_innerÚ
wall_thickÚbottom_thickÚ	top_thickzAF.12311r)   r3   g      (@g      Y@é
   )Úbar_diameter_mmÚtotal_length_mÚhooks_countÚ	lap_countzAF.61121u   táº¥ng      ø?g      4@)Úbottom_widthÚdepthr>   Úslope_múAB.11311N)	r
   Úcalculate_pad_footingr1   r7   r/   r   Úcalculate_box_culvertÚcalculate_rebar_weightÚcalculate_trench_excavation)r   ÚfootingÚculvertÚrebarÚtrenchs        r   Ú(test_geometric_breakdown_engine_formulaszCTestAIQuynhTrainingAcademy.test_geometric_breakdown_engine_formulas?   s¨  € õ +Ô@ØØØØ#$Ø!Ø Øð
ñ 
ô 
ˆð 	×Ò˜ Ô-¨zÑ:Ô:Ð:Ø�Š�g˜wÐ':Ô;Ñ<Ô<Ð<Ø×Ò˜7 :Ô.µ¸±´Ñ?Ô?Ð?õ +Ô@ØØØØØØð
ñ 
ô 
ˆð 	×Ò˜ Ô-¨zÑ:Ô:Ð:Ø�Š�d˜G FœOÑ,Ô,Ð,õ )Ô?Ø °ÀBÐRSð
ñ 
ô 
ˆð 	×Ò˜˜{Ô+¨ZÑ8Ô8Ð8Ø×Ò˜˜vœ¨Ñ0Ô0Ð0õ *ÔEØ C°¸cð
ñ 
ô 
ˆð 	×Ò˜ Ô,¨jÑ9Ô9Ð9Ø×Ò˜6 *Ô-­w°u©~¬~Ñ>Ô>Ð>Ð>Ð>r   c           
     ó  — t          ddddt          d¦  «        ¬¦  «        t          ddd	dt          d
¦  «        ¬¦  «        g}ddddddœd	dddddœg}t          j        ddd||¬¦  «        }|                      |j        d¦  «         |                      |j        d¦  «         |                      |j        t          d¦  «        ¦  «         |                      |j	        t          d¦  «        ¦  «         |  
                    |j        d¦  «         dS )uY   Kiá»ƒm thá»­ bá»™ cháº¥m Ä‘iá»ƒm sai sá»‘ (Scorecard) giá»¯a AI Takeoff vÃ  Ground Truth.r(   rF   u   BÃª tÃ´ng Ä‘Ã i mÃ³ng M250r)   z10.0)r2   rE   Ú	task_namer3   r4   Ú2rT   u   Ä�Ã o Ä‘áº¥t há»‘ mÃ³ngz50.0gÍÌÌÌÌÌ#@u   2 * (2*2*0.5 - cá»�c) = 9.9 m3)r_   rE   r3   r4   r6   g     @H@z20 * 1.5 * 1.6 = 48.5 m3zDRILL-TEST-01u   Dá»± Ã¡n Test Ä�Ã o Táº¡oz
TEST-DA-01©Údrill_idÚproject_nameÚproject_codeÚground_truth_itemsÚai_takeoff_itemsr=   ú100.0z3.5)ÚSÚAN)r   r   r   Úevaluate_takeoffr1   Útotal_ground_truth_itemsÚmatched_itemsÚrecall_rate_pctÚ
assertLessÚvolume_mae_pctr7   Úoverall_grade)r   Úgt_rowsÚai_itemsÚ	scorecards       r   Ú test_drill_evaluator_and_scoringz;TestAIQuynhTrainingAcademy.test_drill_evaluator_and_scoringi   sO  € õ ØØ$Ø6ØÝ  ™œðñ ô õ ØØ$Ø3ØÝ  ™œðñ ô ð
ˆð$ :Ø'ØØØ%Eðð ð 7Ø'ØØ Ø%?ðð ð
ˆõ" %Ô5Ø$Ø4Ø%Ø&Ø%ð
ñ 
ô 
ˆ	ð 	×Ò˜Ô;¸QÑ?Ô?Ð?Ø×Ò˜Ô0°!Ñ4Ô4Ð4Ø×Ò˜Ô2µG¸GÑ4DÔ4DÑEÔEÐEØ�Š˜	Ô0µ'¸%±.´.ÑAÔAÐAØ�Š�iÔ-¨zÑ:Ô:Ð:Ð:Ð:r   c                ó„  — t          dddt          d¦  «        ¬¦  «        g}t          j        ddd|g ¬	¦  «        }|                      |j        d
         j        d¦  «         t          j        || j	        ¦  «        }|  
                    t          |¦  «        d¦  «         |                      d|d
         d         ¦  «         dS )uK   Kiá»ƒm thá»­ tá»± Ä‘á»™ng sinh Learned Rules tá»« cÃ¡c sai sá»‘ bÃ³c tÃ¡ch.r(   u   VÃ¡n khuÃ´n mÃ³ng Ä‘Ã i cá»�cÚm2rg   )r2   r_   r3   r4   zDRILL-TEST-RULEu   Dá»± Ã¡n Test RulezTEST-RULE-01ra   r   ÚMISSEDé   ÚFORMWORKÚrule_categoryN)r   r   r   rj   r1   Úevaluated_itemsÚmatch_statusr   Úsynthesize_and_save_rulesr   ÚassertGreaterEqualr0   r7   )r   rq   rs   Úsynthesizeds       r   Ú%test_rule_synthesizer_and_persistencez@TestAIQuynhTrainingAcademy.test_rule_synthesizer_and_persistence™   sØ   € õ ØØ9ØÝ  Ñ)Ô)ð	ñ ô ð
ˆõ %Ô5Ø&Ø-Ø'Ø&Øð
ñ 
ô 
ˆ	ð 	×Ò˜Ô2°1Ô5ÔBÀHÑMÔMÐMå'ÔAØ�t”~ñ
ô 
ˆð 	×Ò¥ KÑ 0Ô 0°!Ñ4Ô4Ð4Ø�Š�j +¨a¤.°Ô"AÑBÔBÐBÐBÐBr   c                óØ  — d„ | j         j        t          <   | j                             d¦  «        }|                      |j        d¦  «         |                     ¦   «         }|                      t          |¦  «        d¦  «         | j         
                    dddi¬¦  «        }|                      |j        d¦  «         |                     ¦   «         }|                      |d         d¦  «         |                      |d	         d
¦  «         | j                             d¦  «        }|                      |j        d¦  «         |                      |                     ¦   «         d         d¦  «         dS )uM   Kiá»ƒm thá»­ toÃ n bá»™ cÃ¡c API Endpoints cá»§a AI Quá»³nh Training Academy.c                 ó   — ddddœS )Nzadmin-test-idzadmin@dscons.vnÚ
superadmin)ÚidÚemailÚrole© r‡   r   r   ú<lambda>zPTestAIQuynhTrainingAcademy.test_training_academy_api_endpoints.<locals>.<lambda>´   s   € Ø!Ø&Ø ðC
ð C
€ r   z/v1/takeoff/training/drillséÈ   rx   z/v1/takeoff/training/run-drillrb   zDRILL-NVH-DAITHANG-2026)Újsonrk   r   z?/v1/takeoff/training/scorecard?drill_id=DRILL-NVH-DAITHANG-2026N)r   r   r   r   Úgetr1   Ústatus_coderŠ   r~   r0   Úpostr/   )r   Ú
res_drillsÚdrills_dataÚres_runÚscorecard_dataÚres_scs         r   Ú#test_training_academy_api_endpointsz>TestAIQuynhTrainingAcademy.test_training_academy_api_endpoints²   s^  € ð;
ð ;
ˆŒÔ%Õ&6Ñ7ð ”[—_’_Ð%BÑCÔCˆ
Ø×Ò˜Ô/°Ñ5Ô5Ð5Ø —o’oÑ'Ô'ˆØ×Ò¥ KÑ 0Ô 0°!Ñ4Ô4Ð4ð ”+×"Ò"Ø,ØÐ7Ð8ð #ñ 
ô 
ˆð 	×Ò˜Ô,¨cÑ2Ô2Ð2Ø Ÿš™œˆØ×Ò˜¨
Ô3Ð5NÑOÔOÐOØ×Ò˜>Ð*DÔEÀqÑIÔIÐIð ”—’ØMñ
ô 
ˆð 	×Ò˜Ô+¨SÑ1Ô1Ð1Ø×Ò˜Ÿš™œ zÔ2Ð4MÑNÔNÐNÐNÐNr   N)r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r%   r:   r]   rt   r€   r“   r‡   r   r   r   r      s²   € € € € € ØpÐpð
ð 
ð 
ð 
ðð ð ð ð4ð 4ð 4ð 4ð (?ð (?ð (?ð (?ðT.;ð .;ð .;ð .;ð`Cð Cð Cð Cð2Oð Oð Oð Oð Oð Or   r   Ú__main__) Ú
__future__r   ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚunittestÚdecimalr   Úpathlibr   Úfastapi.testclientr   Ú"app.modules.auth.presentation.authr   Úapp.core.postgres.erp_clientr   Úapp.mainr	   Ú:app.modules.takeoff.application.geometric_breakdown_enginer
   Ú0app.modules.takeoff.application.takeoff_trainingr   r   r   r   ÚTestCaser   r”   Úmainr‡   r   r   ú<module>r«      sd  ðØ "Ð "Ð "Ð "Ð "Ð "à  € € € € € € € € € € € € €€€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð à )Ð )Ð )Ð )Ð )Ð )à ?Ð ?Ð ?Ð ?Ð ?Ð ?Ø :Ð :Ð :Ð :Ð :Ð :Ø Ð Ð Ð Ð Ð ðð ð ð ð ð ðð ð ð ð ð ð ð ð ð ð ð ðxOð xOð xOð xOð xO Ô!2ñ xOô xOð xOðv ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr   