bill
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Yavsc.Billing
|
||||
@ -7,5 +8,16 @@ namespace Yavsc.Billing
|
||||
List<IBillItem> GetBillItems();
|
||||
long Id { get; set; }
|
||||
|
||||
string ActivityCode { get; set; }
|
||||
|
||||
string PerformerId { get; set; }
|
||||
string ClientId { get; set; }
|
||||
/// <summary>
|
||||
/// Date de validation de la demande par le client
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
DateTime? ValidationDate { get; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
namespace Yavsc
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
public interface IEstimate
|
||||
|
||||
public interface IEstimate
|
||||
{
|
||||
List<string> AttachedFiles { get; set; }
|
||||
List<string> AttachedGraphics { get; }
|
||||
|
@ -110,6 +110,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="project.json" />
|
||||
<Content Include="Workflow\IQuery.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
@ -19,8 +19,11 @@ namespace Yavsc.ApiControllers
|
||||
|
||||
using Models.Messaging;
|
||||
using ViewModels.Auth;
|
||||
[Route("api/pdfestimate"), Authorize]
|
||||
public class PdfEstimateController : Controller
|
||||
using Yavsc.ViewComponents;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
[Route("api/bill"), Authorize]
|
||||
public class BillingController : Controller
|
||||
{
|
||||
ApplicationDbContext dbContext;
|
||||
private IStringLocalizer _localizer;
|
||||
@ -28,59 +31,64 @@ namespace Yavsc.ApiControllers
|
||||
private IGoogleCloudMessageSender _GCMSender;
|
||||
private IAuthorizationService authorizationService;
|
||||
|
||||
private ILogger logger;
|
||||
|
||||
public PdfEstimateController(
|
||||
private ILogger logger;
|
||||
private IBillingService billingService;
|
||||
|
||||
public BillingController(
|
||||
IAuthorizationService authorizationService,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStringLocalizer<Yavsc.Resources.YavscLocalisation> SR,
|
||||
ApplicationDbContext context,
|
||||
IOptions<GoogleAuthSettings> googleSettings,
|
||||
IGoogleCloudMessageSender GCMSender
|
||||
IGoogleCloudMessageSender GCMSender,
|
||||
IBillingService billingService
|
||||
)
|
||||
{
|
||||
_googleSettings=googleSettings.Value;
|
||||
this.authorizationService = authorizationService;
|
||||
dbContext = context;
|
||||
logger = loggerFactory.CreateLogger<PdfEstimateController>();
|
||||
logger = loggerFactory.CreateLogger<BillingController>();
|
||||
this._localizer = SR;
|
||||
_GCMSender=GCMSender;
|
||||
this.billingService=billingService;
|
||||
}
|
||||
|
||||
[HttpGet("get/{id}", Name = "Get"), Authorize]
|
||||
public async Task<IActionResult> Get(long id)
|
||||
{
|
||||
var estimate = dbContext.Estimates.Include(
|
||||
e=>e.Query
|
||||
).FirstOrDefault(e=>e.Id == id);
|
||||
if (!await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement()))
|
||||
[HttpGet("pdf/facture-{billingCode}-{id}.pdf"), Authorize]
|
||||
public async Task<IActionResult> GetPdf(string billingCode, long id)
|
||||
{
|
||||
var bill = await billingService.GetBillAsync(billingCode, id);
|
||||
|
||||
if (!await authorizationService.AuthorizeAsync(User, bill, new ViewRequirement()))
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
|
||||
var filename = $"estimate-{id}.pdf";
|
||||
var filename = $"facture-{billingCode}-{id}.pdf";
|
||||
|
||||
FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName, filename));
|
||||
if (!fi.Exists) return Ok(new { Error = "Not generated" });
|
||||
return File(fi.OpenRead(), "application/x-pdf", filename); ;
|
||||
}
|
||||
|
||||
[HttpGet("estimate-{id}.tex", Name = "GetTex"), Authorize]
|
||||
public async Task<IActionResult> GetTex(long id)
|
||||
[HttpGet("tex/{billingCode}-{id}.tex"), Authorize]
|
||||
public async Task<IActionResult> GetTex(string billingCode, long id)
|
||||
{
|
||||
var estimate = dbContext.Estimates.Include(
|
||||
e=>e.Query
|
||||
).FirstOrDefault(e=>e.Id == id);
|
||||
if (!await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement()))
|
||||
var bill = await billingService.GetBillAsync(billingCode, id);
|
||||
|
||||
if (bill==null) return this.HttpNotFound();
|
||||
logger.LogVerbose(JsonConvert.SerializeObject(bill));
|
||||
|
||||
if (!await authorizationService.AuthorizeAsync(User, bill, new ViewRequirement()))
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
Response.ContentType = "text/x-tex";
|
||||
return ViewComponent("Estimate",new object[] { id, "LaTeX" });
|
||||
return ViewComponent("Bill",new object[] { billingCode, bill , OutputFormat.LaTeX, true, false });
|
||||
}
|
||||
|
||||
[HttpPost("gen/{id}")]
|
||||
public async Task<IActionResult> GeneratePdf(long id)
|
||||
[HttpPost("genpdf/{billingCode}/{id}")]
|
||||
public async Task<IActionResult> GeneratePdf(string billingCode, long id)
|
||||
{
|
||||
var estimate = dbContext.Estimates.Include(
|
||||
e=>e.Query
|
||||
@ -89,12 +97,12 @@ namespace Yavsc.ApiControllers
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
return ViewComponent("Estimate",new object[] { id, "Pdf" } );
|
||||
return ViewComponent("Bill",new object[] { billingCode, id, OutputFormat.Pdf } );
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("prosign/{id}")]
|
||||
public async Task<IActionResult> ProSign(long id)
|
||||
[HttpPost("prosign/{billingCode}/{id}")]
|
||||
public async Task<IActionResult> ProSign(string billingCode, long id)
|
||||
{
|
||||
var estimate = dbContext.Estimates.
|
||||
Include(e=>e.Client).Include(e=>e.Client.Devices)
|
||||
@ -108,7 +116,7 @@ namespace Yavsc.ApiControllers
|
||||
}
|
||||
if (Request.Form.Files.Count!=1)
|
||||
return new BadRequestResult();
|
||||
User.ReceiveProSignature(id,Request.Form.Files[0],"pro");
|
||||
User.ReceiveProSignature(billingCode,id,Request.Form.Files[0],"pro");
|
||||
estimate.ProviderValidationDate = DateTime.Now;
|
||||
dbContext.SaveChanges(User.GetUserId());
|
||||
// Notify the client
|
||||
@ -125,8 +133,8 @@ namespace Yavsc.ApiControllers
|
||||
return Ok (new { ProviderValidationDate = estimate.ProviderValidationDate, GCMSent = gcmSent });
|
||||
}
|
||||
|
||||
[HttpGet("prosign/{id}")]
|
||||
public async Task<IActionResult> GetProSign(long id)
|
||||
[HttpGet("prosign/{billingCode}/{id}")]
|
||||
public async Task<IActionResult> GetProSign(string billingCode, long id)
|
||||
{
|
||||
// For authorization purpose
|
||||
var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id);
|
||||
@ -135,14 +143,14 @@ namespace Yavsc.ApiControllers
|
||||
return new ChallengeResult();
|
||||
}
|
||||
|
||||
var filename = FileSystemHelpers.SignFileNameFormat("pro",id);
|
||||
var filename = FileSystemHelpers.SignFileNameFormat("pro",billingCode,id);
|
||||
FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName, filename));
|
||||
if (!fi.Exists) return HttpNotFound(new { Error = "Professional signature not found" });
|
||||
return File(fi.OpenRead(), "application/x-pdf", filename); ;
|
||||
}
|
||||
|
||||
[HttpPost("clisign/{id}")]
|
||||
public async Task<IActionResult> CliSign(long id)
|
||||
[HttpPost("clisign/{billingCode}/{id}")]
|
||||
public async Task<IActionResult> CliSign(string billingCode, long id)
|
||||
{
|
||||
var uid = User.GetUserId();
|
||||
var estimate = dbContext.Estimates.Include( e=>e.Query
|
||||
@ -154,14 +162,14 @@ namespace Yavsc.ApiControllers
|
||||
}
|
||||
if (Request.Form.Files.Count!=1)
|
||||
return new BadRequestResult();
|
||||
User.ReceiveProSignature(id,Request.Form.Files[0],"cli");
|
||||
User.ReceiveProSignature(billingCode,id,Request.Form.Files[0],"cli");
|
||||
estimate.ClientValidationDate = DateTime.Now;
|
||||
dbContext.SaveChanges(User.GetUserId());
|
||||
return Ok (new { ClientValidationDate = estimate.ClientValidationDate });
|
||||
}
|
||||
|
||||
[HttpGet("clisign/{id}")]
|
||||
public async Task<IActionResult> GetCliSign(long id)
|
||||
[HttpGet("clisign/{billingCode}/{id}")]
|
||||
public async Task<IActionResult> GetCliSign(string billingCode, long id)
|
||||
{
|
||||
// For authorization purpose
|
||||
var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id);
|
||||
@ -170,7 +178,7 @@ namespace Yavsc.ApiControllers
|
||||
return new ChallengeResult();
|
||||
}
|
||||
|
||||
var filename = FileSystemHelpers.SignFileNameFormat("pro",id);
|
||||
var filename = FileSystemHelpers.SignFileNameFormat("pro",billingCode,id);
|
||||
FileInfo fi = new FileInfo(Path.Combine(Startup.UserBillsDirName, filename));
|
||||
if (!fi.Exists) return HttpNotFound(new { Error = "Professional signature not found" });
|
||||
return File(fi.OpenRead(), "application/x-pdf", filename); ;
|
@ -39,7 +39,7 @@ namespace Yavsc.Controllers
|
||||
var uid = User.GetUserId();
|
||||
var now = DateTime.Now;
|
||||
|
||||
var result = _context.Commands.Include(c => c.Location).
|
||||
var result = _context.RdvQueries.Include(c => c.Location).
|
||||
Include(c => c.Client).Where(c => c.PerformerId == uid && c.Id < maxId && c.EventDate > now
|
||||
&& c.ValidationDate == null).
|
||||
Select(c => new RdvQueryProviderInfo
|
||||
@ -71,7 +71,7 @@ namespace Yavsc.Controllers
|
||||
}
|
||||
var uid = User.GetUserId();
|
||||
|
||||
RdvQuery bookQuery = _context.Commands.Where(c => c.ClientId == uid || c.PerformerId == uid).Single(m => m.Id == id);
|
||||
RdvQuery bookQuery = _context.RdvQueries.Where(c => c.ClientId == uid || c.PerformerId == uid).Single(m => m.Id == id);
|
||||
|
||||
if (bookQuery == null)
|
||||
{
|
||||
@ -133,7 +133,7 @@ namespace Yavsc.Controllers
|
||||
ModelState.AddModelError("ClientId", "You must be the client at creating a book query");
|
||||
return new BadRequestObjectResult(ModelState);
|
||||
}
|
||||
_context.Commands.Add(bookQuery);
|
||||
_context.RdvQueries.Add(bookQuery);
|
||||
try
|
||||
{
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
@ -162,7 +162,7 @@ namespace Yavsc.Controllers
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
var uid = User.GetUserId();
|
||||
RdvQuery bookQuery = _context.Commands.Single(m => m.Id == id);
|
||||
RdvQuery bookQuery = _context.RdvQueries.Single(m => m.Id == id);
|
||||
|
||||
if (bookQuery == null)
|
||||
{
|
||||
@ -170,7 +170,7 @@ namespace Yavsc.Controllers
|
||||
}
|
||||
if (bookQuery.ClientId != uid) return HttpNotFound();
|
||||
|
||||
_context.Commands.Remove(bookQuery);
|
||||
_context.RdvQueries.Remove(bookQuery);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
|
||||
return Ok(bookQuery);
|
||||
@ -187,7 +187,7 @@ namespace Yavsc.Controllers
|
||||
|
||||
private bool BookQueryExists(long id)
|
||||
{
|
||||
return _context.Commands.Count(e => e.Id == id) > 0;
|
||||
return _context.RdvQueries.Count(e => e.Id == id) > 0;
|
||||
}
|
||||
}
|
||||
}
|
19
Yavsc/Attributes/ActivityBillingAttribute.cs
Normal file
19
Yavsc/Attributes/ActivityBillingAttribute.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Yavsc.Attributes
|
||||
{
|
||||
public class ActivityBillingAttribute : Attribute
|
||||
{
|
||||
public string BillingCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Identifie une entité de facturation
|
||||
/// </summary>
|
||||
/// <param name="billingCode">Code de facturation,
|
||||
/// Il doit avoir une valeur unique par usage.
|
||||
/// </param>
|
||||
public ActivityBillingAttribute(string billingCode) {
|
||||
BillingCode = billingCode;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,10 @@ using Microsoft.AspNet.Authorization;
|
||||
|
||||
namespace Yavsc.ViewModels.Auth.Handlers
|
||||
{
|
||||
using Models.Workflow;
|
||||
public class CommandEditHandler : AuthorizationHandler<EditRequirement, RdvQuery>
|
||||
using Billing;
|
||||
public class BillEditHandler : AuthorizationHandler<EditRequirement, IBillable>
|
||||
{
|
||||
protected override void Handle(AuthorizationContext context, EditRequirement requirement, RdvQuery resource)
|
||||
protected override void Handle(AuthorizationContext context, EditRequirement requirement, IBillable resource)
|
||||
{
|
||||
if (context.User.IsInRole("FrontOffice"))
|
||||
context.Succeed(requirement);
|
@ -3,10 +3,11 @@ using Microsoft.AspNet.Authorization;
|
||||
|
||||
namespace Yavsc.ViewModels.Auth.Handlers
|
||||
{
|
||||
using Models.Workflow;
|
||||
public class CommandViewHandler : AuthorizationHandler<ViewRequirement, RdvQuery>
|
||||
using Billing;
|
||||
|
||||
public class BillViewHandler : AuthorizationHandler<ViewRequirement, IBillable>
|
||||
{
|
||||
protected override void Handle(AuthorizationContext context, ViewRequirement requirement, RdvQuery resource)
|
||||
protected override void Handle(AuthorizationContext context, ViewRequirement requirement, IBillable resource)
|
||||
{
|
||||
if (context.User.IsInRole("FrontOffice"))
|
||||
context.Succeed(requirement);
|
@ -10,20 +10,25 @@ namespace Yavsc.Controllers
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Models;
|
||||
using Models.Workflow;
|
||||
using Yavsc.Exceptions;
|
||||
using Yavsc.ViewModels.Workflow;
|
||||
using Yavsc;
|
||||
using Yavsc.Services;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
[Authorize]
|
||||
public class DoController : Controller
|
||||
{
|
||||
private ApplicationDbContext _context;
|
||||
ILogger _logger;
|
||||
|
||||
public DoController(ApplicationDbContext context,ILogger<DoController> logger)
|
||||
private ApplicationDbContext dbContext;
|
||||
ILogger logger;
|
||||
IBillingService billing;
|
||||
public DoController(
|
||||
ApplicationDbContext context,
|
||||
IBillingService billing,
|
||||
ILogger<DoController> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
dbContext = context;
|
||||
this.billing = billing;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// GET: /Do/Index
|
||||
@ -33,14 +38,14 @@ namespace Yavsc.Controllers
|
||||
if (id == null)
|
||||
id = User.GetUserId();
|
||||
|
||||
var userActivities = _context.UserActivities.Include(u => u.Does)
|
||||
var userActivities = dbContext.UserActivities.Include(u => u.Does)
|
||||
.Include(u => u.User).Where(u=> u.UserId == id)
|
||||
.OrderByDescending(u => u.Weight);
|
||||
return View(userActivities.ToList());
|
||||
}
|
||||
|
||||
// GET: Do/Details/5
|
||||
public IActionResult Details(string id, string activityCode)
|
||||
public async Task<IActionResult> Details(string id, string activityCode)
|
||||
{
|
||||
|
||||
if (id == null || activityCode == null)
|
||||
@ -48,29 +53,23 @@ namespace Yavsc.Controllers
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
UserActivity userActivity = _context.UserActivities.Include(m=>m.Does)
|
||||
UserActivity userActivity = dbContext.UserActivities.Include(m=>m.Does)
|
||||
.Include(m=>m.User).Single(m => m.DoesCode == activityCode && m.UserId == id);
|
||||
if (userActivity == null)
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
bool hasConfigurableSettings = (userActivity.Does.SettingsClassName != null);
|
||||
if (hasConfigurableSettings) {
|
||||
ViewBag.ProfileType = Startup.ProfileTypes.Single(t=>t.FullName==userActivity.Does.SettingsClassName);
|
||||
var dbset = (IQueryable<ISpecializationSettings>) _context.GetDbSet(userActivity.Does.SettingsClassName);
|
||||
if (dbset == null) throw new InvalidWorkflowModelException($"pas de db set pour {userActivity.Does.SettingsClassName}, vous avez peut-être besoin de décorer votre propriété avec l'attribut [ActivitySettings]");
|
||||
return View(new UserActivityViewModel {
|
||||
var settings = await billing.GetPerformerSettingsAsync(activityCode,id);
|
||||
ViewBag.ProfileType = Startup.ProfileTypes.Single(t=>t.FullName==userActivity.Does.SettingsClassName);
|
||||
|
||||
var gift = new UserActivityViewModel {
|
||||
Declaration = userActivity,
|
||||
HasSettings = dbset.Any(ua=>ua.UserId==id),
|
||||
Settings = settings,
|
||||
NeedsSettings = hasConfigurableSettings
|
||||
} );
|
||||
}
|
||||
return View(new UserActivityViewModel {
|
||||
Declaration = userActivity,
|
||||
HasSettings = false,
|
||||
NeedsSettings = hasConfigurableSettings
|
||||
} );
|
||||
};
|
||||
logger.LogInformation(JsonConvert.SerializeObject(gift.Settings));
|
||||
return View (gift);
|
||||
}
|
||||
|
||||
// GET: Do/Create
|
||||
@ -80,9 +79,9 @@ namespace Yavsc.Controllers
|
||||
if (userId==null)
|
||||
userId = User.GetUserId();
|
||||
var model = new UserActivity { UserId = userId };
|
||||
ViewBag.DoesCode = new SelectList(_context.Activities, "Code", "Name");
|
||||
ViewBag.DoesCode = new SelectList(dbContext.Activities, "Code", "Name");
|
||||
//ViewData["UserId"] = userId;
|
||||
ViewBag.UserId = new SelectList(_context.Performers.Include(p=>p.Performer), "PerformerId", "Performer", userId);
|
||||
ViewBag.UserId = new SelectList(dbContext.Performers.Include(p=>p.Performer), "PerformerId", "Performer", userId);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
@ -98,12 +97,12 @@ namespace Yavsc.Controllers
|
||||
if (userActivity.UserId == null) userActivity.UserId = uid;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
_context.UserActivities.Add(userActivity);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
dbContext.UserActivities.Add(userActivity);
|
||||
dbContext.SaveChanges(User.GetUserId());
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
ViewBag.DoesCode = new SelectList(_context.Activities, "Code", "Name", userActivity.DoesCode);
|
||||
ViewBag.UserId = new SelectList(_context.Performers.Include(p=>p.Performer), "PerformerId", "User", userActivity.UserId);
|
||||
ViewBag.DoesCode = new SelectList(dbContext.Activities, "Code", "Name", userActivity.DoesCode);
|
||||
ViewBag.UserId = new SelectList(dbContext.Performers.Include(p=>p.Performer), "PerformerId", "User", userActivity.UserId);
|
||||
return View(userActivity);
|
||||
}
|
||||
|
||||
@ -116,7 +115,7 @@ namespace Yavsc.Controllers
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
UserActivity userActivity = _context.UserActivities.Include(
|
||||
UserActivity userActivity = dbContext.UserActivities.Include(
|
||||
u=>u.Does
|
||||
).Include(
|
||||
u=>u.User
|
||||
@ -125,8 +124,8 @@ namespace Yavsc.Controllers
|
||||
{
|
||||
return HttpNotFound();
|
||||
}
|
||||
ViewData["DoesCode"] = new SelectList(_context.Activities, "Code", "Does", userActivity.DoesCode);
|
||||
ViewData["UserId"] = new SelectList(_context.Performers, "PerformerId", "User", userActivity.UserId);
|
||||
ViewData["DoesCode"] = new SelectList(dbContext.Activities, "Code", "Does", userActivity.DoesCode);
|
||||
ViewData["UserId"] = new SelectList(dbContext.Performers, "PerformerId", "User", userActivity.UserId);
|
||||
return View(userActivity);
|
||||
}
|
||||
|
||||
@ -140,12 +139,12 @@ namespace Yavsc.Controllers
|
||||
ModelState.AddModelError("User","You're not admin.");
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
_context.Update(userActivity);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
dbContext.Update(userActivity);
|
||||
dbContext.SaveChanges(User.GetUserId());
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
ViewData["DoesCode"] = new SelectList(_context.Activities, "Code", "Does", userActivity.DoesCode);
|
||||
ViewData["UserId"] = new SelectList(_context.Performers, "PerformerId", "User", userActivity.UserId);
|
||||
ViewData["DoesCode"] = new SelectList(dbContext.Activities, "Code", "Does", userActivity.DoesCode);
|
||||
ViewData["UserId"] = new SelectList(dbContext.Performers, "PerformerId", "User", userActivity.UserId);
|
||||
return View(userActivity);
|
||||
}
|
||||
|
||||
@ -158,7 +157,7 @@ namespace Yavsc.Controllers
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
UserActivity userActivity = _context.UserActivities.Single(m => m.UserId == id && m.DoesCode == activityCode);
|
||||
UserActivity userActivity = dbContext.UserActivities.Single(m => m.UserId == id && m.DoesCode == activityCode);
|
||||
|
||||
if (userActivity == null)
|
||||
{
|
||||
@ -182,8 +181,8 @@ namespace Yavsc.Controllers
|
||||
ModelState.AddModelError("User","You're not admin.");
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
_context.UserActivities.Remove(userActivity);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
dbContext.UserActivities.Remove(userActivity);
|
||||
dbContext.SaveChanges(User.GetUserId());
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
using Yavsc.Controllers.Generic;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Workflow.Profiles;
|
||||
using Yavsc.Services;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
public class FormationSettingsController : SettingsController<FormationSettings>
|
||||
{
|
||||
|
||||
public FormationSettingsController(ApplicationDbContext context) : base(context)
|
||||
public FormationSettingsController(ApplicationDbContext context, IBillingService billing) : base(context, billing)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,9 @@ namespace Yavsc.Controllers
|
||||
|
||||
var model = new FrontOfficeIndexViewModel
|
||||
{
|
||||
EstimateToProduceCount = _context.Commands.Where(c => c.PerformerId == uid && c.EventDate > now
|
||||
EstimateToProduceCount = _context.RdvQueries.Where(c => c.PerformerId == uid && c.EventDate > now
|
||||
&& c.ValidationDate == null && !_context.Estimates.Any(e => (e.CommandId == c.Id && e.ProviderValidationDate != null))).Count(),
|
||||
EstimateToSignAsProCount = _context.Commands.Where(c => (c.PerformerId == uid && c.EventDate > now
|
||||
EstimateToSignAsProCount = _context.RdvQueries.Where(c => (c.PerformerId == uid && c.EventDate > now
|
||||
&& c.ValidationDate == null && _context.Estimates.Any(e => (e.CommandId == c.Id && e.ProviderValidationDate != null)))).Count(),
|
||||
EstimateToSignAsCliCount = _context.Estimates.Where(e => e.ClientId == uid && e.ClientValidationDate == null).Count(),
|
||||
BillToSignAsProCount = 0,
|
||||
|
@ -6,25 +6,31 @@ using Microsoft.Data.Entity;
|
||||
|
||||
namespace Yavsc.Controllers.Generic
|
||||
{
|
||||
using Exceptions;
|
||||
using Models;
|
||||
using Yavsc.Services;
|
||||
|
||||
[Authorize]
|
||||
public abstract class SettingsController<TSettings> : Controller where TSettings : class, ISpecializationSettings, new()
|
||||
{
|
||||
protected ApplicationDbContext _context;
|
||||
private object dbSet;
|
||||
IBillingService billing;
|
||||
DbSet<TSettings> dbSet=null;
|
||||
|
||||
protected string activityCode=null;
|
||||
|
||||
protected DbSet<TSettings> Settings { get {
|
||||
return (DbSet<TSettings>) dbSet;
|
||||
if (dbSet == null) Task.Run( async () => {
|
||||
dbSet = (DbSet<TSettings>) await billing.GetPerformersSettingsAsync(activityCode);
|
||||
});
|
||||
return dbSet;
|
||||
} }
|
||||
|
||||
public SettingsController(ApplicationDbContext context)
|
||||
public SettingsController(ApplicationDbContext context, IBillingService billing)
|
||||
{
|
||||
_context = context;
|
||||
dbSet=_context.GetDbSet<TSettings>();
|
||||
if (dbSet==null) throw new InvalidWorkflowModelException(this.GetType().Name);
|
||||
this.billing = billing;
|
||||
}
|
||||
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var existing = await this.Settings.SingleOrDefaultAsync(p=>p.UserId == User.GetUserId());
|
||||
|
@ -2,6 +2,7 @@ using Yavsc.Models;
|
||||
using Yavsc.Models.Haircut;
|
||||
using Microsoft.AspNet.Authorization;
|
||||
using Yavsc.Controllers.Generic;
|
||||
using Yavsc.Services;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
@ -9,7 +10,7 @@ namespace Yavsc.Controllers
|
||||
public class BrusherProfileController : SettingsController<BrusherProfile>
|
||||
{
|
||||
|
||||
public BrusherProfileController(ApplicationDbContext context) : base(context)
|
||||
public BrusherProfileController(ApplicationDbContext context, IBillingService billing) : base(context, billing)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.Data.Entity;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Relationship;
|
||||
|
@ -184,13 +184,13 @@ namespace Yavsc.Helpers
|
||||
dir, xsmallname), ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
public static Func<string,long,string>
|
||||
SignFileNameFormat = new Func<string,long,string> ((signType,estimateId) => $"estimate-{signType}sign-{estimateId}.png");
|
||||
public static Func<string,string,long,string>
|
||||
SignFileNameFormat = new Func<string,string,long,string> ((signType,billingCode,estimateId) => $"sign-{billingCode}-{signType}-{estimateId}.png");
|
||||
|
||||
public static FileRecievedInfo ReceiveProSignature(this ClaimsPrincipal user, long estimateId, IFormFile formFile, string signtype)
|
||||
public static FileRecievedInfo ReceiveProSignature(this ClaimsPrincipal user, string billingCode, long estimateId, IFormFile formFile, string signtype)
|
||||
{
|
||||
var item = new FileRecievedInfo();
|
||||
item.FileName = SignFileNameFormat("pro",estimateId);
|
||||
item.FileName = SignFileNameFormat("pro",billingCode,estimateId);
|
||||
var destFileName = Path.Combine(Startup.SiteSetup.UserFiles.Bills, item.FileName);
|
||||
|
||||
var fi = new FileInfo(destFileName);
|
||||
|
@ -170,5 +170,8 @@ namespace Yavsc.Helpers
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsSuccess(PaymentInfo info) {
|
||||
return info.DbContent.State == PayPal.PayPalAPIInterfaceService.Model.PaymentStatusCodeType.COMPLETED.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ namespace Yavsc.Helpers
|
||||
|
||||
}
|
||||
|
||||
public static TeXString operator+ (TeXString a, TeXString b) {
|
||||
return new TeXString(a.ToString()+b.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
public class Replacement
|
||||
|
@ -6,15 +6,10 @@ default: pushInPre
|
||||
watch:
|
||||
ASPNET_ENV=Development dnx-watch web --configuration=Debug
|
||||
|
||||
cleanRelease:
|
||||
clean:
|
||||
rm -rf bin/Release
|
||||
|
||||
cleanoutput:
|
||||
rm -rf bin/output
|
||||
|
||||
clean: cleanoutput cleanRelease
|
||||
gulp clean
|
||||
|
||||
bin/Release:
|
||||
dnu build --configuration=Release
|
||||
|
||||
@ -31,9 +26,13 @@ pushInPre: bin/output/wwwroot/version
|
||||
ssh root@localhost sync
|
||||
ssh root@localhost systemctl start kestrel-pre
|
||||
|
||||
push: bin/output/wwwroot/version
|
||||
pushInProd: bin/output/wwwroot/version
|
||||
ssh root@localhost systemctl stop kestrel
|
||||
ssh root@localhost rm -rf $(PRODDESTDIR)/approot
|
||||
(cd bin/output && rsync -ravu ./ root@localhost:$(PRODDESTDIR) >/dev/null)
|
||||
ssh root@localhost sync
|
||||
ssh root@localhost systemctl start kestrel
|
||||
|
||||
status:
|
||||
git status -s --porcelain
|
||||
|
||||
|
@ -60,21 +60,7 @@ namespace Yavsc.Models
|
||||
}
|
||||
|
||||
}
|
||||
public DbSet<TSettings> GetDbSet<TSettings>() where TSettings : class, ISpecializationSettings
|
||||
|
||||
{
|
||||
return (DbSet<TSettings>) GetDbSet(typeof(TSettings).FullName);
|
||||
}
|
||||
public IQueryable<ISpecializationSettings> GetDbSet(string settingsClassName)
|
||||
{
|
||||
var dbSetPropInfo = Startup.GetUserSettingPropertyInfo(settingsClassName);
|
||||
if (dbSetPropInfo == null) return null;
|
||||
// var settingType = dbSetPropInfo.PropertyType;
|
||||
// var dbSetType = typeof(DbSet<>).MakeGenericType(new Type[] { settingType } );
|
||||
// avec une info method Remove et Update, ça le ferait ...
|
||||
|
||||
return (IQueryable<ISpecializationSettings>) dbSetPropInfo.GetValue(this);
|
||||
}
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseNpgsql(Startup.ConnectionString);
|
||||
@ -107,23 +93,18 @@ namespace Yavsc.Models
|
||||
/// <returns></returns>
|
||||
public DbSet<CircleMember> CircleMembers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Commands, from an user, to a performer
|
||||
/// (A performer is an user who's actived a main activity
|
||||
/// on his profile).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DbSet<RdvQuery> Commands { get; set; }
|
||||
/// <summary>
|
||||
/// Special commands, talking about
|
||||
/// a given place and date.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DbSet<RdvQuery> RdvQueries { get; set; }
|
||||
|
||||
public DbSet<HairCutQuery> HairCutQueries { get; set; }
|
||||
public DbSet<HairPrestation> HairPrestation { get; set; }
|
||||
|
||||
public DbSet<HairMultiCutQuery> HairMultiCutQueries { get; set; }
|
||||
public DbSet<PerformerProfile> Performers { get; set; }
|
||||
|
||||
public DbSet<Estimate> Estimates { get; set; }
|
||||
public DbSet<AccountBalance> BankStatus { get; set; }
|
||||
public DbSet<BalanceImpact> BankBook { get; set; }
|
||||
|
@ -82,5 +82,6 @@ namespace Yavsc.Models.Billing
|
||||
|
||||
[ForeignKey("PaymentId"), Display(Name = "Acquittement de la facture")]
|
||||
public virtual PayPalPayment Regularisation { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Yavsc.Models.Billing
|
||||
{
|
||||
public partial class satisfaction
|
||||
{
|
||||
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long _id { get; set; }
|
||||
public string comnt { get; set; }
|
||||
public int? rate { get; set; }
|
||||
|
||||
[ForeignKey("Skill.Id")]
|
||||
public long? userskillid { get; set; }
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
|
||||
namespace Yavsc.Models.Billing
|
||||
{
|
||||
public partial class writtings
|
||||
{
|
||||
public long _id { get; set; }
|
||||
public int? count { get; set; }
|
||||
public string description { get; set; }
|
||||
public long estimid { get; set; }
|
||||
public string productid { get; set; }
|
||||
public decimal? ucost { get; set; }
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
|
||||
namespace Yavsc.Models.Billing
|
||||
{
|
||||
public partial class wrtags
|
||||
{
|
||||
public long wrid { get; set; }
|
||||
public long tagid { get; set; }
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace Yavsc.Models.Relationship
|
||||
[ForeignKey("OwnerId"),JsonIgnore,NotMapped]
|
||||
public virtual ApplicationUser Owner { get; set; }
|
||||
|
||||
[InverseProperty("Circle")]
|
||||
[InverseProperty("Circle"),JsonIgnore]
|
||||
public virtual List<CircleMember> Members { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ namespace Yavsc.Models.Workflow
|
||||
{
|
||||
using System;
|
||||
using Models.Relationship;
|
||||
using Newtonsoft.Json;
|
||||
using Yavsc.Workflow;
|
||||
|
||||
public class PerformerProfile : IPerformerProfile {
|
||||
@ -16,7 +17,7 @@ namespace Yavsc.Models.Workflow
|
||||
public virtual ApplicationUser Performer { get; set; }
|
||||
|
||||
[InverseProperty("User")]
|
||||
[Display(Name="Activity")]
|
||||
[Display(Name="Activity"), JsonIgnore]
|
||||
public virtual List<UserActivity> Activity { get; set; }
|
||||
|
||||
[Required,StringLength(14),Display(Name="SIREN"),
|
||||
|
62
Yavsc/Services/BillingService.cs
Normal file
62
Yavsc/Services/BillingService.cs
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Yavsc.Billing;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
public class BillingService : IBillingService
|
||||
{
|
||||
public ApplicationDbContext DbContext { get; private set; }
|
||||
private ILogger logger;
|
||||
|
||||
public BillingService(ILoggerFactory loggerFactory, ApplicationDbContext dbContext)
|
||||
{
|
||||
logger = loggerFactory.CreateLogger<BillingService>();
|
||||
DbContext = dbContext;
|
||||
}
|
||||
public async Task<IQueryable<ISpecializationSettings>> GetPerformersSettings(string activityCode)
|
||||
{
|
||||
logger.LogDebug("searching for "+activityCode);
|
||||
var activity = await DbContext.Activities.SingleAsync(a=>a.Code == activityCode);
|
||||
logger.LogDebug(JsonConvert.SerializeObject(activity));
|
||||
|
||||
|
||||
if (activity.SettingsClassName==null) return null;
|
||||
var dbSetPropInfo = Startup.UserSettings.SingleOrDefault(s => s.PropertyType.GenericTypeArguments[0].FullName == activity.SettingsClassName);
|
||||
|
||||
|
||||
if (dbSetPropInfo == null) return null;
|
||||
// var settingType = dbSetPropInfo.PropertyType;
|
||||
// var dbSetType = typeof(DbSet<>).MakeGenericType(new Type[] { settingType } );
|
||||
// avec une info method Remove et Update, ça le ferait ...
|
||||
|
||||
return (IQueryable<ISpecializationSettings>) dbSetPropInfo.GetValue(DbContext);
|
||||
}
|
||||
|
||||
public async Task<IBillable> GetBillAsync(string billingCode, long queryId)
|
||||
{
|
||||
var dbFunc = Startup.Billing[billingCode];
|
||||
IBillable query = null;
|
||||
await Task.Run(()=> dbFunc(DbContext, queryId));
|
||||
return query;
|
||||
}
|
||||
|
||||
public async Task<ISpecializationSettings> GetPerformerSettingsAsync(string activityCode, string userId)
|
||||
{
|
||||
return await (await GetPerformersSettings(activityCode)).SingleOrDefaultAsync(s=> s.UserId == userId);
|
||||
}
|
||||
|
||||
public Task<IQueryable<ISpecializationSettings>> GetPerformersSettingsAsync(string activityCode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
26
Yavsc/Services/IBillingService.cs
Normal file
26
Yavsc/Services/IBillingService.cs
Normal file
@ -0,0 +1,26 @@
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Billing;
|
||||
public interface IBillingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Renvoye la facture associée à une clé de facturation:
|
||||
/// le couple suivant :
|
||||
///
|
||||
/// * un code de facturation
|
||||
/// (identifiant associé à un type de facturation d'un flux de travail)
|
||||
/// * un entier long identifiant la demande du client
|
||||
/// (à une demande, on associe au maximum une seule facture)
|
||||
/// </summary>
|
||||
/// <param name="billingCode">Identifiant du type de facturation</param>
|
||||
/// <param name="queryId">Identifiant de la demande du client</param>
|
||||
/// <returns>La facture</returns>
|
||||
Task<IBillable> GetBillAsync(string billingCode, long queryId);
|
||||
Task<IQueryable<ISpecializationSettings>> GetPerformersSettingsAsync(string activityCode);
|
||||
|
||||
Task<ISpecializationSettings> GetPerformerSettingsAsync(string activityCode, string userId);
|
||||
|
||||
}
|
||||
}
|
@ -7,65 +7,83 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
using Exceptions;
|
||||
using Microsoft.Data.Entity;
|
||||
using Models;
|
||||
using Yavsc.Billing;
|
||||
public partial class Startup
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists Available user profile classes,
|
||||
/// populated at startup, using reflexion.
|
||||
/// </summary>
|
||||
public static List<Type> ProfileTypes = new List<Type>() ;
|
||||
public static List<PropertyInfo> UserSettings = new List<PropertyInfo> ();
|
||||
public static List<Type> ProfileTypes = new List<Type>();
|
||||
public static List<PropertyInfo> UserSettings = new List<PropertyInfo>();
|
||||
public static Dictionary<string,Func<ApplicationDbContext,long,IBillable>> Billing =
|
||||
new Dictionary<string,Func<ApplicationDbContext,long,IBillable>> ();
|
||||
|
||||
/// <summary>
|
||||
/// Lists available command forms.
|
||||
/// This is hard coded.
|
||||
/// </summary>
|
||||
public static readonly string [] Forms = new string [] { "Profiles" , "HairCut" };
|
||||
|
||||
public static PropertyInfo GetUserSettingPropertyInfo(string settingsClassName)
|
||||
{
|
||||
return UserSettings.SingleOrDefault(s => s.PropertyType.GenericTypeArguments[0].FullName == settingsClassName ) ;
|
||||
}
|
||||
public static readonly string[] Forms = new string[] { "Profiles", "HairCut" };
|
||||
|
||||
private void ConfigureWorkflow(IApplicationBuilder app, SiteSettings settings, ILogger logger)
|
||||
{
|
||||
System.AppDomain.CurrentDomain.ResourceResolve += OnYavscResourceResolve;
|
||||
|
||||
foreach (var a in System.AppDomain.CurrentDomain.GetAssemblies()) {
|
||||
foreach (var c in a.GetTypes()) {
|
||||
foreach (var a in System.AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var c in a.GetTypes())
|
||||
{
|
||||
if (c.IsClass && !c.IsAbstract &&
|
||||
c.GetInterface("ISpecializationSettings")!=null) {
|
||||
c.GetInterface("ISpecializationSettings") != null)
|
||||
{
|
||||
ProfileTypes.Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var propinfo in typeof(ApplicationDbContext).GetProperties()) {
|
||||
foreach (var attr in propinfo.CustomAttributes) {
|
||||
if (attr.AttributeType == typeof(Yavsc.Attributes.ActivitySettingsAttribute)) {
|
||||
// bingo
|
||||
if (typeof(IQueryable<ISpecializationSettings>).IsAssignableFrom(propinfo.PropertyType))
|
||||
{
|
||||
logger.LogVerbose($"Paramêtres utilisateur déclaré: {propinfo.Name}");
|
||||
UserSettings.Add(propinfo);
|
||||
} else
|
||||
// Design time error
|
||||
{
|
||||
var msg =
|
||||
$@"La propriété {propinfo.Name} du contexte de la
|
||||
|
||||
foreach (var propinfo in typeof(ApplicationDbContext).GetProperties())
|
||||
{
|
||||
foreach (var attr in propinfo.CustomAttributes)
|
||||
{
|
||||
// something like a DbSet?
|
||||
if (attr.AttributeType == typeof(Yavsc.Attributes.ActivitySettingsAttribute))
|
||||
{
|
||||
// TODO swith () case {}
|
||||
if (typeof(IQueryable<ISpecializationSettings>).IsAssignableFrom(propinfo.PropertyType))
|
||||
{// double-bingo
|
||||
logger.LogVerbose($"Pro: {propinfo.Name}");
|
||||
UserSettings.Add(propinfo);
|
||||
}
|
||||
else
|
||||
// Design time error
|
||||
{
|
||||
var msg =
|
||||
$@"La propriété {propinfo.Name} du contexte de la
|
||||
base de donnée porte l'attribut [ActivitySetting],
|
||||
mais n'implemente pas l'interface IQueryable<ISpecializationSettings>
|
||||
({propinfo.MemberType.GetType()})";
|
||||
logger.LogCritical(msg);
|
||||
|
||||
throw new InvalidWorkflowModelException(msg);
|
||||
}
|
||||
logger.LogCritical(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Billing.Add("Brush", new Func<ApplicationDbContext,long,IBillable>
|
||||
( ( db, id) =>
|
||||
{
|
||||
var query = db.HairCutQueries.Include(q=>q.Prestation).Single(q=>q.Id == id) ;
|
||||
query.SelectedProfile = db.BrusherProfile.Single(b=>b.UserId == query.PerformerId);
|
||||
return query;
|
||||
})) ;
|
||||
|
||||
Billing.Add("MBrush",new Func<ApplicationDbContext,long,IBillable>
|
||||
( (db, id) => db.HairMultiCutQueries.Single(q=>q.Id == id)));
|
||||
Billing.Add("Rdv", new Func<ApplicationDbContext,long,IBillable>
|
||||
( (db, id) => db.RdvQueries.Single(q=>q.Id == id)));
|
||||
}
|
||||
public static System.Reflection.Assembly OnYavscResourceResolve (object sender, ResolveEventArgs ev)
|
||||
public static System.Reflection.Assembly OnYavscResourceResolve(object sender, ResolveEventArgs ev)
|
||||
{
|
||||
return AppDomain.CurrentDomain.GetAssemblies()[0];
|
||||
}
|
||||
|
@ -189,10 +189,9 @@ namespace Yavsc
|
||||
services.AddSingleton<IAuthorizationHandler, HasTemporaryPassHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, BlogEditHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, BlogViewHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, CommandEditHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, CommandViewHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, BillEditHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, BillViewHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, PostUserFileHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, EstimateViewHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, ViewFileHandler>();
|
||||
|
||||
services.AddMvc(config =>
|
||||
@ -227,6 +226,9 @@ namespace Yavsc
|
||||
// Add application services.
|
||||
services.AddTransient<IEmailSender, AuthMessageSender>();
|
||||
services.AddTransient<IGoogleCloudMessageSender, AuthMessageSender>();
|
||||
services.AddTransient<IBillingService, BillingService>((servs) =>
|
||||
new BillingService(servs.GetRequiredService<ILoggerFactory>(), servs.GetService<ApplicationDbContext>())
|
||||
);
|
||||
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
|
||||
services.AddLocalization(options =>
|
||||
@ -333,9 +335,7 @@ namespace Yavsc
|
||||
// before fixing the security protocol, let beleive our lib it's done with it.
|
||||
var cxmgr = ConnectionManager.Instance;
|
||||
// then, fix it.
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType) 0xC00;
|
||||
|
||||
logger.LogInformation($"ServicePointManager.SecurityProtocol: {ServicePointManager.SecurityProtocol}");
|
||||
ServicePointManager.SecurityProtocol = (SecurityProtocolType) 0xC00; // Tls12, required by PayPal
|
||||
|
||||
app.UseIISPlatformHandler(options =>
|
||||
{
|
||||
|
108
Yavsc/ViewComponents/BillViewComponent.cs
Normal file
108
Yavsc/ViewComponents/BillViewComponent.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Yavsc.Billing;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Services;
|
||||
using Yavsc.ViewModels.Gen;
|
||||
|
||||
namespace Yavsc.ViewComponents
|
||||
{
|
||||
public enum OutputFormat {
|
||||
Html,
|
||||
LaTeX,
|
||||
Pdf
|
||||
}
|
||||
public class BillViewComponent : ViewComponent
|
||||
{
|
||||
ApplicationDbContext dbContext;
|
||||
IBillingService billingService;
|
||||
IStringLocalizer<Yavsc.Resources.YavscLocalisation> localizer;
|
||||
|
||||
public BillViewComponent(ApplicationDbContext dbContext,
|
||||
IStringLocalizer<Yavsc.Resources.YavscLocalisation> localizer)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.localizer = localizer;
|
||||
}
|
||||
/*
|
||||
public async Task<IViewComponentResult> InvokeAsync(string code, long id)
|
||||
{
|
||||
return await InvokeAsync(code, id, OutputFormat.Html);
|
||||
}
|
||||
public async Task<IViewComponentResult> InvokeAsync(string code, long id, OutputFormat outputFormat)
|
||||
{
|
||||
return await InvokeAsync(code,id,outputFormat,false,false);
|
||||
}
|
||||
public async Task<IViewComponentResult> InvokeAsync(string code, long id, OutputFormat outputFormat, bool asBill, bool acquitted)
|
||||
{
|
||||
var billable = await Task.Run( () => billingService.GetBillAsync(code,id));
|
||||
|
||||
if (billable == null)
|
||||
throw new Exception("No data");
|
||||
return await InvokeAsync(code, billable, outputFormat,asBill,acquitted);
|
||||
|
||||
} */
|
||||
|
||||
public async Task<IViewComponentResult> InvokeAsync(string code, IBillable billable, OutputFormat format, bool asBill, bool acquitted)
|
||||
{
|
||||
var di = new DirectoryInfo(Startup.SiteSetup.UserFiles.Bills);
|
||||
var dia = new DirectoryInfo(Startup.SiteSetup.UserFiles.Avatars);
|
||||
ViewBag.BillsDir = di.FullName;
|
||||
ViewBag.AvatarsDir = dia.FullName;
|
||||
ViewBag.AsBill = asBill; // vrai pour une facture, sinon, c'est un devis
|
||||
ViewBag.Acquitted = acquitted;
|
||||
ViewBag.BillingCode = code;
|
||||
switch (format) {
|
||||
case OutputFormat.LaTeX :
|
||||
var client = await dbContext.Users
|
||||
.Include(u=>u.PostalAddress)
|
||||
.SingleAsync(u=>u.Id == billable.ClientId);
|
||||
ViewBag.Client = client;
|
||||
var performer = await dbContext.Users
|
||||
.Include(u=>u.BankInfo)
|
||||
.Include(u=>u.PostalAddress)
|
||||
.SingleAsync(u=>u.Id == billable.PerformerId);
|
||||
ViewBag.Performer = performer;
|
||||
|
||||
ViewBag.ClientAddress = client.PostalAddress?.Address.SplitAddressToTeX();
|
||||
|
||||
var profile = await dbContext.Performers
|
||||
.Include(p=>p.OrganizationAddress)
|
||||
.SingleAsync(p=>p.PerformerId == billable.PerformerId);
|
||||
ViewBag.PerformerProfile = profile;
|
||||
ViewBag.ActivityLabel = localizer[billable.ActivityCode];
|
||||
ViewBag.PerformerOrganizationAddress = profile.OrganizationAddress.Address.SplitAddressToTeX() ;
|
||||
ViewBag.PerformerAddress = performer.PostalAddress?.Address.SplitAddressToTeX() ;
|
||||
return this.View("Bill_tex", billable);
|
||||
case OutputFormat.Pdf :
|
||||
string tex = null;
|
||||
var oldWriter = ViewComponentContext.ViewContext.Writer;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
this.ViewComponentContext.ViewContext.Writer = writer;
|
||||
|
||||
var resultTex = View("Bill_tex", billable);
|
||||
await resultTex.ExecuteAsync(this.ViewComponentContext);
|
||||
tex = writer.ToString();
|
||||
|
||||
}
|
||||
ViewComponentContext.ViewContext.Writer = oldWriter;
|
||||
|
||||
return this.View("Bill_pdf",
|
||||
new PdfGenerationViewModel{
|
||||
Temp = Startup.Temp,
|
||||
TeXSource = tex,
|
||||
DestDir = Startup.UserBillsDirName,
|
||||
BaseFileName = $"bill-{code}-{billable.Id}"
|
||||
} );
|
||||
}
|
||||
return View("Default",billable);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Data.Entity;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Billing;
|
||||
using Yavsc.ViewModels.Gen;
|
||||
|
||||
namespace Yavsc.ViewComponents
|
||||
{
|
||||
public class EstimateViewComponent : ViewComponent
|
||||
{
|
||||
ApplicationDbContext dbContext;
|
||||
public EstimateViewComponent(ApplicationDbContext dbContext)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
}
|
||||
public async Task<IViewComponentResult> InvokeAsync(long id)
|
||||
{
|
||||
return await InvokeAsync(id,"Html");
|
||||
}
|
||||
public async Task<IViewComponentResult> InvokeAsync(long id, string outputFormat ="Html")
|
||||
{
|
||||
return await InvokeAsync(id,outputFormat,false,false);
|
||||
}
|
||||
public async Task<IViewComponentResult> InvokeAsync(long id, string outputFormat ="Html", bool asBill = false, bool acquitted = false)
|
||||
{
|
||||
return await Task.Run( ()=> {
|
||||
Estimate estimate =
|
||||
dbContext.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");
|
||||
var di = new DirectoryInfo(Startup.SiteSetup.UserFiles.Bills);
|
||||
var dia = new DirectoryInfo(Startup.SiteSetup.UserFiles.Avatars);
|
||||
ViewBag.BillsDir = di.FullName;
|
||||
ViewBag.AvatarsDir = dia.FullName;
|
||||
ViewBag.AsBill = asBill;
|
||||
ViewBag.Acquitted = acquitted;
|
||||
if (outputFormat == "LaTeX") {
|
||||
return this.View("Estimate_tex", estimate);
|
||||
}
|
||||
else if (outputFormat == "Pdf")
|
||||
{
|
||||
// Sorry for this code
|
||||
string tex = null;
|
||||
var oldWriter = ViewComponentContext.ViewContext.Writer;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
this.ViewComponentContext.ViewContext.Writer = writer;
|
||||
|
||||
var resultTex = View("Estimate_tex", estimate);
|
||||
resultTex.Execute(this.ViewComponentContext);
|
||||
tex = writer.ToString();
|
||||
|
||||
}
|
||||
ViewComponentContext.ViewContext.Writer = oldWriter;
|
||||
|
||||
return this.View("Estimate_pdf",
|
||||
new PdfGenerationViewModel{
|
||||
Temp = Startup.Temp,
|
||||
TeXSource = tex,
|
||||
DestDir = Startup.UserBillsDirName,
|
||||
BaseFileName = $"estimate-{id}"
|
||||
} );
|
||||
}
|
||||
return View("Default",estimate);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Authorization;
|
||||
using Yavsc.Models.Billing;
|
||||
|
||||
namespace Yavsc.ViewModels.Auth.Handlers
|
||||
{
|
||||
public class EstimateViewHandler : AuthorizationHandler<ViewRequirement, Estimate>
|
||||
{
|
||||
protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Estimate resource)
|
||||
{
|
||||
|
||||
if (context.User.IsInRole(Constants.AdminGroupName)
|
||||
|| context.User.IsInRole(Constants.FrontOfficeGroupName))
|
||||
context.Succeed(requirement);
|
||||
else if (context.User.Identity.IsAuthenticated) {
|
||||
var uid = context.User.GetUserId();
|
||||
if (resource.OwnerId == uid || resource.ClientId == uid)
|
||||
context.Succeed(requirement);
|
||||
// TODO && ( resource.Circles == null || context.User belongs to resource.Circles )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,6 @@ namespace Yavsc.ViewModels.Workflow
|
||||
{
|
||||
public UserActivity Declaration { get; set; }
|
||||
public bool NeedsSettings { get; set; }
|
||||
public bool HasSettings { get; set; }
|
||||
public ISpecializationSettings Settings { get; set; }
|
||||
}
|
||||
}
|
@ -15,10 +15,10 @@
|
||||
@if (Model.NeedsSettings) {
|
||||
<a asp-controller="@ViewBag.ProfileType.Name" asp-action="Index" class="btn btn-default">
|
||||
@SR[Model.Declaration.Does.SettingsClassName]
|
||||
@if (!Model.HasSettings) {
|
||||
<span class="badge">Non renseigné: Cliquez vite<br/> ici pour positionner les<br/> paramêtres de cette activité</span>
|
||||
@if (Model.Settings==null) {
|
||||
<span class="badge">Non renseigné: Cliquez vite<br/> ici pour positionner les<br/>
|
||||
paramêtres de cette activité</span>
|
||||
}
|
||||
|
||||
</a>
|
||||
}
|
||||
</dd>
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model HairCutQuery
|
||||
@model Yavsc.Models.Haircut.HairCutQuery
|
||||
@{ ViewData["Title"] = $"{ViewBag.Activity.Name}: Votre commande"; }
|
||||
@await Html.PartialAsync("BrusherProfileScript",ViewData["PerfPrefs"])
|
||||
|
||||
@ -186,8 +186,8 @@
|
||||
var pos = loc.geometry.location;
|
||||
var lat = new Number(pos.lat);
|
||||
var lng = new Number(pos.lng);
|
||||
$('#' + config.latId).val(lat.toLocaleString('en'));
|
||||
$('#' + config.longId).val(lng.toLocaleString('en'));
|
||||
$('#' + config.latId).val(lat);
|
||||
$('#' + config.longId).val(lng);
|
||||
gmap.setCenter(pos);
|
||||
if (marker) {
|
||||
marker.setMap(null);
|
||||
@ -335,7 +335,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="EventDate" class="col-md-2 control-label">
|
||||
@SR["Event date"]
|
||||
|
22
Yavsc/Views/Shared/Components/Bill/Bill_pdf.cshtml
Normal file
22
Yavsc/Views/Shared/Components/Bill/Bill_pdf.cshtml
Normal file
@ -0,0 +1,22 @@
|
||||
@using System.Reflection
|
||||
@using System.IO
|
||||
@using Microsoft.Extensions.WebEncoders
|
||||
@using System.Diagnostics
|
||||
@using System.Text
|
||||
@using Yavsc.Formatters
|
||||
@using Yavsc.Helpers
|
||||
@model Yavsc.ViewModels.Gen.PdfGenerationViewModel
|
||||
|
||||
@{
|
||||
Model.GenerateEstimatePdf();
|
||||
}
|
||||
@if (Model.Generated) {
|
||||
<div>
|
||||
@(Model.BaseFileName).pdf was generated
|
||||
</div>
|
||||
} else {
|
||||
<div class="error">
|
||||
@Model.GenerationErrorMessage
|
||||
<p>Something went wrong ...</p>
|
||||
</div>
|
||||
}
|
216
Yavsc/Views/Shared/Components/Bill/Bill_tex.cshtml
Normal file
216
Yavsc/Views/Shared/Components/Bill/Bill_tex.cshtml
Normal file
@ -0,0 +1,216 @@
|
||||
@using Yavsc.Helpers
|
||||
@using System.IO
|
||||
@using System.Globalization
|
||||
@model IBillable
|
||||
@{
|
||||
Layout = null;
|
||||
var pro = ViewBag.PerformerProfile;
|
||||
var from = ViewBag.Performer;
|
||||
var to = ViewBag.Client;
|
||||
var PostalAddress = ViewBag.ClientAddress;
|
||||
var proaddr = ViewBag.PerformerOrganizationAddress;
|
||||
var proaddrm = proaddr;
|
||||
var isestimate = !ViewBag.AsBill;
|
||||
var prosign = new FileInfo($"{ViewBag.BillsDir}/sign-{ViewBag.BillingCode}-{Model.Id}.png");
|
||||
var clisign = new FileInfo($"{ViewBag.BillsDir}/sign-{ViewBag.BillingCode}-{Model.Id}.png");
|
||||
var activity = ViewBag.ActivityLabel;
|
||||
var bill = Model.GetBillItems();
|
||||
string validationDate = null ;
|
||||
if (Model.ValidationDate.HasValue) {
|
||||
validationDate = Model.ValidationDate.Value.ToString("dddd dd MMMM yyyy", CultureInfo.CreateSpecificCulture("fr-FR"));
|
||||
}
|
||||
}
|
||||
\documentclass[french,11pt]{article}
|
||||
\usepackage{eurosym}
|
||||
\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 {@Model.Id.ToString()} % Numéro de facture
|
||||
\def\FactureAcquittee {@ViewBag.Acquitted?"oui":"non"} % Facture acquittée : oui/non
|
||||
\def\FactureLieu {@proaddrm} % Lieu de l'édition de la facture
|
||||
\def\FactureObjet {@(new HtmlString(isestimate?"Devis":"Facture")) en @TeXHelpers.ToTeX(activity)} % Objet du document
|
||||
% Description de la facture
|
||||
\def\FactureDescr {
|
||||
@TeXHelpers.ToTeX(Model.GetDescription())
|
||||
}
|
||||
|
||||
% Infos Client
|
||||
\def\ClientNom{@TeXHelpers.ToTeX(to.UserName)} % Nom du client
|
||||
|
||||
\def\ClientAdresse{
|
||||
% Adresse du client
|
||||
@PostalAddress
|
||||
@if (PostalAddress!=null) {<text>@PostalAddress</text>}
|
||||
@if (!string.IsNullOrWhiteSpace(to.PhoneNumber)) {<text>@TeXHelpers.ToTeX(to.PhoneNumber)<text>\\</text>
|
||||
</text>}
|
||||
E-mail: @TeXHelpers.ToTeX(to.Email)
|
||||
}
|
||||
|
||||
% Liste des produits facturés : Désignation, prix
|
||||
@foreach (var line in bill) {
|
||||
<text>\AjouterService{@TeXHelpers.ToTeX(line.Description)}{@line.Count}{@line.UnitaryCost.ToString("F2",CultureInfo.InvariantCulture)}
|
||||
</text>}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
\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{ @TeXHelpers.ToTeX(from.UserName) @if (proaddrm!=null) { <text> - @proaddrm </text> } \newline
|
||||
\small{ E-mail: @TeXHelpers.ToTeX(from.Email) @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { <text> - Téléphone fixe: @TeXHelpers.ToTeX(from.PhoneNumber) </text> }
|
||||
}
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% Logo de la société
|
||||
@if (from.Avatar != null) {
|
||||
<text>\includegraphics[height=60pt]{@(ViewBag.AvatarsDir)/@(from.UserName).png}
|
||||
</text>
|
||||
} else {
|
||||
<text>%\includegraphics{logo.png}
|
||||
</text>
|
||||
}
|
||||
% Nom et adresse de la société
|
||||
@TeXHelpers.ToTeX(from.UserName) \\
|
||||
@proaddr
|
||||
|
||||
@(isestimate?"Devis":"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 (\euro)} \\
|
||||
\hline
|
||||
\AfficheResultat{}
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\begin{flushright}
|
||||
\textit{Auto entreprise en franchise de TVA}\\
|
||||
|
||||
\end{flushright}
|
||||
~\\
|
||||
@if (ViewBag.AsBill) {
|
||||
|
||||
} else if (ViewBag.Acquitted) {
|
||||
<text>
|
||||
\ifthenelse{\equal{\FactureAcquittee}{oui}}{
|
||||
Facture acquittée.
|
||||
}
|
||||
</text>
|
||||
} else {
|
||||
var bi = from.BankInfo;
|
||||
if (bi!=null) {
|
||||
<text>À régler par chèque ou par virement bancaire :
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{|c c c c|}
|
||||
@if (!string.IsNullOrWhiteSpace(bi.BankCode) && !string.IsNullOrWhiteSpace(bi.WicketCode)
|
||||
&& !string.IsNullOrWhiteSpace(bi.AccountNumber) ) {
|
||||
<text>\hline \textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB} \\
|
||||
@bi.BankCode & @bi.WicketCode & @bi.AccountNumber & @bi.BankedKey \\
|
||||
</text>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(@bi.IBAN) && !string.IsNullOrWhiteSpace(@bi.BIC)) {
|
||||
<text>
|
||||
\hline \textbf{IBAN N°} & \multicolumn{3}{|l|}{ @bi.IBAN } \\
|
||||
\hline \textbf{Code BIC} & \multicolumn{3}{|l|}{ @bi.BIC }
|
||||
</text>
|
||||
} \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}</text>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@if (validationDate!=null) {
|
||||
<text>
|
||||
\begin{flushright}
|
||||
@(new TeXString(isestimate?"Devis demandé le ":"Facture suite à la demande du ")+
|
||||
TeXHelpers.ToTeX(validationDate))
|
||||
\end{flushright}
|
||||
@if (prosign.Exists) {
|
||||
<text>
|
||||
\begin{center}
|
||||
\hspace{263pt}
|
||||
\includegraphics[height=60pt]{@(ViewBag.BillsDir)/estimate-prosign-@(Model.Id).png}
|
||||
\end{center}
|
||||
</text>
|
||||
}
|
||||
</text>
|
||||
}
|
||||
\end{document}
|
13
Yavsc/Views/Shared/Components/Bill/Default.cshtml
Normal file
13
Yavsc/Views/Shared/Components/Bill/Default.cshtml
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
@model IBillable
|
||||
<div class="bill">
|
||||
|
||||
<a href="~/api/pdfbill/bill-@(Model.ActivityCode)-@(Model.Id).tex" >Export au format LaTeX</a>
|
||||
|
||||
|
||||
<form action="~/api/pdfbill/gen/@(Model.ActivityCode)-@Model.Id" method="POST">
|
||||
<input type="submit" value="Générer le Pdf"/>
|
||||
</form>
|
||||
|
||||
<a href="~/api/pdfbill/get/@(Model.Id)" >Télécharger le document généré</a>
|
||||
</div>
|
@ -2,12 +2,12 @@
|
||||
@model Estimate
|
||||
<div class="estimate">
|
||||
|
||||
<a href="~/api/pdfestimate/estimate-@(Model.Id).tex" >Export au format LaTeX</a>
|
||||
<a href="~/api/pdfbill/estimate-@(Model.Id).tex" >Export au format LaTeX</a>
|
||||
|
||||
|
||||
<form action="~/api/pdfestimate/gen/@Model.Id" method="POST">
|
||||
<form action="~/api/pdfbill/gen/@Model.Id" method="POST">
|
||||
<input type="submit" value="Générer le Pdf"/>
|
||||
</form>
|
||||
|
||||
<a href="~/api/pdfestimate/get/@(Model.Id)" >Télécharger le document généré</a>
|
||||
<a href="~/api/pdfbill/get/@(Model.Id)" >Télécharger le document généré</a>
|
||||
</div>
|
||||
|
@ -191,8 +191,7 @@
|
||||
@if (!(Model.ProviderValidationDate==null)) {
|
||||
<text>
|
||||
\begin{flushright}
|
||||
@(new HtmlString(isestimate?"Devis validé":"Facture validée")) le @TeXHelpers.ToTeX(Model.ProviderValidationDate.ToString("dddd dd MMMM yyyy",
|
||||
CultureInfo.CreateSpecificCulture("fr-FR")))
|
||||
@(new HtmlString(isestimate?"Devis validé":"Facture validée")) le @TeXHelpers.ToTeX(Model.ProviderValidationDate.ToString("dddd dd MMMM yyyy"))
|
||||
\end{flushright}
|
||||
@if (prosign.Exists) {
|
||||
<text>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user