o
    š�žiÙÚ  ã                   @   sä  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d dlZd dlmZmZ d dlmZ d d	lmZ d d
lmZm Z m!Z!m"Z"m#Z#m$Z$ d dl%m&Z&m'Z'm(Z(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/m0Z0 d dl1m2Z2m3Z3m4Z4m5Z5 d dl6m7Z7m8Z8m9Z9 d dl:m;Z; d dl<m=Z=m>Z>m?Z? d dl@mAZAmBZB de_Ce DeE¡ZFdd„ ZGdd„ ZHG dd„ de	jIƒZJe  Kd¡deJfdd„ƒZLG dd „ d e!jMƒZNdS )!é    N)Úliteral_eval)ÚOrderedDict)ÚclosingÚ	ExitStack)Úislice)Úurlparse)ÚImageÚ	ImageFile)Úetree)ÚMarkup)ÚapiÚfieldsÚmodelsÚmodulesÚtoolsÚ_)Ú	UserErrorÚAccessErrorÚRedirectWarningÚValidationError)ÚDomain)Úsecurity)ÚrequestÚroot)ÚconfigÚis_html_emptyÚparse_versionÚsplit_every)Úcheck_barcode_encodingÚcreateBarcodeDrawingÚget_barcode_font)Úfind_in_path)ÚPdfFileReaderÚPdfFileWriterÚPdfReadError)Ú	safe_evalÚtimeTc                 C   s    t ƒ j}tj|g| ¢dddd�S )zd
    Runs the given arguments against the wkhtmltopdf binary.

    Returns:
        The process
    Túutf-8F)Úcapture_outputÚencodingÚcheck)Ú_wkhtmlÚbinÚ
subprocessÚrun)ÚargsÚbin_path© r1   úE/home/minischoggi19/odoo/odoo/addons/base/models/ir_actions_report.pyÚ_run_wkhtmltopdf)   s   ür3   c                 C   s\   t |  d¡ƒD ]$}|}tt||ƒddƒD ]}tjd|jd�}| |¡ | |¡ |}qqdS )a—  
    Walks through the etree and splits tables with more than max_rows rows into
    multiple tables with max_rows rows.

    This function is needed because wkhtmltopdf has a exponential processing
    time growth when processing tables with many rows. This function is a
    workaround for this problem.

    :param tree: The etree to process
    :param max_rows: The maximum number of rows per table
    Útableé   N)Úattrib)	ÚlistÚiterr   r   r
   ÚElementr6   ÚextendÚaddnext)ÚtreeÚmax_rowsr4   ÚprevÚrowsÚsiblingr1   r1   r2   Ú_split_table9   s   

üþrA   c                   @   sX   e Zd ZU ejd ed< eed< eed< eed< eed< eed< eedf d	B ed
< d	S )Ú
WkhtmlInfo)ÚinstallÚokÚstateÚdpi_zoom_ratior,   ÚversionÚis_patched_qtÚwkhtmltoimage_bin.NÚwkhtmltoimage_version)	Ú__name__Ú
__module__Ú__qualname__ÚtypingÚLiteralÚ__annotations__ÚboolÚstrÚtupler1   r1   r1   r2   rB   N   s   
 rB   r5   Úreturnc               	   C   s¾  d} d}d}d}d}zt dƒ}tj|dgtjtjd�}W n ty*   t d¡ Y nVw t d|¡ | ¡ \}}| d	¡}d
|v rBd}t	 
d|¡}|ry| d¡}t|ƒtdƒk r_t d¡ d} nd} t|ƒtdƒkrkd}td dkrxt d¡ d} nt d¡ d} d }	d}
zt dƒ}
tj|
dgtjtjd�}W n ty¤   t d¡ Y n0w t d|
¡ | ¡ \}}t	 
d|¡}|rÏt| d¡ d	¡ƒ}	td dkrÎt d¡ nt d¡ t| |||||
|	d�S )NrC   ÚwkhtmltopdfÚ Fz	--version)ÚstdoutÚstderrz;You need Wkhtmltopdf to print a pdf version of the reports.z%Will use the Wkhtmltopdf binary at %sÚasciiz(with patched qt)Tz	([0-9.]+)r   ú0.12.0z(Upgrade Wkhtmltopdf to (at least) 0.12.0ÚupgraderD   z0.12.2Úworkersr5   zWYou need to start Odoo with at least two workers to print a pdf version of the reports.zWkhtmltopdf seems to be broken.ÚbrokenÚwkhtmltoimagez4You need Wkhtmltoimage to generate images from html.z'Will use the Wkhtmltoimage binary at %ss	   ([0-9.]+)zKYou need to start Odoo with at least two workers to convert images to html.z!Wkhtmltoimage seems to be broken.)rE   rF   r,   rG   rH   rI   rJ   )r!   r-   ÚPopenÚPIPEÚOSErrorÚ_loggerÚinfoÚcommunicateÚdecodeÚreÚsearchÚgroupr   r   rB   )rE   r0   rG   rH   rF   ÚprocessÚoutÚ_errÚmatchrJ   Úimage_bin_pathr1   r1   r2   r+   X   sz   
ÿÿ



€

ÿÿ
€
ùr+   c                       s¼  e Zd ZdZdZdgZdZdZdZe	j
dd�Ze	jdd�Ze	j
d	d
d�Ze	jddddd�Ze	jg d¢d	ddd�Ze	j
dd	d�Ze	j
dddd	dd�Ze	jdddddd�Ze	jd d!d"�Ze	jd#d$d%d&�Ze	j
d'd	d(d)�Ze	jd*d+d"�Ze	j
d,d-d"�Ze	j
d.d/d"�Ze d0¡d1d2„ ƒZd3d4„ Z ‡ fd5d6„Z!d7d8„ Z"d9d:„ Z#d;d<„ Z$d=d>„ Z%ejd?d@„ ƒZ&dAdB„ Z'dCdD„ Z(dEdF„ Z)d}dHdI„Z*ej	G	d~dJdK„ƒZ+ddLdM„Z,d€dOe-e.dGB  fdPdQ„Z/ej		G	G		G	d�dRdS„ƒZ0ejdTdU„ ƒZ1ejdVdW„ ƒZ2ejdXdY„ ƒZ3ejdZd[„ ƒZ4d}d\d]„Z5d‚d^d_„Z6eje6fd`da„ƒZ7d}dbdc„Z8ddde„ Z9d‚dfdg„Z:d‚dhdi„Z;ejd}djdk„ƒZ<ejd}dldm„ƒZ=dndo„ Z>dpdq„ Z?ejd}drds„ƒZ@dƒdtdu„ZAd„dwdx„ZBdydz„ ZCejd{d|„ ƒZD‡  ZES )…ÚIrActionsReportúir.actions.reportzReport Actionúir.actions.actionsÚir_act_report_xmlzname, idF©ÚdefaultÚreportTz
Model Name)ÚrequiredÚstringúir.modelÚModelÚ_compute_model_idÚ_search_model_id)rv   Úcomputerg   ))z	qweb-htmlÚHTML)úqweb-pdfÚPDF)z	qweb-textÚTextr}   zéThe type of the report that will be rendered, each one having its own rendering method. HTML means the report will be opened directly in your browser PDF means the report will be rendered using Wkhtmltopdf and downloaded by the user.)ru   rs   ÚhelpzTemplate Name)rv   ru   zReport FilezgThe path to the main report file (depending on Report Type) or empty if the content is in another field)rv   ru   ÚreadonlyÚstorer€   z
res.groupsÚres_groups_report_relÚuidÚgidÚGroups)rv   zOn Multiple Doc.zUIf set to true, the action will not be displayed on the right toolbar of a form view.)rv   r€   zreport.paperformatzPaper FormatÚbtree_not_null)ÚindexzPrinted Report Namez«This is the filename of the report going to download. Keep empty to not change the report filename. You can use a python expression with the 'object' and 'time' variables.)Ú	translater€   zReload from AttachmentzkIf enabled, then the second time the user prints with same attachment name, it returns the previous report.zSave as Attachment Prefixz¹This is the filename of the attachment used to store the printing result. Keep empty to not save the printed reports. You can use a python expression with the object and time variables.zFilter domainzGIf set, the action will only appear on records that matches the domain.Úmodelc                 C   s$   | D ]}| j d  |j¡j|_qd S )Nrw   )ÚenvÚ_getrŠ   ÚidÚmodel_id)ÚselfÚactionr1   r1   r2   ry   Â   s   ÿz!IrActionsReport._compute_model_idc                    sÊ   ˆ t jv rtS | jd }t|tƒr| t dˆ |ƒ¡}nAt|t ƒr&| |¡}n6ˆ dkr6| ¡  t dˆ |ƒ¡}n&ˆ dks?t|tƒrI| t dˆ |ƒ¡}nˆ dkr\| t  	‡ fdd„|D ƒ¡¡}t d	d| 
d	¡ƒS )
Nrw   Údisplay_namezany!r�   ÚanyÚinc                 3   s.   � | ]}|rt t|tƒrd ndˆ |ƒV  qdS )r�   r‘   N)r   Ú
isinstanceÚint)Ú.0Úv©Úoperatorr1   r2   Ú	<genexpr>Ô   s   € ý
ÿz3IrActionsReport._search_model_id.<locals>.<genexpr>rŠ   )r   ÚNEGATIVE_OPERATORSÚNotImplementedr‹   r”   rR   rg   Úsudor•   ÚORÚmapped)r�   r™   Úvaluer   r1   r˜   r2   rz   Ç   s    




þz IrActionsReport._search_model_idc                    s   t ƒ  ¡ h d£B S )N>   ÚdataÚdomainÚtargetÚcontextÚreport_nameÚreport_typeÚclose_on_report_download)ÚsuperÚ_get_readable_fields©r�   ©Ú	__class__r1   r2   r©   Û   ó   z$IrActionsReport._get_readable_fieldsc                 C   s^   |   ¡  | j d¡}|rt| j d¡ƒdk rdS | ¡ d }dd| j d¡d fd	g|d
< |S )z|Used in the ir.actions.report form view in order to search naively after the view(s)
        used in the rendering.
        zbase.action_ui_viewÚ.é   Fr   ÚnameÚiliker5   )Útypeú=Úqwebr¢   )Ú
ensure_oner‹   ÚrefÚlenr¥   ÚsplitÚread)r�   Ú
action_refÚaction_datar1   r1   r2   Úassociated_viewç   s   zIrActionsReport.associated_viewc                 C   s2   | D ]}| j d  |j¡}| |jddœ¡ qdS )z- Create a contextual action for each report. rw   rt   )Úbinding_model_idÚbinding_typeT)r‹   rŒ   rŠ   Úwriter�   )r�   rt   rŠ   r1   r1   r2   Úcreate_actionó   s   zIrActionsReport.create_actionc                 C   s"   |   d¡ |  d¡ ddi¡ dS )z8 Remove the contextual actions created for the reports. r¿   r½   FT)Úcheck_accessÚfilteredr¿   rª   r1   r1   r2   Úunlink_actionú   s   
zIrActionsReport.unlink_actionc                 C   sT   | j rt| j |tdœƒnd}|sdS | jd jdd|fdd| jfdd|jfgd	d
�S )z¦Retrieve an attachment for a specific record.

        :param record: The record owning of the attachment.
        :return: A recordset of length <=1 or None
        ©Úobjectr&   rV   Núir.attachmentr°   r³   Ú	res_modelÚres_idr5   ©Úlimit)Ú
attachmentr%   r&   r‹   rg   rŠ   r�   )r�   ÚrecordÚattachment_namer1   r1   r2   Úretrieve_attachment  s   


ýüz#IrActionsReport.retrieve_attachmentc                 C   s   t ƒ jS )a¹  Get the current state of wkhtmltopdf: install, ok, upgrade, workers or broken.
        * install: Starting state.
        * upgrade: The binary is an older version (< 0.12.0).
        * ok: A binary was found with a recent version (>= 0.12.0).
        * workers: Not enough workers found to perform the pdf rendering process (< 2 workers).
        * broken: A binary was found but not responding.

        :return: wkhtmltopdf_state
        )r+   rE   rª   r1   r1   r2   Úget_wkhtmltopdf_state  s   z%IrActionsReport.get_wkhtmltopdf_statec                 C   s   | j p| jjj S ©N)Úpaperformat_idr‹   Úcompanyrª   r1   r1   r2   Úget_paperformat   ó   zIrActionsReport.get_paperformatc                 C   s   |r
| j  |¡ ¡ S | j jjS rÐ   )r‹   r¶   rÓ   rÒ   rÑ   )r�   Úxml_idr1   r1   r2   Úget_paperformat_by_xmlid#  s   z(IrActionsReport.get_paperformat_by_xmlidc                 C   s   | j jddd�S )Nzweb.minimal_layoutF©Úraise_if_not_found)r‹   r¶   rª   r1   r1   r2   Ú_get_layout&  rÔ   zIrActionsReport._get_layoutNc                 C   s,   | j d  ¡  d¡}|p|p|  ¡ p|  ¡ S )Núir.config_parameterz
report.url)r‹   r�   Ú	get_paramrÙ   Úget_base_url)r�   ÚlayoutÚ
report_urlr1   r1   r2   Ú_get_report_url)  s   zIrActionsReport._get_report_urlc                 C   sœ  |du r|r|  d¡r|  d¡}dg}|r | d|rdpdg¡ | dg¡ |�r0|jr9|jdkr9| d	|jg¡ |jr\|jr\|jdkr\| d
t|jƒd g¡ | dt|jƒd g¡ |rnd|v rn| dt|d ƒg¡ n
| dt|jƒg¡ d}|rˆ|  d¡rˆt|d ƒ}n|jr¢t	j
dkrŸt|jƒdkrŸt d¡ d}n|j}|r¼| dt|ƒg¡ tƒ jr¼| dtd| ƒg¡ |rÎd|v rÎ| dt|d ƒg¡ n|jrÛ| dt|jƒg¡ | dt|jƒg¡ |r÷d|v r÷| dt|d ƒg¡ n
| dt|jƒg¡ | dt|jƒg¡ |�s|j�r| dt|jƒg¡ |j�r&| dg¡ |j�r0| dg¡ | jd   ¡  d!d"¡}| d#|g¡ |�rL| dd$g¡ |S )%aë  Build arguments understandable by wkhtmltopdf bin.

        :param paperformat_id: A report.paperformat record.
        :param landscape: Force the report orientation to be landscape.
        :param specific_paperformat_args: A dictionary containing prioritized wkhtmltopdf arguments.
        :param set_viewport_size: Enable a viewport sized '1024x1280' or '1280x1024' depending of landscape arg.
        :return: A list of string representing the wkhtmltopdf process command args.
        Nzdata-report-landscapeú--disable-local-file-accessz--viewport-sizeÚ	1024x1280Ú	1280x1024ú--quietÚcustomz--page-sizez--page-widthÚmmz--page-heightzdata-report-margin-topz--margin-topzdata-report-dpiÚnté_   zGGenerating PDF on Windows platform require DPI >= 96. Using 96 instead.é`   z--dpiz--zoomg      X@zdata-report-header-spacingz--header-spacingz--margin-leftzdata-report-margin-bottomz--margin-bottomz--margin-rightz--orientationz--header-linez--disable-smart-shrinkingrÚ   zreport.print_delayÚ1000z--javascript-delayÚ	landscape)Úgetr:   ÚformatÚpage_heightÚ
page_widthrR   Ú
margin_topr•   ÚdpiÚosr°   rb   rc   r+   rF   Úheader_spacingÚmargin_leftÚmargin_bottomÚmargin_rightÚorientationÚheader_lineÚdisable_shrinkingr‹   r�   rÛ   )r�   rÑ   rê   Úspecific_paperformat_argsÚset_viewport_sizeÚcommand_argsrð   Údelayr1   r1   r2   Ú_build_wkhtmltopdf_args-  s^   

z'IrActionsReport._build_wkhtmltopdf_argsc              
   C   sd  |   ¡ }|si S | j|d�}tjj|tjjdd�d�}d}tjddd�}tjdd	d�}g }	g }
| d
¡d }| | 	d¡¡D ]}| 
¡ }| 
¡  |¡ | |¡ q>| | 	d¡¡D ]}| 
¡ }| 
¡  |¡ | |¡ qY| | 	d¡¡D ]O}| jd }| d¡r‰|j| d¡d�}|j|jdttjj|dd�ƒ|| j| jj d¡dœdd�}|	 |¡ | d¡|kr¾|
 t| dd¡ƒ¡ qt|
 d¡ qt|	s×d dd„ | ¡ D ƒ¡}|	 |¡ i }| ¡ D ]}|d  d¡rî|d ||d < qÝ| jd  |jdttjj|dd�ƒ|| j| jj d¡dœ¡}| jd  |jdttjj|dd�ƒ|| j| jj d¡dœ¡}|	|
|||fS ) aÖ  Divide and recreate the header/footer html by merging all found in html.
        The bodies are extracted and added to a list. Then, extract the specific_paperformat_args.
        The idea is to put all headers/footers together. Then, we will use a javascript trick
        (see minimal_layout template) to set the right header/footer during the processing of wkhtmltopdf.
        This allows the computation of multiple reports in a single call to wkhtmltopdf.
        )rÝ   r'   ©r)   )ÚparserzB//div[contains(concat(' ', normalize-space(@class), ' '), ' {} ')]ÚdivÚminimal_layout_report_headers)r�   Úminimal_layout_report_footersz//mainr   ÚheaderÚfooterÚarticlezir.qwebzdata-oe-lang)ÚlangFÚunicodeÚdebug)ÚsubstÚbodyÚbase_urlÚreport_xml_idr  r×   zdata-oe-modelz
data-oe-idNrV   c                 s   s    � | ]}t jj|d d�V  qdS )r  rþ   N)ÚlxmlÚhtmlÚtostring)r–   Úcr1   r1   r2   rš   ¶  s   € z0IrActionsReport._prepare_html.<locals>.<genexpr>zdata-report-r5   T)rÙ   rß   r  r  Ú
fromstringÚ
HTMLParserr
   r9   Úxpathrì   Ú	getparentÚremoveÚappendr‹   rë   Úwith_contextÚ_renderr�   r   r  rÕ   r¤   r•   ÚjoinÚgetchildrenÚitemsÚ
startswith)r�   r  Úreport_modelrÝ   r  r   Úmatch_klassÚheader_nodeÚfooter_nodeÚbodiesÚres_idsÚbody_parentÚnodeÚIrQwebr
  rù   Ú	attributer  r  r1   r1   r2   Ú_prepare_html  sv   	

ûú

€ûûzIrActionsReport._prepare_htmlÚjpgrT   c              
   C   sÜ  t jjrdgt|ƒ S tƒ j}|r|tdƒk rttdƒƒ‚ddddt	|ƒdt	|ƒd	|g	}t
ƒ �µ}g }|D ]P}	tjd
dd�\}
}tjd|› �dd�\}}| tj|¡ | tj|¡ t |¡ tt |
d¡ƒ�}| |	 ¡ ¡ W d  ƒ n1 sxw   Y  | ||f¡ q4g }|D ]R\}}tƒ jg|¢|‘|‘}tj|tjtjddd�}|jr¿td|j|jdd… d�}t |¡ | d¡ q‰t|dƒ�}| |  ¡ ¡ W d  ƒ n1 sÖw   Y  q‰W d  ƒ |S 1 sçw   Y  |S )a  
        :param str bodies: valid html documents as strings
        :param int width: width in pixels
        :param int height: height in pixels
        :param image_format: format of the image
        :type image_format: typing.Literal['jpg', 'png']
        NrZ   zEwkhtmltoimage 0.12.0^ is required in order to render images from htmlrà   z--disable-javascriptrã   z--widthz--heightz--formatú.htmlzreport_image_html_input.tmp.©ÚsuffixÚprefixr®   zreport_image_output.tmp.ÚwbFr'   )rW   rX   r*   r)   zQWkhtmltoimage failed (error code: %(error_code)s). Message: %(error_message_end)séüÿÿ)Ú
error_codeÚerror_message_endÚrb)!r   ÚmoduleÚcurrent_testr·   r+   rJ   r   r   r   rR   r   ÚtempfileÚmkstempÚcallbackrñ   r  Úcloser   Úfdopenr¿   Úencoder  rI   r-   r.   ÚDEVNULLr`   Ú
returncoderX   rb   ÚwarningÚopenr¹   )r�   r!  ÚwidthÚheightÚimage_formatrJ   rû   ÚstackÚfilesr
  Úinput_fdÚ
input_pathÚ	output_fdÚoutput_pathÚ
input_fileÚoutput_imagesr^   Úcompleted_processÚmessageÚoutput_filer1   r1   r2   Ú_run_wkhtmltoimageÑ  sV   ü
ÿý
ÿ€ó
ôåz"IrActionsReport._run_wkhtmltoimagec           *   
   C   s,  |r	|   |¡ ¡ n|  ¡ }| j||||d�}	g }
dd„ }tƒ ��ë}tr™tjr™tj ¡ }| 	i tj
¥dddœ¥¡ |jrCt || j¡|_tj |¡ | tjj|¡ |  ¡ }t|ƒj}d|j› d|› d	�}tjd
dd�\}}| ||¡ tt |d¡ƒ�}| | ¡ ¡ W d  ƒ n1 s�w   Y  |	 d|g¡ |rÐtjddd�\}}tt |d¡ƒ�}| | ¡ ¡ W d  ƒ n1 s¾w   Y  | ||¡ |
 d|g¡ |�rtjddd�\}}tt |d¡ƒ�}| | ¡ ¡ W d  ƒ n1 söw   Y  | ||¡ |
 d|g¡ g }d}t|ƒD ][\}}d|› d�}tjd|d�\}}tt |d¡ƒ�+} t |ƒdk �r;|  | ¡ ¡ nt!j" #|¡}!t$|!dƒ |  t!j" %|!¡¡ W d  ƒ n	1 �sZw   Y  | &|¡ | ||¡ �qtjddd�\}"}#t '|"¡ | ||#¡ t(|	|
 | |#g ƒ}$|$j)}%|$j* dk�r— nJ dk�r¼ |�rµt+ƒ j,�sµt-j.j/�r¯t0 1d¡‚t2t3dƒƒ‚t4 5d|%¡ n%}&|&d k�rÍt3d!|&|%d"d… d#�n
t3d$|&|%d"d… d#�}'t4 5|'¡ t2|'ƒ‚t6|#d%ƒ�}(|( 7¡ })W d  ƒ n1 �söw   Y  W d  ƒ |)S W d  ƒ |)S 1 �sw   Y  |)S )&a  Execute wkhtmltopdf as a subprocess in order to convert html given in input into a pdf
        document.

        :param Iterable[str] bodies: The html bodies of the report, one per page.
        :param report_ref: report reference that is needed to get report paperformat.
        :param str header: The html header of the report containing all headers.
        :param str footer: The html footer of the report containing all footers.
        :param landscape: Force the pdf to be rendered under a landscape format.
        :param specific_paperformat_args: dict of prioritized paperformat arguments.
        :param set_viewport_size: Enable a viewport sized '1024x1280' or '1280x1024' depending of landscape arg.
        :return: Content of the pdf as bytes
        :rtype: bytes
        )rù   rú   c                 S   s2   zt  | ¡ W d S  ty   t d| ¡ Y d S w )Nz#Error when trying to remove file %s)rñ   Úunlinkra   rb   Úerror)Ú	file_pathr1   r1   r2   Údelete_file#  s
   ÿz5IrActionsReport._run_wkhtmltopdf.<locals>.delete_filerV   T)r  Ú_trace_disablezsession_id=z; HttpOnly; domain=z	; path=/;z.txtzreport.cookie_jar.tmp.r*  r-  Nz--cookie-jarr)  zreport.header.tmp.z--header-htmlzreport.footer.tmp.z--footer-htmlr   zreport.body.tmp.r®   i  @ iô  z.pdfzreport.tmp.r5   zGUnable to convert multiple documents via wkhtmltopdf using unpatched QTzETried to convert multiple documents in wkhtmltopdf using unpatched QTzwkhtmltopdf: %siõÿÿÿz‰Wkhtmltopdf failed (error code: %(error_code)s). Memory limit too low or maximum file number of subprocess reached. Message : %(message)sr.  )r/  rJ  zEWkhtmltopdf failed (error code: %(error_code)s). Message: %(message)sr1  )8Ú_get_reportrÓ   rý   r   r   Údbr   Úsession_storeÚnewÚupdateÚsessionr„   r   Úcompute_session_tokenr‹   Úsession_tokenÚsaver6  Údeleterß   r   ÚhostnameÚsidr4  r5  r   rñ   r8  r¿   r9  r:   Ú	enumerater·   r  r  r  rA   r  r  r7  r3   rX   r;  r+   rH   r   r2  r3  ÚunittestÚSkipTestr   r   rb   r<  r=  r¹   )*r�   r!  Ú
report_refr  r  rê   rù   rú   rÑ   rû   Úfiles_command_argsrP  rA  Útemp_sessionr  r¢   ÚcookieÚcookie_jar_file_fdÚcookie_jar_file_pathÚcookie_jar_fileÚhead_file_fdÚhead_file_pathÚ	head_fileÚfoot_file_fdÚfoot_file_pathÚ	foot_fileÚpathsÚbody_idxr
  r,  Úbody_file_fdÚbody_file_pathÚ	body_filer<   Úpdf_report_fdÚpdf_report_pathri   Úerrr  rJ  Úpdf_documentÚpdf_contentr1   r1   r2   r3     sÈ   ü


ÿ
ý
ÿÿÿ
€ó





ü
ý
ýü
	
 ÿ
¥^ý
¥^¢^z IrActionsReport._run_wkhtmltopdfc                 C   s<   | j d }dd|fg}| j d  ¡ }| |¡ ¡ j|dd�S )zyGet the first record of ir.actions.report having the ``report_name`` as value for
        the field report_name.
        ro   r¥   r³   ú	res.usersr5   rÉ   )r‹   Úcontext_getr  r�   rg   )r�   r¥   Ú
report_objÚ
conditionsr¤   r1   r1   r2   Ú_get_report_from_name‰  s   
z%IrActionsReport._get_report_from_namec                 C   s´   | j d  ¡ }t|tƒr| |¡S t|tjƒr+|j| jkr'td| j|jf ƒ‚| ¡ S |j	dd|fgdd�}|r:|S | j  
|¡}|rT|jdkrPtd||jf ƒ‚| ¡ S td| ƒ‚)	a  Get the report (with sudo) from a reference

        :param report_ref: can be one of

            - ir.actions.report id
            - ir.actions.report record
            - ir.model.data reference to ir.actions.report
            - ir.actions.report report_name
        ro   z"Expected report of type %s, got %sr¥   r³   r5   rÉ   z7Fetching report %r: type %s, expected ir.actions.reportz$Fetching report %r: report not found)r‹   r�   r”   r•   Úbrowser   rx   Ú_nameÚ
ValueErrorrg   r¶   )r�   ra  Ú
ReportSudort   r1   r1   r2   rR  “  s    


zIrActionsReport._get_reportc           	   	      sÌ  dt fdt fddd„ fddd„ fd dd„ fd	t fd
dd„ fdœ}‡ fdd„| ¡ D ƒ‰ ˆ  d¡ˆ d< ˆ d r;tƒ ˆ d< ˆ d ˆ d  dksPtˆ d ˆ d ƒdkrTtdƒ‚|dkrkt|ƒdv rkd}t|ƒdv rjd| }n|dkr}dddœ}| t|ƒd¡}n|d kr‰ˆ d! s‰d"ˆ d#< |d$v r”t||ƒs”d}z,t	|f|d%d&œˆ ¤Ž}ˆ d' r»|  
¡ }| ˆ d' ¡}|r»|ˆ d ˆ d |ƒ | d%¡W S  ttfyå   |dkrÑtd(ƒ‚|d krÙtd)ƒ‚| jd|fi ˆ ¤Ž Y S w )*NiX  éd   Fc                 S   ó   t t| ƒƒS rÐ   ©rQ   r•   ©Úxr1   r1   r2   Ú<lambda>´  ó    z)IrActionsReport.barcode.<locals>.<lambda>Tc                 S   r‚  rÐ   rƒ  r„  r1   r1   r2   r†  µ  r‡  c                 S   s   | S rÐ   r1   r„  r1   r1   r2   r†  ¶  s    é   ÚLc                 S   s   | dv r| pdS )N)r‰  ÚMÚQÚHr‰  r1   r„  r1   r1   r2   r†  ¾  s    )r>  r?  ÚhumanreadableÚquietÚmaskÚ	barBorderÚbarLevelc                    s&   i | ]\}\}}||ˆ   ||¡ƒ“qS r1   )rë   )r–   Úkr—   Ú	validator©Úkwargsr1   r2   Ú
<dictcomp>À  s   & z+IrActionsReport.barcode.<locals>.<dictcomp>r�  ÚhumanReadableÚfontNamer>  r?  i€O i'  zBarcode too largeÚUPCA)é   é   é   ÚEAN13)rš  r›  z0%sÚautoÚEAN8)é   rœ  ÚCode128ÚQRrŽ  r   r�  )rŸ  r�  Úpng)r    rì   r�  zCannot convert into barcode.zCannot convert into QR code.)r•   r  Úpopr    Úmaxr  r·   rë   r   r   Úget_available_barcode_masksÚasStringÚAttributeErrorÚbarcode)	r�   Úbarcode_typer    r•  ÚdefaultsÚsymbology_guessr©  Úavailable_masksÚmask_to_applyr1   r”  r2   r©  ¯  sT   



ó
*€
úzIrActionsReport.barcodec                 C   s   i S )a   Hook for extension.

        This function returns the available QR-code masks, in the form of a
        list of (code, mask_function) elements, where code is a string identifying
        the mask uniquely, and mask_function is a function returning a reportlab
        Drawing object with the result of the mask, and taking as parameters:

            - width of the QR-code, in pixels
            - height of the QR-code, in pixels
            - reportlab Drawing object containing the barcode to apply the mask on
        r1   rª   r1   r1   r2   r¦  ò  s   z+IrActionsReport.get_available_barcode_masksc              	      sx   |du ri }ˆ j d  ˆ j j¡‰ˆ j d jdd�}|jt‡ ‡fdd„ˆˆ j jˆ j d  ¡ jd	d
d�d� | 	||¡ 
¡ S )a?  Allow to render a QWeb template python-side. This function returns the 'ir.ui.view'
        render but embellish it with some variables/methods used in reports.
        :param values: additional methods/variables used in the rendering
        :returns: html representation of the template
        :rtype: bytes
        Nrx  z
ir.ui.viewF)Úinherit_brandingc                    s   t j ˆ jˆjd�| ¡S )N)Útz)r   ÚDatetimeÚcontext_timestampr  r°  )Út©r�   Úuserr1   r2   r†    s    z2IrActionsReport._render_template.<locals>.<lambda>rÚ   zweb.base.urlrV   rr   )r&   r²  rµ  Úres_companyÚweb_base_url)r‹   r}  r„   r  rV  r&   rÒ   r�   rÛ   Ú_render_templater9  )r�   ÚtemplateÚvaluesÚview_objr1   r´  r2   r¸    s   ûz IrActionsReport._render_templatec                 C   s   t tdƒƒ‚)Nú+Odoo is unable to merge the generated PDFs.)r   r   )r�   rN  Úerror_streamr1   r1   r2   Ú_handle_merge_pdfs_error  s   z(IrActionsReport._handle_merge_pdfs_errorc                 C   sœ   t ƒ }|D ])}zt|ƒ}| |¡ W q ttttfy. } z|||d� W Y d }~qd }~ww t ¡ }| 	|¡ z| 
|¡ W |S  tyM   ttdƒƒ‚w )N©rN  r½  r¼  )r#   r"   ÚappendPagesFromReaderr$   Ú	TypeErrorÚNotImplementedErrorr  ÚioÚBytesIOr  r¿   r   r   )r�   ÚstreamsÚhandle_errorÚwriterÚstreamÚreaderÚeÚresult_streamr1   r1   r2   Ú_merge_pdfs  s"   €ÿ
þÿzIrActionsReport._merge_pdfsc           (   
   C   s@  |si }|  dd¡ |  |¡}|ot|ƒtt|ƒƒk}tƒ }|r|| j|j  |¡}|D ]P}|j}	|	|v r5q+d }
d }|st|j	rt| jj
 d¡st| |¡}|rt|jrtt |j¡}
|j d¡rtt |
¡}t ¡ }| d¡j|dd� |
 ¡  |}
|
|dœ||	< q+dd	„ | ¡ D ƒ}|r‰|n|}| p�|}|�r|  ¡ d
krŸttdƒƒ‚ddi}|  dd¡ | jd!i |¤Žj|||d�d }|jd!i |¤Žj||jd�\}}}}}|sá|j	rát|ƒt|ƒkráttd|jƒƒ‚| j ||||| jj
 d¡|| jj
 d¡d�}t |¡}|�s|�s	d|d dœiS t|ƒdk�r|||d  d< |S dd	„ |D ƒ}t!|ƒ}|j"t|ƒk�rTt#|j"ƒD ]}t$ƒ }| %| &|¡¡ t ¡ }
| '|
¡ |
|||  d< �q2|S t|ƒdk�rt|ƒt|ƒk�r|j(d }d|v �osd|d v }|�sd| |d dœiS g } |d d }!	 |  )|d |!d  d ¡ d|!v�r›n|!d }!�qˆt*t| ƒƒ} t| ƒt|ƒk}"| d dk}#|"�rþ|#�rþt+| ƒD ]<\}}$|d t| ƒk �rÒ| |d  n|j"}%t$ƒ }t#|$|%ƒD ]}&| %| &|&¡¡ �qÝt ¡ }
| '|
¡ |
|||  d< �q¿|S |D ]}	| j,|||	gd �}'|'|	 d ||	 d< �q |d dœ|d< |S )"Nr¦   ÚpdfÚreport_pdf_no_attachmentÚimageÚRGB)rì   )rÈ  rË   c                 S   s   g | ]
\}}|d  s|‘qS ©rÈ  r1   )r–   rÈ   Ústream_datar1   r1   r2   Ú
<listcomp>V  s    zDIrActionsReport._render_qweb_pdf_prepare_streams.<locals>.<listcomp>rC   zFUnable to find Wkhtmltopdf on this system. The PDF can not be created.r  F©r¡   r   )r  u  Report template â€œ%sâ€� has an issue, please contact your administrator. 

Cannot separate file to save as attachment because the report's template does not contain the attributes 'data-oe-model' and 'data-oe-id' as part of the div with 'article' classname.rê   rú   )ra  r  r  rê   rù   rú   r5   rÈ  c                 S   s   g | ]}|r|‘qS r1   r1   ©r–   r…  r1   r1   r2   rÓ  –  s    z/Rootz	/Outlinesz/First)Úreport_actionrÈ  rË   Tz/Destsz/Destz/Next)ra  r¡   r"  r1   )-Ú
setdefaultrR  r·   Úsetr   r‹   rŠ   r}  r�   rË   r¤   rë   rÎ   Úattachment_userÃ  rÄ  ÚrawÚmimetyper  r   r=  ÚconvertrZ  r7  r  rÏ   r   r   r  Ú_render_qweb_htmlr'  r°   r3   r"   ÚnumPagesÚranger#   ÚaddPageÚgetPager¿   Útrailerr  Úsortedr^  Ú _render_qweb_pdf_prepare_streams)(r�   ra  r¡   r"  Úreport_sudoÚhas_duplicated_idsÚcollected_streamsÚrecordsrÌ   rÈ   rÈ  rË   ÚimgÚ
new_streamÚres_ids_wo_streamÚall_res_ids_wo_streamÚis_whtmltopdf_neededÚadditional_contextr  r!  Úhtml_idsr  r  rù   rw  Úpdf_content_streamÚhtml_ids_wo_nonerÉ  ÚiÚattachment_writerr   Úhas_valid_outlinesÚoutlines_pagesr$  Úhas_same_number_of_outlinesÚhas_top_level_headingÚnumÚtoÚjÚindividual_collected_streamr1   r1   r2   rä  +  sÔ   



þ
 &üù
	þÿ

 
ý
ü$
z0IrActionsReport._render_qweb_pdf_prepare_streamsc              	   C   sŒ   g }|  ¡ D ]=\}}|d rq|r|d st d|j¡ q| j|j  |¡}t|j|t	dœƒ}|s2q| 
||d  ¡ |j|jddœ¡ q|S )av  Hook to prepare attachment values needed for attachments creation
        during the pdf report generation.

        :param report: The report (with sudo) from a reference report_ref.
        :param streams: Dict of streams for each report containing the pdf content and existing attachments.
        :return: attachment values list needed for attachments creation.
        rË   rÈ  zÄThese documents were not saved as an attachment because the template of %s doesn't have any headers seperating different instances of it. If you want it saved,please print the documents separatelyrÄ   Úbinary)r°   rÚ  rÇ   rÈ   r²   )r  rb   r<  r¥   r‹   rŠ   r}  r%   rË   r&   r  Úgetvaluer�   )r�   rt   rÅ  Úattachment_vals_listrÈ   rÒ  rÌ   rÍ   r1   r1   r2   Ú(_prepare_pdf_report_attachment_vals_listÒ  s,   ý

ûz8IrActionsReport._prepare_pdf_report_attachment_vals_listc                 C   st   |si }t |tƒr|g}| dd¡ tjjstjd r*| jj	 
d¡s*| j|||d�S | jdd�} | j|||d�dfS )	Nr¦   rÍ  Útest_enableÚforce_report_renderingrÔ  T)Úwebp_as_jpg)r"  )r”   r•   r×  r   r2  r3  r   r   r‹   r¤   rë   rÝ  r  rä  )r�   ra  r"  r¡   r1   r1   r2   Ú_pre_render_qweb_pdfø  s   
 z$IrActionsReport._pre_render_qweb_pdfc                    s  |si }t |tƒr|g}| dd¡ | j|||d�\}}|dkr$||fS |o/t|ƒtt|ƒƒk}|  |¡}|sw|jrw| jj	 
d¡sw|  ||¡}|rwd dd„ |D ƒ¡}	z
| jd  |¡ W n typ   t d	|	| jjj¡ Y nw t d
|	¡ ‡ ‡fdd„}
dd„ | ¡ D ƒ‰tˆ ¡ ƒ}g ‰ t|ƒdkrœ|d  ¡ }n|  ||
¡�}| ¡ }W d   ƒ n1 s±w   Y  ˆ rédtdƒ|jddˆ fgddgdœ}tˆ ƒ}|dkrÜ| dgˆ d dœ¡ ttd|d�|tdƒd�‚|D ]}| ¡  që|rþt d|jt|ƒ¡ |dfS )Nr¦   rÍ  )r"  r¡   rÎ  z, c                 s   s   � | ]}|d  V  qdS )r°   Nr1   rÕ  r1   r1   r2   rš     s   € z3IrActionsReport._render_qweb_pdf.<locals>.<genexpr>rÆ   z1Cannot save PDF report %r attachments for user %rz2The PDF documents %r are now saved in the databasec                    s   ˆ   ˆ| ¡ d S rÐ   )r  r¿  ©Úerror_record_idsÚstream_to_idsr1   r2   Úcustom_handle_merge_pdfs_error"  r­   zHIrActionsReport._render_qweb_pdf.<locals>.custom_handle_merge_pdfs_errorc                 S   s"   i | ]\}}|d  r|d  |“qS rÑ  r1   )r–   r’  r—   r1   r1   r2   r–  %  s   " z4IrActionsReport._render_qweb_pdf.<locals>.<dictcomp>r5   r   zir.actions.act_windowzProblematic record(s)r�   r“   )Fr7   )FÚform)r²   r°   rÇ   r¢   Úviews)r	  rÈ   zVOdoo is unable to merge the generated PDFs because of %(num_errors)s corrupted file(s))Ú
num_errorszView Problematic Record(s))rJ  r�   Úbutton_textz<The PDF report has been generated for model: %s, records %s.)r”   r•   r×  r  r·   rØ  rR  rË   r‹   r¤   rë   rÿ  r  Úcreater   rb   rc   rµ  r‘   r  r7   Úkeysrý  rÌ  r   rŠ   rV  r   r7  rR   )r�   ra  r"  r¡   rç  r¦   ræ  rå  rþ  Úattachment_namesr  Ústreams_to_mergerw  Úpdf_merged_streamr�   r
  rÈ  r1   r  r2   Ú_render_qweb_pdf  sh   

ÿ
ÿ
ûþ
ý
z IrActionsReport._render_qweb_pdfc                 C   ó>   |si }|  dd¡ |  |¡}|  |||¡}|  |j|¡dfS )Nr¦   Útext©r×  rR  Ú_get_rendering_contextr¸  r¥   ©r�   ra  Údocidsr¡   rt   r1   r1   r2   Ú_render_qweb_textL  ó   
z!IrActionsReport._render_qweb_textc                 C   r  )Nr¦   r  r  r  r1   r1   r2   rÝ  U  r  z!IrActionsReport._render_qweb_htmlc                 C   s   d|j  }| j |¡S )Nz	report.%s)r¥   r‹   rë   )r�   rt   Úreport_model_namer1   r1   r2   Ú_get_rendering_context_model^  s   
z,IrActionsReport._get_rendering_context_modelc                 C   sj   |   |¡}|rt|ƒpi }|d ur| |j||d�¡ n| j|j  |¡}| ||j|dœ¡ t|d< |S )NrÔ  )Údoc_idsÚ	doc_modelÚdocsr   )r  ÚdictrV  Ú_get_report_valuesr‹   rŠ   r}  r   )r�   rt   r  r¡   r  r  r1   r1   r2   r  b  s   
ýz&IrActionsReport._get_rendering_contextc                 C   sB   |   |¡}|j ¡  dd¡}t| d| d ƒ}|sd S ||||d�S )Nú-r   Ú_render_rÔ  )rR  r¦   ÚlowerÚreplaceÚgetattr)r�   ra  r"  r¡   rt   r¦   Úrender_funcr1   r1   r2   r  u  s   
zIrActionsReport._renderc                 C   s¤   | j j}|r(t|tjƒr|j}nt|tƒr|g}nt|tƒr |}t| j j|d�}||d| j	| j
| j| jdœ}| j j d¡}| j  ¡ rP| j jjsP|rP|sP|  |¡S |S )zâReturn an action of type ir.actions.report.

        :param docids: id/ids/browse record of the records to print (if not used, pass an empty list)
        :param data:
        :param bool config:
        :rtype: bytes
        )Ú
active_idsro   )r¤   r¡   r²   r¥   r¦   Úreport_filer°   Údiscard_logo_check)r‹   r¤   r”   r   rx   Úidsr•   r7   r  r¥   r¦   r(  r°   rë   Úis_adminrÒ   Úexternal_report_layout_idÚ(_action_configure_external_report_layout)r�   r  r¡   r   r¤   r'  rÖ  r)  r1   r1   r2   rÖ  ~  s*   

ù

zIrActionsReport.report_actionú,web.action_base_document_layout_configuratorc                 C   s>   | j d  |¡}t | di ¡¡}d|d< ||d< ||d< |S )Nrp   r¤   Tr§   rÖ  )r‹   Ú_for_xml_idÚjsonÚloadsrë   )r�   rÖ  rÕ   r�   Úpy_ctxr1   r1   r2   r-     s   z8IrActionsReport._action_configure_external_report_layoutc                 C   sN   | j |  |¡}|  d¡}| | j}|D ]}| t|jƒ¡r$| |j¡ q|S )zô Return the list of ids of actions for which the domain is
        satisfied by at least one record in record_ids.
        :param model: the model of the records to validate
        :param record_ids: list of ids of records to validate
        r¢   )	r‹   r}  rÂ   r*  Úfiltered_domainr   r¢   r  r�   )r�   rŠ   Ú
record_idsrè  Úactions_with_domainÚvalid_action_report_idsr�   r1   r1   r2   Úget_valid_action_reports¨  s   

€z(IrActionsReport.get_valid_action_reportsc                 C   sj   |D ]+}|  ¡ r-z| ¡  W q ttjjfy, } zt d|j|¡ W Y d }~qd }~ww q| 	dd„ ¡S )Nz,Failed to migrate attachment %s to local: %sc                 S   s
   |   ¡  S rÐ   )Ú_is_remote_source)Úar1   r1   r2   r†  ¾  s   
 z<IrActionsReport._prepare_local_attachments.<locals>.<lambda>)
r8  Ú_migrate_remote_to_localr   ÚrequestsÚ
exceptionsÚRequestExceptionrb   rN  r�   rÂ   )r�   ÚattachmentsrË   rÊ  r1   r1   r2   Ú_prepare_local_attachments¶  s   €ÿýz*IrActionsReport._prepare_local_attachmentsrÐ   )NF)F)r(  )FNNFNF)NN)NT)r.  )FrK   rL   rM   r~  Ú_descriptionÚ_inheritÚ_tableÚ_orderÚ_allow_sudo_commandsr   ÚCharr²   Ú	Selectionr¾   rŠ   ÚMany2onerŽ   r¦   r¥   r(  Ú	Many2manyÚ	group_idsÚBooleanÚmultirÑ   Úprint_report_namerÙ  rË   r¢   r   Údependsry   rz   r©   r¼   rÀ   rÃ   rÎ   rÏ   rÓ   rÖ   rÙ   rß   rý   r'  r7   ÚbytesrL  r3   r|  rR  r©  r¦  r¸  r¾  rÌ  rä  rÿ  r  r  r  rÝ  r  r  r  rÖ  r-  r7  r?  Ú__classcell__r1   r1   r«   r2   rn   �   s¶    
û	ÿÿÿÿ



û
QR0ø 
	

B



 (
&
F

"rn   )OÚ	functoolsrÃ  r0  Úloggingrñ   rf   r;  r-   r4  rN   r_  Úastr   Úcollectionsr   Ú
contextlibr   r   Ú	itertoolsr   Úurllib.parser   Ú	lxml.htmlr  ÚPILr   r	   r
   Ú
markupsafer   Úodoor   r   r   r   r   r   Úodoo.exceptionsr   r   r   r   Úodoo.fieldsr   Úodoo.servicer   Ú	odoo.httpr   r   Ú
odoo.toolsr   r   r   r   Úodoo.tools.barcoder   r   r    Úodoo.tools.miscr!   Úodoo.tools.pdfr"   r#   r$   Úodoo.tools.safe_evalr%   r&   ÚLOAD_TRUNCATED_IMAGESÚ	getLoggerrK   rb   r3   rA   Ú
NamedTuplerB   Ú	lru_cacher+   rx   rn   r1   r1   r1   r2   Ú<module>   sL    

D