§
    	1šj«Ÿ  ã                  ó„   — d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m
Z
  ej        d¦  «        Z G d„ d	¦  «        ZdS )
u2  AEC 3-Way Matching Service (HÃ³a Ä�Æ¡n Mua VÃ o <-> Dá»± Ã�n WBS <-> Ä�Æ¡n GiÃ¡ Sá»Ÿ XÃ¢y Dá»±ng Háº£i PhÃ²ng).
COMPLIANT WITH: Luáº­t XÃ¢y dá»±ng 2025, Quy chuáº©n 4 Trá»¥ Cá»™t Ä�á»‹nh SÆ¡n (MST 0202111150) & SOP-DSCONS-AEC-BOQ-ALLOC-2026.
Strict Zero-Tolerance Synthetic Data & Decimal(18,4) COMPLIANT.
é    )ÚannotationsN)ÚDecimal)ÚAny)ÚErpDatabaseClientzdscons.aec_3way_matchingc                  ó„   — e Zd ZdZd-d.d„Zd/d	„Z	 	 	 	 	 d0d1d„Zd2d„Zd3d„Zd4d„Z	d5d6d#„Z
d4d$„Z	 	 d7d8d(„Zd4d)„Z	 d9d:d,„ZdS );ÚAec3WayMatchingServiceuX   Dá»‹ch vá»¥ Ä‘á»‘i soÃ¡t 3 chiá»�u AEC cho hÃ³a Ä‘Æ¡n Ä‘áº§u vÃ o CÃ´ng ty Ä�á»‹nh SÆ¡n.NÚ
erp_clientúErpDatabaseClient | NoneÚreturnÚNonec                ó0   — |pt          ¦   «         | _        d S ©N)r   Údb)Úselfr	   s     úPC:\Projects\DSCons\app\modules\invoices\application\aec_3way_matching_service.pyÚ__init__zAec3WayMatchingService.__init__   s   € ØÐ3Õ 1Ñ 3Ô 3ˆŒˆˆó    údict[str, Any]c                ó’  — | j                              ¦   «         5 }|                     ¦   «         5 }|                     d¦  «         |                     ¦   «         pi }|                     d¦  «         |                     ¦   «         pi }t          |                     d¦  «        pd¦  «        }t          |                     d¦  «        pd¦  «        }|dk    rt          ||z  dz  d¦  «        nd}|t          |                     d	¦  «        pd¦  «        |t          |                     d
¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        |t          |                     d¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        t          |                     d¦  «        pd¦  «        dœdœcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )u>   Tá»•ng há»£p chá»‰ sá»‘ KPI 3-Way Matching toÃ n há»‡ thá»‘ng.a•  
                SELECT 
                    count(*) as total_invoices,
                    coalesce(sum(total_amount_vnd), 0) as total_amount,
                    count(*) FILTER (WHERE matched_project_id IS NOT NULL) as matched_invoices,
                    coalesce(sum(total_amount_vnd) FILTER (WHERE matched_project_id IS NOT NULL), 0) as matched_amount,
                    count(*) FILTER (WHERE matched_project_id IS NULL) as unmatched_invoices,
                    coalesce(sum(total_amount_vnd) FILTER (WHERE matched_project_id IS NULL), 0) as unmatched_amount
                FROM erp_invoices
                WHERE direction = 'input';
            a¡  
                WITH sample_items AS (
                    SELECT it.id, it.item_name, it.unit_price_vnd, it.quantity
                    FROM erp_invoice_items it
                    JOIN erp_invoices i ON it.invoice_id = i.id
                    WHERE i.direction = 'input' AND it.unit_price_vnd > 0
                    LIMIT 400
                ),
                benchmark_items AS (
                    SELECT 
                        it.id,
                        it.unit_price_vnd,
                        it.quantity,
                        sp.state_unit_price_vnd
                    FROM sample_items it
                    JOIN LATERAL (
                        SELECT state_unit_price_vnd
                        FROM erp_state_published_prices sp
                        WHERE it.item_name ILIKE ('%%' || split_part(sp.material_name, ' ', 1) || '%%')
                        LIMIT 1
                    ) sp ON TRUE
                    WHERE sp.state_unit_price_vnd > 0
                )
                SELECT 
                    count(*) as audited_count,
                    count(*) FILTER (WHERE unit_price_vnd <= state_unit_price_vnd) as safe_count,
                    count(*) FILTER (WHERE unit_price_vnd > state_unit_price_vnd) as alert_count,
                    coalesce(sum(GREATEST(0, (unit_price_vnd - state_unit_price_vnd) * quantity)), 0) as total_risk_vnd
                FROM benchmark_items;
            Útotal_invoicesr   Úmatched_invoiceséd   é   ç        Útotal_amountÚmatched_amountÚunmatched_invoicesÚunmatched_amountÚaudited_countÚ
safe_countÚalert_countÚtotal_risk_vnd)Úaudited_items_countÚsafe_items_countÚalert_items_countÚtotal_risk_amount_vnd)r   Útotal_amount_vndr   Úmatched_amount_vndr   Úunmatched_amount_vndÚmatched_rate_pctÚprice_benchmarkN)	r   Úget_connectionÚcursorÚexecuteÚfetchoneÚintÚgetÚroundÚfloat)r   ÚconnÚcurÚinv_statÚ
bench_statÚ	total_invÚmatched_invÚmatched_rates           r   Úget_matching_summaryz+Aec3WayMatchingService.get_matching_summary   s÷  € àŒW×#Ò#Ñ%Ô%ð B	¨¨t¯{ª{©}¬}ð B	Àà�KŠKð 
ñ 
ô 
ð 
ð —|’|‘~”~Ð+¨ˆHð �KŠKð ñ ô ð ð< Ÿš™œÐ-¨2ˆJå˜HŸLšLÐ)9Ñ:Ô:Ð?¸aÑ@Ô@ˆIÝ˜hŸlšlÐ+=Ñ>Ô>ÐCÀ!ÑDÔDˆKØHQÐTUÊÈ�5 +°	Ñ"9¸CÑ"?À!ÑDÔDÐDÐ[^ˆLð #,Ý$)¨(¯,ª,°~Ñ*FÔ*FÐ*KÈ!Ñ$LÔ$LØ$/Ý&+¨H¯LªLÐ9IÑ,JÔ,JÐ,OÈaÑ&PÔ&PÝ&)¨(¯,ª,Ð7KÑ*LÔ*LÐ*QÐPQÑ&RÔ&RÝ(-¨h¯lªlÐ;MÑ.NÔ.NÐ.SÐRSÑ(TÔ(TØ$0å+.¨z¯~ª~¸oÑ/NÔ/NÐ/SÐRSÑ+TÔ+TÝ(+¨J¯NªN¸<Ñ,HÔ,HÐ,MÈAÑ(NÔ(NÝ),¨Z¯^ª^¸MÑ-JÔ-JÐ-OÈaÑ)PÔ)PÝ-2°:·>²>ÐBRÑ3SÔ3SÐ3XÐWXÑ-YÔ-Yð	$ð $ðð ðiB	ð B	ð B	ð B	ñ B	ô B	ð B	ð B	ð B	ð B	ð B	ñ B	ô B	ð B	ð B	ð B	ð B	ð B	ð B	øøøð B	ð B	ð B	ð B	ð B	ð B	ð B	ñ B	ô B	ð B	ð B	ð B	ð B	ð B	ð B	ð B	øøøð B	ð B	ð B	ð B	ð B	ð B	s5   šH<¯GH$ÈH<È$H(	È(H<È+H(	È,H<È<I ÉI ÚALLé2   r   ÚstatusÚstrÚ
project_idú
str | NoneÚsearchÚlimitr0   Úoffsetc                ót  — | j                              ¦   «         5 }|                     ¦   «         5 }dg}g }	|                     ¦   «         dk    r|                     d¦  «         n-|                     ¦   «         dk    r|                     d¦  «         |r*|                     d¦  «         |	                     |¦  «         |rE|                     d¦  «         d|                     ¦   «         › d�}
|	                     |
|
|
g¦  «         d	                     |¦  «        }d
|› d�}|                     ||	¦  «         | 	                    ¦   «         d         }d|› d�}|                     ||	||gz   ¦  «         | 
                    ¦   «         }g }|D ]n}t          |¦  «        }|d         s|                      ||¦  «        }||d<   nd|d<   |                      |d         |¦  «        |d<   |                     |¦  «         Œo||||dœcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )uB   Danh sÃ¡ch hÃ³a Ä‘Æ¡n mua vÃ o phá»¥c vá»¥ Ä‘á»‘i soÃ¡t 3 chiá»�u.zi.direction = 'input'ÚMATCHEDz i.matched_project_id IS NOT NULLÚ	UNMATCHEDzi.matched_project_id IS NULLzi.matched_project_id::text = %szI(i.invoice_number ILIKE %s OR i.seller_name ILIKE %s OR i.notes ILIKE %s)ú%z AND z3SELECT count(*) as total FROM erp_invoices i WHERE ú;Útotala^  
                SELECT 
                    i.id, i.invoice_number, i.invoice_series, i.issue_date,
                    i.seller_name, i.seller_tax_code, i.total_amount_vnd,
                    i.subtotal_amount_vnd, i.vat_amount_vnd, i.reconciliation_status,
                    i.matched_project_id, i.matched_wbs_id, i.notes,
                    p.project_code as matched_project_code,
                    p.project_name as matched_project_name,
                    (
                        SELECT count(*) 
                        FROM erp_invoice_items it 
                        WHERE it.invoice_id = i.id
                    ) as item_count,
                    (
                        SELECT string_agg(it.item_name, '; ')
                        FROM (
                            SELECT item_name FROM erp_invoice_items 
                            WHERE invoice_id = i.id 
                            LIMIT 3
                        ) it
                    ) as sample_items
                FROM erp_invoices i
                LEFT JOIN projects p ON i.matched_project_id = p.id
                WHERE zu
                ORDER BY i.issue_date DESC, i.total_amount_vnd DESC
                LIMIT %s OFFSET %s;
            Úmatched_project_idÚ
suggestionNÚidÚsxd_benchmark)rJ   rC   rD   Úinvoices)r   r,   r-   ÚupperÚappendÚstripÚextendÚjoinr.   r/   ÚfetchallÚdictÚ_suggest_project_for_invoiceÚ_quick_check_sxd_benchmark)r   r>   r@   rB   rC   rD   r4   r5   Úwhere_clausesÚparamsÚs_paramÚ	where_strÚcount_queryrJ   ÚqueryÚrowsÚresultsÚrÚinv_dictrL   s                       r   Úlist_matching_invoicesz-Aec3WayMatchingService.list_matching_invoices^   s>  € ð ŒW×#Ò#Ñ%Ô%ð G	¨¨t¯{ª{©}¬}ð G	ÀØ4Ð5ˆMØ "ˆFà�|Š|‰~Œ~ Ò*Ð*Ø×$Ò$Ð%GÑHÔHÐHÐHØ—’‘” ;Ò.Ð.Ø×$Ò$Ð%CÑDÔDÐDàð *Ø×$Ò$Ð%FÑGÔGÐGØ—’˜jÑ)Ô)Ð)àð ;Ø×$Ò$Ð%pÑqÔqÐqØ/˜fŸlšl™nœnÐ/Ð/Ð/�Ø—’˜w¨°Ð9Ñ:Ô:Ð:àŸš ]Ñ3Ô3ˆIà\ÐPYÐ\Ð\Ð\ˆKØ�KŠK˜ VÑ,Ô,Ð,Ø—L’L‘N”N 7Ô+ˆEðð. !ð/ð ð ˆEð6 �KŠK˜˜v¨°¨Ñ7Ñ8Ô8Ð8Ø—<’<‘>”>ˆDàˆGØð 	)ð 	)�Ý ™7œ7�ØÐ 4Ô5ð 2Ø!%×!BÒ!BÀ8ÈSÑ!QÔ!Q�JØ-7�H˜\Ñ*Ð*à-1�H˜\Ñ*à,0×,KÒ,KÈHÐUYÌNÐ\_Ñ,`Ô,`�˜Ñ)Ø—’˜xÑ(Ô(Ð(Ð(ð ØØ Ø#ð	ð ðEG	ð G	ð G	ð G	ñ G	ô G	ð G	ð G	ð G	ð G	ð G	ñ G	ô G	ð G	ð G	ð G	ð G	ð G	ð G	øøøð G	ð G	ð G	ð G	ð G	ð G	ð G	ñ G	ô G	ð G	ð G	ð G	ð G	ð G	ð G	ð G	øøøð G	ð G	ð G	ð G	ð G	ð G	s5   šH-¯GHÇ<H-ÈH	ÈH-ÈH	ÈH-È-H1È4H1Ú
invoice_idr5   r   c                óŒ  — |                      d|f¦  «         |                     ¦   «         }|sddddœS t          d„ |D ¦   «         ¦  «        }|rqt          |d„ ¬¦  «        }t	          t          |d	         ¦  «        t          |d
         ¦  «        z  dz
  dz  d¦  «        }dd|› d�|dk     rdnd|d         |d         dœS ddddœS )uL   Ä�Ã¡nh giÃ¡ nhanh tráº¡ng thÃ¡i so vá»›i giÃ¡ Sá»Ÿ XÃ¢y dá»±ng Háº£i PhÃ²ng.ab  
            SELECT it.item_name, it.unit_price_vnd, sp.state_unit_price_vnd, sp.material_name as sxd_name
            FROM erp_invoice_items it
            JOIN LATERAL (
                SELECT state_unit_price_vnd, material_name
                FROM erp_state_published_prices sp
                WHERE it.item_name ILIKE ('%%' || split_part(sp.material_name, ' ', 1) || '%%')
                ORDER BY sp.effective_date DESC NULLS LAST
                LIMIT 1
            ) sp ON TRUE
            WHERE it.invoice_id = %s AND it.unit_price_vnd > 0 AND sp.state_unit_price_vnd > 0
            LIMIT 5;
        Ú
UNASSESSEDu   ChÆ°a cÃ³ Ä‘á»‹nh má»©c SXDÚgray)r>   ÚlabelÚcolorc              3  ót   K  — | ]3}t          |d          ¦  «        t          |d         ¦  «        dz  k    V — Œ4dS )Úunit_price_vndÚstate_unit_price_vndgÍÌÌÌÌÌð?N©r3   ©Ú.0Úits     r   ú	<genexpr>zDAec3WayMatchingService._quick_check_sxd_benchmark.<locals>.<genexpr>Ã   sJ   è è € ÐoÐoÐce�˜bÐ!1Ô2Ñ3Ô3µe¸BÐ?UÔ<VÑ6WÔ6WÐZ^Ñ6^Ò^ÐoÐoÐoÐoÐoÐor   c                óX   — t          | d         ¦  «        t          | d         ¦  «        z  S )Nrk   rl   rm   ©Úxs    r   ú<lambda>zCAec3WayMatchingService._quick_check_sxd_benchmark.<locals>.<lambda>Å   s(   € µ°aÐ8HÔ6IÑ0JÔ0JÍUÐSTÐUkÔSlÑMmÔMmÑ0m€ r   )Úkeyrk   rl   r   r   ÚALERTu   VÆ°á»£t SXD (+z%)é   ÚamberÚroseÚ	item_nameÚsxd_name)r>   rh   ri   r{   r|   ÚSAFEu   Ä�áº¡t chuáº©n Sá»Ÿ XDÚgreen)r.   rU   ÚanyÚmaxr2   r3   )r   rd   r5   ÚitemsÚ	has_alertÚmax_itemÚpct_overs          r   rX   z1Aec3WayMatchingService._quick_check_sxd_benchmark°   s  € à�Šð ð ˆ]ñ	ô 	ð 	ð —’‘”ˆØð 	eØ*Ð5RÐ]cÐdÐdÐdåÐoÐoÐinÐoÑoÔoÑoÔoˆ	Øð 		Ý˜5Ð&mÐ&mÐnÑnÔnˆHÝ�e HÐ-=Ô$>Ñ?Ô?Å%ÈÐQgÔHhÑBiÔBiÑiÐlmÑmÐqtÑtÐvwÑxÔxˆHà!Ø6¨(Ð6Ð6Ð6Ø$,¨r¢M M˜˜°vØ% kÔ2Ø$ ZÔ0ðð ð ð !Ð+CÈgÐVÐVÐVr   Úinvúdict[str, Any] | Nonec           	     ó0  ‡— t          |                     d¦  «        pd¦  «                             ¦   «         }t          |                     d¦  «        pd¦  «                             ¦   «         }t          |                     d¦  «        pd¦  «                             ¦   «         }t          |                     d¦  «        pd¦  «                             ¦   «         }|› d|› d|› �Šd|v sd‰v rd	d
ddddœS d‰v sd‰v sd‰v sd‰v rd	dddddœS d‰v sd‰v sd‰v sd‰v rd	dddddœS d‰v sd|v rdd d!dd"dœS d#‰v sd$‰v rdd%d&dd'dœS g d(¢}|D ]]\  }}	}
|‰v rS|                     d)|	f¦  «         |                     ¦   «         }|rt          |d*         ¦  «        nd+}d,||	|
dd-|› d.�d/œc S Œ^t          ˆfd0„d1D ¦   «         ¦  «        rS|                     d2¦  «         |                     ¦   «         }|r(d,t          |d*         ¦  «        |d3         |d4         d5d6d/œS d+S )7uW   Gá»£i Ã½ dá»± Ã¡n & WBS thÃ´ng minh dá»±a trÃªn 4 Trá»¥ Cá»™t vÃ  PhÃ¢n rÃ£ Tá»« KhÃ³a.Úseller_tax_codeÚ Úseller_nameÚnotesÚsample_itemsú Ú
0200149705õ   thoÃ¡t nÆ°á»›cé   zTC2-LOGISTICSuJ   Há»£p Ä�á»“ng Váº­n Chuyá»ƒn BÃ¹n Ä�áº¥t - Cty ThoÃ¡t NÆ°á»›c Háº£i PhÃ²ngÚhighuF   NhÃ  tháº§u phá»¥/KhÃ¡ch hÃ ng Trá»¥ Cá»™t 2 (Váº­n táº£i & Logistics))ÚpillarÚproject_codeÚproject_nameÚ
confidenceÚreasonÚ
petrolimexu   tÃ¢n tháº¿ huynhõ   dáº§u doõ   dáº§u Ä‘iÃªzenzFLEET-FUEL-POOLu>   NhiÃªn Liá»‡u Dáº§u DO Ä�oÃ n Xe Ben Howo & Ca MÃ¡y CÆ¡ Giá»›iu@   HÃ³a Ä‘Æ¡n cáº¥p dáº§u DO váº­n hÃ nh Ä�oÃ n Xe Ben & MÃ¡y Ä�Ã ou   Ã´ tÃ´ táº£i tá»± Ä‘á»•ÚhowoÚcnhtcu   táº­p Ä‘oÃ n thiÃªn khzFLEET-ASSETu*   TÃ i Sáº£n CÆ¡ Giá»›i - Ä�oÃ n Xe Ben Howou>   HÃ³a Ä‘Æ¡n Ä‘áº§u tÆ° phÆ°Æ¡ng tiá»‡n cÆ¡ giá»›i Ä�oÃ n Xe Benu   loan kháº£iÚ
0201889988é   zTC3-MACHINERYu@   Há»£p Ä�á»“ng Cho ThuÃª MÃ¡y Ä�Ã o BÃ¡nh XÃ­ch - Cty Loan Kháº£iu4   KhÃ¡ch hÃ ng Trá»¥ Cá»™t 3 (Cho thuÃª ca mÃ¡y Ä‘Ã o)u   mÃ¡y Ä‘Ã o bÃ¡nh xÃ­chu   mÃ¡y Ä‘Ã o bÃ¡nh lá»‘pzTC3-EQUIPMENTu9   Ä�á»™i MÃ¡y Ä�Ã o BÃ¡nh XÃ­ch & MÃ¡y Thi CÃ´ng CÆ¡ Giá»›iu3   Thiáº¿t bá»‹ mÃ¡y thi cÃ´ng Ä‘Ã o Ä‘áº¯p cÆ¡ giá»›i))õ   Ä‘áº¡i tháº¯ngúDA-2608281122õ#   NhÃ  vÄƒn hÃ³a thÃ´n Ä�áº¡i Tháº¯ng)u   thÃ´n Ä‘áº¡i tháº¯ngrŸ   r    )u   máº¡nh hÃ¹ngrŸ   uJ   NhÃ  vÄƒn hÃ³a thÃ´n Ä�áº¡i Tháº¯ng (Váº­t tÆ° xÃ  gá»“ thÃ©p & mÃ¡i tÃ´n))Úvinhomesz
DA-2026-46u,   KÄ�T Má»›i Vinhomes Golden City DÆ°Æ¡ng Kinh)õ	   báº¿n kemú
DA-2026-02õ,   Cá»‘ng Báº¿n Kem & Chiáº¿u sÃ¡ng Kiáº¿n Minh)u   kiáº¿n minhr£   r¤   )õ	   Ä‘a Ä‘á»™z
DA-2026-01u+   KÃ¨ SÃ´ng Ä�a Ä�á»™ - Huyá»‡n Kiáº¿n Thá»¥y)u   cá»• tiá»ƒuz
DA-2026-32u&   Cá»‘ng Cá»• Tiá»ƒu 2, 3 xÃ£ Ä�oÃ n XÃ¡)õ
   tÃ¢n trÃ oz
DA-2026-03u   TrÆ°á»�ng Máº§m Non TÃ¢n TrÃ o)u
   Ã´ng Ä‘Ã¨nz
DA-2026-05u   KÃªnh Ã”ng Ä�Ã¨n)u   ráº¡ng Ä‘Ã´ngz
DA-2026-10u'   Háº¡ Táº§ng Chiáº¿u SÃ¡ng Ráº¡ng Ä�Ã´ngú8SELECT id FROM projects WHERE project_code = %s LIMIT 1;rM   Nr   u    Khá»›p tá»« khÃ³a cÃ´ng trÃ¬nh 'u   ' trÃªn hÃ³a Ä‘Æ¡n)r’   r@   r“   r”   r•   r–   c              3  ó    •K  — | ]}|‰v V — Œ	d S r   © ©ro   ÚwÚ	full_texts     €r   rq   zFAec3WayMatchingService._suggest_project_for_invoice.<locals>.<genexpr>"  s'   øè è € Ð]Ð] !ˆq�Iˆ~Ð]Ð]Ð]Ð]Ð]Ð]r   )õ   thÃ©pu   sáº¯tõ   xi mÄƒngõ	   bÃª tÃ´ngõ   gáº¡chzaSELECT id, project_code, project_name FROM projects WHERE project_code = 'DA-2608281122' LIMIT 1;r“   r”   ÚmediumuP   Váº­t tÆ° xÃ¢y láº¯p chÃ­nh (Æ¯u tiÃªn dá»± Ã¡n Ä‘ang thi cÃ´ng trá»�ng Ä‘iá»ƒm))r?   r1   rR   Úlowerr.   r/   r   )r   r…   r5   Ú
seller_taxrŠ   r‹   Ú
items_textÚproject_keywordsÚkwÚp_codeÚp_nameÚp_rowÚp_idr¬   s                @r   rW   z3Aec3WayMatchingService._suggest_project_for_invoiceÑ   sW  ø€ å˜ŸšÐ!2Ñ3Ô3Ð9°rÑ:Ô:×@Ò@ÑBÔBˆ
Ý˜#Ÿ'š' -Ñ0Ô0Ð6°BÑ7Ô7×=Ò=Ñ?Ô?ˆÝ�C—G’G˜GÑ$Ô$Ð*¨Ñ+Ô+×1Ò1Ñ3Ô3ˆÝ˜Ÿš Ñ0Ô0Ð6°BÑ7Ô7×=Ò=Ñ?Ô?ˆ
Ø"Ð9Ð9 UÐ9Ð9¨ZÐ9Ð9ˆ	ð ˜:Ð%Ð%Ð)9¸YÐ)FÐ)FàØ /Ø lØ$Øbðð ð ð ˜9Ð$Ð$Ð(:¸iÐ(GÐ(GÈ:ÐYbÐKbÐKbÐfvð  {Dð  gDð  gDàØ 1Ø `Ø$Ø\ðð ð ð %¨	Ð1Ð1°V¸yÐ5HÐ5HÈGÐW`ÐL`ÐL`Ðd|ð  AJð  eJð  eJàØ -Ø LØ$ØZðð ð ð ˜IÐ%Ð%¨¸Ð)CÐ)CàØ /Ø bØ$ØPðð ð ð $ yÐ0Ð0Ð4LÐPYÐ4YÐ4YàØ /Ø [Ø$ØOðð ð ð
ð 
ð 
Ðð #3ð 	ð 	ÑˆB�˜Ø�YˆˆØ—’ÐVÐY_ÐXaÑbÔbÐbØŸš™œ�Ø+0Ð:•s˜5 œ;Ñ'Ô'Ð'°d�àØ"&Ø$*Ø$*Ø"(ØWÀÐWÐWÐWðð ð ð ð ð	 õ Ð]Ð]Ð]Ð]Ð'\Ð]Ñ]Ô]Ñ]Ô]ð 	Ø�KŠKÐ{Ñ|Ô|Ð|Ø—L’L‘N”NˆEØð àÝ"% e¨D¤kÑ"2Ô"2Ø$)¨.Ô$9Ø$)¨.Ô$9Ø"*Øpðð ð ð ˆtr   c                ó~  — | j                              ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|st          d|› �¦  «        ‚t          |¦  «        }|                     d|f¦  «         |                     ¦   «         }g }t          d¦  «        }|D �]_}	t          |	¦  «        }
t          t          |
d         pd¦  «        ¦  «        }t          t          |
d         pd¦  «        ¦  «        }|                     d|
d	         |
d	         f¦  «         |                     ¦   «         }|r­t          t          |d
         pd¦  «        ¦  «        }||z
  }|dk    rt          ||z  dz  d¦  «        nd}|dk    r|||z  z  }d|d         |d         t          |¦  «        t          |¦  «        t          |¦  «        |d         p|d         |dk    rdnddœ|
d<   n	ddddœ|
d<   |                     |
¦  «         �Œad}|d         sBd                     d„ |dd …         D ¦   «         ¦  «        }||d!<   |                      ||¦  «        }|||t          |¦  «        |dk    d"œcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )#uc   Chi tiáº¿t Ä‘á»‘i soÃ¡t 3 chiá»�u cho 1 hÃ³a Ä‘Æ¡n: HÃ³a Ä‘Æ¡n vs WBS vs GiÃ¡ Sá»Ÿ XD Háº£i PhÃ²ng.zÑ
                SELECT i.*, p.project_code, p.project_name
                FROM erp_invoices i
                LEFT JOIN projects p ON i.matched_project_id = p.id
                WHERE i.id = %s;
            õ"   KhÃ´ng tÃ¬m tháº¥y hÃ³a Ä‘Æ¡n ID: a…  
                SELECT 
                    it.id, it.item_order, it.item_name, it.unit, it.quantity,
                    it.unit_price_vnd, it.total_item_amount_vnd, it.vat_rate_percent,
                    it.cost_category, it.matched_wbs_code
                FROM erp_invoice_items it
                WHERE it.invoice_id = %s
                ORDER BY it.item_order, it.id;
            Ú0rk   r   Úquantityañ  
                    SELECT material_code, material_name, specifications, unit, 
                           state_unit_price_vnd, document_reference, publish_period
                    FROM erp_state_published_prices
                    WHERE material_name ILIKE ('%%' || split_part(%s, ' ', 1) || '%%')
                       OR specifications ILIKE ('%%' || split_part(%s, ' ', 1) || '%%')
                    ORDER BY effective_date DESC NULLS LAST
                    LIMIT 1;
                r{   rl   r   r   r   TÚmaterial_nameÚunitÚdocument_referenceÚpublish_periodé   rw   r}   )Úmatchedr¿   rÀ   rl   Údiff_vndÚdiff_pctÚdocument_refr>   rN   Fu<   KhÃ´ng tÃ¬m tháº¥y Ä‘á»‹nh má»©c cÃ´ng bá»‘ tÆ°Æ¡ng Ä‘Æ°Æ¡ngrf   )rÄ   Úmessager>   NrK   ú; c              3  ó&   K  — | ]}|d          V — ŒdS )r{   Nr©   rn   s     r   rq   zBAec3WayMatchingService.get_invoice_audit_detail.<locals>.<genexpr>{  s&   è è € Ð&TÐ&T¸2 r¨+¤Ð&TÐ&TÐ&TÐ&TÐ&TÐ&Tr   r�   rŒ   )ÚinvoicerL   r�   Útotal_price_risk_vndÚis_compliant)r   r,   r-   r.   r/   Ú
ValueErrorrV   rU   r   r?   r2   r3   rQ   rT   rW   )r   rd   r4   r5   r…   rb   r�   Úenriched_itemsÚtotal_variance_vndra   rp   Úu_priceÚqtyÚ	sxd_matchÚ	sxd_pricerÅ   rÆ   rL   Ú
sample_strs                      r   Úget_invoice_audit_detailz/Aec3WayMatchingService.get_invoice_audit_detail1  sõ  € àŒW×#Ò#Ñ%Ô%ð R	¨¨t¯{ª{©}¬}ð R	ÀØ�KŠKð ð
 �ñ ô  ð  ð —,’,‘.”.ˆCØð TÝ Ð!RÀjÐ!RÐ!RÑSÔSÐSå˜C‘y”yˆHà�KŠKð ð �ñ ô  ð  ð —L’L‘N”NˆEàˆNÝ!(¨¡¤Ðàð )*ñ )*�Ý˜!‘W”W�Ý!¥# bÐ)9Ô&:Ð&?¸aÑ"@Ô"@ÑAÔA�Ý�c " Z¤.Ð"5°AÑ6Ô6Ñ7Ô7�à—’ð ð ˜”o r¨+¤Ð7ñ9ô 9ð 9ð  ŸLšL™NœN�	àð Ý '­¨IÐ6LÔ,MÐ,RÐQRÑ(SÔ(SÑ TÔ T�IØ&¨Ñ2�HØIRÐUVÊÈ�u h°Ñ&:¸SÑ&@À1ÑEÔEÐEÐ\_�Hà !’|�|Ø*¨x¸#©~Ñ>Ð*ð $(Ø)2°?Ô)CØ )¨&Ô 1Ý05°iÑ0@Ô0@Ý$)¨(¡O¤OÝ$)¨(¡O¤OØ(1Ð2FÔ(GÐ(fÈ9ÐUeÔKfØ-5¸ª\¨\ ' '¸vð	+ð 	+�B�Ñ'Ð'ð $)Ø#aØ".ð+ð +�B�Ñ'ð ×%Ò% bÑ)Ô)Ð)Ñ)àˆJØÐ0Ô1ð NØ!ŸYšYÐ&TÐ&TÀÐPRÐQRÐPRÔASÐ&TÑ&TÔ&TÑTÔT�
Ø+5�˜Ñ(Ø!×>Ò>¸xÈÑMÔM�
ð $Ø(Ø'Ý(-Ð.@Ñ(AÔ(AØ!3°qÒ!8ðð ðYR	ð R	ð R	ð R	ñ R	ô R	ð R	ð R	ð R	ð R	ð R	ñ R	ô R	ð R	ð R	ð R	ð R	ð R	ð R	øøøð R	ð R	ð R	ð R	ð R	ð R	ð R	ñ R	ô R	ð R	ð R	ð R	ð R	ð R	ð R	ð R	øøøð R	ð R	ð R	ð R	ð R	ð R	s5   šJ2¯IJÊJ2ÊJ	ÊJ2Ê!J	Ê"J2Ê2J6Ê9J6Téè  Údry_runÚboolÚ	max_itemsc                ó€  — | j                              ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }d}t          d¦  «        }dddddœ}g }	|D �]É}
|                      t          |
¦  «        |¦  «        }|�r |                     d¦  «        dv �rˆ|                     d¦  «        }|                     d¦  «        }|sD|rB|                     d	|f¦  «         | 	                    ¦   «         }|rt          |d
         ¦  «        }t          t          |
d         pd¦  «        ¦  «        }|dz  }||z  }|                     dd¦  «        }|                     |d¦  «        dz   ||<   |	                     t          |
d
         ¦  «        |
d         |
d         t          |¦  «        |||                     d¦  «        |                     d¦  «        | ot          |¦  «        dœ	¦  «         |s5|r3|                     d||                     dd¦  «        |
d
         f¦  «         �ŒË|s|                     ¦   «          |t          |¦  «        |t          |¦  «        ||	dd…         dœcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )ug   Tá»± Ä‘á»™ng phÃ¢n bá»• hÃ ng loáº¡t cÃ¡c hÃ³a Ä‘Æ¡n mua vÃ o chÆ°a khá»›p vÃ o Dá»± Ã¡n / Trá»¥ Cá»™t.aÒ  
                SELECT i.id, i.invoice_number, i.seller_name, i.seller_tax_code,
                       i.notes, i.total_amount_vnd,
                       (SELECT string_agg(it.item_name, '; ') FROM erp_invoice_items it WHERE it.invoice_id = i.id) as sample_items
                FROM erp_invoices i
                WHERE i.direction = 'input' AND i.matched_project_id IS NULL
                ORDER BY i.total_amount_vnd DESC
                LIMIT %s;
            r   r½   )r   r�   r�   é   r•   )r‘   r±   r@   r“   r§   rM   r'   r   r’   Úinvoice_numberrŠ   r”   r–   )	rd   rÝ   rŠ   Ú
amount_vndÚsuggested_pillarÚsuggested_project_codeÚsuggested_project_namer–   Úapplieda˜  
                            UPDATE erp_invoices
                            SET matched_project_id = %s,
                                reconciliation_status = '3WAY_MATCHED',
                                notes = COALESCE(notes, '') || ' [AI 3-Way Matched: ' || %s || ']',
                                updated_at = CURRENT_TIMESTAMP
                            WHERE id = %s;
                        zAI AutoNr=   )rØ   Útotal_unmatched_scannedÚmatched_countr(   Úpillar_breakdownÚmatched_records)r   r,   r-   r.   rU   r   rW   rV   r1   r/   r?   rQ   r3   rÙ   ÚcommitÚlen)r   rØ   rÚ   r4   r5   Úunmatched_rowsrä   r   Úpillar_countsÚactionsra   Úsugrº   r·   ÚfoundÚ
inv_amountr’   s                    r   Úbatch_auto_matchz'Aec3WayMatchingService.batch_auto_match‡  s½  € àŒW×#Ò#Ñ%Ô%ð C	
¨¨t¯{ª{©}¬}ð C	
ÀØ�KŠKð ð �ñô ð ð !Ÿ\š\™^œ^ˆNàˆMÝ$ S™\œ\ˆNØ ! a¨A°!Ð4Ð4ˆMØˆGà#ð &Lñ &L�Ø×7Ò7½¸Q¹¼ÀÑEÔE�Øñ $L˜3Ÿ7š7 <Ñ0Ô0Ð4FÐFÑFØŸ7š7 <Ñ0Ô0�DØ ŸWšW ^Ñ4Ô4�Fàð 4 Fð 4ØŸšÐ$^ÐagÐ`iÑjÔjÐjØ #§¢¡¤˜Ø ð 4Ý#& u¨T¤{Ñ#3Ô#3˜Då!(­¨QÐ/AÔ-BÐ-GÀaÑ)HÔ)HÑ!IÔ!I�JØ! QÑ&�MØ" jÑ0�NØ ŸWšW X¨qÑ1Ô1�FØ,9×,=Ò,=¸fÀaÑ,HÔ,HÈ1Ñ,L�M &Ñ)à—N’NÝ&)¨!¨D¬'¡l¤lØ*+Ð,<Ô*=Ø'(¨Ô'7Ý&+¨JÑ&7Ô&7Ø,2Ø28Ø25·'²'¸.Ñ2IÔ2IØ"%§'¢'¨(Ñ"3Ô"3Ø'. ;Ð#=µ4¸±:´:ð
$ð 
$ñ 
ô 
ð 
ð #ð L tð LØŸšð %ð # C§G¢G¨H°iÑ$@Ô$@À!ÀDÄ'ÐJñLô Lð Lùð ð Ø—’‘”�ð Ý'*¨>Ñ':Ô':Ø*Ý"'¨Ñ"7Ô"7Ø -Ø& s¨ sœ|ð
ð 
ðyC	
ð C	
ð C	
ð C	
ñ C	
ô C	
ð C	
ð C	
ð C	
ð C	
ð C	
ñ C	
ô C	
ð C	
ð C	
ð C	
ð C	
ð C	
ð C	
øøøð C	
ð C	
ð C	
ð C	
ð C	
ð C	
ð C	
ñ C	
ô C	
ð C	
ð C	
ð C	
ð C	
ð C	
ð C	
ð C	
øøøð C	
ð C	
ð C	
ð C	
ð C	
ð C	
s5   šJ3¯IJÊJ3ÊJ	ÊJ3Ê"J	Ê#J3Ê3J7Ê:J7c                ó
  ‡‡— | j                              ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|st          d|› �¦  «        ‚|                     d|f¦  «         |                     ¦   «         }|d         pd                     ¦   «         }|d         pd                     ¦   «         }|d         pd                     ¦   «         }d                     d	„ |D ¦   «         ¦  «        }	|› d|› d|› d|	› �Št          ˆfd
„dD ¦   «         ¦  «        }
t          ˆfd„dD ¦   «         ¦  «        }t          ˆfd„dD ¦   «         ¦  «        }t          ˆfd„dD ¦   «         ¦  «        }|                     d¦  «         |                     ¦   «         }g }|D �]y}t          |d         ¦  «        }|d         pd}|d         pd}|d         pd}|d         pd}|› d|› d|› d|› �                     ¦   «         Šd}g }|d         r3t          |d         ¦  «        |k    r|dz  }|                     d¦  «         |
rxd‰v sd‰v r|dz  }t          ˆfd„d D ¦   «         ¦  «        r|d!z  }|                     d"¦  «         n5t          ˆfd#„d$D ¦   «         ¦  «        r|d%z  }|                     d&¦  «         |rtd'‰v r|d%z  }t          ˆfd(„d)D ¦   «         ¦  «        r|d*z  }|                     d+¦  «         n5t          ˆfd,„d-D ¦   «         ¦  «        r|dz  }|                     d.¦  «         |rTt          ˆfd/„d0D ¦   «         ¦  «        r|d1z  }|                     d2¦  «         nd3‰v r|d!z  }|                     d4¦  «         d5‰v rd5‰v r|d6z  }|                     d7¦  «         d8‰v rd8‰v r|d6z  }|                     d9¦  «         d:|v r|d;z  }|dk    rB|                     |||||t          d<|¦  «        |rd=                     |¦  «        nd>d?œ¦  «         �Œ{|                     d@„ dA¬B¦  «         |dCdD…         }|sU|dCdE…         D ]J}|                     t          |d         ¦  «        |d         |d         |d         |d         dFdGd?œ¦  «         ŒK||dH         |d         |	dCdI…         |dJœcdCdCdC¦  «         cdCdCdC¦  «         S # 1 swxY w Y   dCdCdC¦  «         dCS # 1 swxY w Y   dCS )Kud   TÃ­nh toÃ¡n vÃ  xáº¿p háº¡ng top dá»± Ã¡n thÃ´ng minh phÃ¹ há»£p nháº¥t cho 1 hÃ³a Ä‘Æ¡n cá»¥ thá»ƒ.aÆ  
                SELECT i.id, i.invoice_number, i.seller_name, i.seller_tax_code,
                       i.seller_address, i.notes, i.total_amount_vnd,
                       p.id as current_project_id, p.project_code as current_project_code,
                       p.project_name as current_project_name
                FROM erp_invoices i
                LEFT JOIN projects p ON i.matched_project_id = p.id
                WHERE i.id = %s;
            r¼   z³
                SELECT item_name, unit, quantity, unit_price_vnd, total_item_amount_vnd
                FROM erp_invoice_items
                WHERE invoice_id = %s;
            rŠ   r‰   Úseller_addressr‹   r�   c              3  óN   K  — | ] }|d          pd                      ¦   «         V — Œ!dS )r{   r‰   N)r²   rn   s     r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>é  s7   è è € Ð QÐ QÀR " [¤/Ð"7°R×!>Ò!>Ñ!@Ô!@Ð QÐ QÐ QÐ QÐ QÐ Qr   c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   rª   s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>í  s?   øè è € ð  $Lð  $L°q A¨ Nð  $Lð  $Lð  $Lð  $Lð  $Lð  $Lr   )u	   cá»�c treu   cá»�cu   cá»«u   phÃªnu   rÆ¡mõ   Ä‘áº¯p bá»�u   bá»� kÃ¨u
   náº¡o vÃ©tu   bÆ¡mõ   kÃªnhu   mÆ°Æ¡ngõ   cá»‘ngõ   thá»§y lá»£ic              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   rª   s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>î  s?   øè è € ð   ]ð   ]°1  Y ð   ]ð   ]ð   ]ð   ]ð   ]ð   ]r   )
u   tÃ´nr­   u   xÃ  gá»“u   sÆ¡nr°   u   ngÃ³iu   cá»­ar®   u   vá»¯ar¯   c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   rª   s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>ï  s?   øè è € ð  $`ð  $`°q A¨ Nð  $`ð  $`ð  $`ð  $`ð  $`ð  $`r   )r˜   r™   zxe benrš   u   váº­n chuyá»ƒnu   cÆ°á»›cu   cÃ¡tu	   san láº¥pc              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   rª   s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>ð  s'   øè è € ÐsÐs°!˜q I˜~ÐsÐsÐsÐsÐsÐsr   )u
   mÃ¡y Ä‘Ã ou	   mÃ¡y á»§iu   ca mÃ¡yÚyanmarÚkomatsuz½
                SELECT id, project_code, project_name, project_type, location, status, contract_value
                FROM projects
                ORDER BY project_code DESC;
            rM   r“   r”   Úproject_typeÚlocationr   Úcurrent_project_idr   u#   Dá»± Ã¡n hiá»‡n Ä‘ang Ä‘Æ°á»£c gÃ¡nr÷   u   kÃ¨ Ä‘Ãªé#   c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   ©ro   r«   Úp_fulls     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>  s'   øè è € ÐoÐo¨1˜1 ˜;ÐoÐoÐoÐoÐoÐor   )r¥   u   sÃ´ng Ä‘a Ä‘á»™rô   u   ngÄƒn máº·né-   uG   CÃ´ng trÃ¬nh Ä�áº¯p bá»� kÃ¨ sÃ´ng Ä�a Ä�á»™ (dÃ¹ng cá»�c tre gia cá»‘)c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   r  s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>  s'   øè è € ÐbÐb¨Q˜Q &˜[ÐbÐbÐbÐbÐbÐbr   )r¢   rö   rõ   u   tráº¡m bÆ¡mé   u=   Háº¡ng má»¥c Thá»§y lá»£i / Cá»‘ng kÃªnh tiÃªu thoÃ¡t nÆ°á»›cu   dÃ¢n dá»¥ngc              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   r  s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>  s'   øè è € ÐUÐU¨1˜1 ˜;ÐUÐUÐUÐUÐUÐUr   )rž   u   nhÃ  vÄƒn hÃ³aé7   uQ   CÃ´ng trÃ¬nh NhÃ  vÄƒn hÃ³a thÃ´n Ä�áº¡i Tháº¯ng (Váº­t tÆ° mÃ¡i tÃ´n & xÃ  gá»“)c              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   r  s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>  s'   øè è € ÐNÐN¨Q˜Q &˜[ÐNÐNÐNÐNÐNÐNr   )r¦   u	   trÆ°á»�ngu6   CÃ´ng trÃ¬nh XÃ¢y láº¯p TrÆ°á»�ng Máº§m Non TÃ¢n TrÃ oc              3  ó    •K  — | ]}|‰v V — Œ	d S r   r©   r  s     €r   rq   zGAec3WayMatchingService.get_smart_project_suggestions.<locals>.<genexpr>#  s'   øè è € ÐMÐM¨1˜1 ˜;ÐMÐMÐMÐMÐMÐMr   )r¡   u   dÆ°Æ¡ng kinhr=   uF   Dá»‹ch vá»¥ váº­n chuyá»ƒn cÃ¡t KÄ�T Vinhomes Golden City DÆ°Æ¡ng Kinhr�   u:   Há»£p Ä‘á»“ng náº¡o vÃ©t váº­n chuyá»ƒn Cty ThoÃ¡t NÆ°á»›cu   an lÃ£orx   u#   Ä�á»“ng Ä‘á»‹a bÃ n Huyá»‡n An LÃ£ou   kiáº¿n thá»¥yu)   Ä�á»“ng Ä‘á»‹a bÃ n Huyá»‡n Kiáº¿n Thá»¥yÚ2026é
   éb   rÉ   u<   TÆ°Æ¡ng Ä‘á»“ng danh má»¥c váº­t tÆ° & loáº¡i hÃ¬nh dá»± Ã¡n)rM   r“   r”   rý   rþ   Úscorer–   c                ó   — | d         S )Nr  r©   rs   s    r   ru   zFAec3WayMatchingService.get_smart_project_suggestions.<locals>.<lambda>B  s
   € °!°G´*€ r   T)rv   ÚreverseNrÃ   r�   é<   u2   Dá»± Ã¡n trá»�ng Ä‘iá»ƒm Ä‘ang thi cÃ´ng nÄƒm 2026rÝ   éx   )rd   rÝ   rŠ   Úitems_summaryÚsuggestions)r   r,   r-   r.   r/   rÎ   rU   r²   rT   r   r?   rQ   ÚminÚsort)r   rd   r4   r5   r…   r�   rŠ   rñ   r‹   Ú	items_strÚis_bamboo_or_dykeÚis_steel_roofÚis_logistics_fuelÚis_excavatorÚall_projectsÚscored_suggestionsÚprº   r·   r¸   Úp_typeÚp_locr  ÚreasonsÚtop_suggestionsr¬   r  s                            @@r   Úget_smart_project_suggestionsz4Aec3WayMatchingService.get_smart_project_suggestionsÎ  sÁ  øø€ àŒW×#Ò#Ñ%Ô%ð H	¨¨t¯{ª{©}¬}ð H	Àà�KŠKð ð �ñ ô  ð  ð —,’,‘.”.ˆCØð TÝ Ð!RÀjÐ!RÐ!RÑSÔSÐSà�KŠKð ð �ñ	 ô  ð  ð
 —L’L‘N”NˆEà˜}Ô-Ð3°×:Ò:Ñ<Ô<ˆKØ!Ð"2Ô3Ð9°r×@Ò@ÑBÔBˆNØ˜”\Ð' R×.Ò.Ñ0Ô0ˆEØŸšÐ QÐ QÈ5Ð QÑ QÔ QÑQÔQˆIØ&ÐMÐM¨ÐMÐM¸%ÐMÐMÀ)ÐMÐMˆIõ !$ð  $Lð  $Lð  $Lð  $Lð  =Kð  $Lñ  $Lô  $Lñ  !Lô  !LÐÝð   ]ð   ]ð   ]ð   ]ð  9\ð   ]ñ   ]ô   ]ñ  ]ô  ]ˆMÝ #ð  $`ð  $`ð  $`ð  $`ð  =_ð  $`ñ  $`ô  $`ñ  !`ô  !`ÐÝÐsÐsÐsÐsÐ7rÐsÑsÔsÑsÔsˆLð �KŠKð ñ ô ð ð
 Ÿ<š<™>œ>ˆLà!#ÐØ!ð Dñ D�Ý˜1˜Tœ7‘|”|�Ø˜>Ô*Ð0¨b�Ø˜>Ô*Ð0¨b�Ø˜>Ô*Ð0¨b�Ø˜*œÐ+¨�Ø"Ð>Ð> VÐ>Ð>¨fÐ>Ð>°uÐ>Ð>×DÒDÑFÔF�à�Ø�ð Ð+Ô,ð Jµ°SÐ9MÔ5NÑ1OÔ1OÐSWÒ1WÐ1WØ˜S‘L�EØ—N’NÐ#HÑIÔIÐIð %ð hØ%¨Ð/Ð/°:ÀÐ3GÐ3GØ ™˜ÝÐoÐoÐoÐoÐ0nÐoÑoÔoÑoÔoð hØ ™˜ØŸšÐ'pÑqÔqÐqÐqÝÐbÐbÐbÐbÐ2aÐbÑbÔbÑbÔbð hØ ™˜ØŸšÐ'fÑgÔgÐgð !ð aØ$¨Ð.Ð.Ø ™˜ÝÐUÐUÐUÐUÐ0TÐUÑUÔUÑUÔUð aØ ™˜ØŸšÐ'zÑ{Ô{Ð{Ð{ÝÐNÐNÐNÐNÐ2MÐNÑNÔNÑNÔNð aØ ™˜ØŸšÐ'_Ñ`Ô`Ð`ð %ð eÝÐMÐMÐMÐMÐ0LÐMÑMÔMÑMÔMð eØ ™˜ØŸšÐ'oÑpÔpÐpÐpØ)¨VÐ3Ð3Ø ™˜ØŸšÐ'cÑdÔdÐdð  	Ð)Ð)¨i¸6Ð.AÐ.AØ˜R‘K�EØ—N’NÐ#HÑIÔIÐIØ" iÐ/Ð/°OÀvÐ4MÐ4MØ˜R‘K�EØ—N’NÐ#NÑOÔOÐOð ˜VÐ#Ð#Ø˜R‘K�Eà˜1’9�9Ø&×-Ò-Ø"Ø(.Ø(.Ø(.Ø$)Ý!$ R¨¡¤Ø8?ð  #D $§)¢)¨GÑ"4Ô"4Ð"4ð  FDð/ð /ñ ô ð ùð ×#Ò#Ð(<Ð(<ÀdÐ#ÑKÔKÐKØ0°°!°Ô4ˆOð #ð 
Ø% b q bÔ)ð 	ð 	�AØ#×*Ò*Ý! ! D¤'™lœlØ()¨.Ô(9Ø()¨.Ô(9Ø()¨.Ô(9Ø$% j¤MØ!#Ø"Vð,ð ,ñ ô ð ð ð )Ø"%Ð&6Ô"7Ø" =Ô1Ø!*¨4¨C¨4¤Ø.ðð ðEH	ð H	ð H	ð H	ñ H	ô H	ð H	ð H	ð H	ð H	ð H	ñ H	ô H	ð H	ð H	ð H	ð H	ð H	ð H	øøøð H	ð H	ð H	ð H	ð H	ð H	ð H	ñ H	ô H	ð H	ð H	ð H	ð H	ð H	ð H	ð H	øøøð H	ð H	ð H	ð H	ð H	ð H	s5   œS5±RSÓS5ÓS!	Ó!S5Ó$S!	Ó%S5Ó5S9Ó<S9õ   GiÃ¡m Ä�á»‘c Nguyá»…n SÄ© SÆ¡nÚwbs_idÚ	user_namec                ó<  — | j                              ¦   «         5 }|                     ¦   «         5 }|                     d|||f¦  «         |                     ¦   «         }|st          d|› �¦  «        ‚|                     d||t          j        ||dœd¬¦  «        f¦  «         |                     ¦   «          dd|d	         › d
�|d	         t          |d         pd¦  «        dœcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )uC   PhÃª duyá»‡t khá»›p ná»‘i chÃ­nh thá»©c 1 hÃ³a Ä‘Æ¡n vÃ o dá»± Ã¡n.aP  
                UPDATE erp_invoices
                SET matched_project_id = %s,
                    matched_wbs_id = %s,
                    reconciliation_status = '3WAY_MATCHED',
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = %s
                RETURNING invoice_number, total_amount_vnd;
            r¼   z³
                INSERT INTO erp_invoice_audit_logs (invoice_id, action_type, performed_by, details_json)
                VALUES (%s, '3WAY_MATCH_CONFIRMED', %s, %s);
            )r@   r%  F©Úensure_asciiÚsuccessu*   Ä�Ã£ phÃª duyá»‡t khá»›p ná»‘i hÃ³a Ä‘Æ¡n rÝ   u    vÃ o dá»± Ã¡n thÃ nh cÃ´ng.r'   r   )r>   rÈ   rÝ   r'   N)
r   r,   r-   r.   r/   rÎ   ÚjsonÚdumpsrç   r3   )r   rd   r@   r%  r&  r4   r5   r…   s           r   Úconfirm_matchingz'Aec3WayMatchingService.confirm_matchingZ  sê  € ð ŒW×#Ò#Ñ%Ô%ð 	¨¨t¯{ª{©}¬}ð 	ÀØ�KŠKð ð ˜f jÐ1ñ3ô 3ð 3ð —,’,‘.”.ˆCØð TÝ Ð!RÀjÐ!RÐ!RÑSÔSÐSà�KŠKð ð ØÝ”
¨*ÀÐGÐGÐV[Ð\Ñ\Ô\ðñô ð ð �KŠK‰MŒMˆMð $Ø{ÈÐL\ÔH]Ð{Ð{Ð{Ø"%Ð&6Ô"7Ý$)¨#Ð.@Ô*AÐ*FÀQÑ$GÔ$Gð	ð ð1	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s5   šD¯B1C9Ã DÃ9C=	Ã=DÄ C=	ÄDÄDÄDc                ó¢  — | j                              ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|st          d|› �¦  «        ‚|                     d|f¦  «         d„ |                     ¦   «         D ¦   «         }|                     d|f¦  «         d„ |                     ¦   «         D ¦   «         }t          d„ |D ¦   «         ¦  «        }t          t          |d         pd	¦  «        ¦  «        }||d
         |d         t          |¦  «        t          |¦  «        t          t          t          d¦  «        ||z
  ¦  «        ¦  «        t          |¦  «        d„ |D ¦   «         d„ |D ¦   «         dœ	cddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )uZ   Láº¥y danh sÃ¡ch cÃ¡c dÃ²ng hÃ ng vÃ  chi tiáº¿t phÃ¢n bá»• Ä‘a dá»± Ã¡n cá»§a hÃ³a Ä‘Æ¡n.zÙ
                SELECT id, invoice_number, seller_name, total_amount_vnd,
                       matched_project_id, reconciliation_status
                FROM erp_invoices
                WHERE id = %s;
            r¼   zë
                SELECT id, item_order, item_name, unit, quantity, unit_price_vnd, total_item_amount_vnd
                FROM erp_invoice_items
                WHERE invoice_id = %s
                ORDER BY item_order, id;
            c                ó,   — g | ]}t          |¦  «        ‘ŒS r©   ©rV   ©ro   ra   s     r   ú
<listcomp>zBAec3WayMatchingService.get_invoice_allocations.<locals>.<listcomp>•  s   € Ð5Ð5Ð5 •T˜!‘W”WÐ5Ð5Ð5r   a#  
                SELECT a.id, a.invoice_item_id, a.project_id,
                       p.project_code, p.project_name, it.item_name,
                       a.allocated_quantity, a.allocated_total_amount_vnd,
                       a.debit_account, a.credit_account, a.notes
                FROM erp_invoice_item_allocations a
                JOIN projects p ON a.project_id = p.id
                LEFT JOIN erp_invoice_items it ON a.invoice_item_id = it.id
                WHERE a.invoice_id = %s
                ORDER BY a.created_at;
            c                ó,   — g | ]}t          |¦  «        ‘ŒS r©   r0  r1  s     r   r2  zBAec3WayMatchingService.get_invoice_allocations.<locals>.<listcomp>£  s   € Ð;Ð;Ð; q�4 ™7œ7Ð;Ð;Ð;r   c              3  ó^   K  — | ](}t          t          |d          pd¦  «        ¦  «        V — Œ)dS )Úallocated_total_amount_vndr   N)r   r?   ©ro   Úas     r   rq   zAAec3WayMatchingService.get_invoice_allocations.<locals>.<genexpr>¥  s?   è è € Ð!jÐ!jÐYZ¥'­#¨aÐ0LÔ.MÐ.RÐQRÑ*SÔ*SÑ"TÔ"TÐ!jÐ!jÐ!jÐ!jÐ!jÐ!jr   r'   r   rÝ   rŠ   r½   c                óê   — g | ]p}t          |d          ¦  «        |d         |d         |d         t          |d         pd¦  «        t          |d         pd¦  «        t          |d         pd¦  «        dœ‘ŒqS )	rM   Ú
item_orderr{   rÀ   r¾   r   rk   Útotal_item_amount_vnd)rM   r9  r{   rÀ   r¾   rk   r:  ©r?   r3   rn   s     r   r2  zBAec3WayMatchingService.get_invoice_allocations.<locals>.<listcomp>°  s•   € ð ð ð ð õ " " T¤(™mœmØ&(¨Ô&6Ø%'¨¤_Ø " 6¤
Ý$)¨"¨Z¬.Ð*=¸AÑ$>Ô$>Ý*/°Ð3CÔ0DÐ0IÈÑ*JÔ*JÝ16°rÐ:QÔ7RÐ7WÐVWÑ1XÔ1Xðð ðð ð r   c                ón  — g | ]²}t          |d          ¦  «        |d         rt          |d         ¦  «        nd|d         pdt          |d         ¦  «        |d         |d         t          |d         pd	¦  «        t          |d
         pd	¦  «        |d         p
d|d         › �|d         pd|d         pddœ‘Œ³S )rM   Úinvoice_item_idNr{   u   ToÃ n bá»™ hÃ³a Ä‘Æ¡nr@   r“   r”   Úallocated_quantityr   r5  Údebit_accountÚ621_Úcredit_accountÚ331r‹   r‰   )rM   r=  r{   r@   r“   r”   r>  r5  r?  rA  r‹   r;  r6  s     r   r2  zBAec3WayMatchingService.get_invoice_allocations.<locals>.<listcomp>¼  sî   € ð  ð  ð  ð õ " ! D¤'™lœlØHIÐJ[ÔH\Ð+f­3¨qÐ1BÔ/CÑ+DÔ+DÐ+DÐbfØ%& {¤^Ð%NÐ7NÝ&)¨!¨L¬/Ñ&:Ô&:Ø()¨.Ô(9Ø()¨.Ô(9Ý.3°AÐ6JÔ4KÐ4PÈqÑ.QÔ.QÝ6;¸AÐ>ZÔ<[Ð<`Ð_`Ñ6aÔ6aØ)*¨?Ô);Ð)YÐ?YÀaÈÔFWÐ?YÐ?YØ*+Ð,<Ô*=Ð*FÀØ!" 7¤Ð!1¨rðð ð ð  ð  r   )	rd   rÝ   rŠ   r'   Útotal_allocated_vndÚremaining_unallocated_vndÚallocation_countr�   ÚallocationsN)r   r,   r-   r.   r/   rÎ   rU   Úsumr   r?   r3   r€   rè   )	r   rd   r4   r5   r…   r�   rF  Útotal_allocatedr8   s	            r   Úget_invoice_allocationsz.Aec3WayMatchingService.get_invoice_allocations�  sØ  € àŒW×#Ò#Ñ%Ô%ð I	¨¨t¯{ª{©}¬}ð I	ÀØ�KŠKð ð
 �ñ ô  ð  ð —,’,‘.”.ˆCØð TÝ Ð!RÀjÐ!RÐ!RÑSÔSÐSð �KŠKð ð
 �ñ ô  ð  ð 6Ð5 c§l¢l¡n¤nÐ5Ñ5Ô5ˆEð �KŠKð 
ð �ñ
 ô 
 ð 
 ð <Ð;¨C¯LªL©N¬NÐ;Ñ;Ô;ˆKå!Ð!jÐ!jÐ^iÐ!jÑ!jÔ!jÑjÔjˆOÝ¥ CÐ(:Ô$;Ð$@¸qÑ AÔ AÑBÔBˆIð )Ø"%Ð&6Ô"7Ø" =Ô1Ý$)¨)Ñ$4Ô$4Ý',¨_Ñ'=Ô'=Ý-2µ3µw¸s±|´|ÀYÐQ`ÑE`Ñ3aÔ3aÑ-bÔ-bÝ$'¨Ñ$4Ô$4ðð ð $ðñ ô ð ð  ð )ð ñ  ô  ð)$ð $ðKI	ð I	ð I	ð I	ñ I	ô I	ð I	ð I	ð I	ð I	ð I	ñ I	ô I	ð I	ð I	ð I	ð I	ð I	ð I	øøøð I	ð I	ð I	ð I	ð I	ð I	ð I	ñ I	ô I	ð I	ð I	ð I	ð I	ð I	ð I	ð I	øøøð I	ð I	ð I	ð I	ð I	ð I	s5   šG¯E$F,ÆGÆ,F0	Æ0GÆ3F0	Æ4GÇGÇGrF  úlist[dict[str, Any]]c                óþ  — |st          d¦  «        ‚| j                             ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|st          d|› �¦  «        ‚t          t          |d         pd¦  «        ¦  «        }|                     d|f¦  «         t          ¦   «         }t          d¦  «        }	|D �]î}
|
 	                    d¦  «        }|sŒ| 
                    |¦  «         |                     d	|f¦  «         |                     ¦   «         }|r|d
         nd}|
 	                    d¦  «        }|sƒ|                     d|f¦  «         |                     ¦   «         }|rt          |d         ¦  «        }n@|                     d|||f¦  «         t          |                     ¦   «         d         ¦  «        }t          t          |
 	                    d¦  «        pd¦  «        ¦  «        }t          t          |
 	                    d¦  «        pd¦  «        ¦  «        }|
 	                    d¦  «        pd|› �}|
 	                    d¦  «        pd|› �}|
 	                    d¦  «        pd}|t          d¦  «        z  }||z
  }|                     d||r|nd||||||||f
¦  «         |	|z  }	�Œð|rt          |¦  «        d         nd}t          |¦  «        dk    rdnd}|                     d|||f¦  «         |                     d||t          j        t          |¦  «        t          |	¦  «        t          |¦  «        d œd!¬"¦  «        f¦  «         |                     ¦   «          d#d$t          |¦  «        › d%t          |	¦  «        d&›d'�t          |¦  «        t          |	¦  «        d(œcddd¦  «         cddd¦  «         S # 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS ))u`   LÆ°u báº£ng phÃ¢n bá»• Ä‘a dá»± Ã¡n cho 1 hÃ³a Ä‘Æ¡n (nhiá»�u cÃ´ng trÃ¬nh/nhiá»�u dÃ²ng hÃ ng).u=   Danh sÃ¡ch phÃ¢n bá»• dá»± Ã¡n khÃ´ng Ä‘Æ°á»£c Ä‘á»ƒ trá»‘ng.zŠ
                SELECT id, invoice_number, total_amount_vnd
                FROM erp_invoices
                WHERE id = %s;
            r¼   r'   r   z?DELETE FROM erp_invoice_item_allocations WHERE invoice_id = %s;r½   r@   z0SELECT project_code FROM projects WHERE id = %s;r“   ÚDAr=  zWSELECT id FROM erp_invoice_items WHERE invoice_id = %s ORDER BY item_order, id LIMIT 1;rM   u*  
                            INSERT INTO erp_invoice_items (invoice_id, item_order, item_name, quantity, unit_price_vnd, total_item_amount_vnd)
                            VALUES (%s, 1, 'HÃ ng hÃ³a / Dá»‹ch vá»¥ chung', 1, %s, %s)
                            RETURNING id;
                        r>  r5  r‹   u   PhÃ¢n bá»• cho cÃ´ng trÃ¬nh r?  r@  rA  rB  z0.08a’  
                    INSERT INTO erp_invoice_item_allocations (
                        invoice_id, invoice_item_id, project_id,
                        allocated_quantity, allocated_amount_before_vat_vnd,
                        allocated_vat_amount_vnd, allocated_total_amount_vnd,
                        allocation_method, debit_account, credit_account,
                        confidence_score, notes
                    ) VALUES (
                        %s, %s, %s,
                        %s, %s,
                        %s, %s,
                        'MANUAL_SPLIT', %s, %s,
                        100.0, %s
                    );
                Nr   Ú
reconciledÚmulti_project_allocatedzà
                UPDATE erp_invoices
                SET matched_project_id = %s,
                    reconciliation_status = %s,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = %s;
            z¶
                INSERT INTO erp_invoice_audit_logs (invoice_id, action_type, performed_by, details_json)
                VALUES (%s, 'MULTI_PROJECT_ALLOCATED', %s, %s);
            )Úprojects_countrC  Úallocations_countFr(  r*  u&   Ä�Ã£ lÆ°u thÃ nh cÃ´ng phÃ¢n bá»• cho u"    cÃ´ng trÃ¬nh (Tá»•ng phÃ¢n bá»•: z,.0fu    VNÄ�))r>   rÈ   rO  rC  )rÎ   r   r,   r-   r.   r/   r   r?   Úsetr1   ÚaddÚlistrè   r+  r,  r3   rç   )r   rd   rF  r&  r4   r5   r…   Útotal_inv_amountÚdistinct_projectsrH  ÚallocÚproj_idr¹   r·   Úitem_idÚfirst_itÚ	alloc_qtyÚalloc_amountÚalloc_notesÚ	debit_accÚ
credit_accÚ
vat_amountÚsubtotalÚfirst_proj_idÚrecon_statuss                            r   Úsave_invoice_multi_allocationsz5Aec3WayMatchingService.save_invoice_multi_allocationsÎ  s†  € ð ð 	^ÝÐ\Ñ]Ô]Ð]àŒW×#Ò#Ñ%Ô%ð t	¨¨t¯{ª{©}¬}ð t	Àà�KŠKð ð �ñ	 ô  ð  ð
 —,’,‘.”.ˆCØð TÝ Ð!RÀjÐ!RÐ!RÑSÔSÐSå&¥s¨3Ð/AÔ+BÐ+GÀaÑ'HÔ'HÑIÔIÐð �KŠKÐYÐ\fÐ[hÑiÔiÐiõ !$¡¤ÐÝ% c™lœlˆOà$ð =0ñ =0�ØŸ)š) LÑ1Ô1�Øð ØØ!×%Ò% gÑ.Ô.Ð.ð —’ÐNÐQXÐPZÑ[Ô[Ð[ØŸš™œ�Ø27ÐA˜˜~Ô.Ð.¸T�àŸ)š)Ð$5Ñ6Ô6�Øð <Ø—K’KÐ yð  }Gð  |Iñ  Jô  Jð  JØ"Ÿ|š|™~œ~�HØð <Ý"% h¨t¤nÑ"5Ô"5˜˜àŸšð %ð )Ð*:Ð<LÐMñ	Oô Oð Oõ
 #& c§l¢l¡n¤n°TÔ&:Ñ";Ô";˜å#¥C¨¯	ª	Ð2FÑ(GÔ(GÐ(LÈ1Ñ$MÔ$MÑNÔN�	Ý&¥s¨5¯9ª9Ð5QÑ+RÔ+RÐ+WÐVWÑ'XÔ'XÑYÔY�Ø#Ÿiši¨Ñ0Ô0Ð[Ð4[ÐSYÐ4[Ð4[�Ø!ŸIšI oÑ6Ô6ÐI¸/À¸/¸/�	Ø"ŸYšYÐ'7Ñ8Ô8ÐA¸E�
ð *­G°F©O¬OÑ;�
Ø'¨*Ñ4�à—’ð ð Ø&Ð0�G�G¨DØØØØØ ØØØðñô ð ð4   <Ñ/�‘ð ;LÐU�DÐ!2Ñ3Ô3°AÔ6Ð6ÐQUˆMÝ+.Ð/@Ñ+AÔ+AÀQÒ+FÐ+F˜<˜<ÐLeˆLà�KŠKð ð   ¨zÐ:ñ<ô <ð <ð �KŠKð ð ØÝ”
Ý&)Ð*;Ñ&<Ô&<Ý+0°Ñ+AÔ+AÝ),¨[Ñ)9Ô)9ðð ð !&ð	'ñ 'ô 'ðñô ð ð �KŠK‰MŒMˆMð $ð bÅCÐHYÑDZÔDZð  bð  bõ  Dð  ETñ  Uô  Uð  bð  bð  bð  bÝ"%Ð&7Ñ"8Ô"8Ý',¨_Ñ'=Ô'=ð	ð ð_t	ð t	ð t	ð t	ñ t	ô t	ð t	ð t	ð t	ð t	ð t	ñ t	ô t	ð t	ð t	ð t	ð t	ð t	ð t	øøøð t	ð t	ð t	ð t	ð t	ð t	ð t	ñ t	ô t	ð t	ð t	ð t	ð t	ð t	ð t	ð t	øøøð t	ð t	ð t	ð t	ð t	ð t	s6   «O2Á NOÏO2ÏO	ÏO2Ï!O	Ï"O2Ï2O6Ï9O6r   )r	   r
   r   r   )r   r   )r<   NNr=   r   )r>   r?   r@   rA   rB   rA   rC   r0   rD   r0   r   r   )rd   r?   r5   r   r   r   )r…   r   r5   r   r   r†   )rd   r?   r   r   )Tr×   )rØ   rÙ   rÚ   r0   r   r   )Nr$  )
rd   r?   r@   r?   r%  rA   r&  r?   r   r   )r$  )rd   r?   rF  rJ  r&  r?   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r;   rc   rX   rW   rÖ   rï   r#  r-  rI  rc  r©   r   r   r   r      s_  € € € € € ØbÐbð4ð 4ð 4ð 4ð 4ðDð Dð Dð DðP Ø!%Ø!ØØðPð Pð Pð Pð PðdWð Wð Wð WðB^ð ^ð ^ð ^ð@Tð Tð Tð TðlE
ð E
ð E
ð E
ð E
ðNJð Jð Jð Jð` "Ø9ð%ð %ð %ð %ð %ðNKð Kð Kð Kðb :ð	~ð ~ð ~ð ~ð ~ð ~ð ~r   r   )rg  Ú
__future__r   r+  ÚloggingÚdecimalr   Útypingr   Úapp.core.postgres.erp_clientr   Ú	getLoggerÚloggerr   r©   r   r   ú<module>ro     sº   ððð ð
 #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð à :Ð :Ð :Ð :Ð :Ð :à	ˆÔ	Ð5Ñ	6Ô	6€ðzð zð zð zð zñ zô zð zð zð zr   