我会尽量准确地解释我的问题,请随时向我询问更多详细信息:
我目前正在使用 LateX 和模板工具包开发发票生成器,我知道它不是最佳的,但它是遗留代码,我们无法创建新的;
我想在 pdf 文档的某个特定部分(即表格)的顶部添加一个横幅,当表格足够长以创建新页面时,我需要将此横幅放在表格第二页的顶部;
我得到了多个依赖于服务/商品类型的模板,因此调试非常复杂,因为我永远不知道错误真正发生在哪个文件或行(是的,我使用了-file-line-error debug,但它显示var/tmp中编译的临时文件而不是我当前正在处理的文件);
问题 :这真的可能吗?对我来说,LaTex 只能用来设计科学文档,不能用来制作发票,而且包含文件的编译过程似乎运行得很糟糕。
我尝试过:制作一个包含不同模板部分的表格,表格标题看起来像横幅。问题是不同的模板部分也是表格,我遇到了多个错误,由于此发票生成器的架构,我无法解决这些错误,因为调试点位于临时编译的 pdf 中,而不是我所在的工作文件中。错误如下:
段落第 xxx--xxx 行中的 \hbox 未满(badness 10000);
./tempi6163.tex:723: } 太多。
欢迎提供任何提示、解决方法和建议,我确实不知道有谁除了论文文档之外使用过 LaTeX,但只是以非常基本的方式。
这是代码,警告它可能会吓到你:
发票布局骨架:
\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[frenchb]{babel}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage{underscore}
\usepackage{color}
\usepackage{colortbl}
\usepackage{xcolor}
\usepackage{transparent}
\usepackage{wallpaper}
\usepackage{atbegshi,picture}
\usepackage{lastpage}
\usepackage{longtable}
%\usepackage[top=[%- document_config.document_top -%],left=0.15cm,bottom=2.5cm,right=0.3cm]{geometry}
% Use this package below to modify document layout : https://texdoc.org/serve/geometry.pdf/0
\usepackage[top=2.5cm,left=0.15cm,bottom=2.5cm,right=0.3cm]{geometry}
\usepackage{setspace}
\usepackage{array}
\usepackage{avant}
\usepackage{hyperref}
\usepackage{booktabs}
\usepackage{multicol}
\usepackage{multirow}
\usepackage{makecell}
\usepackage{hhline}
\usepackage[nomessages]{fp}
\definecolor{labelcolor}{HTML}{E8E8E8}
[%- IF document_config.document_watermark %]
\usepackage{draftwatermark}
[%- END %]
[%- IF document_config.entity_ref == 'DCFORDATA' %]
\hypersetup{colorlinks=true,urlcolor=[HTML]{49906D},linkcolor=black}
[%- ELSE %]
\hypersetup{colorlinks=true,urlcolor=blue,linkcolor=black}
[%- END %]
% }}}
% {{{ definition de commandes specifiques
\newcounter{period}
[%- IF document_datas.info_client.bill_period_num %]
\setcounter{period}{[%- document_datas.info_client.bill_period_num -%]}
[%- ELSE %]
\setcounter{period}{1}
[%- END %]
%
% chargement des fichiers multi-langues
%
\input{[%- document_config.template_path -%]/jn_pdf_intl_defs.tex}
[% IF document_datas.headcell_type.head_type == 1 %]
\newcommand{\JNHeadCellTitle}{\Fr{Frais d'acc\`{e}s au Service}\En{Non-reccuring}}
[% ELSIF document_datas.headcell_type.head_type == 2 %]
\newcommand{\JNHeadCellTitle}{\Fr{N\'{e}goce}\En{Resale}}
[% ELSIF document_datas.headcell_type.head_type == 3 %]
\newcommand{\JNHeadCellTitle}{\Fr{FAS / N\'{e}goce}\En{Non-reccuring / Resale}}
[% ELSE %]
\newcommand{\JNHeadCellTitle}{\Fr{Frais d'acc\`{e}s au Service}\En{Non-reccuring}}
[% END %]
%
% definitions de commandes
%
%\renewcommand{\familydefault}{\sfdefault}
\renewcommand{\rmdefault}{phv} % Arial
\renewcommand{\sfdefault}{phv} % Arial
\renewcommand\textrangle{>}
\renewcommand\textlangle{<}
\renewcommand\arraystretch{1}
\renewcommand\footnotemark{}
\renewcommand\footnoterule{}
\newcommand{\HRule}{\rule{\linewidth}{0.1mm}}
\newcommand{\tabularnewline}{\\}
\newcommand{\tabularendbloc}{
\medskip
}
\newcommand{\csp}[1]{\hspace{#1mm}}
\newcommand{\cell}{&}
\newcommand{\hcell}[1]{\cell \hspace{#1mm}}
\newcommand{\price}[1]{\footnotesize #1}
\newcommand{\rprice}[1]{\multicolumn{1}{r|}{\footnotesize #1}}
\newcommand{\infoline}[2]{\multicolumn{#1}{c}{\footnotesize\textit{#2} } }
\newcommand{\infoprice}[2]{\multicolumn{#1}{r}{\footnotesize\textit{#2} } }
\newcommand{\infototalprice}[2]{\multicolumn{#1}{r}{#2} }
\newcommand{\emptyline}[1]{\multicolumn{#1}{r}{}}
\providecommand{\bloctitle}[1]{
{\renewcommand{\arraystretch}{1.3}
\footnotesize
\setlength{\tabcolsep}{1mm}
\begin{tabular}{|>{\raggedright}p{19.12cm}|}
\hline
\multicolumn{1}{|>{\columncolor{mycellcolor}}l|}{ \tabulartitlebox{19.12cm}{\LARGE \textbf{#1}} } \tabularnewline
\hline
\end{tabular} \tabularendbloc
}
}
\providecommand{\blocsubtitle}[1]{
{\renewcommand{\arraystretch}{1}
\footnotesize
\setlength{\tabcolsep}{1mm}
\begin{tabular}{|>{\raggedright}p{19.12cm}|}
\multicolumn{1}{l}{\multirow{-1}{19.12cm}{\large{\textbf{#1}} \dotfill}} \\
\end{tabular} \tabularendbloc
}
}
\providecommand{\tabulartitlebox}[2]{
\makebox{
\parbox{#1}{
\vspace{0.1cm}
\large{#2}
\vspace{0.1cm}
}
}
}
%taille de la ram
\newcommand{\ramsize}[1]{
\FPeval\sram{round((#1)/1024,0)}%
\sram
}
%calcul prix*periode
\newcommand{\PPerPeriod}[2]{
\FPeval\pperiod{round(\theperiod*(#1)*(#2),2)}%
\pperiod
}
%calcul prix*periode
\newcommand{\QPerPeriod}[1]{
\FPeval\pperiod{round(\theperiod*(#1),0)}%
\pperiod
}
\newcommand{\PPerQuantity}[2]{
\FPeval\qprice{round((#1)*(#2),2)}%
\qprice
}
%prix unitaire 0.2f
\newcommand{\UnitPrice}[2][2]{
\FPeval\pperiod{round(1*(#2),#1)}%
\pperiod
}
%prix unitaire à 5 chiffres 0.5f
\newcommand{\UnitPriceFiveDigits}[2][5]{
\FPeval\pperiod{round(1*(#2),#1)}%
\pperiod
}
%total 0.2f
\newcommand{\TotalPrice}[2][2]{
\FPeval\pperiod{round(1*(#2),#1)}%
\pperiod
}
%ligne vide
\newcommand{\DSLineEmpty}{
\cell
\cell
\cell
\cell
\cell
\cell \tabularnewline
}
%ligne titre, nom Service sans prix)
\newcommand{\DSLineTitle}[1]{
\rowcolor{mycellcolor}
\normalsize{\textbf{#1}}
\cell
\cell
\cell
\cell
\cell
\cell \tabularnewline
}
%ligne rubrique (options, extremite etc..., sans prix)
\newcommand{\DSLineSubTitle}[2]{
\csp{#1} \footnotesize{\textbf{#2}}
\cell
\cell
\cell
\cell
\cell
\cell \tabularnewline
}
%ligne texte (sans prix)
\newcommand{\DSLineSimpleText}[2]{
\csp{#1} \footnotesize{#2}
\cell
\cell
\cell
\cell
\cell
\cell \tabularnewline
}
%ligne texte LABEL (sans prix)
\newcommand{\DSLineSimpleLabel}[2]{
\cellcolor{labelcolor}\csp{#1} \footnotesize{#2}
\cell
\cell
\cell
\cell
\cell
\cell \tabularnewline
}
%ligne texte (prix fas)
\newcommand{\DSLineFasPrice}[4]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPrice{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}}
\cell
\cell
\cell \tabularnewline
}
\newcommand{\DSLineFasPriceFiveDigits}[4]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPriceFiveDigits{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}}
\cell
\cell
\cell \tabularnewline
}
%ligne texte (prix rec)
\newcommand{\DSLineRecPrice}[4]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \dotfill
\cell \dotfill
\cell \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPrice{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}} \tabularnewline
}
\newcommand{\DSLineRecPriceFiveDigits}[4]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \dotfill
\cell \dotfill
\cell \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPriceFiveDigits{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}} \tabularnewline
}
%ligne texte (prix rec)
\newcommand{\DSLineFasRecPrice}[6]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPrice{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}}
\cell \footnotesize{#5}
\cell \footnotesize{\UnitPrice{#6}}
\cell \footnotesize{\PPerQuantity{#5}{#6}} \tabularnewline
}
\newcommand{\DSLineFasRecPriceFiveDigits}[6]{
\csp{#1} \footnotesize{#2} \dotfill
\cell \footnotesize{#3}
\cell \footnotesize{\UnitPriceFiveDigits{#4}}
\cell \footnotesize{\PPerQuantity{#3}{#4}}
\cell \footnotesize{#5}
\cell \footnotesize{\UnitPriceFiveDigits{#6}}
\cell \footnotesize{\PPerQuantity{#5}{#6}} \tabularnewline
}
\definecolor{mycellcolor}{gray}{0.95}
\setlength\arrayrulewidth{0.7pt}
\arrayrulecolor{black}
% }}}
% {{{ definition fond de page
\newcommand\BackgroundPic{
\put(0,0){
\parbox[b][\paperheight]{\paperwidth}{
\vfill
\centering
[% IF NOT document_config.document_watermark -%]
\includegraphics[width=\paperwidth,height=\paperheight,keepaspectratio]{[%- document_config.background_path -%]/[%- document_config.background_file -%]}%
[%- END %]
\vfill
}
}
}
\newcommand{\margin}[2] {
\hspace{#1}\makebox{
\parbox[t]{21cm}{
#2
}
}
}
% }}}
% {{{ entete et pied de page en mode galerien
\AtBeginShipout{
\AtBeginShipoutUpperLeftForeground{
%link
\small
[%- IF document_config.header_url %]
\put(16.2cm,-1.5cm){
\makebox{
[%- IF NOT document_config.document_watermark -%]
\href{[%- document_config.document_head_url_link -%]}{[%- document_config.document_head_url_name -%]}
[%- END -%]
}
}
[%- END %]
%foot address
[%- IF document_config.footer ;
IF document_datas.pdf_langage != 'FR' ;
document_config.document_foot_address_infos = document_config.document_foot_address_infos.replace('au capital de', 'with a capital of');
END %]
\put(0.6cm,-\dimexpr\paperheight-1cm){
\makebox{
\parbox{\paperwidth-1cm}{
[%- IF NOT document_config.document_watermark -%]
\centering
\color[gray]{0.60}
\footnotesize
\singlespacing{
[% document_config.document_foot_address -%] \\
[% document_config.document_foot_address_infos %]
}
[%- END -%]
}
}
} %End of 'foot address' block
[%- END %]
%pager
\put(0.8cm,-\dimexpr\paperheight-1.1cm){
\makebox[19.5cm][r]{
\color{black}
\small
page \thepage / \pageref{LastPage}
}
} %End of 'pager' block
%foot engagement
\put(0.6cm,-\dimexpr\paperheight-2cm){
\makebox{
\parbox{\paperwidth-1cm}{
\centering
\footnotesize
\singlespacing{
[%- IF NOT document_config.document_watermark -%]
%
[%- IF document_datas.entity_contract == '' -%]
%
[% "bdc.cgv_accept" | trans %]\Fr{ [%- document_datas.header.engagment_entity -%]}\En{}.\\
[% "bdc.valid_30_days" | trans %]
%
[%- ELSE -%]
%
~ \\
[% "bdc.contract_accept" | trans %] \textbf{[%- document_datas.entity_contract -%]}.
%
[%- END %]
%
[%- END %]
}
}
}
} %End of 'foot engagement' block
%foot paraph
\put(19.5cm, -29.4cm){
\makebox{
\normalfont{
\tiny
\transparent{0}
doc\_PR
}
}
} %End of 'foot paraph' block
}
} %End of 'AtBeginShipoutUpperLeftForeground' block
% }}}
% {{{ document pdf info et watermark
\pdfinfo{
/Author ([%- document_config.document_author -%])
/Title ([%- document_config.document_title -%])
/CreationDate (D:[%- document_config.document_date -%])
/Subject ([%- document_config.document_subject -%])
/Keywords ([%- document_config.document_keywords -%])
/Creator (JNTools)
/Producer ([%- document_config.document_author -%])
}
[% IF document_config.document_watermark -%]
%document_wathermark
\SetWatermarkText{[%- document_config.document_watermark_text -%]}
\SetWatermarkScale{[%- document_config.document_watermark_size -%]}
\SetWatermarkAngle{[%- document_config.document_watermark_angle -%]}
[% END -%]
% }}}
% {{{ contenu document
\begin{document}
\AddToShipoutPicture{\BackgroundPic}
\pagestyle{empty}
\singlespacing
\small
[% INCLUDE $document_config.body_to_include %]
\end{document}
% }}}
发票正文:
# Customer information
INCLUDE 'bdc/informations.tt' ;
global.voice_grid_list = [] ;
global.storage_is_autosized = 0;
# List of services
INCLUDE 'bdc/description_services.tt' ;
# Sign bloc
IF NOT document_config.document_watermark ;
INCLUDE 'bdc/signature_engagement.tt' ;
END ;
# Grilles voix
IF global.voice_grid_list.size > 0 ;
global.voice_grid_list_unique = global.voice_grid_list.unique;
INCLUDE 'bdc/generics/voice_grid.tt' ;
END ;
# Grilles v5
IF document_datas.grids.size > 0 ;
INCLUDE 'bdc/generics/grids.tt' ;
END ;
IF NOT document_config.document_watermark ;
# SEPA Mandate
IF (document_datas.entity_status == 'prospect' && document_datas.info_client.bill_type_payment == 'PRVLT' && document_datas.mandat.rendering == 'auto') || (document_datas.mandat.rendering == 'yes') ;
INCLUDE 'bdc/mandat_prelevement.tt' ;
END ;
IF document_datas.lic_mobility == 'yes' ;
INCLUDE 'bdc/lic_mobility.tt' ;
END ;
# CGV
IF ((document_datas.entity_status == 'prospect'
&& document_datas.info_client.bill_type_payment == 'PRVLT'
&& document_datas.cgv.rendering == 'auto')
|| (document_datas.cgv.rendering == 'yes'))
&& (document_datas.entity_contract == '');
cgvfile = 'bdc/cgv_' _ document_datas.cgv.version _ '.tt' ;
INCLUDE $cgvfile ;
INCLUDE 'bdc/cgv_signature.tt' ;
END ;
END ;
-%]
发票正文中包含的网格部分,我想要添加上面描述的横幅,对于每个 INCLUDE'grids/grid.tt',我想要在其顶部添加横幅,第一页除外:
[%# collect voice groups informations %]
[%
SET global.has_voice_groups = 0;
SET global.voice_group_defs = {};
SET global.voice_uuid_names = {};
FOREACH topgrid IN document_datas.grids;
SET grid = topgrid.info;
SET additional_info = topgrid.additional_info;
INCLUDE 'grids/informations.tt';
%]
\vspace{0.1cm}
[% IF grid.rendering_mode == 'child'; %]
\bloctitle{[% grid.grid_ref %] : [% "grids.type.${grid.grid_line_type_ref}" | trans %]}
[% ELSE; %]
\bloctitle{[% grid.grid_ref %] : [% grid.name %]}
[% END; %]
[%
SET additional_info = topgrid.additional_info;
IF grid.rendering_mode == 'meta';
engagement_coefs = grid.engagement_coefs;
FOREACH grid IN topgrid.childs;
SET additional_info = grid.additional_info;
INCLUDE 'grids/grid.tt';
IF engagement_coefs.${grid.grid_line_type_ref} ;
INCLUDE 'grids/engagement_coefs.tt';
END;
END;
ELSE;
INCLUDE 'grids/grid.tt';
END;
END;
IF global.has_voice_groups > 0;
INCLUDE 'grids/generic/voice_groups.tt';
END;
IF NOT document_datas.is_preview;
INCLUDE 'grids/signature.tt';
END;
-%]
在 INCLUDE 'grids/grid.tt' 中我尝试了以下操作:
% The banner I want to include on table format
\vspace{0.1cm}
{\renewcommand{\arraystretch}{1.2}
\setlength{\LTleft}{0.50cm}
\setlength{\tabcolsep}{1mm}
\begin{longtable}{|>{\raggedright}p{11.1cm}|>{\raggedleft}p{0.65cm}|>{\raggedleft}p{1.3cm}|>{\raggedleft}p{1.5cm}|>{\raggedleft}p{0.65cm}|>{\raggedleft}p{1.3cm}|>{\raggedleft}p{1.5cm}|}
% I choose 4 column to test but is there a way to detect how many column are going to be included ?
\multicolumn{4}{c}{
[%- IF NOT document_config.document_watermark -%]
\parbox[t]{19.55cm}{\HRule\\[0cm]
\parbox[t]{7.7cm}{\footnotesize{\textbf{~\Fr{Responsable de compte}\En{Account Manager}~:~[%- document_datas.header.commercial -%]} } }
\parbox[t]{5cm}{\vrule\footnotesize{\textbf{~\Fr{Date d'\'{e}mission}\En{Date}~:~}{[%- document_datas.header.date_emission -%]} } }
[%- IF (document_datas.doctype == 'bdc') -%]
\parbox[t]{6cm}{\vrule\footnotesize{\textbf{~\Fr{R\'{e}f\'{e}rence de commande}\En{PO Number}~:~}{[%- document_datas.header.bdc_ref -%]} } }
[%- ELSE -%]
[%- IF (document_datas.type_ent == 'client') AND (grid.is_signed) -%]
\parbox[t]{6cm}{\vrule\footnotesize{\textbf{~\Fr{Date de signature}\En{Signature date}~:~}{[%- grid.signature_date -%]} } }
[%- END -%]
[%- END -%]
\\[-0.2cm]\HRule\\
}
[%- END -%]
}
%the different template which depend on type of services/goods
[% INCLUDE "grids/grid/${grid.grid_line_type_ref}.tt" %]
\endhead
\end{longtable}
下面是一个模板 (${grid.grid_line_type_ref}.tt) 的示例,我想在其中集成表格:
{\renewcommand{\arraystretch}{1.5}
\setlength{\LTleft}{0.50cm}
\setlength{\tabcolsep}{1mm}
\begin{longtable}{|c|r|r|r|}
\hline
\rowcolor{mycellcolor}
\multicolumn{1}{|c|}{\multirow{-1}{7cm}{\Fr{Type de ligne}\En{Line type}}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.fas"|trans -%]}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.abo"|trans -%]}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.gtrs1"|trans -%]}}
\\ [0.7ex]
\hline
\endfirsthead
\hline
\endfoot
\hline
\rowcolor{mycellcolor}
\multicolumn{1}{|c|}{\multirow{-1}{7cm}{\Fr{Type de ligne}\En{Line type}}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.fas"|trans -%]}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.abo"|trans -%]}}
& \multicolumn{1}{r|}{\multirow{-1}{2cm}{[%- "grids.type.sfr-adsl.gtrs1"|trans -%]}}
\\ [0.7ex]
\hline
\endhead
\infoprice{4}{[%- "grids.infos.all_prices_euros_ht"|trans -%]}
\endlastfoot
[% FOREACH object IN grid.objects %]
\multicolumn{1}{|l|}{[% object.description %]}
& \multicolumn{1}{r|}{\UnitPrice[2]{[%-object.fas-%]}}
& \multicolumn{1}{r|}{\UnitPrice[2]{[%-object.abo-%]}}
[% IF (object.gtrs1 == 0) %]
& \multicolumn{1}{r|}{\Fr{Incluse}\En{Included}}
[% ELSE %]
& \multicolumn{1}{r|}{\UnitPrice[2]{[%-object.gtrs1-%]}}
[% END %]
\\
[% END %]
\hline
\end{longtable}
}