This commit is contained in:
David Štaleker
2025-07-18 05:33:16 +02:00
parent 401a367e5d
commit db0cc8d3de
14776 changed files with 9251484 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
@page
@model EveryThing.Pages.Invoices.CreateModel
@{
ViewData["Title"] = "Vnos fakture";
Layout = "~/Pages/Layouts/_Layout.cshtml";
}
<!-- Editor -->
<link rel="stylesheet" href="~/vendor/libs/quill/typography.css" asp-append-version="true" />
<link rel="stylesheet" href="~/vendor/libs/quill/editor.css" asp-append-version="true" />
<form method="post" onsubmit="handleEditors()">
<h4 class="d-flex justify-content-between align-items-center w-100 font-weight-bold py-1 mb-4">
<span>
<span class="text-muted font-weight-light">
@switch (ViewData["Type"])
{
case 1:
<i>Naročila dobaviteljem</i>
break;
case 0:
<i>Računi</i>
break;
case 2:
<i>Dobavnice</i>
break;
case 3:
<i>Naročila kupcev</i>
break;
default:
<i>Fakture</i>
break;
}
/</span> Vnos
</span>
</h4>
<div class="card">
<h6 class="card-header">
Podatki fakture
</h6>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="@ViewData["Type"]" name="type"/>
<div class="form-group">
<label asp-for="Invoice.IdPartnerFk" class="control-label"></label>
<select asp-for="Invoice.IdPartnerFk" class="form-control" asp-items="ViewBag.IdPartnerFk"></select>
<span asp-validation-for="Invoice.IdPartnerFk" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Invoice.Date" class="form-label"></label>
<input autocomplete="off" asp-for="Invoice.Date" type="date" class="form-control" />
<span asp-validation-for="Invoice.Date" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-group mb-0">
<label asp-for="Invoice.PreText" class="form-label"></label>
<input type="hidden" id="value-pretext" asp-for="@Model.Invoice.PreText" />
<div id="editor-pretext" style="height: 250px">
@Html.Raw(Model.Invoice.PreText)
</div>
</div>
</div>
<div class="col-6">
<div class="form-group mb-0">
<label asp-for="Invoice.PostText" class="form-label"></label>
<input type="hidden" id="value-posttext" asp-for="@Model.Invoice.PostText" />
<div id="editor-posttext" style="height: 250px">
@Html.Raw(Model.Invoice.PostText)
</div>
</div>
</div>
</div>
<div class="row" style="margin-top:10px;">
<div class="col-6">
<div class="form-group">
<input type="submit" value="Shrani" class="btn btn-primary" />
<a class="btn btn-default" asp-page="./Index" asp-route-type="@ViewData["Type"]">Nazaj na seznam</a>
</div>
</div>
</div>
</div>
</div>
</form>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<!-- Editor -->
<script src="~/vendor/libs/quill/quill.js" asp-append-version="true"></script>
<script>
var Block = Quill.import('blots/block');
Block.tagName = 'DIV';
Quill.register(Block, true);
let editorPreText = new Quill('#editor-pretext', { modules: { toolbar: [['bold', 'italic', 'underline'], ['color'],[{ 'list': 'ordered' }, { 'list': 'bullet' }],['align'],['clean']] }, theme: 'snow' });
let editorPostText = new Quill('#editor-posttext', { modules: { toolbar: [['bold', 'italic', 'underline'], ['color'],[{ 'list': 'ordered' }, { 'list': 'bullet' }],['align'],['clean']] }, theme: 'snow' });
let editorCargoDescription = new Quill('#editor-cargodescription', { modules: { toolbar: [['bold', 'italic', 'underline'], ['color'], [{ 'list': 'ordered' }, { 'list': 'bullet' }], ['align'], ['clean']] }, theme: 'snow' });
function handleEditors() {
document.getElementById('value-pretext').value = editorPreText.root.innerHTML;
document.getElementById('value-posttext').value = editorPostText.root.innerHTML;
document.getElementById('value-cargodescription').value = editorCargoDescription.root.innerHTML;
}
$(document).ready(function () {
loadPosition();
});
</script>
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using EveryThing.Data;
using EveryThing.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
namespace EveryThing.Pages.Invoices
{
[Authorize(Roles = "Administrator,InvoicingUser,ProjecThingUser")]
public class CreateModel : PageModel
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityApplicationUser> _userManager;
private readonly SignInManager<IdentityApplicationUser> _loginManager;
private readonly RoleManager<IdentityApplicationRole> _roleManager;
public CreateModel(ApplicationDbContext context, UserManager<IdentityApplicationUser> userManager, SignInManager<IdentityApplicationUser> loginManager, RoleManager<IdentityApplicationRole> roleManager)
{
_context = context;
_userManager = userManager;
_loginManager = loginManager;
_roleManager = roleManager;
}
public IActionResult OnGet(int type)
{
var user = _userManager.GetUserAsync(User).Result;
ViewData["Type"] = type;
ViewData["IdPartnerFk"] = new SelectList(_context.CodeTablePartners.Where(x => x.IdCompanyFk == user.IdCompanyFk && x.Active), "IdPartner", "Title");
Invoice = new Models.Invoice.Invoice
{
PreText = "",
PostText = ""
};
return Page();
}
[BindProperty]
public Models.Invoice.Invoice Invoice { get; set; }
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync(int type)
{
if (!ModelState.IsValid)
{
return Page();
}
var user = _userManager.GetUserAsync(User).Result;
var invoice = Invoice;
SetNewInvoice(user.IdCompanyFk, (Models.Invoice.Invoice.InvoiceType)type, ref invoice, _context);
invoice.PostText = invoice.PostText.Replace("<div><br></div>", "");
invoice.PreText = invoice.PreText.Replace("<div><br></div>", "");
_context.Invoices.Add(invoice);
await _context.SaveChangesAsync();
return RedirectToPage("./Edit", new { id = invoice.IdInvoice });
}
public static void SetNewInvoice(int idCompany, Models.Invoice.Invoice.InvoiceType type, ref Models.Invoice.Invoice invoice, ApplicationDbContext context)
{
var year = DateTime.Now.Year;
invoice.InvoiceYear = year;
invoice.State = Models.Invoice.Invoice.InvoiceState.New;
invoice.Type = type;
var items = context.Invoices
.Where(x => x.IdCompanyFk == idCompany
&& x.InvoiceYear == year
&& x.Type == type).ToList();
invoice.InvoiceNumber = items == null || items.Count <= 0 ? 1 : items.Max(x => x.InvoiceNumber) + 1;
invoice.IdCompanyFk = idCompany;
}
}
}

View File

@@ -0,0 +1,54 @@
@page
@model EveryThing.Pages.Invoices.CreateItemModel
<h4>Faktura</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="@ViewData["IdInvoice"]" name="idInvoice"/>
<div class="form-group">
<label asp-for="InvoiceItem.IdItemFk" class="control-label"></label>
<select asp-for="InvoiceItem.IdItemFk" class="form-control" asp-items="ViewBag.Items"></select>
<span asp-validation-for="InvoiceItem.IdItemFk" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InvoiceItem.ItemDescription" class="control-label"></label>
<textarea asp-for="InvoiceItem.ItemDescription" class="form-control"></textarea>
<span asp-validation-for="InvoiceItem.ItemDescription" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InvoiceItem.Quantity" class="control-label"></label>
<input asp-for="InvoiceItem.Quantity" class="form-control" />
<span asp-validation-for="InvoiceItem.Quantity" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InvoiceItem.Price" class="control-label"></label>
<input asp-for="InvoiceItem.Price" class="form-control" />
<span asp-validation-for="InvoiceItem.Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InvoiceItem.Discount" class="control-label"></label>
<input asp-for="InvoiceItem.Discount" class="form-control" />
<span asp-validation-for="InvoiceItem.Discount" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="InvoiceItem.Note" class="control-label"></label>
<textarea asp-for="InvoiceItem.Note" class="form-control" ></textarea>
<span asp-validation-for="InvoiceItem.Note" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Shrani" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a class="btn btn-default" asp-page="./Edit" asp-route-id="@ViewData["IdInvoice"]">Nazaj</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using EveryThing.Data;
using EveryThing.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
namespace EveryThing.Pages.Invoices
{
[Authorize(Roles = "Administrator,InvoicingUser,ProjecThingUser")]
public class CreateItemModel : PageModel
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityApplicationUser> _userManager;
private readonly SignInManager<IdentityApplicationUser> _loginManager;
private readonly RoleManager<IdentityApplicationRole> _roleManager;
public CreateItemModel(ApplicationDbContext context, UserManager<IdentityApplicationUser> userManager, SignInManager<IdentityApplicationUser> loginManager, RoleManager<IdentityApplicationRole> roleManager)
{
_context = context;
_userManager = userManager;
_loginManager = loginManager;
_roleManager = roleManager;
}
public IActionResult OnGet(int idInvoice)
{
var user = _userManager.GetUserAsync(User).Result;
ViewData["IdInvoice"] = idInvoice;
ViewData["Items"] = new SelectList(_context.CodeTableItems.Where(x => x.IdCompanyFk == user.IdCompanyFk && x.Active), "IdItem", "Title");
return Page();
}
[BindProperty]
public Models.Invoice.InvoiceItem InvoiceItem { get; set; }
public async Task<IActionResult> OnPostAsync(int idInvoice)
{
if (!ModelState.IsValid)
{
return Page();
}
var user = _userManager.GetUserAsync(User).Result;
InvoiceItem.IdInvoiceFk = idInvoice;
_context.InvoiceItems.Add(InvoiceItem);
await _context.SaveChangesAsync();
return RedirectToPage("./Edit", new { id = idInvoice });
}
}
}

View File

@@ -0,0 +1,408 @@
@page
@model EveryThing.Pages.Invoices.EditModel
@{
ViewData["Title"] = "Vnos fakture";
Layout = "~/Pages/Layouts/_Layout.cshtml";
}
<!-- Editor -->
<link rel="stylesheet" href="~/vendor/libs/quill/typography.css" asp-append-version="true" />
<link rel="stylesheet" href="~/vendor/libs/quill/editor.css" asp-append-version="true" />
<link rel="stylesheet" href="~/vendor/libs/select2/select2.css" asp-append-version="true" />
<style type="text/css">
.tab-pane{
padding: 10px;
}
.table-eddit {
padding-left: 2px !important;
padding-right: 2px !important;
}
.table-number-edit {
width: 50px;
}
.table-price-edit {
width: 70px;
}
.table-number {
width: 70px;
text-align: right;
}
.table-header-number {
text-align: right;
}
.table-status {
width: 140px;
}
</style>
<form method="post" onsubmit="handleEditors()">
<h4 class="d-flex justify-content-between align-items-center w-100 font-weight-bold py-1 mb-4">
<span>
<span class="text-muted font-weight-light">
@switch (ViewData["Type"])
{
case 1:
<i>Naročila dobaviteljem</i>
break;
case 0:
<i>Računi</i>
break;
case 2:
<i>Dobavnice</i>
break;
case 3:
<i>Naročila kupcev</i>
break;
default:
<i>Fakture</i>
break;
}
/</span> Urejanje
</span>
</h4>
<hr />
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Invoice.IdInvoice"/>
<input type="hidden" asp-for="Invoice.IdCompanyFk"/>
<input type="hidden" asp-for="Invoice.Type"/>
<input type="hidden" asp-for="Invoice.InvoiceYear"/>
<input type="hidden" asp-for="Invoice.InvoiceNumber"/>
<input type="hidden" asp-for="@ViewData["Reffer"]" />
<div class="row">
<div class="col-12">
<div class="form-group">
<label asp-for="Invoice.IdPartnerFk" class="control-label"></label>
<select asp-for="Invoice.IdPartnerFk" class="form-control select2" asp-items="ViewBag.IdPartnerFk"></select>
<span asp-validation-for="Invoice.IdPartnerFk" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label asp-for="Invoice.BuyersOrderNumber" class="form-label"></label>
<input asp-for="Invoice.BuyersOrderNumber" class="form-control"/>
<span asp-validation-for="Invoice.BuyersOrderNumber" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-4">
<div class="form-group">
<label asp-for="Invoice.State" class="control-label"></label>
<select asp-for="Invoice.State" class="form-control" asp-items="ViewBag.States"></select>
<span asp-validation-for="Invoice.State" class="text-danger"></span>
</div>
</div>
<div class="col-4">
<div class="form-group">
<label asp-for="Invoice.Date" class="form-label"></label>
@Html.TextBoxFor(m => m.Invoice.Date, "{0:yyyy-MM-dd}", new { @class = "form-control", type = "date" })
@*<input autocomplete="off" asp-for="Invoice.Date" type="date" class="form-control" />*@
<span asp-validation-for="Invoice.Date" class="text-danger"></span>
</div>
</div>
<div class="col-4">
<div class="form-group">
@switch (ViewData["Type"])
{
case 1:
case 3:
<label class="form-label">Dobavni rok</label>
break;
default:
<label class="form-label">Datum odpreme</label>
break;
}
@Html.TextBoxFor(m => m.Invoice.DateOfDispatch, "{0:yyyy-MM-dd}", new { @class = "form-control", type = "date" })
@*<input autocomplete="off" asp-for="Invoice.Date" type="date" class="form-control" />*@
<span asp-validation-for="Invoice.DateOfDispatch" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="col-6 text-right">
<label class="form-label">
@switch (ViewData["Type"])
{
case 1:
<i>Naročilo dobavitelja</i>
break;
case 0:
<i>Račun</i>
break;
case 2:
<i>Dobavnica</i>
break;
case 3:
<i>Naročilo kupca</i>
break;
default:
<i>Faktura</i>
break;
}
</label>
<br />
<h4>
@Html.DisplayFor(modelItem => Model.Invoice.InvoiceYear) - @Html.DisplayFor(modelItem => Model.Invoice.InvoiceNumber)
</h4>
</div>
</div>
<div class="nav-tabs-top nav-responsive-sm">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#tab-items">Pozicije</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tab-additional-informations">Ostali podatki</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="tab-items">
<table class="table table-hover">
<thead>
<tr>
<th>Artikel</th>
<th class="table-header-number">Količina</th>
<th class="table-header-number">Cena</th>
<th class="table-header-number">Rabat</th>
<th class="table-header-number">DDV</th>
<th class="table-header-number">Vrednost</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.InvoiceItems)
{
<partial name="InvoiceItemDetails" model="item"></partial>
}
</tbody>
</table>
<div class="row">
<div class="col-12 text-right">
<a asp-page="CreateItem" asp-route-idInvoice="@Model.Invoice.IdInvoice" class="btn btn-sm btn-primary">Dodaj pozicijo</a>
</div>
</div>
</div>
<div class="tab-pane fade" id="tab-additional-informations">
<div class="row">
<div class="col-6">
<div class="form-group mb-0">
<label asp-for="Invoice.PreText" class="form-label"></label>
<input type="hidden" id="value-pretext" asp-for="@Model.Invoice.PreText" />
<div id="editor-pretext" style="height: 250px">
@Html.Raw(Model.Invoice.PreText)
</div>
</div>
</div>
<div class="col-6">
<div class="form-group mb-0">
<label asp-for="Invoice.PostText" class="form-label"></label>
<input type="hidden" id="value-posttext" asp-for="@Model.Invoice.PostText" />
<div id="editor-posttext" style="height: 250px">
@Html.Raw(Model.Invoice.PostText)
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer py-3 text-right">
<a class="btn btn-primary" asp-page="/Invoices/Print" asp-route-id="@Model.Invoice.IdInvoice" data-toggle="tooltip" data-placement="top" title="Tiskanje" data-state="primary"><i class="ion ion-md-print"></i>&nbsp;Natisni</a>
<input type="submit" value="Shrani" class="btn btn-primary"/>
@if (!string.IsNullOrWhiteSpace((ViewData["Reffer"] as string)))
{
<a class="btn btn-default" href="@ViewData["Reffer"]">Nazaj</a>
}
else
{
<a class="btn btn-default" asp-page="./Index" asp-route-type="@ViewData["Type"]">Nazaj na seznam</a>
}
</div>
</div>
</form>
@Html.AntiForgeryToken()
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<!-- HTMX -->
<script src="~/vendor/libs/htmx.org/dist/htmx.js" asp-append-version="true"></script>
<!-- Editor -->
<script src="~/vendor/libs/quill/quill.js" asp-append-version="true"></script>
<script src="~/vendor/libs/select2/select2.js" asp-append-version="true"></script>
<script>
var Block = Quill.import('blots/block');
Block.tagName = 'DIV';
Quill.register(Block, true);
let editorPreText = new Quill('#editor-pretext', { modules: { toolbar: [['bold', 'italic', 'underline'], ['color'],[{ 'list': 'ordered' }, { 'list': 'bullet' }],['align'],['clean']] }, theme: 'snow' });
let editorPostText = new Quill('#editor-posttext', { modules: { toolbar: [['bold', 'italic', 'underline'], ['color'],[{ 'list': 'ordered' }, { 'list': 'bullet' }],['align'],['clean']] }, theme: 'snow' });
function handleEditors() {
document.getElementById('value-pretext').value = editorPreText.root.innerHTML;
document.getElementById('value-posttext').value = editorPostText.root.innerHTML;
document.getElementById('value-cargodescription').value = editorCargoDescription.root.innerHTML;
}
$(document).ready(function () {
$('.select2').select2();
});
function updateInvoiceItem(element) {
let id = $(element).attr('data-iditem');
let row = $(element).parent().parent();
let idItem = parseInt(row.find("select[id=selTblItem_" + id + "]").val());
let quantity = parseFloat(row.find("input[id=inpTblQuantity_" + id + "]").val());
console.log(id);
console.log("input[id=inpTbQuantity_" + id + "]");
if (isNaN(quantity)) {//TODO preverjanje pravo
alert('Nepravilna vrednost v polju količina!');
return;
}
let price = parseFloat(row.find("input[id=inpTblPrice_" + id + "]").val().replace(',', '.'));
if (isNaN(price)) {//TODO preverjanje pravo
alert('Nepravilna vrednost v polju cena!');
return;
}
let discount = parseFloat(row.find("input[id=inpTblDiscount_" + id + "]").val().replace(',', '.'));
if (isNaN(discount)) {//TODO preverjanje pravo
alert('Nepravilna vrednost v polju rabat!');
return;
}
let tax = parseFloat(row.find("input[id=inpTblTax_" + id + "]").val().replace(',', '.'));
if (isNaN(tax)) {//TODO preverjanje pravo
alert('Nepravilna vrednost v polju ddv!');
return;
}
let itemDescription = row.find("input[id=inpTblItemDescription_" + id + "]").val();
let status = parseInt(row.find("select[id=selTblStatus_" + id + "]").val());
console.log(status);
var item = {
IdItemFk : idItem,
Quantity : quantity,
Price : price,
Discount : discount,
Tax : tax,
State : status,
ItemDescription: itemDescription
};
var jsonString = JSON.stringify(item);
$.blockUI();
$.ajax({
type: "POST",
beforeSend: function(xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
url: "Edit/?handler=UpdateInvoiceItem",
data: { idItem : id, json : jsonString },
success: function(data) {
document.getElementById('btnTblCancel_' + id).click();
$.unblockUI();
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.responseText);
$.unblockUI();
}
});
}
function deleteInvoiceItem(element) {
const idInvoiceItem = $(element).parent().parent().attr('data-idinvoiceitem');
$.blockUI();
$.ajax({
type: "GET",
url: "Edit/?handler=InvoiceItem",
data: {
idInvoiceItem
},
success: function (data) {
$.unblockUI();
if (data.successful) {
if (data.inUse) {
Swal.fire('Pozicija ima vezavo!',
'Brisanje ni možno!',
'warning');
return;
}
Swal.fire({
title: `Izbrišem pozicijo?`,
text: "Tega dejanja ni možno razveljaviti!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Da, izbriši!',
cancelButtonText: 'Prekliči!'
}).then((result) => {
if (result.isConfirmed) {
$.blockUI();
$.ajax({
type: "DELETE",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
url: "Edit/?handler=InvoiceItem",
data: {
idInvoiceItem
},
success: function (data) {
$.unblockUI();
if (data.successful) {
$(element).parent().parent().remove();
} else {
Swal.fire('Napaka pri brisanju pozicije',
data.error,
'error');
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.responseText);
$.unblockUI();
}
});
} else {
if (onCancel != null) {
onCancel();
}
}
});
} else {
Swal.fire('Napaka pri branju pozicije',
data.error,
'error');
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.responseText);
$.unblockUI();
}
});
}
</script>
}

View File

@@ -0,0 +1,244 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using EveryThing.Data;
using EveryThing.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using EveryThing.Models.Project;
using System.Text.Json;
using static EveryThing.Pages.Projects.EditModel;
namespace EveryThing.Pages.Invoices
{
[Authorize(Roles = "Administrator,InvoicingUser,ProjecThingUser")]
public class EditModel : PageModel
{
public class EditInvoiceItemData
{
public Models.Invoice.InvoiceItem InvoiceItem { get; set; }
public SelectList SelectListItems { get; set; }
//public SelectList SelectListMaterials { get; set; }
//public SelectList SelectListSuppliers { get; set; }
}
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityApplicationUser> _userManager;
private readonly SignInManager<IdentityApplicationUser> _loginManager;
private readonly RoleManager<IdentityApplicationRole> _roleManager;
public EditModel(ApplicationDbContext context, UserManager<IdentityApplicationUser> userManager, SignInManager<IdentityApplicationUser> loginManager, RoleManager<IdentityApplicationRole> roleManager)
{
_context = context;
_userManager = userManager;
_loginManager = loginManager;
_roleManager = roleManager;
}
[BindProperty]
public Models.Invoice.Invoice Invoice { get; set; }
public IList<Models.Invoice.InvoiceItem> InvoiceItems { get; set; }
[BindProperty]
public string Reffer { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Invoice = await _context.Invoices
.Include(f => f.Company).FirstOrDefaultAsync(m => m.IdInvoice == id);
var user = _userManager.GetUserAsync(User).Result;
if (Invoice == null)
{
return NotFound();
}
InvoiceItems = await _context.InvoiceItems
.Include(f => f.Item)
.Where(m => m.IdInvoiceFk == id)
.ToListAsync();
ViewData["Type"] = (int)Invoice.Type;
ViewData["IdPartnerFk"] = new SelectList(_context.CodeTablePartners.Where(x => x.IdCompanyFk == user.IdCompanyFk && x.Active), "IdPartner", "Title");
ViewData["States"] = new SelectList(Enum.GetValues(typeof(Models.Invoice.Invoice.InvoiceState))
.Cast<Models.Invoice.Invoice.InvoiceState>()
.Where(x => GetAttribute<Models.Invoice.Invoice.InvoiceStateAttribute>(x).AllowedTypes.Split(',').Contains(((int)Invoice.Type).ToString()))
.Select(x => new { Name = GetAttribute<DisplayAttribute>(x).Name, Value = x.ToString()})
.ToList(), "Value", "Name");
if (!string.IsNullOrEmpty(Request.Headers["Referer"]))
{
ViewData["Reffer"] = Reffer = Request.Headers["Referer"].ToString();
}
return Page();
}
public static TAttribute GetAttribute<TAttribute>(Enum value)
where TAttribute : Attribute
{
var enumType = value.GetType();
var name = Enum.GetName(enumType, value);
return enumType.GetField(name).GetCustomAttributes(false).OfType<TAttribute>().SingleOrDefault();
}
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
Invoice.PostText = Invoice.PostText.Replace("<div><br></div>", "");
Invoice.PreText = Invoice.PreText.Replace("<div><br></div>", "");
_context.Attach(Invoice).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!FileExists(Invoice.IdInvoice))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Edit", new { id = Invoice.IdInvoice});
if (Reffer != null)
return RedirectToPage(Reffer);
return RedirectToPage("./Index", new { type = (int)Invoice.Type });
}
private bool FileExists(int id)
{
return _context.Invoices.Any(e => e.IdInvoice == id);
}
public IActionResult OnPostUpdateInvoiceItem(int idItem, string json)
{
var tmpItem = JsonSerializer.Deserialize<Models.Invoice.InvoiceItem>(json);
var item = _context.InvoiceItems.First(x => x.IdInvoiceItem == idItem);
if (item == null)
{
//TODO error
return new OkResult();
}
item.IdItemFk = tmpItem.IdItemFk;
item.Quantity = tmpItem.Quantity;
item.Price = tmpItem.Price;
item.Discount = tmpItem.Discount;
item.Tax = tmpItem.Tax;
item.State = tmpItem.State;
item.ItemDescription = tmpItem.ItemDescription;
_context.SaveChanges();
return new OkResult();
}
public IActionResult OnGetInvoiceItemEdit(int id)
{
var user = _userManager.GetUserAsync(User).Result;
var item = _context.InvoiceItems
.Include(x => x.Item)
.First(x => x.IdInvoiceItem == id);
var selListItems = new SelectList(_context.CodeTableItems.Where(x => x.IdCompanyFk == user.IdCompanyFk && x.Active), "IdItem", "Title");
return Partial("InvoiceItemEdit", new EditInvoiceItemData
{
InvoiceItem = item,
SelectListItems = selListItems,
});
}
public IActionResult OnGetInvoiceItemDetails(int id)
{
var item = _context.InvoiceItems
.Include(x => x.Item)
.First(x => x.IdInvoiceItem == id);
return Partial("InvoiceItemDetails", item);
}
public IActionResult OnDeleteInvoiceItem(int idInvoiceItem)
{
var user = _userManager.GetUserAsync(User).Result;
var item = _context.InvoiceItems
.Include(x => x.Invoice)
.FirstOrDefault(x => x.IdInvoiceItem == idInvoiceItem
&& x.Invoice.IdCompanyFk == user.IdCompanyFk);
if (item == null)
{
return new JsonResult(new { error = $"Invoice item with id {idInvoiceItem} not exists!", successful = false });
}
_context.InvoiceItems.Remove(item);
_context.SaveChanges();
return new JsonResult(new { error = "", successful = true });
}
public IActionResult OnGetInvoiceItem(int idInvoiceItem)
{
var user = _userManager.GetUserAsync(User).Result;
var successful = true;
var error = "";
var inUse = false;
var invoiceItem = _context.InvoiceItems
.Include(x => x.Invoice)
.FirstOrDefault(x => x.IdInvoiceItem == idInvoiceItem
&& x.Invoice.IdCompanyFk == user.IdCompanyFk);
if (invoiceItem == null)
{
successful = false;
error = $"Invoice item with ID: {idInvoiceItem} not found";
}
else
{
inUse = false;
//Cene se json zacikla neki IDK.
invoiceItem.Invoice = null;
}
return new JsonResult(new { invoiceItem, error, successful, inUse });
}
}
}

View File

@@ -0,0 +1,224 @@
@page
@using EveryThing.Models.Invoice
@model EveryThing.Pages.Invoices.IndexModel
@{
ViewData["Title"] = "Projekti";
Layout = "~/Pages/Layouts/_Layout.cshtml";
}
<h4 class="d-flex justify-content-between align-items-center w-100 font-weight-bold py-1 mb-4">
<span>
<span class="text-muted font-weight-light">@switch (@ViewData["Type"])
{
case 1:
<i>Naročila dobaviteljem</i>
break;
case 0:
<i>Računi</i>
break;
case 2:
<i>Dobavnice</i>
break;
case 3:
<i>Naročila kupcev</i>
break;
default:
<i>Fakture</i>
break;
}
/</span> Pregled
</span>
</h4>
<div class="row">
<div class="col-12 mb-2 text-right">
<form method="get">
<input type="hidden" asp-for="@ViewData["Type"]" name="type"/>
<div class="btn-group">
<input class="form-control" type="text" name="searchString" value="@ViewData["SearchString"]" placeholder="Iskanje..." autocomplete="off">
<button type="submit" class="btn btn-secondary" aria-label="Osveži" title="Osveži" asp-route-type="@ViewData["Type"]">
<i class="opacity-75 ion ion-md-refresh"></i>
</button>
<div class="btn-group" title="Columns">
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-label="Nastavitve" title="Nastavitve">
<i class="opacity-75 ion ion-md-apps"></i>
<span class="caret"></span>
</button>
<div class="dropdown-menu dropdown-menu-right">
<label class="dropdown-item">
<input type="checkbox" name="finishedProjects" @ViewData["FinishedProjects"]> <span>Zaprte fakture</span>
</label>
</div>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<table class="table card-table table-hover">
<thead>
<tr>
<th style="width: 200px;">#</th>
<th style="width: auto;">
@Html.DisplayNameFor(invoice => invoice.Invoice[0].IdPartnerFk)
</th>
<th style="width: 100px;">
@Html.DisplayNameFor(invoice => invoice.Invoice[0].Date)
</th>
<th style="width: 100px">
@Html.DisplayNameFor(invoice => invoice.Invoice[0].State)
</th>
@if (Model.ShowProjects)
{
<th style="width: 100px">
Projekti
</th>
}
<th style="width: 140px;"></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Invoice)
{
<tr data-idinvoice="@item.IdInvoice" data-number="@item.InvoiceNumberFormatted">
<td>@Html.DisplayFor(modelItem => item.InvoiceNumberFormatted)</td>
<td>
@Html.DisplayFor(modelItem => item.Partner.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@switch (item.State)
{
case Invoice.InvoiceState.Closed:
<span class='badge badge-success'>@Html.DisplayFor(modelItem => item.State)</span>
break;
case Invoice.InvoiceState.Confirmed:
<span class='badge badge-warning'>@Html.DisplayFor(modelItem => item.State)</span>
break;
default:
<span class='badge badge-info'>@Html.DisplayFor(modelItem => item.State)</span>
break;
}
</td>
@if (Model.ShowProjects)
{
<td>
@if (item.InvoiceInvoiceItem.FirstOrDefault() != null)
{
<a asp-page="/Projects/Edit" asp-route-id="@item.InvoiceInvoiceItem.FirstOrDefault()?.ProjectPartItem?.ProjectPart?.Project?.IdProject">@string.Join(" ", item.InvoiceInvoiceItem.Select(x => x.ProjectPartItem?.ProjectPart?.Project?.ProjectNumberFormatted).Distinct())</a>
}
</td>
}
<td class="text-right">
<a class="btn btn-xs icon-btn btn-outline-success borderless" href='javascript:;' onclick="generateExcel(this)" data-toggle="tooltip" data-placement="left" title="Izvozi pozicije v .xlsx format" data-state="success"><i class="far fa-file-excel"></i></a>
<a class="btn btn-xs icon-btn btn-outline-primary borderless" asp-page="/Invoices/Print" asp-route-id="@item.IdInvoice" data-toggle="tooltip" data-placement="top" title="Tiskanje" data-state="primary"><i class="ion ion-md-print"></i></a>
<a class="btn btn-xs icon-btn btn-outline-secondary borderless" asp-page="Edit" asp-route-id="@item.IdInvoice" data-toggle="tooltip" data-placement="top" title="Urejanje" data-state="secondary"><i class="fas fa-pencil-alt"></i></a>
<a class="btn btn-xs icon-btn btn-outline-danger borderless" data-state="danger" href='javascript:;' onclick="deleteInvoice(this)"><i class="fas fa-times"></i></a>
</td>
</tr>
}
</tbody>
</table>
<div class="card-footer py-3 text-right">
<a asp-page="Create" asp-route-type="@ViewData["Type"]" class="btn btn-primary">Vnos fakture</a>
</div>
</div>
@Html.AntiForgeryToken()
@section Scripts {
<script>
$('[data-toggle="tooltip"]').tooltip({container: 'table'});
function deleteInvoice(element){
let row = $(element).parent().parent();
let idInvoice = $(row).attr('data-idinvoice');
let invoiceNumber = $(row).attr('data-number');
Swal.fire({
title: `Izbrišem dokument ${invoiceNumber}?`,
text: "Tega dejanja ni možno razveljaviti!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Da, izbriši!',
cancelButtonText: 'Prekliči!'
}).then((result) => {
if (result.isConfirmed) {
$.blockUI();
$.ajax({
type: "DELETE",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
url: "/Invoices/Index/?handler=Invoice",
data: {
idInvoice
},
success: function (data) {
$.unblockUI();
if (data.successful) {
$(row).remove();
} else {
console.log(data);
Swal.fire('Napaka pri brisanju dokumenta',
data.error,
'error');
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.responseText);
$.unblockUI();
}
});
}
});
}
function generateExcel(element) {
const row = $(element).parent().parent();
const idInvoice = $(row).attr('data-idinvoice');
$.blockUI();
$.ajax({
type: "GET",
url: "/Invoices/Index/?handler=Excel",
data: {
idInvoice
},
success: function (data) {
$.unblockUI();
if (data.successful) {
var tmpElement = document.createElement('A');
tmpElement.href = 'data:application/octet-stream;base64,' + data.base64;
tmpElement.download = data.name;
document.body.appendChild(tmpElement);
tmpElement.click();
document.body.removeChild(tmpElement);
} else {
console.log(data);
Swal.fire('Napaka pri kreiranju excela',
data.error,
'error');
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.responseText);
$.unblockUI();
}
});
}
</script>
}

View File

@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using EveryThing.Data;
using EveryThing.Models;
using EveryThing.Models.Project;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using ClosedXML.Excel;
using System.IO;
using Microsoft.AspNetCore.Hosting;
namespace EveryThing.Pages.Invoices
{
[Authorize(Roles = "Administrator,InvoicingUser,ProjecThingUser")]
public class IndexModel : PageModel
{
private readonly IWebHostEnvironment _hostingEnvironment;
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityApplicationUser> _userManager;
public IndexModel(ApplicationDbContext context, UserManager<IdentityApplicationUser> userManager, IWebHostEnvironment environment)
{
_context = context;
_userManager = userManager;
_hostingEnvironment = environment;
}
public IList<Models.Invoice.Invoice> Invoice { get;set; }
public bool ShowProjects { get; set; } = false;
public async Task OnGetAsync(int type, string searchString, string finishedProjects)
{
var user = _userManager.GetUserAsync(User).Result;
ShowProjects = User.IsInRole("ProjecThingUser") || User.IsInRole("Administrator");
var invoiceType = (Models.Invoice.Invoice.InvoiceType)type;
//Kako spraviti type preko osvezovanja
ViewData["Type"] = type;
ViewData["SearchString"] = searchString;
ViewData["FinishedProjects"] = finishedProjects == "on" ? "checked" : "";
if (ShowProjects)
{
Invoice = await _context.Invoices
.Include(p => p.Company)
.Include(p => p.Partner)
.Include(x => x.InvoiceInvoiceItem)
.ThenInclude(x => x.ProjectPartItem)
.ThenInclude(x => x.ProjectPart)
.ThenInclude(x => x.Project)
.Where(x => x.Type == invoiceType)
.OrderBy(x => x.InvoiceYear)
.ThenBy(x => x.InvoiceNumber)
.ToListAsync();
}
else
{
Invoice = await _context.Invoices
.Include(p => p.Company)
.Include(p => p.Partner)
.Where(x => x.Type == invoiceType)
.OrderBy(x => x.InvoiceYear)
.ThenBy(x => x.InvoiceNumber)
.ToListAsync();
}
// Search string
if (!string.IsNullOrEmpty(searchString))
{
Invoice = Invoice.Where(s => s.Partner.Title.Contains(searchString, StringComparison.OrdinalIgnoreCase)
|| s.InvoiceNumberFormatted.Contains(searchString, StringComparison.OrdinalIgnoreCase)).ToList();
}
}
public IActionResult OnDeleteInvoice(int idInvoice)
{
var user = _userManager.GetUserAsync(User).Result;
var successful = true;
var error = "";
var invoice = _context.Invoices
.Where(x => x.IdCompanyFk == user.IdCompanyFk)
.FirstOrDefault(x => x.IdInvoice == idInvoice);
if (invoice != null)
{
var invoiceItems = _context.InvoiceItems.Where(x => x.IdInvoiceFk == idInvoice).ToList();
for (var i = 0; i < invoiceItems.Count(); i++)
{
_context.InvoiceItems.Remove(invoiceItems[i]);
}
_context.Invoices.Remove(invoice);
_context.SaveChanges();
}
else
{
successful = false;
error = $"Invoice with ID: {idInvoice} not found";
}
return new JsonResult(new { idInvoice = idInvoice, error = error, successful = successful });
}
public IActionResult OnGetExcel(int idInvoice)
{
var user = _userManager.GetUserAsync(User).Result;
var successful = true;
var error = "";
var name = "";
var base64 = "";
var invoice = _context.Invoices
.Where(x => x.IdCompanyFk == user.IdCompanyFk)
.FirstOrDefault(x => x.IdInvoice == idInvoice);
if (invoice != null)
{
name = invoice.InvoiceNumberFull.Replace("-", "_") + ".xlsx";
var invoiceItems = _context.InvoiceItems
.Include(x => x.Item)
.Include(x => x.InvoiceItemJoin)
.ThenInclude(x=> x.Invoice)
.Where(x => x.IdInvoiceFk == idInvoice).ToList();
var workbook = new XLWorkbook();
var workSheet = workbook.Worksheets.Add("Dokument");
var counter = 1;
workSheet.Cell($"A{counter}").Value = "Artikel";
workSheet.Cell($"B{counter}").Value = "Količina";
workSheet.Cell($"C{counter}").Value = "Cena";
workSheet.Cell($"D{counter}").Value = "Rabat";
workSheet.Cell($"E{counter}").Value = "Vrednost";
workSheet.Cell($"F{counter}").Value = "Opis";
workSheet.Cell($"G{counter}").Value = "Št. kup. naročila";
workSheet.Cell($"H{counter}").Value = "Št. naročila";
workSheet.Cell($"I{counter}").Value = "Dobavni rok";
//workSheet.Cell($"J{counter}").Value = "DN Z";
//workSheet.Cell($"K{counter}").Value = "DN Z Vnos";
//workSheet.Cell($"L{counter}").Value = "DN P";
//workSheet.Cell($"M{counter}").Value = "DN P Vnos";
//workSheet.Cell($"N{counter}").Value = "DN N";
//workSheet.Cell($"O{counter}").Value = "DN N Vnos";
//workSheet.Cell($"P{counter}").Value = "Prihod/Odhod nepreračunan";
//workSheet.Cell($"Q{counter}").Value = "Skupaj nepreračunan";
foreach (var invoiceItem in invoiceItems)
{
counter++;
workSheet.Cell($"A{counter}").Value = invoiceItem.Item?.Title;
workSheet.Cell($"B{counter}").Value = invoiceItem.Quantity;
workSheet.Cell($"C{counter}").Value = invoiceItem.Price;
workSheet.Cell($"D{counter}").Value = invoiceItem.Discount;
workSheet.Cell($"E{counter}").Value = invoiceItem.TotalValue;
workSheet.Cell($"F{counter}").Value = invoiceItem.ItemDescription;
workSheet.Cell($"G{counter}").Value = "'" + invoiceItem.InvoiceItemJoin?.Invoice?.BuyersOrderNumber;
workSheet.Cell($"H{counter}").Value = "'" + invoiceItem.InvoiceItemJoin?.Invoice?.InvoiceNumberFormatted;
workSheet.Cell($"I{counter}").Value = invoice.DateOfDispatch == null ? "" : ((DateTime)invoice.DateOfDispatch).ToString("dd.MM.yyyy");
}
//var range = workSheet.Range(1, 1, counter - 1, 9);
//var table = range.CreateTable();
//table.Theme = XLTableTheme.TableStyleMedium5;
var tmpFilePath = Path.Combine(_hostingEnvironment.WebRootPath, "Uploads", Guid.NewGuid().ToString().Replace("-", "_") + ".xlsx");
workbook.SaveAs(tmpFilePath);
var tempByte = System.IO.File.ReadAllBytes(tmpFilePath);
base64 = Convert.ToBase64String(tempByte);
System.IO.File.Delete(tmpFilePath);
}
else
{
successful = false;
error = $"Invoice with ID: {idInvoice} not found";
}
return new JsonResult(new { idInvoice, error, successful, name, base64 });
}
}
}

View File

@@ -0,0 +1,18 @@
@model EveryThing.Models.Invoice.InvoiceItem
<tr data-idinvoiceitem="@Model.IdInvoiceItem">
<td>
@Html.DisplayFor(x => Model.Item.Title) <br/>
@Html.DisplayFor(x => Model.ItemDescription)
</td>
<td class="table-number">@Html.DisplayFor(x => Model.Quantity)</td>
<td class="table-number">@Html.DisplayFor(x => Model.Price)</td>
<td class="table-number">@Html.DisplayFor(x => Model.Discount)</td>
<td class="table-number">@Html.DisplayFor(x => Model.Tax)</td>
<td class="table-number">@Html.DisplayFor(x => Model.TotalValue)</td>
<td class="table-status">@Html.DisplayFor(modelItem => Model.State)</td>
<td class="text-right" style="width: 70px;">
<a class="btn btn-xs icon-btn btn-outline-secondary borderless" data-state="secondary" href='javascript:;'><i class="fas fa-pencil-alt" hx-get="@Url.Page("Edit", "InvoiceItemEdit", new {id = Model.IdInvoiceItem})" hx-swap="outerHTML" hx-target="closest tr"></i></a>
<a class="btn btn-xs icon-btn btn-outline-danger borderless" data-state="danger" href='javascript:;' onclick="deleteInvoiceItem(this)"><i class="fas fa-times"></i></a>
</td>
</tr>

View File

@@ -0,0 +1,35 @@
@model EveryThing.Pages.Invoices.EditModel.EditInvoiceItemData
<tr>
@using (Html.BeginForm("UpdateInvoiceItem", "Edit", FormMethod.Post))
{
<td>
<input type="hidden" asp-for="InvoiceItem.IdInvoiceItem" />
<select id="selTblItem_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.IdItemFk" class="form-control" asp-items="Model.SelectListItems" style="width: 100%"></select>
<input id="inpTblItemDescription_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.ItemDescription" class="form-control" style="width:100%" />
</td>
<td class="table-eddit table-price-edit">
<input id="inpTblQuantity_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.Quantity" class="form-control" style="width:100%"/>
</td>
<td class="table-eddit table-price-edit">
<input id="inpTblPrice_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.Price" class="form-control" style="width: 100%"/>
</td>
<td class="table-eddit table-price-edit">
<input id="inpTblDiscount_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.Discount" class="form-control"style="width: 100%"/>
</td>
<td class="table-eddit table-price-edit">
<input id="inpTblTax_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.Tax" class="form-control" style="width: 100%"/>
</td>
<td class="table-eddit table-price-edit">
@Html.DisplayFor(x => Model.InvoiceItem.TotalValue)
</td>
<td class="table-status">
<select id="selTblStatus_@(Model.InvoiceItem.IdInvoiceItem.ToString())" asp-for="InvoiceItem.State" asp-items="Html.GetEnumSelectList<EveryThing.Models.Invoice.InvoiceItem.InvoiceItemState>()" class="form-control" style="width: 100%">
</select>
</td>
<td class="text-right" style="width: 70px;">
<a class="btn btn-xs icon-btn btn-outline-success borderless" href='javascript:;' data-state="success" data-iditem="@(Model.InvoiceItem.IdInvoiceItem)" onclick="updateInvoiceItem(this)"><i class="fas fa-check"></i></a>
<a id="btnTblCancel_@(Model.InvoiceItem.IdInvoiceItem.ToString())" href='javascript:;' class="btn btn-xs icon-btn btn-outline-danger borderless" data-state="danger" hx-get="@Url.Page("Edit", "InvoiceItemDetails", new { id = Model.InvoiceItem.IdInvoiceItem })" hx-swap="outerHTML" hx-target="closest tr"><i class="fas fa-ban"></i></a>
</td>
}
</tr>

View File

@@ -0,0 +1,387 @@
@page
@using System.Web
@using EveryThing.Models.Invoice
@using Org.BouncyCastle.Asn1
@model EveryThing.Pages.Invoices.PrintModel
@{
ViewData["Title"] = "Izpis";
Layout = "~/Pages/Layouts/_Layout.cshtml";
}
<style type="text/css">
table {
page-break-inside: auto;
color: black !important;
}
tr {
page-break-inside: avoid;
page-break-after: auto
}
thead {
display: table-header-group
}
tfoot {
display: table-footer-group
}
body {
color: black !important;
}
</style>
<h4 class="d-flex justify-content-between align-items-center w-100 font-weight-bold py-1 mb-4">
<span>
<span class="text-muted font-weight-light">
@switch ((int)Model.Invoice.Type)
{
case 1:
<i>Naročila dobaviteljem</i>
break;
case 0:
<i>Računi</i>
break;
case 2:
<i>Dobavnice</i>
break;
case 3:
<i>Naročila kupcev</i>
break;
default:
<i>Fakture</i>
break;
}
/</span> Izpis
</span>
</h4>
<div class="card pt-2" style="width: 595pt">
<div id="print-content" class="card-body pb-4 pl-4 pt-0" style="padding-right: 2rem !important">
<div class="row">
<div class="col-6 h-100 my-auto">
@*<img src="~/img/logos/trans-fer.png"/>*@
<img src="~/img/logos/@Html.DisplayFor(modelItem => Model.Invoice.Company.LogoFileName)"/>
</div>
<div class="col-6">
<address class="mb-0">
<strong>@Html.DisplayFor(modelItem => Model.Invoice.Company.Title)</strong> <br/>
@Html.DisplayFor(modelItem => Model.Invoice.Company.Street) @Html.DisplayFor(modelItem => Model.Invoice.Company.HouseNumber) <br/>
@Html.DisplayFor(modelItem => Model.Invoice.Company.PostNumber) @Html.DisplayFor(modelItem => Model.Invoice.Company.Post) <br/>
<div style="font-size: 0.7rem">
<label>@Model.Translation.Email</label> @Html.DisplayFor(modelItem => Model.Invoice.Company.Email),<label>@Model.Translation.Telephone</label> @Html.DisplayFor(modelItem => Model.Invoice.Company.Phone) <br />
<label>@Model.Translation.IdTax</label> @Html.DisplayFor(modelItem => Model.Invoice.Company.TaxNumber), Matična številka: @Html.DisplayFor(modelItem => Model.Invoice.Company.RegistrationNumber)<br />
<label>@Model.Translation.Iban</label> @Html.DisplayFor(modelItem => Model.Invoice.Company.Iban) <label>@Model.Translation.SwiftBic</label> @Html.DisplayFor(modelItem => Model.Invoice.Company.SwiftBic)
</div>
</address>
</div>
</div>
<hr/>
<address class="mb-2">
<strong>@Html.DisplayFor(modelItem => Model.Invoice.Partner.Title)</strong> <br/>
@Html.DisplayFor(modelItem => Model.Invoice.Partner.Street) @Html.DisplayFor(modelItem => Model.Invoice.Partner.HouseNumber) <br/>
@Html.DisplayFor(modelItem => Model.Invoice.Partner.PostNumber) @Html.DisplayFor(modelItem => Model.Invoice.Partner.Post) <br/>
@Html.DisplayFor(modelItem => Model.Invoice.Partner.Country.TranslationSlovenian) <br/>
</address>
<h6 class="text-big font-weight-bold mb-3">
<label>@Model.Translation.InvoiceType</label> <label>@Model.Translation.Number</label>: @Html.DisplayFor(modelItem => Model.Invoice.InvoiceYear)-@Html.DisplayFor(modelItem => Model.Invoice.InvoiceNumber)
</h6>
<div class="mb-3" style="margin-top: 0 !important; margin-bottom: 0 !important;">
<label style="margin-top: 0 !important; margin-bottom: 0 !important;">@Model.Translation.Date</label>: <strong class="font-weight-semibold">@Html.DisplayFor(modelItem => Model.Invoice.Date)</strong>
</div>
@if ((Model.Invoice.Type == Invoice.InvoiceType.DeliveryNote
|| Model.Invoice.Type == Invoice.InvoiceType.BuyersOrder
|| Model.Invoice.Type == Invoice.InvoiceType.Invoice)
&& !string.IsNullOrEmpty(Model.Invoice.BuyersOrderNumber))
{
<div class="mb-3" style="margin-top: 0 !important; margin-bottom: 0 !important;">
<label style="margin-top: 0 !important; margin-bottom: 0 !important;">@Model.Translation.OrderNumber</label>:&nbsp;
<strong class="font-weight-semibold">@Html.DisplayFor(modelItem => Model.Invoice.BuyersOrderNumber)</strong>
</div>
}
@if (!string.IsNullOrEmpty(Model.ProjectNumber))
{
<div class="mb-3" style="margin-top: 0 !important; margin-bottom: 0 !important;">
<label style="margin-top: 0 !important; margin-bottom: 0 !important;">@Model.Translation.Project</label>:&nbsp;
<strong class="font-weight-semibold">@Html.DisplayFor(modelItem => Model.ProjectNumber)</strong>
</div>
}
<div class="mb-3">
@switch (Model.Invoice.Type)
{
case Models.Invoice.Invoice.InvoiceType.Order:
case Models.Invoice.Invoice.InvoiceType.BuyersOrder:
<label>@Model.Translation.DeliveryTime</label>
break;
default:
<label>@Model.Translation.DateOfDispatch</label>
break;
}
<strong class="font-weight-semibold">@Html.DisplayFor(modelItem => Model.Invoice.DateOfDispatch)</strong>
</div>
<div class="mb-2" style="font-size: 0.75rem">
@Html.Raw(HttpUtility.HtmlDecode(Model.Invoice.PreText))
</div>
<div class="table-responsive mb-4">
<table class="table m-0">
<thead style="font-size: 0.75rem">
<tr>
<th>#</th>
<th class="py-1">
@Model.Translation.Article
</th>
<th class="py-1 text-right">
@Model.Translation.Quantity
</th>
@if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Invoice
|| Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.BuyersOrder)
{
<th class="py-1 text-right">
@Model.Translation.Price
</th>
<th class="py-1 text-right">
@Model.Translation.Amount
</th>
}
else if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Order)
{
<th class="py-1">
@Model.Translation.Dimensions
</th>
}
</tr>
</thead>
<tbody style="font-size: 0.75rem">
@foreach (var item in Model.InvoiceItems)
{
<tr>
<td>
@(Model.InvoiceItems.IndexOf(item) + 1)
</td>
<td>
@Html.DisplayFor(x => item.Item.Title)
@if (Model.Invoice.Type != Models.Invoice.Invoice.InvoiceType.Order && !string.IsNullOrEmpty(item.ItemDescription))
{
<br/>
<small>
@Html.DisplayFor(x => item.ItemDescription)
</small>
}
@if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Invoice)
{
<br/>
<small>
@Model.Translation.DeliveryNote
<b>@Html.DisplayFor(x => item.InvoiceItemJoin.Invoice.InvoiceNumberFormatted)</b>
</small>
}
</td>
<td class="text-right">@Html.DisplayFor(x => item.Quantity)</td>
@if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Invoice
|| Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.BuyersOrder)
{
<td class="text-right">@Html.DisplayFor(x => item.Price)</td>
<td class="text-right">@Html.DisplayFor(x => item.TotalValue)</td>
}
else if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Order)
{
<td>@Html.DisplayFor(x => item.ItemDescription)</td>
}
</tr>
}
</tbody>
</table>
</div>
@if (Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.Invoice
|| Model.Invoice.Type == Models.Invoice.Invoice.InvoiceType.BuyersOrder)
{
<div class="mb-4">
@{
string total = Model.InvoiceItems.Sum(x => x.TotalValue).ToString("0.00");
}
<label>@Model.Translation.Total</label> <b>@total €</b>
</div>
}
<div style="font-size: 0.75rem">
@Html.Raw(HttpUtility.HtmlDecode(Model.Invoice.PostText))
</div>
@if (Model.Invoice.Type == Invoice.InvoiceType.DeliveryNote)
{
<div class="row pt-3" style="font-size: 0.85rem">
<div class="col-4">
<label>@Model.Translation.Issued</label> <br />__________________________
</div>
<div class="col-4"></div>
<div class="col-4">
<label>@Model.Translation.Received</label> <br />__________________________
</div>
</div>
}
else
{
<div class="row pt-3" style="font-size: 0.85rem">
<div class="col-4"></div>
<div class="col-4"></div>
<div class="col-4 text-center">
<label>@Model.Translation.Director</label> <br /> @Html.DisplayFor(modelItem => Model.Invoice.Company.Ceo)
</div>
</div>
}
<div style="display: none" id="footer1">@Html.DisplayFor(modelItem => Model.Invoice.Company.Title), @Html.DisplayFor(modelItem => Model.Invoice.Company.Street) @Html.DisplayFor(modelItem => Model.Invoice.Company.HouseNumber), @Html.DisplayFor(modelItem => Model.Invoice.Company.PostNumber) @Html.DisplayFor(modelItem => Model.Invoice.Company.Post), @Html.DisplayFor(modelItem => Model.Invoice.Company.Country.TranslationSlovenian); ID za DDV: @Html.DisplayFor(modelItem => Model.Invoice.Company.TaxNumber), E-pošta: @Html.DisplayFor(modelItem => Model.Invoice.Company.Email)</div>
<div style="display: none" id="footer2">Tel.: @Html.DisplayFor(modelItem => Model.Invoice.Company.Phone), @Html.DisplayFor(modelItem => Model.Invoice.Company.Bank); IBAN: @Html.DisplayFor(modelItem => Model.Invoice.Company.Iban); SWIFT/BIC: @Html.DisplayFor(modelItem => Model.Invoice.Company.SwiftBic)</div>
</div>
<div class="card-footer">
<div class="row">
<div class="col-6">
<select id="selTranslationLangue" asp-items="Html.GetEnumSelectList<PrintModel.PrintTranslationLanguage>()" class="form-control" style="width: 200px;">
</select>
<button id="btnTranslate" type="button" class="btn btn-success pull-right" data-style="zoom-out" onclick="setLanguage();return false;">Prevedi</button>
</div>
<div class="col-6 text-right">
@if (Model.Invoice.State == Models.Invoice.Invoice.InvoiceState.New)
{
<button id="btnPrintAndConfirm" type="button" class="btn btn-success btn-print ladda-button pull-right" data-style="zoom-out" data-confirm="true"><i class="ion ion-md-print"></i>&nbsp; Natisni in potrdi</button>
}
<button id="btnPrint" type="button" class="btn btn-primary btn-print ladda-button pull-right" data-style="zoom-out"><i class="ion ion-md-print"></i>&nbsp; Natisni</button>
</div>
</div>
</div>
</div>
@Html.AntiForgeryToken()
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<!-- PDF -->
<script src="~/vendor/libs/html2pdf.js/dist/html2pdf.bundle.min.js" asp-append-version="true"></script>
<script>
var laddaPrint = Ladda.create(document.querySelector('#btnPrint'));
var laddaPrintAndConfirm = document.querySelector('#btnPrintAndConfirm') == null ? null : Ladda.create(document.querySelector('#btnPrintAndConfirm'));
var element = document.getElementById('print-content');
var opt = {
//pagebreak: { mode: 'avoid-all' },
filename: 'nalog.pdf',
image: { type: 'png' },
enableLinks: false,
margin: [5, 0, 13, 0],
html2canvas: {
scale: 1.2,
scrollX: 0,
scrollY: 0,
dpi: 300,
letterRendering: true
},
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
};
function print(confirm) {
laddaPrint.start();
if (laddaPrintAndConfirm != null) {
laddaPrintAndConfirm.start();
}
html2pdf().set(opt).from(element).toPdf().get('pdf').then(function (pdf) {
var totalPages = pdf.internal.getNumberOfPages();
for (i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(8);
pdf.setTextColor(0);
var fontSize = pdf.internal.getFontSize();
var pageWidth = pdf.internal.pageSize.width;
var txt = $('#footer1').text();
var txtWidth = pdf.getStringUnitWidth(txt) * fontSize / pdf.internal.scaleFactor;
var x = (pageWidth - txtWidth) / 2;
pdf.text(x, pdf.internal.pageSize.getHeight() - 8, txt);
txt = $('#footer2').text();
txtWidth = pdf.getStringUnitWidth(txt) * fontSize / pdf.internal.scaleFactor;
x = (pageWidth - txtWidth) / 2;
pdf.text(x, pdf.internal.pageSize.getHeight() - 5, txt);
//pdf.addImage("YOUR_IMAGE", 'JPEG', pdf.internal.pageSize.getWidth() - 1.1, pdf.internal.pageSize.getHeight() - 0.25, 1, 0.2);
}
laddaPrint.stop();
if (laddaPrintAndConfirm != null) {
laddaPrintAndConfirm.stop();
}
//window.open(pdf.output('bloburl'), '_blank');
let link = document.createElement('a');
link.target = '_blank';
link.href = pdf.output('bloburl');
link.download = '@Model.Invoice.InvoiceNumberFull.Replace("-", "_")';
link.click();
link.remove();
if (confirm) {
confirmInvoice();
}
});
}
$(document).ready(function () {
//print();
});
$(".btn-print").click(function () {
print($(this).attr("data-confirm") === 'true');
});
function confirmInvoice() {
$.blockUI();
$.ajax({
type: "POST",
beforeSend: function(xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
url: "Print/?handler=ConfirmInvoice",
data: {
idInvoice : @Model.Invoice.IdInvoice
},
success: function(data) {
if (data.successful){
location.reload();
} else {
Swal.fire('Napaka pri potrjevanju dokumenta',
data.error,
'error');
}
$.unblockUI();
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr);
alert(xhr.responseText);
$.unblockUI();
}
});
}
function setLanguage() {
const language = $('#selTranslationLangue').val();
const idInvoice = @Model.Invoice.IdInvoice;
window.location.replace('/Invoices/Print?id=' + idInvoice + '&printTranslationLanguage=' + language);
}
</script>
}

View File

@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using EveryThing.Data;
using EveryThing.Models;
using EveryThing.Models.Invoice;
using EveryThing.Models.Transport;
using DocumentFormat.OpenXml.Wordprocessing;
using System.ComponentModel.DataAnnotations;
namespace EveryThing.Pages.Invoices
{
[Authorize(Roles = "Administrator,InvoicingUser,ProjecThingUser")]
public class PrintModel : PageModel
{
public class PrintTranslation
{
public string Email { get; set; } = "E-pošta";
public string Telephone { get; set; } = "Tel.";
public string IdTax { get; set; } = "ID za DDV";
public string Iban { get; set; } = "IBAN";
public string SwiftBic { get; set; } = "SWIFT/BIC";
public string InvoiceType { get; set; } = "Faktura";
public string Number { get; set; } = "št.";
public string Date { get; set; } = "Datum";
public string OrderNumber { get; set; } = "Številka naroèila";
public string DeliveryNote { get; set; } = "Številka dobavnice:";
public string DeliveryTime { get; set; } = "Dobavni rok";
public string DateOfDispatch { get; set; } = "Datum odpreme";
public string Article { get; set; } = "Artikel";
public string Quantity { get; set; } = "Kolièina";
public string Price { get; set; } = "Cena";
public string Amount { get; set; } = "Znesek";
public string Dimensions { get; set; } = "Dimenzije";
public string Total { get; set; } = "Skupaj";
public string Director { get; set; } = "Direktor";
public string Project { get; set; } = "Projekt";
public string Issued { get; set; } = "Izdal:";
public string Received { get; set; } = "Prejel:";
}
public enum PrintTranslationLanguage
{
[Display(Name = "Slovensko")]
Slovenian = 1,
[Display(Name = "Nemško")]
German = 2
}
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityApplicationUser> _userManager;
public Models.Invoice.Invoice Invoice { get; set; }
public PrintTranslation Translation { get; set; }
public IList<Models.Invoice.InvoiceItem> InvoiceItems { get; set; }
public string ProjectNumber { get; set; }
public PrintModel(ApplicationDbContext context, UserManager<IdentityApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task<IActionResult> OnGetAsync(int id, int? printTranslationLanguage)
{
var user = _userManager.GetUserAsync(User).Result;
Invoice = await _context.Invoices
.Include(x => x.Company)
.Include(x => x.Company.Country)
.Include(x => x.Partner)
.Include(x => x.Partner.Country)
.FirstOrDefaultAsync(x => x.IdInvoice == id && x.IdCompanyFk == user.IdCompanyFk);
if (Invoice != null)
{
InvoiceItems = await _context.InvoiceItems
.Where(x => x.IdInvoiceFk == Invoice.IdInvoice)
.Include(x => x.Item)
.Include(x => x.InvoiceItemJoin)
.ThenInclude(x => x.Invoice)
.ToListAsync();
var translationLanguage = PrintTranslationLanguage.Slovenian;
if (printTranslationLanguage != null)
translationLanguage = (PrintTranslationLanguage)printTranslationLanguage;
SetTranslation(translationLanguage, Invoice.State);
var showProjects = User.IsInRole("ProjecThingUser") || User.IsInRole("Administrator");
if (showProjects)
{
var project = _context.InvoiceItems
.Include(x => x.ProjectPartItem)
.ThenInclude(x => x.ProjectPart)
.ThenInclude(x => x.Project).FirstOrDefault(x => x.IdInvoiceFk == Invoice.IdInvoice);
if (project != null && project.ProjectPartItem != null)
ProjectNumber = project.ProjectPartItem.ProjectPart.Project.ProjectNumberFormatted;
}
return Page();
}
return NotFound();
}
public IActionResult OnPostConfirmInvoice(int idInvoice)
{
var user = _userManager.GetUserAsync(User).Result;
bool successful = true;
string error = "";
var invoice = _context.Invoices
.Where(x => x.IdCompanyFk == user.IdCompanyFk)
.FirstOrDefault(x => x.IdInvoice == idInvoice);
if (invoice != null)
{
invoice.State = Models.Invoice.Invoice.InvoiceState.Confirmed;
_context.SaveChanges();
}
else
{
successful = false;
error = $"Invoice with ID: {idInvoice} not found";
}
return new JsonResult(new { idInvoice = idInvoice, error = error, successful = successful });
}
private void SetTranslation(PrintTranslationLanguage printTranslationLanguage, Invoice.InvoiceState invoiceState)
{
Translation = new PrintTranslation();
switch (printTranslationLanguage)
{
case PrintTranslationLanguage.Slovenian:
switch(Invoice.Type)
{
case Invoice.InvoiceType.Order:
case Invoice.InvoiceType.BuyersOrder:
if (Invoice.State == Invoice.InvoiceState.Offer)
{
Translation.InvoiceType = "Ponudba";
}
else if (Invoice.State == Invoice.InvoiceState.Inquiry)
{
Translation.InvoiceType = "Povpraševanje";
}
else if (Invoice.State == Invoice.InvoiceState.OfferConfirmation)
{
Translation.InvoiceType = "Potrditev naroèila";
}
else
{
Translation.InvoiceType = "Naroèilo";
}
break;
case Invoice.InvoiceType.Invoice:
Translation.InvoiceType = "Raèun";
break;
case Invoice.InvoiceType.DeliveryNote:
Translation.InvoiceType = "Dobavnica";
break;
default:
Translation.InvoiceType = "Faktura";
break;
}
if (invoiceState == Invoice.InvoiceState.Offer)
Translation.OrderNumber = "Št. povpraševanja.";
break;
case PrintTranslationLanguage.German:
Translation = new PrintTranslation
{
Amount = "Menge",
Article = "Artikel",
Date = "Datum",
DateOfDispatch = "Lieferdatum",
DeliveryTime = "Lieferdatum",
Dimensions = "Maße",
Director = "Direktor",
Email = "Email",
Iban = "IBAN",
IdTax = "Ihre UID Nr.",
Number = "Num.",
OrderNumber = invoiceState == Invoice.InvoiceState.Offer ? "Anfrage No." : "Bestellnummer",
Price = "Preis(€)",
Quantity = "Menge(Stk)",
SwiftBic = "SWIFT/BIC",
Total = "Gesamtsumme",
Project = "Projekt",
Issued = "Bearbeiter:",
Received = "Empfänger:",
DeliveryNote = "Lieferschein:"
};
switch (Invoice.Type)
{
case Invoice.InvoiceType.Order:
case Invoice.InvoiceType.BuyersOrder:
if (Invoice.State == Invoice.InvoiceState.Offer)
{
Translation.InvoiceType = "Angebot";
}
else if (Invoice.State == Invoice.InvoiceState.Inquiry)
{
Translation.InvoiceType = "Anfrage";
}
else if (Invoice.State == Invoice.InvoiceState.OfferConfirmation)
{
Translation.InvoiceType = "Auftragsbestätigung";
}
else
{
Translation.InvoiceType = "Bestellung";
}
break;
case Invoice.InvoiceType.Invoice:
Translation.InvoiceType = "Rechnung";
break;
case Invoice.InvoiceType.DeliveryNote:
Translation.InvoiceType = "Lieferschein";
break;
default:
Translation.InvoiceType = "Faktura";
break;
}
break;
}
}
}
}