WIP estimate pdf

This commit is contained in:
2016-11-07 19:34:56 +01:00
parent 7844467ed0
commit b391459734
13 changed files with 407 additions and 63 deletions

View File

@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Security.Claims;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Mvc;
namespace Yavsc.ApiControllers
{
[Route("api/pdfestimate"), Authorize]
public class PdfEstimateController : Controller
{
[HttpGet("{id}", Name = "Get")]
public IActionResult Get(long id)
{
var filename = $"estimate-{id}.pdf";
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = filename,
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName,filename));
FileStreamResult result = null;
var s = fi.OpenRead();
result = File(s,"application/x-pdf",filename);
return result;
}
}
}

BIN
Yavsc/Bills/estimate-3.pdf Normal file

Binary file not shown.

View File

@ -8,10 +8,20 @@ using Microsoft.Extensions.Logging;
using Yavsc.Models.Booking;
using Yavsc.Helpers;
using System;
using System.IO;
using System.Diagnostics;
using System.Text;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Extensions.OptionsModel;
using System.Threading.Tasks;
using System.Security.Claims;
namespace Yavsc.Controllers
{
[ServiceFilter(typeof(LanguageActionFilter)),
[ServiceFilter(typeof(LanguageActionFilter)),
Route("do")]
public class FrontOfficeController : Controller
{
@ -35,44 +45,45 @@ namespace Yavsc.Controllers
return View(latestPosts);
}
[Route("Book/{id?}"),HttpGet]
[Route("Book/{id?}"), HttpGet]
public ActionResult Book(string id)
{
if (id == null) {
if (id == null)
{
throw new NotImplementedException("No Activity code");
}
ViewBag.Activities = _context.ActivityItems(id);
ViewBag.Activity = _context.Activities.FirstOrDefault(
a => a.Code == id );
ViewBag.Activity = _context.Activities.FirstOrDefault(
a => a.Code == id);
return View(
_context.Performers.Include(p=>p.Performer).Where
_context.Performers.Include(p => p.Performer).Where
(p => p.ActivityCode == id && p.Active).OrderBy(
x=>x.MinDailyCost
x => x.MinDailyCost
)
);
}
[Route("Book/{id}"),HttpPost]
[Route("Book/{id}"), HttpPost]
public ActionResult Book(BookQuery bookQuery)
{
if (ModelState.IsValid) {
if (ModelState.IsValid)
{
var pro = _context.Performers.Include(
pr => pr.Performer
).FirstOrDefault(
x=>x.PerformerId == bookQuery.PerformerId
x => x.PerformerId == bookQuery.PerformerId
);
if (pro==null)
if (pro == null)
return HttpNotFound();
// Let's create a command
if (bookQuery.Id==0)
if (bookQuery.Id == 0)
{
_context.BookQueries.Add(bookQuery);
}
else {
else
{
_context.BookQueries.Update(bookQuery);
}
_context.SaveChanges();
@ -81,36 +92,146 @@ namespace Yavsc.Controllers
return View("Index");
}
ViewBag.Activities = _context.ActivityItems(null);
return View( _context.Performers.Include(p=>p.Performer).Where
return View(_context.Performers.Include(p => p.Performer).Where
(p => p.Active).OrderBy(
x=>x.MinDailyCost
x => x.MinDailyCost
));
}
[Produces("text/x-tex"), Authorize, Route("estimate-{id}.tex")]
public ViewResult EstimateTex(long id)
{
var estimate = _context.Estimates.Include(x=>x.Query)
.Include(x=>x.Query.Client)
.Include(x=>x.Query.PerformerProfile)
.Include(x=>x.Query.PerformerProfile.OrganizationAddress)
.Include(x=>x.Query.PerformerProfile.Performer)
.Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id);
var estimate = _context.Estimates.Include(x => x.Query)
.Include(x => x.Query.Client)
.Include(x => x.Query.PerformerProfile)
.Include(x => x.Query.PerformerProfile.OrganizationAddress)
.Include(x => x.Query.PerformerProfile.Performer)
.Include(e => e.Bill).FirstOrDefault(x => x.Id == id);
Response.ContentType = "text/x-tex";
return View("Estimate.tex", estimate);
}
[Produces("application/x-pdf"), Authorize, Route("estimate-{id}.pdf")]
public ViewResult EstimatePdf(long id)
class TeOtions : IOptions<MvcViewOptions>
{
var estimate = _context.Estimates.Include(x=>x.Query)
.Include(x=>x.Query.Client)
.Include(x=>x.Query.PerformerProfile)
.Include(x=>x.Query.PerformerProfile.OrganizationAddress)
.Include(x=>x.Query.PerformerProfile.Performer)
.Include(e=>e.Bill).FirstOrDefault(x=>x.Id==id);
return View("Estimate.pdf", estimate);
public MvcViewOptions Value
{
get
{
return new MvcViewOptions();
}
}
}
[Authorize,Route("Estimate-{id}.pdf")]
public async Task<IActionResult> EstimatePdf(long id)
{
ViewBag.TempDir = Startup.SiteSetup.TempDir;
ViewBag.BillsDir = Startup.UserBillsDirName;
var estimate = _context.Estimates.Include(x => x.Query)
.Include(x => x.Query.Client)
.Include(x => x.Query.PerformerProfile)
.Include(x => x.Query.PerformerProfile.OrganizationAddress)
.Include(x => x.Query.PerformerProfile.Performer)
.Include(e => e.Bill).FirstOrDefault(x => x.Id == id);
if (estimate==null)
throw new Exception("No data");
return View("Estimate.pdf",estimate);
/*
await result.ExecuteResultAsync(ActionContext);
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = $"estimate-{id}.pdf",
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return File((Byte[])ViewData["Pdf"], "application/x-pdf"); */
}
/*
[Produces("application/x-pdf"), Authorize, Route("testimate-{id}.pdf")]
public async Task<IActionResult> BadEstimatePdf(long id)
{
var tempDir = Startup.SiteSetup.TempDir;
string name = $"tmpestimtex-{id}";
string fullname = new FileInfo(
System.IO.Path.Combine(tempDir, name)).FullName;
var writer = new System.IO.StringWriter();
try
{
using (StringWriter sw = new StringWriter())
{
Microsoft.AspNet.Mvc.ViewEngines.CompositeViewEngine ve = new CompositeViewEngine(
new TeOtions {}
);
ViewEngineResult viewResult = ve.FindPartialView(ActionContext, $"estimate-{id}.tex");
ViewContext viewContext = new ViewContext(); // ActionContext, viewResult.View, ViewData, TempData, sw);
await viewResult.View.RenderAsync(viewContext);
}
} catch (Exception ex)
{
}
FileInfo fo = new FileInfo(fullname + ".pdf");
if (!fi.Exists)
{
throw new Exception("Source write failed");
}
using (Process p = new Process())
{
p.StartInfo.WorkingDirectory = tempDir;
p.StartInfo = new ProcessStartInfo();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "/usr/bin/texi2pdf";
p.StartInfo.Arguments = $"--batch --build-dir=.";
p.Start();
using (p.StandardInput)
{
}
p.WaitForExit();
if (p.ExitCode != 0)
{
throw new Exception("Pdf generation failed with exit code:" + p.ExitCode);
}
}
byte[] pdf = null;
if (fo.Exists)
{
using (StreamReader sr = new StreamReader(fo.FullName))
{
pdf = System.IO.File.ReadAllBytes(fo.FullName);
}
fo.Delete();
}
fi.Delete();
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = $"estimate-{id}.pdf",
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.Headers.Add("Content-Disposition", cd.ToString());
return File(pdf, "application/x-pdf");
} */
}
}

View File

@ -16,15 +16,32 @@ namespace Yavsc
/// </summary>
/// <returns></returns>
public string Authority { get; set; }
/// <summary>
/// Owner's email
/// </summary>
/// <returns></returns>
public EmailEntry Owner { get; set; }
/// <summary>
/// Administrator's email
/// </summary>
/// <returns></returns>
public EmailEntry Admin { get; set; }
/// <summary>
/// User's files directory
/// </summary>
/// <returns></returns>
public ThirdPartyFiles UserFiles { get; set; }
public string BusinessName { get; set; }
public string Street { get; set; }
public string PostalCode { get; set; }
public string CountryCode { get; set; }
/// <summary>
/// Specifies the directory where should be
/// generated pdf files using pandoc
/// </summary>
/// <returns>The temporary directory to use</returns>
public string TempDir { get; set; } = "Temp";
}
}

View File

@ -12,6 +12,7 @@ namespace Yavsc
{
public static string UserFilesDirName { get; private set; }
public static FileServerOptions UserFilesOptions { get; private set; }
public void ConfigureFileServerApp(IApplicationBuilder app,
SiteSettings siteSettings, IHostingEnvironment env)
{

View File

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Optimization;
@ -32,8 +33,11 @@ namespace Yavsc
public partial class Startup
{
public static string ConnectionString { get; private set; }
public static string UserBillsDirName { private set; get; }
public static string Authority { get; private set; }
public static string Audience { get; private set; }
public static SiteSettings SiteSetup { get; private set; }
private static ILogger logger;
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
@ -225,7 +229,11 @@ namespace Yavsc
RoleManager<IdentityRole> roleManager,
ILoggerFactory loggerFactory)
{
SiteSetup = siteSettings.Value;
var tempdi = new DirectoryInfo(SiteSetup.TempDir);
if (!tempdi.Exists) tempdi.Create();
Startup.UserFilesDirName = siteSettings.Value.UserFiles.DirName;
Startup.UserBillsDirName = siteSettings.Value.UserFiles.Bills;
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
logger = loggerFactory.CreateLogger<Startup>();

146
Yavsc/Temp/estimate-8.tex Normal file
View File

@ -0,0 +1,146 @@
\documentclass[french,11pt]{article}
\usepackage{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[a4paper]{geometry}
\usepackage{units}
\usepackage{bera}
\usepackage{graphicx}
\usepackage{fancyhdr}
\usepackage{fp}
\def\TVA{20} % Taux de la TVA
\def\TotalHT{0}
\def\TotalTVA{0}
\newcommand{\AjouterService}[3]{% Arguments : Désignation, quantité, prix
\FPround{\prix}{#3}{2}
\FPeval{\montant}{#2 * #3}
\FPround{\montant}{\montant}{2}
\FPadd{\TotalHT}{\TotalHT}{\montant}
\eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr}
}
\newcommand{\AfficheResultat}{%
\ListeProduits
\FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
\FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
\FPround{\TotalHT}{\TotalHT}{2}
\FPround{\TotalTVA}{\TotalTVA}{2}
\FPround{\TotalTTC}{\TotalTTC}{2}
\global\let\TotalHT\TotalHT
\global\let\TotalTVA\TotalTVA
\global\let\TotalTTC\TotalTTC
\cr
\hline
\textbf{Total} & & & \TotalHT
}
\newcommand*\eaddto[2]{% version développée de \addto
\edef\tmp{#2}%
\expandafter\addto
\expandafter#1%
\expandafter{\tmp}%
}
\newcommand{\ListeProduits}{}
%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%%
\def\FactureNum {8} % Numéro de facture
\def\FactureAcquittee {non} % Facture acquittée : oui/non
\def\FactureLieu {2 Boulevard Aristide Briand, 92150 Suresnes, France} % Lieu de l'édition de la facture
\def\FactureObjet {Facture : } % Objet du document
% Description de la facture
\def\FactureDescr {
# **Hello Estimate!**&#xA;&#xA;coup&#xA;&#xA;blah
}
% Infos Client
\def\ClientNom{Paul} % Nom du client
\def\ClientAdresse{
% Adresse du client
E-mail: redienhcs.luap@gmail.com
}
% Liste des produits facturés : Désignation, prix
\AjouterService {une premi&#xE8;re} {3} {121,6000}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em}
\setlength{\parindent}{0pt}
\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
\thispagestyle{fancy}
\pagestyle{fancy}
\setlength{\parindent}{0pt}
\renewcommand{\headrulewidth}{0pt}
\cfoot{ Paul - 2 Boulevard Aristide Briand, 92150 Suresnes, France \newline
\small{ E-mail: redienhcs.luap@gmail.com
}
}
\begin{document}
% Logo de la société
%\includegraphics{logo.png}
% Nom et adresse de la société
Paul \\
2 Boulevard Aristide Briand, 92150 Suresnes, France
Facture n°\FactureNum
{\addtolength{\leftskip}{10.5cm} %in ERT
\textbf{\ClientNom} \\
\ClientAdresse \\
} %in ERT
\hspace*{10.5cm}
\FactureLieu, le \today
~\\~\\
\textbf{Objet : \FactureObjet \\}
\textnormal{\FactureDescr}
~\\
\begin{center}
\begin{tabular}{lrrr}
\textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\
\hline
\AfficheResultat{}
\end{tabular}
\end{center}
\begin{flushright}
\textit{Auto entreprise en franchise de TVA}\\
\end{flushright}
~\\
\ifthenelse{\equal{\FactureAcquittee}{oui}}{
Facture acquittée.
}{
}
\end{document}

View File

@ -40,5 +40,5 @@
@{ var filenametex = $"estimate-{Model.Id}.tex" ;
var filenamepdf = $"estimate-{Model.Id}.pdf" ;}
<a href="~/do/@filenametex" >Export au format LaTeX</a>
<a href="~/do/@filenamepdf" >Export au format LaTeX</a>
<a href="~/do/@filenamepdf" >Export au format Pdf</a>
</p>

View File

@ -1,26 +1,27 @@
@using System.Reflection
@using System.IO
@using Microsoft.Extensions.WebEncoders
@using System.Diagnostics
@using System.Text
@using Yavsc.Formatters
@using System.Reflection;
@using System.IO;
@using Microsoft.Extensions.WebEncoders;
@using System.Diagnostics;
@using System.Text;
@using Yavsc.Formatters;
@model Estimate
@{
Layout = null;
ViewBag.Pdf = "";
ViewBag.TeX = "";
var writer = new System.IO.StringWriter();
var content = await Html.PartialAsync("Estimate.tex", Model );
if (ViewBag.TempDir==null) { throw new InvalidOperationException(); }
ViewBag.Pdf = "";
ViewBag.TeX = "";
var writer = new System.IO.StringWriter();
var content = await Html.PartialAsync("Estimate.tex", Model );
content.WriteTo(writer, new TexEncoder());
var contentStr = writer.ToString();
string name = $"tmpestimtex-{Model.Id}";
string fullname = new FileInfo(
string name = $"estimate-{Model.Id}";
string fullname = new FileInfo(
System.IO.Path.Combine(ViewBag.TempDir,name)).FullName;
string ofullname = new FileInfo(
System.IO.Path.Combine(ViewBag.BillsDir,name)).FullName;
FileInfo fi = new FileInfo(fullname + ".tex");
FileInfo fo = new FileInfo(fullname + ".pdf");
FileInfo fo = new FileInfo(ofullname + ".pdf");
using (StreamWriter sw = new StreamWriter (fi.FullName))
{
sw.Write (contentStr);
@ -41,15 +42,10 @@
throw new Exception ("Pdf generation failed with exit code:" + p.ExitCode);
}
}
if (fo.Exists) {
UTF8Encoding utf8 = new UTF8Encoding();
using (StreamReader sr = new StreamReader (fo.FullName)) {
byte[] buffer = File.ReadAllBytes (fo.FullName);
ViewBag.Pdf = utf8.GetString(buffer,0,buffer.Length);
}
fo.Delete();
}
ViewBag.Success = fo.Exists;
fi.Delete();
var uri = $"~/api/pdfestimate/{Model.Id}";
}
@ViewBag.Pdf
<a href="@uri" >@uri</a>

View File

@ -0,0 +1,9 @@
\relax
\catcode `:\active
\catcode `;\active
\catcode `!\active
\catcode `?\active
\select@language{french}
\@writefile{toc}{\select@language{french}}
\@writefile{lof}{\select@language{french}}
\@writefile{lot}{\select@language{french}}

View File

@ -0,0 +1,9 @@
\relax
\catcode `:\active
\catcode `;\active
\catcode `!\active
\catcode `?\active
\select@language{french}
\@writefile{toc}{\select@language{french}}
\@writefile{lof}{\select@language{french}}
\@writefile{lot}{\select@language{french}}