diff options
Diffstat (limited to 'FS')
| -rw-r--r-- | FS/FS/Conf.pm | 28 | ||||
| -rw-r--r-- | FS/FS/Mason.pm | 2 | ||||
| -rw-r--r-- | FS/FS/Misc/DepositSlip.pm | 376 | ||||
| -rw-r--r-- | FS/MANIFEST | 1 | 
4 files changed, 406 insertions, 1 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index b4140b7e7..ad566731c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -6116,6 +6116,34 @@ and customer address. Include units.',      'type'        => 'checkbox',    }, +  { +    'key'         => 'deposit_slip-bank_name', +    'section'     => 'payments', #XXX payment_deposit_slips +    'description' => 'Bank name to print on check deposit slips', +    'type'        => 'text', +  }, + +  { +    'key'         => 'deposit_slip-bank_address', +    'section'     => 'payments', #XXX payment_deposit_slips +    'description' => 'Bank address to print on check deposit slips', +    'type'        => 'textarea', +  }, + +  { +    'key'         => 'deposit_slip-bank_routingnumber', +    'section'     => 'payments', #XXX payment_deposit_slips +    'description' => '9 digit bank routing number to print on check deposit slips', +    'type'        => 'text', +  }, + +  { +    'key'         => 'deposit_slip-bank_accountnumber', +    'section'     => 'payments', #XXX payment_deposit_slips +    'description' => 'Bank account number to print on check deposit slips', +    'type'        => 'text', +  }, +    # for internal use only; test databases should declare this option and    # everyone else should pretend it doesn't exist diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ed3b66c12..fcefb734b 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -386,7 +386,6 @@ if ( -e $addl_handler_use_file ) {    use FS::export_batch_item;    use FS::part_pkg_fcc_option;    use FS::state; -  use FS::state;    use FS::queue_stat;    use FS::deploy_zone;    use FS::deploy_zone_block; @@ -417,6 +416,7 @@ if ( -e $addl_handler_use_file ) {    use FS::part_svc_msgcat;    use FS::saved_search;    use FS::svc_group; +  use FS::Misc::DepositSlip qw( deposit_slip_pdf );    # Sammath Naur    if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Misc/DepositSlip.pm b/FS/FS/Misc/DepositSlip.pm new file mode 100644 index 000000000..b687691ef --- /dev/null +++ b/FS/FS/Misc/DepositSlip.pm @@ -0,0 +1,376 @@ +package FS::Misc::DepositSlip; +use base 'Exporter'; + +use strict; +use warnings; +use vars qw( @EXPORT_OK ); + +#use Date::Format; +use IPC::Run qw( run timeout );   # for _xelatex +use Text::Template; + +@EXPORT_OK = qw( deposit_slip_pdf ); + +=item deposit_slip_pdf + +=cut + +sub deposit_slip_pdf { +  my %arg = @_; +  my $conf = $arg{'conf'}; +  my @cust_pay = @{ $arg{'cust_pay'} }; + +  if ( scalar(@cust_pay) > 25 ) { +    return 'ERROR: Maxiumum of 25 items per deposit slip at this time'; +  } + +  my $text_template = new Text::Template( +    TYPE       => 'STRING', +    SOURCE     => slip_template(), +    DELIMITERS => [ '[@--', '--@]' ], +  ); + +  $text_template->compile() or die $Text::Template::ERROR; + +  my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc; +  chdir($dir); + +  #my $date = time2str( $self->conf->config('date_format_long') || '%b %o, %Y', +  #                     time #XXX future deposit date +  #                   ); + +  my $total = 0; +  foreach my $cust_pay (@cust_pay) { +    $total += $cust_pay->paid; +  } +  $total = sprintf('%.2f', $total + 0.00000001); #so FP math errors round out +  my ($total_dollars, $total_cents) = split(/\./, $total); + +  my $gtotal = sprintf('%11.2f', $total); +  $gtotal =~ s/\.//; +  my @gtotal = split('', $gtotal); + +  #XXX agent virt for company name, address +  my %fill_in = ( +    'company_name'    => _latex_escape($conf->config('company_name')), +    'company_address' => join('\\\\', map _latex_escape($_), +                           $conf->config('company_address') ), + +    'bank_name'       => _latex_escape($conf->config('deposit_slip-bank_name')), +    'bank_address'    => join('\\\\', map _latex_escape($_), +                           $conf->config('deposit_slip-bank_address') ), + +    'bank_routingnumber' => _latex_escape( +                              $conf->config('deposit_slip-bank_routingnumber')), +    'bank_accountnumber' => _latex_escape( +                              $conf->config('deposit_slip-bank_accountnumber')), + +    #already defaulting to today +    #'depositdate'     => _latex_escape($date), + +    'currency_dollars'   => '', +    'currency_cents'     => '', +    'coin_dollars'       => '', +    'coin_cents'         => '', +    'checks_dollars'     => '', +    'checks_cents'       => '', + +    'reverse_dollars'    => '', +    'reverse_cents'      => '', +    'total_dollars'      => $total_dollars, +    'total_cents'        => $total_cents, + +    'cust_pay'           => \@cust_pay, + +    'totalitems'         => scalar(@cust_pay), + +    'grandtotalboxone'   => $gtotal[0], +    'grandtotalboxtwo'   => $gtotal[1], +    'grandtotalboxthree' => $gtotal[2], +    'grandtotalboxfour'  => $gtotal[3], +    'grandtotalboxfive'  => $gtotal[4], +    'grandtotalboxsix'   => $gtotal[5], +    'grandtotalboxseven' => $gtotal[6], +    'grandtotalboxeight' => $gtotal[7], +    'grandtotalboxnine'  => $gtotal[8], +    'grandtotalboxten'   => $gtotal[9], +  ); + +  #XXX better unique filename +  my $file = "deposit$$"; + +  open(DEPOSIT_TEX, ">$file.tex") or die $!; +  print DEPOSIT_TEX $text_template->fill_in( HASH => \%fill_in ); +  close DEPOSIT_TEX or die $!; + +  _xelatex($file); + +  #XXX use File::Slurp +  my $pdf = ''; +  open(PDF, "<$file.pdf") or die $!; + +  unlink("$file.log", "$file.aux", "$file.pdf", "$file.tex"); + +  while (<PDF>) { +    $pdf .= $_; +  } +  close PDF; + +  return $pdf; + +}  + +#some false laziness w/_pslatex in Misc.pm +sub _xelatex { +  my $file = shift; + +  #my $sfile = shell_quote $file; + +  my @cmd = ( +    'xelatex', +    '-interaction=batchmode', +    "$file.tex" +  ); + +  my $timeout = 30; #? should be more than enough + +  for ( 1, 2 ) { + +    local($SIG{CHLD}) = sub {}; +    run( \@cmd, '>'=>'/dev/null', '2>'=>'/dev/null', timeout($timeout) ) +      or warn "bad exit status from xelatex pass $_\n"; + +  } + +  return if -e "$file.pdf" && -s "$file.pdf"; +  die "xelatex $file.tex failed, see $file.log for details?\n"; + +} + +#false laxiness w/Template_Mixin.pm +sub _latex_escape { +  my $value = shift; +  $value =~ s/([#\$%&~_\^{}])( )?/"\\$1". ( ( defined($2) && length($2) ) ? "\\$2" : '' )/ge; +  $value =~ s/([<>])/\$$1\$/g; +  $value; +} + +sub slip_template { <<'__END__'; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Freeside Deposit Slip +% LaTeX Template +% Version 1.1 (May 9, 2020) +% +% This template was created by: +% Vel (enquiries@latextypesetting.com) +% LaTeXTypesetting.com +% +%!TEX program = xelatex +% Note: this template must be compiled with XeLaTeX rather than PDFLaTeX +% due to the custom fonts used. The line above should ensure this happens +% automatically, but if it doesn't, your LaTeX editor should have a simple toggle +% to switch to using XeLaTeX. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%---------------------------------------------------------------------------------------- +%	PACKAGES AND OTHER DOCUMENT CONFIGURATIONS +%---------------------------------------------------------------------------------------- + +\documentclass{article} + +%---------------------------------------------------------------------------------------- +%	REQUIRED PACKAGES AND MISC CONFIGURATIONS +%---------------------------------------------------------------------------------------- + +\setlength{\parindent}{0pt} % Stop paragraph indentation + +\usepackage{tikz} % Required for custom graphics +\usetikzlibrary{calc} % Required for coordinate calculations within TikZ + +% Suppress hyphenation across the whole document +\hyphenpenalty=10000 +\exhyphenpenalty=10000 + +%---------------------------------------------------------------------------------------- +%	MARGINS +%---------------------------------------------------------------------------------------- + +\usepackage[ +	paperwidth=8.5in, +	paperheight=3.25in, +	top=0cm, % Top margin +	bottom=1cm, % Bottom margin +	left=1cm, % Left margin +	right=1cm, % Right margin +	footskip=0.6cm, % Space from the bottom margin to the baseline of the footer +	headsep=0.8cm, % Space from the top margin to the baseline of the header +	headheight=0.5cm, % Height of the header +	%showframe % Uncomment to show the frames around the margins for debugging purposes +]{geometry} + +%---------------------------------------------------------------------------------------- +%	FONTS +%---------------------------------------------------------------------------------------- + +\usepackage{fontspec} % Required for specifying custom fonts + +\defaultfontfeatures{Ligatures=TeX} % To support LaTeX ligatures (`` and --) +\defaultfontfeatures{Path=/usr/local/etc/freeside/} % Specify the location of font files + +\newfontface\GNUMicr{GnuMICR.otf} % MICR font from file + +\usepackage[default]{sourcesanspro} % Use the Source Sans Pro font for the document body + +%---------------------------------------------------------------------------------------- +%	HEADERS AND FOOTERS +%---------------------------------------------------------------------------------------- + +\usepackage{fancyhdr} % Required for customising headers and footers +\pagestyle{fancy} % Enable custom headers and footers + +\renewcommand{\headrulewidth}{0pt} % Remove default top horizontal rule + +\fancyhf{} % Clear default headers/footers + +\fancyfoot[C]{{\Large\GNUMicr\MICR}} % Centre footer + +%---------------------------------------------------------------------------------------- +%	TABLES +%---------------------------------------------------------------------------------------- + +\usepackage{booktabs} % Required for better horizontal rules in tables + +\usepackage{array} % Required for manipulating table columns + +\renewcommand{\arraystretch}{1.35} % Increase the space between table rows + +\newcolumntype{R}[1]{>{\raggedleft\arraybackslash}p{#1}} % Define a new right-aligned paragraph column type +\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}} % Define a new left-aligned (no justification) paragraph column type +\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}} % Define a new centred paragraph column type + +%---------------------------------------------------------------------------------------- +%	CUSTOM COMMANDS +%---------------------------------------------------------------------------------------- + +\newcommand{\MICR}[1]{\renewcommand{\MICR}{#1}} +\newcommand{\disclaimer}[1]{\renewcommand{\disclaimer}{#1}} +\newcommand{\companyaddress}[1]{\renewcommand{\companyaddress}{#1}} +\newcommand{\bankaddress}[1]{\renewcommand{\bankaddress}{#1}} +\newcommand{\totalitems}[1]{\renewcommand{\totalitems}{#1}} +\newcommand{\grandtotalboxone}[1]{\renewcommand{\grandtotalboxone}{#1}} +\newcommand{\grandtotalboxtwo}[1]{\renewcommand{\grandtotalboxtwo}{#1}} +\newcommand{\grandtotalboxthree}[1]{\renewcommand{\grandtotalboxthree}{#1}} +\newcommand{\grandtotalboxfour}[1]{\renewcommand{\grandtotalboxfour}{#1}} +\newcommand{\grandtotalboxfive}[1]{\renewcommand{\grandtotalboxfive}{#1}} +\newcommand{\grandtotalboxsix}[1]{\renewcommand{\grandtotalboxsix}{#1}} +\newcommand{\grandtotalboxseven}[1]{\renewcommand{\grandtotalboxseven}{#1}} +\newcommand{\grandtotalboxeight}[1]{\renewcommand{\grandtotalboxeight}{#1}} +\newcommand{\grandtotalboxnine}[1]{\renewcommand{\grandtotalboxnine}{#1}} +\newcommand{\grandtotalboxten}[1]{\renewcommand{\grandtotalboxten}{#1}} +\newcommand{\depositdate}[1]{\renewcommand{\depositdate}{#1}} + +%\newcommand{\command}[1]{\renewcommand{\command}{#1}} + +%---------------------------------------------------------------------------------------- +%	DEPOSIT SLIP INFORMATION +%---------------------------------------------------------------------------------------- + +\MICR{A[@-- $bank_routingnumber --@]A  [@-- $bank_accountnumber --@]C} % Displayed at the bottom of the slip + +\disclaimer{Checks and other items are received for deposit subject to the provisions of the Uniform Commercial Code and any applicable collection agreement. Deposits May Not Be Available For Immediate Withdrawal.} + +\companyaddress{\textbf{[@-- $company_name --@]}\\[@-- $company_address --@]} + +\bankaddress{\textbf{[@-- $bank_name --@]}\\ [@-- $bank_address --@]} + +\totalitems{[@-- $totalitems --@]} + +\grandtotalboxone{[@-- $grandtotalboxone --@]} +\grandtotalboxtwo{[@-- $grandtotalboxtwo --@]} +\grandtotalboxthree{[@-- $grandtotalboxthree --@]} +\grandtotalboxfour{[@-- $grandtotalboxfour --@]} +\grandtotalboxfive{[@-- $grandtotalboxfive --@]} +\grandtotalboxsix{[@-- $grandtotalboxsix --@]} +\grandtotalboxseven{[@-- $grandtotalboxseven --@]} +\grandtotalboxeight{[@-- $grandtotalboxeight --@]} +\grandtotalboxnine{[@-- $grandtotalboxnine --@]} +\grandtotalboxten{[@-- $grandtotalboxten --@]} + +\depositdate{\today} + +%---------------------------------------------------------------------------------------- + +\begin{document} + +%---------------------------------------------------------------------------------------- +%	DEPOSIT SLIP +%---------------------------------------------------------------------------------------- + +\begin{tikzpicture}[remember picture, overlay] +	\node [anchor=north, rotate=90, xshift=-0.5\paperheight, yshift=-0.4cm, inner sep=0pt] (title) at (current page.north west) {\textbf{DEPOSIT TICKET}}; % Deposit ticket title text +	 +	\node [anchor=north, rotate=90, yshift=-0.4cm, inner sep=0pt] (dateline) at (title.south) {DATE: \rule{0.58\paperheight}{1pt}}; % Date line +	\node [anchor=south, rotate=90, yshift=-0.2cm, inner sep=0pt] (date) at (dateline.north) {\depositdate}; % Date +	 +	\node [anchor=north west, rotate=90, yshift=-0.25cm, text width=0.8\paperheight, inner sep=0pt] (disclaimer) at (dateline.south west) {\fontsize{6pt}{7pt}\selectfont \disclaimer\par}; % Disclaimer text +	 +	\node [anchor=north east, rotate=90, inner sep=0pt] (table) at (disclaimer.south east) {% Table +		\begin{tabular}{| L{1.8cm} | L{1cm} | L{0.5cm}} +			\cline{2-3} +			\multicolumn{1}{R{1.8cm} |}{} & \scriptsize DOLLARS & \scriptsize CENTS \\\cline{2-3} +			\multicolumn{1}{R{1.8cm} |}{\scriptsize CURRENCY} & [@-- $currency_dollars --@] & [@-- $currency_cents --@]\\\cline{2-3} +			\multicolumn{1}{R{1.8cm} |}{\scriptsize COIN} & [@-- $coin_dollars --@] & [@-- $coin_cents --@]\\\cline{2-3} +			\multicolumn{1}{| R{1.8cm} |}{\vspace{-1.2\baselineskip}\scriptsize CHECKS \newline \tiny (ENTER SEPARATELY)} & [@-- $checks_dollars --@] & [@-- $checks_cents --@]\\[-3pt]\cline{1-3} +[@-- +  for (0 .. 24) { +    if ( scalar(@cust_pay) ) { +      my $cust_pay = shift @cust_pay; +      my ($dollars, $cents) = split(/\./, $cust_pay->paid); +      $OUT .= $cust_pay->payinfo. " & $dollars & $cents". '\\\\\\cline{1-3}'. "\n"; +    } else { +      $OUT .= ' & & \\\\\\cline{1-3}'. "\n"; +    } +  } +--@] +			\fontsize{6pt}{6pt}\selectfont TOTAL OF \newline REVERSE SIDE & [@-- $reverse_dollars --@] & [@-- $reverse_cents --@] \\\cline{1-3} +			\fontsize{10pt}{10pt}\selectfont\textbf{TOTAL} \newline DEPOSIT & [@-- $total_dollars --@] & [@-- $total_cents --@] \\\cline{1-3} +		\end{tabular} +	}; % Table +	\node [anchor=north east, rotate=90, yshift=-0.07cm, inner sep=0pt] (totalguidetext) at (table.south east) {\fontsize{6pt}{6pt}\selectfont PLEASE ENTER TOTAL HERE}; % Total guide text +	\draw [->] ($(totalguidetext.west)-(0, 0.1cm)$) -- ($(totalguidetext.west)-(0cm, 2.7cm)$); % Total guide text arrow +	 +	\node [anchor=south west, xshift=0.3cm, text width=0.3\paperwidth, inner sep=0pt] (companyaddress) at (disclaimer.south west) {\Large\companyaddress\par}; % Company and address +	 +	\node [anchor=north west, text width=0.3\paperwidth, inner sep=0pt] (bankaddress) at (companyaddress.north east) {\footnotesize\bankaddress\par}; % Financial institution address +	 +	\node [anchor=south west, xshift=0.5cm, yshift=1.4cm, text width=0.75cm, inner sep=0pt] (totalitemstext) at (current page.south) {\fontsize{6pt}{6pt}\selectfont TOTAL ITEMS\par}; % Total items text +	\node [rectangle, anchor=west, draw=black, line width=1pt, minimum width=1cm, minimum height=0.5cm, inner sep=0pt] (totalitemsbox) at (totalitemstext.east) {\totalitems}; % Total items box +	 +	\node [anchor=west, xshift=1cm, text width=0.4cm, inner sep=0pt] (dollarsign) at (totalitemsbox.east) {\Large\textbf{\$}}; % Dollar sign text +	\node [rectangle, anchor=west, fill=black!7, minimum width=6.7cm, minimum height=1.25cm, inner sep=0pt] (totalbox) at (dollarsign.east) {}; % Grand total grey box +	\node [rectangle, anchor=west, fill=white, xshift=0.3cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxone) at (totalbox.west) {\grandtotalboxone}; % White box 1 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxtwo) at (whiteboxone.east) {\grandtotalboxtwo}; % White box 2 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxthree) at (whiteboxtwo.east) {\grandtotalboxthree}; % White box 3 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxfour) at (whiteboxthree.east) {\grandtotalboxfour}; % White box 4 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxfive) at (whiteboxfour.east) {\grandtotalboxfive}; % White box 5 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxsix) at (whiteboxfive.east) {\grandtotalboxsix}; % White box 6 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxseven) at (whiteboxsix.east) {\grandtotalboxseven}; % White box 7 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxeight) at (whiteboxseven.east) {\grandtotalboxeight}; % White box 8 +	\node [anchor=west, xshift=-0.5pt, inner sep=0pt] (centsperiod) at (whiteboxeight.south east) {.}; % Cents period +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxnine) at (whiteboxeight.east) {\grandtotalboxnine}; % White box 9 +	\node [rectangle, anchor=west, fill=white, xshift=0.05cm, minimum width=0.55cm, minimum height=0.55cm, inner sep=0pt] (whiteboxten) at (whiteboxnine.east) {\grandtotalboxten}; % White box 10 +	\draw [fill=white, draw=white] ($(whiteboxtwo.south east)+(0.02cm, 0cm)$) -- ($(whiteboxtwo.south east)-(0.03cm, 0.1cm)$) -- ($(whiteboxtwo.south east)+(0.07cm, -0.1cm)$) -- cycle; % Triangle 1 +	\draw [fill=white, draw=white] ($(whiteboxfive.south east)+(0.02cm, 0cm)$) -- ($(whiteboxfive.south east)-(0.03cm, 0.1cm)$) -- ($(whiteboxfive.south east)+(0.07cm, -0.1cm)$) -- cycle; % Triangle 2 +\end{tikzpicture} + +%---------------------------------------------------------------------------------------- + +\end{document} + +__END__ + +} + +1; diff --git a/FS/MANIFEST b/FS/MANIFEST index 6541a6b09..edde7414c 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -869,3 +869,4 @@ FS/saved_search.pm  t/saved_search.t  FS/svc_group.pm  FS/h_svc_group.pm +FS/Misc/DepositSlip.pm  | 
