Compare commits
13 Commits
3414400efe
...
8953e917e1
| Author | SHA1 | Date | |
|---|---|---|---|
| 8953e917e1 | |||
| 6e14130a9c | |||
| f01f05e126 | |||
|
|
c1695b4967 | ||
|
|
205d27c6c7 | ||
|
|
03594bba3f | ||
|
|
2e537337f5 | ||
|
|
9497afe262 | ||
|
|
6df185d519 | ||
|
|
97688542fe | ||
|
|
236eb6792c | ||
|
|
d02414edbb | ||
| be0350f458 |
@@ -20,4 +20,8 @@
|
|||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Pos.ServiceDefaults\Pos.ServiceDefaults.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.AddServiceDefaults();
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
@@ -13,6 +15,8 @@ builder.Services.AddScoped<EpsonPrintService>();
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.MapDefaultEndpoints();
|
||||||
|
|
||||||
// Swagger (altid aktiv – vi er på en Pi, ikke i produktion)
|
// Swagger (altid aktiv – vi er på en Pi, ikke i produktion)
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
},
|
},
|
||||||
"EpsonPrinter": {
|
"EpsonPrinter": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": "true",
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
|||||||
@@ -10,3 +10,9 @@ Buket..............1 á 50,50 DKK : 50,50 DKK
|
|||||||
Total: 50,50 DKK
|
Total: 50,50 DKK
|
||||||
Moms udgør 25% : 12,63 DKK
|
Moms udgør 25% : 12,63 DKK
|
||||||
Tak for handlen
|
Tak for handlen
|
||||||
|
Dato: 30-07-2026
|
||||||
|
-----------------------------------
|
||||||
|
string : .00
|
||||||
|
-----------------------------------
|
||||||
|
Total salg: .00
|
||||||
|
Antal kunder: 0
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
var builder = DistributedApplication.CreateBuilder(args);
|
var builder = DistributedApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.AddProject<Projects.Database>("database");
|
var epsonPrinter =
|
||||||
|
builder.AddProject<Projects.EpsonPrinter>("epsonprinter");
|
||||||
|
|
||||||
|
builder
|
||||||
|
.AddProject<Projects.Pos_Web>("pos-web")
|
||||||
|
.WithReference(epsonPrinter)
|
||||||
|
.WaitFor(epsonPrinter);
|
||||||
|
|
||||||
builder.Build().Run();
|
builder.Build().Run();
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Pos.Ui\Database\Database.csproj" />
|
<ProjectReference Include="..\EpsonPrinterLinux\EpsonPrinter.csproj" />
|
||||||
|
<ProjectReference Include="..\Pos.Web\Pos.Web.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ namespace Pos.Models
|
|||||||
{
|
{
|
||||||
public class AmountGridModel
|
public class AmountGridModel
|
||||||
{
|
{
|
||||||
public string PaymentMethodText { get; set; }
|
public string PaymentMethodText { get; set; } = string.Empty;
|
||||||
public decimal Amount { get; set; }
|
public decimal Amount { get; set; }
|
||||||
public string AmountText { get; set; }
|
public string AmountText { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,4 @@ public enum PaymentMethod
|
|||||||
Card,
|
Card,
|
||||||
GiftCard,
|
GiftCard,
|
||||||
MobilePay
|
MobilePay
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,11 @@ namespace Pos.Json
|
|||||||
{
|
{
|
||||||
public class BodyModel
|
public class BodyModel
|
||||||
{
|
{
|
||||||
public ProductModel[] products { get; set; }
|
public ProductModel[] products { get; set; } = Array.Empty<ProductModel>();
|
||||||
public float totalPrice { get; set; }
|
public float totalPrice { get; set; }
|
||||||
public float totalVat { get; set; }
|
public float totalVat { get; set; }
|
||||||
public int receiptNumber { get; set; }
|
public int receiptNumber { get; set; }
|
||||||
public string receiptTime { get; set; }
|
public string receiptTime { get; set; } = string.Empty;
|
||||||
public string staff { get; set; }
|
public string staff { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ namespace Pos.Json
|
|||||||
{
|
{
|
||||||
public class FooterModel
|
public class FooterModel
|
||||||
{
|
{
|
||||||
public string value { get; set; }
|
public string value { get; set; } = string.Empty;
|
||||||
public PrintStylesModel printStyles { get; set; }
|
public PrintStylesModel printStyles { get; set; } = new();
|
||||||
public int textAlignment { get; set; }
|
public int textAlignment { get; set; }
|
||||||
public int feedingLines { get; set; }
|
public int feedingLines { get; set; }
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ namespace Pos.Json
|
|||||||
{
|
{
|
||||||
public class HeaderModel
|
public class HeaderModel
|
||||||
{
|
{
|
||||||
public string value { get; set; }
|
public string value { get; set; } = string.Empty;
|
||||||
public PrintStylesModel printStyles { get; set; }
|
public PrintStylesModel printStyles { get; set; } = new();
|
||||||
public int textAlignment { get; set; }
|
public int textAlignment { get; set; }
|
||||||
public int feedingLines { get; set; }
|
public int feedingLines { get; set; }
|
||||||
}
|
}
|
||||||
@@ -8,9 +8,9 @@ namespace Pos.Json
|
|||||||
{
|
{
|
||||||
public class PosReceipt
|
public class PosReceipt
|
||||||
{
|
{
|
||||||
public string logoBase64 { get; set; }
|
public string logoBase64 { get; set; } = string.Empty;
|
||||||
public HeaderModel[] header { get; set; }
|
public HeaderModel[] header { get; set; } = Array.Empty<HeaderModel>();
|
||||||
public BodyModel bodyModel { get; set; } = new();
|
public BodyModel bodyModel { get; set; } = new();
|
||||||
public FooterModel[] footer { get; set; }
|
public FooterModel[] footer { get; set; } = Array.Empty<FooterModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ namespace Pos.Json
|
|||||||
{
|
{
|
||||||
public class ProductModel
|
public class ProductModel
|
||||||
{
|
{
|
||||||
public string product { get; set; }
|
public string product { get; set; } = string.Empty;
|
||||||
public string noOfProduct { get; set; }
|
public string noOfProduct { get; set; } = string.Empty;
|
||||||
public float price { get; set; }
|
public float price { get; set; }
|
||||||
public float totalPrice { get; set; }
|
public float totalPrice { get; set; }
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ namespace Pos.Json
|
|||||||
|
|
||||||
public class SaleOfDayDetail
|
public class SaleOfDayDetail
|
||||||
{
|
{
|
||||||
public string Category { get; set; }
|
public string Category { get; set; } = string.Empty;
|
||||||
public decimal TotalSale { get; set; }
|
public decimal TotalSale { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
PointOfSale/Pos.Models/Pos.Models.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -8,7 +8,7 @@ namespace Pos.Models
|
|||||||
{
|
{
|
||||||
public class PriceLineModel
|
public class PriceLineModel
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; } = string.Empty;
|
||||||
public int NumberProducts { get; set; }
|
public int NumberProducts { get; set; }
|
||||||
public decimal Price { get; set; }
|
public decimal Price { get; set; }
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
11
PointOfSale/Pos.Models/ReceiptDetailModel.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Pos.Models
|
||||||
|
{
|
||||||
|
public class ReceiptDetailModel
|
||||||
|
{
|
||||||
|
public int SaleId { get; set; }
|
||||||
|
public List<ReceiptLineModel> Lines { get; set; } = new();
|
||||||
|
public decimal Total { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
PointOfSale/Pos.Models/ReceiptLineModel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Pos.Models
|
||||||
|
{
|
||||||
|
public class ReceiptLineModel
|
||||||
|
{
|
||||||
|
public string Product { get; set; } = string.Empty;
|
||||||
|
public int Pieces { get; set; }
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
public decimal Total { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
PointOfSale/Pos.Models/ReceiptSummaryModel.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Pos.Models
|
||||||
|
{
|
||||||
|
public class ReceiptSummaryModel
|
||||||
|
{
|
||||||
|
public int SaleId { get; set; }
|
||||||
|
public DateTime SaleTime { get; set; }
|
||||||
|
public decimal Total { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,10 +8,10 @@ namespace Pos.Models
|
|||||||
{
|
{
|
||||||
public class SaleGridModel
|
public class SaleGridModel
|
||||||
{
|
{
|
||||||
public string Navn { get; set; }
|
public string Navn { get; set; } = string.Empty;
|
||||||
public string Stk { get; set; }
|
public string Stk { get; set; } = string.Empty;
|
||||||
public string Pris { get; set; }
|
public string Pris { get; set; } = string.Empty;
|
||||||
public string Total { get; set; }
|
public string Total { get; set; } = string.Empty;
|
||||||
public SaleGridInternalModel SaleGridInternalModel { get; set; }
|
public SaleGridInternalModel SaleGridInternalModel { get; set; } = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ namespace Pos.Models
|
|||||||
{
|
{
|
||||||
public class TotalSaleCategory
|
public class TotalSaleCategory
|
||||||
{
|
{
|
||||||
public string Category { get; set; }
|
public string Category { get; set; } = string.Empty;
|
||||||
public decimal Sale { get; set; }
|
public decimal Sale { get; set; }
|
||||||
public string SaleString { get; set; }
|
public string SaleString { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,8 @@ namespace Pos.Service
|
|||||||
|
|
||||||
private static bool _invalidEmployee = false;
|
private static bool _invalidEmployee = false;
|
||||||
private static bool _invalidProductGroup = false;
|
private static bool _invalidProductGroup = false;
|
||||||
private static List<EmployeeEntity> _employees;
|
private static List<EmployeeEntity> _employees = new();
|
||||||
private static List<ProductGroupEntity> _productGroups;
|
private static List<ProductGroupEntity> _productGroups = new();
|
||||||
|
|
||||||
|
|
||||||
public static void Invalidate()
|
public static void Invalidate()
|
||||||
67
PointOfSale/Pos.Service/EmployeeService.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Database.Models;
|
||||||
|
using Database.Repository;
|
||||||
|
|
||||||
|
namespace Pos.Service
|
||||||
|
{
|
||||||
|
public class EmployeeService
|
||||||
|
{
|
||||||
|
private readonly EmployeeRepository _employeeRepository =
|
||||||
|
new EmployeeRepository();
|
||||||
|
|
||||||
|
public List<EmployeeEntity> GetEmployees()
|
||||||
|
{
|
||||||
|
return _employeeRepository.GetAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEmployee(string name)
|
||||||
|
{
|
||||||
|
_employeeRepository.Add(ValidateName(name));
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenameEmployee(int employeeId, string name)
|
||||||
|
{
|
||||||
|
ValidateId(employeeId);
|
||||||
|
_employeeRepository.Edit(employeeId, ValidateName(name));
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ArchiveEmployee(int employeeId)
|
||||||
|
{
|
||||||
|
ValidateId(employeeId);
|
||||||
|
_employeeRepository.Delete(employeeId);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ValidateName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Medarbejderens navn skal være udfyldt.",
|
||||||
|
nameof(name));
|
||||||
|
|
||||||
|
return name.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateId(int employeeId)
|
||||||
|
{
|
||||||
|
if (employeeId <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(employeeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<EmployeeEntity>> GetEmployeesAsync()
|
||||||
|
{
|
||||||
|
return await _employeeRepository.GetAllAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EmployeeEntity> AddEmployeeAsync(string name)
|
||||||
|
{
|
||||||
|
EmployeeEntity employee =
|
||||||
|
await _employeeRepository.AddAsync(ValidateName(name));
|
||||||
|
CacheService.Invalidate();
|
||||||
|
return employee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
PointOfSale/Pos.Service/Pos.Service.csproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.10" />
|
||||||
|
<PackageReference Include="RestSharp" Version="108.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Pos.Models\Pos.Models.csproj" />
|
||||||
|
<ProjectReference Include="..\Pos.Ui\Database\Database.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
85
PointOfSale/Pos.Service/ProductGroupService.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Database.Models;
|
||||||
|
using Database.Repository;
|
||||||
|
|
||||||
|
namespace Pos.Service
|
||||||
|
{
|
||||||
|
public class ProductGroupService
|
||||||
|
{
|
||||||
|
private readonly ProductGroupRepository _productGroupRepository =
|
||||||
|
new ProductGroupRepository();
|
||||||
|
|
||||||
|
public List<ProductGroupEntity> GetProductGroups()
|
||||||
|
{
|
||||||
|
return _productGroupRepository.GetAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasProductGroups()
|
||||||
|
{
|
||||||
|
return _productGroupRepository.Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddProductGroup(string name)
|
||||||
|
{
|
||||||
|
_productGroupRepository.Add(ValidateName(name));
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenameProductGroup(int productGroupId, string name)
|
||||||
|
{
|
||||||
|
ValidateId(productGroupId);
|
||||||
|
_productGroupRepository.Edit(
|
||||||
|
ValidateName(name),
|
||||||
|
productGroupId);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ArchiveProductGroup(int productGroupId)
|
||||||
|
{
|
||||||
|
ValidateId(productGroupId);
|
||||||
|
_productGroupRepository.Archive(productGroupId);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOrder(IReadOnlyList<int> orderedProductGroupIds)
|
||||||
|
{
|
||||||
|
ValidateOrder(orderedProductGroupIds);
|
||||||
|
_productGroupRepository.SetOrder(orderedProductGroupIds);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ValidateName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Produktgruppen skal have et navn.",
|
||||||
|
nameof(name));
|
||||||
|
|
||||||
|
return name.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateId(int productGroupId)
|
||||||
|
{
|
||||||
|
if (productGroupId <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(productGroupId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateOrder(IReadOnlyList<int> orderedIds)
|
||||||
|
{
|
||||||
|
if (orderedIds == null)
|
||||||
|
throw new ArgumentNullException(nameof(orderedIds));
|
||||||
|
|
||||||
|
if (orderedIds.Any(id => id <= 0))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Rækkefølgen indeholder et ugyldigt id.",
|
||||||
|
nameof(orderedIds));
|
||||||
|
|
||||||
|
if (orderedIds.Distinct().Count() != orderedIds.Count)
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Rækkefølgen indeholder dubletter.",
|
||||||
|
nameof(orderedIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
PointOfSale/Pos.Service/ProductService.cs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Database.Models;
|
||||||
|
using Database.Repository;
|
||||||
|
|
||||||
|
namespace Pos.Service
|
||||||
|
{
|
||||||
|
public class ProductService
|
||||||
|
{
|
||||||
|
private readonly ProductRepository _productRepository =
|
||||||
|
new ProductRepository();
|
||||||
|
|
||||||
|
public List<ProductEntity> GetProducts(int productGroupId)
|
||||||
|
{
|
||||||
|
ValidateId(productGroupId, nameof(productGroupId));
|
||||||
|
return _productRepository.GetByProductGroup(productGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductEntity GetProduct(int productId)
|
||||||
|
{
|
||||||
|
ValidateId(productId, nameof(productId));
|
||||||
|
return _productRepository.GetById(productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddProduct(string name, int productGroupId)
|
||||||
|
{
|
||||||
|
ValidateId(productGroupId, nameof(productGroupId));
|
||||||
|
_productRepository.Add(ValidateName(name), productGroupId);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateProduct(
|
||||||
|
int productId,
|
||||||
|
int productGroupId,
|
||||||
|
string name)
|
||||||
|
{
|
||||||
|
ValidateId(productId, nameof(productId));
|
||||||
|
ValidateId(productGroupId, nameof(productGroupId));
|
||||||
|
_productRepository.Update(
|
||||||
|
productId,
|
||||||
|
productGroupId,
|
||||||
|
ValidateName(name));
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ArchiveProduct(int productId)
|
||||||
|
{
|
||||||
|
ValidateId(productId, nameof(productId));
|
||||||
|
_productRepository.Archive(productId);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOrder(
|
||||||
|
int productGroupId,
|
||||||
|
IReadOnlyList<int> orderedProductIds)
|
||||||
|
{
|
||||||
|
ValidateId(productGroupId, nameof(productGroupId));
|
||||||
|
|
||||||
|
if (orderedProductIds == null)
|
||||||
|
throw new ArgumentNullException(nameof(orderedProductIds));
|
||||||
|
|
||||||
|
if (orderedProductIds.Any(id => id <= 0))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Rækkefølgen indeholder et ugyldigt id.",
|
||||||
|
nameof(orderedProductIds));
|
||||||
|
|
||||||
|
if (orderedProductIds.Distinct().Count() != orderedProductIds.Count)
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Rækkefølgen indeholder dubletter.",
|
||||||
|
nameof(orderedProductIds));
|
||||||
|
|
||||||
|
_productRepository.SetOrder(
|
||||||
|
productGroupId,
|
||||||
|
orderedProductIds);
|
||||||
|
CacheService.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ValidateName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Produktet skal have et navn.",
|
||||||
|
nameof(name));
|
||||||
|
|
||||||
|
return name.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateId(int id, string parameterName)
|
||||||
|
{
|
||||||
|
if (id <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(parameterName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
PointOfSale/Pos.Service/SaleHistoryService.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Database.Models;
|
||||||
|
using Database.Repository;
|
||||||
|
using Pos.Models;
|
||||||
|
|
||||||
|
namespace Pos.Service
|
||||||
|
{
|
||||||
|
public class SaleHistoryService
|
||||||
|
{
|
||||||
|
private readonly SaleRepository _saleRepository =
|
||||||
|
new SaleRepository();
|
||||||
|
|
||||||
|
public List<ReceiptSummaryModel> Search(
|
||||||
|
DateTime startDate,
|
||||||
|
DateTime endDate)
|
||||||
|
{
|
||||||
|
if (endDate.Date < startDate.Date)
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Slutdatoen må ikke ligge før startdatoen.");
|
||||||
|
|
||||||
|
List<SaleEntity> sales =
|
||||||
|
_saleRepository.GetByDateRange(startDate, endDate);
|
||||||
|
|
||||||
|
List<ReceiptSummaryModel> receipts =
|
||||||
|
new List<ReceiptSummaryModel>();
|
||||||
|
|
||||||
|
foreach (SaleEntity sale in sales)
|
||||||
|
{
|
||||||
|
decimal total = _saleRepository
|
||||||
|
.GetSaleLineBySaleId(sale.Id)
|
||||||
|
.Sum(line => line.Total);
|
||||||
|
|
||||||
|
receipts.Add(new ReceiptSummaryModel
|
||||||
|
{
|
||||||
|
SaleId = sale.Id,
|
||||||
|
SaleTime = sale.Time,
|
||||||
|
Total = total
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return receipts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReceiptDetailModel GetReceipt(int saleId)
|
||||||
|
{
|
||||||
|
if (saleId <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(saleId));
|
||||||
|
|
||||||
|
List<SaleLineEntity> saleLines =
|
||||||
|
_saleRepository.GetSaleLineBySaleId(saleId);
|
||||||
|
|
||||||
|
ReceiptDetailModel receipt = new ReceiptDetailModel
|
||||||
|
{
|
||||||
|
SaleId = saleId
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (SaleLineEntity saleLine in saleLines)
|
||||||
|
{
|
||||||
|
receipt.Lines.Add(new ReceiptLineModel
|
||||||
|
{
|
||||||
|
Product = saleLine.Product,
|
||||||
|
Pieces = saleLine.Pieces,
|
||||||
|
Price = saleLine.Price,
|
||||||
|
Total = saleLine.Total
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
receipt.Total = receipt.Lines.Sum(line => line.Total);
|
||||||
|
return receipt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,7 +84,9 @@ namespace Pos.Service
|
|||||||
|
|
||||||
LoadConfig loadConfig = new LoadConfig();
|
LoadConfig loadConfig = new LoadConfig();
|
||||||
IConfiguration config = loadConfig.ByEnvironment();
|
IConfiguration config = loadConfig.ByEnvironment();
|
||||||
string url = config["API:URL"];
|
string url = config["API:URL"]
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"API:URL mangler i konfigurationen.");
|
||||||
|
|
||||||
RestClient restClient = new RestClient($"{url}/api/PosPrinter/SaleOfDay");
|
RestClient restClient = new RestClient($"{url}/api/PosPrinter/SaleOfDay");
|
||||||
RestRequest request = new RestRequest();
|
RestRequest request = new RestRequest();
|
||||||
@@ -159,7 +161,9 @@ namespace Pos.Service
|
|||||||
|
|
||||||
LoadConfig loadConfig = new LoadConfig();
|
LoadConfig loadConfig = new LoadConfig();
|
||||||
IConfiguration config = loadConfig.ByEnvironment();
|
IConfiguration config = loadConfig.ByEnvironment();
|
||||||
string apiUrl = config["API:URL"];
|
string apiUrl = config["API:URL"]
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"API:URL mangler i konfigurationen.");
|
||||||
string url = $"{apiUrl}/api/PosPrinter/Receipt";
|
string url = $"{apiUrl}/api/PosPrinter/Receipt";
|
||||||
|
|
||||||
RestClient restClient = new RestClient(url);
|
RestClient restClient = new RestClient(url);
|
||||||
171
PointOfSale/Pos.Service/SalesTransactionService.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Pos.Models;
|
||||||
|
|
||||||
|
namespace Pos.Service
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holder styr på den igangværende handel og dens beregninger.
|
||||||
|
/// Servicen har ingen afhængighed til WPF eller web.
|
||||||
|
/// </summary>
|
||||||
|
public class SalesTransactionService
|
||||||
|
{
|
||||||
|
private readonly List<PriceLineModel> _saleLines = new List<PriceLineModel>();
|
||||||
|
private readonly List<AmountGridModel> _payments = new List<AmountGridModel>();
|
||||||
|
|
||||||
|
public IReadOnlyList<PriceLineModel> SaleLines => _saleLines;
|
||||||
|
public IReadOnlyList<AmountGridModel> Payments => _payments;
|
||||||
|
|
||||||
|
public decimal TotalPrice =>
|
||||||
|
_saleLines.Sum(line =>
|
||||||
|
CalculateLineTotal(line.Price, line.NumberProducts));
|
||||||
|
|
||||||
|
public decimal AmountPaid =>
|
||||||
|
_payments.Sum(payment => payment.Amount);
|
||||||
|
|
||||||
|
public decimal RemainingAmount =>
|
||||||
|
Math.Max(TotalPrice - AmountPaid, 0);
|
||||||
|
|
||||||
|
public decimal Change =>
|
||||||
|
Math.Max(AmountPaid - TotalPrice, 0);
|
||||||
|
|
||||||
|
public bool IsFullyPaid =>
|
||||||
|
TotalPrice > 0 && AmountPaid >= TotalPrice;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Beregner totalen for en enkelt salgslinje.
|
||||||
|
/// Parsing og visning af resultatet er fortsat UI-ansvar.
|
||||||
|
/// </summary>
|
||||||
|
public decimal CalculateLineTotal(decimal price, int numberOfProducts)
|
||||||
|
{
|
||||||
|
ValidatePriceAndQuantity(price, numberOfProducts);
|
||||||
|
return price * numberOfProducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PriceLineModel AddSaleLine(
|
||||||
|
int id,
|
||||||
|
string name,
|
||||||
|
int numberOfProducts,
|
||||||
|
decimal price,
|
||||||
|
bool isProductGroup)
|
||||||
|
{
|
||||||
|
if (id <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(id),
|
||||||
|
"Id skal være større end 0.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
throw new ArgumentException(
|
||||||
|
"Navn skal være udfyldt.",
|
||||||
|
nameof(name));
|
||||||
|
|
||||||
|
ValidatePriceAndQuantity(price, numberOfProducts);
|
||||||
|
|
||||||
|
PriceLineModel saleLine = new PriceLineModel
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Name = name,
|
||||||
|
NumberProducts = numberOfProducts,
|
||||||
|
Price = price,
|
||||||
|
IsProductGroup = isProductGroup
|
||||||
|
};
|
||||||
|
|
||||||
|
_saleLines.Add(saleLine);
|
||||||
|
return saleLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSaleLineAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= _saleLines.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
_saleLines.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registrerer en betaling. Hvis amount er null, betales restbeløbet.
|
||||||
|
/// </summary>
|
||||||
|
public AmountGridModel AddPayment(
|
||||||
|
PaymentMethod paymentMethod,
|
||||||
|
decimal? amount = null)
|
||||||
|
{
|
||||||
|
if (_saleLines.Count == 0)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Der kan ikke registreres betaling på et tomt salg.");
|
||||||
|
|
||||||
|
decimal paymentAmount = amount ?? RemainingAmount;
|
||||||
|
|
||||||
|
if (paymentAmount <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(amount),
|
||||||
|
"Betalingsbeløbet skal være større end 0.");
|
||||||
|
|
||||||
|
AmountGridModel payment = new AmountGridModel
|
||||||
|
{
|
||||||
|
Amount = paymentAmount,
|
||||||
|
PaymentMethodText = GetPaymentMethodText(paymentMethod)
|
||||||
|
};
|
||||||
|
|
||||||
|
_payments.Add(payment);
|
||||||
|
return payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePaymentAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= _payments.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
_payments.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnsureCanComplete()
|
||||||
|
{
|
||||||
|
if (_saleLines.Count == 0)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Et tomt salg kan ikke afsluttes.");
|
||||||
|
|
||||||
|
if (!IsFullyPaid)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Salget er ikke fuldt betalt.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_saleLines.Clear();
|
||||||
|
_payments.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidatePriceAndQuantity(
|
||||||
|
decimal price,
|
||||||
|
int numberOfProducts)
|
||||||
|
{
|
||||||
|
if (price < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(price),
|
||||||
|
"Prisen må ikke være negativ.");
|
||||||
|
|
||||||
|
if (numberOfProducts <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(numberOfProducts),
|
||||||
|
"Antal skal være større end 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPaymentMethodText(PaymentMethod paymentMethod)
|
||||||
|
{
|
||||||
|
switch (paymentMethod)
|
||||||
|
{
|
||||||
|
case PaymentMethod.Card:
|
||||||
|
return "Kort";
|
||||||
|
case PaymentMethod.Cash:
|
||||||
|
return "Kontant";
|
||||||
|
case PaymentMethod.GiftCard:
|
||||||
|
return "Gavekort";
|
||||||
|
case PaymentMethod.MobilePay:
|
||||||
|
return "MobilePay";
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(paymentMethod));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsAspireSharedProject>true</IsAspireSharedProject>
|
<IsAspireSharedProject>true</IsAspireSharedProject>
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ namespace Database
|
|||||||
public DbSet<SaleLineEntity> SalesLines { get; set; }
|
public DbSet<SaleLineEntity> SalesLines { get; set; }
|
||||||
public DbSet<PaymentEntity> Payment { get; set; }
|
public DbSet<PaymentEntity> Payment { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<SaleLineEntity>()
|
||||||
|
.Property(saleLine => saleLine.Pieces)
|
||||||
|
.HasConversion<short>()
|
||||||
|
.HasColumnType("smallint");
|
||||||
|
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(
|
protected override void OnConfiguring(
|
||||||
DbContextOptionsBuilder optionsBuilder)
|
DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using Database.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Database.Models;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace Database.Repository
|
namespace Database.Repository
|
||||||
{
|
{
|
||||||
@@ -58,5 +59,32 @@ namespace Database.Repository
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<EmployeeEntity>> GetAllAsync()
|
||||||
|
{
|
||||||
|
await using PosDbContext context = new PosDbContext();
|
||||||
|
|
||||||
|
return await context.Employee
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(employee => !employee.IsArchived)
|
||||||
|
.OrderBy(employee => employee.Name)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EmployeeEntity> AddAsync(string name)
|
||||||
|
{
|
||||||
|
EmployeeEntity employee = new EmployeeEntity
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
IsModified = true
|
||||||
|
};
|
||||||
|
|
||||||
|
await using PosDbContext context = new PosDbContext();
|
||||||
|
|
||||||
|
context.Employee.Add(employee);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return employee;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,10 +69,30 @@ namespace Database.Repository
|
|||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetOrder(IReadOnlyList<int> orderedIds)
|
||||||
|
{
|
||||||
|
using PosDbContext context = new PosDbContext();
|
||||||
|
List<ProductGroupEntity> productGroups = context.ProductGroups
|
||||||
|
.Where(productGroup => orderedIds.Contains(productGroup.Id))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (productGroups.Count != orderedIds.Count)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"En eller flere produktgrupper findes ikke.");
|
||||||
|
|
||||||
|
Dictionary<int, ProductGroupEntity> productGroupsById =
|
||||||
|
productGroups.ToDictionary(productGroup => productGroup.Id);
|
||||||
|
|
||||||
|
for (int index = 0; index < orderedIds.Count; index++)
|
||||||
|
productGroupsById[orderedIds[index]].Index = index;
|
||||||
|
|
||||||
|
context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
public bool Any()
|
public bool Any()
|
||||||
{
|
{
|
||||||
using PosDbContext context = new PosDbContext();
|
using PosDbContext context = new PosDbContext();
|
||||||
bool any = context.ProductGroups.Any();
|
bool any = context.ProductGroups.Any(c => !c.IsArchived);
|
||||||
return any;
|
return any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Database.Models;
|
using Database.Models;
|
||||||
|
|
||||||
@@ -38,6 +39,33 @@ namespace Database.Repository
|
|||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetOrder(
|
||||||
|
int productGroupId,
|
||||||
|
IReadOnlyList<int> orderedIds)
|
||||||
|
{
|
||||||
|
using PosDbContext context = new PosDbContext();
|
||||||
|
List<ProductEntity> products = context.Products
|
||||||
|
.Where(product => product.ProductGroupId == productGroupId)
|
||||||
|
.Where(product => orderedIds.Contains(product.Id))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (products.Count != orderedIds.Count)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Et eller flere produkter findes ikke i produktgruppen.");
|
||||||
|
|
||||||
|
Dictionary<int, ProductEntity> productsById =
|
||||||
|
products.ToDictionary(product => product.Id);
|
||||||
|
|
||||||
|
for (int index = 0; index < orderedIds.Count; index++)
|
||||||
|
{
|
||||||
|
ProductEntity product = productsById[orderedIds[index]];
|
||||||
|
product.Index = index;
|
||||||
|
product.IsModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
public ProductEntity GetById(int id)
|
public ProductEntity GetById(int id)
|
||||||
{
|
{
|
||||||
using PosDbContext context = new PosDbContext();
|
using PosDbContext context = new PosDbContext();
|
||||||
@@ -72,7 +100,11 @@ namespace Database.Repository
|
|||||||
product.ProductGroupId = productGroupId;
|
product.ProductGroupId = productGroupId;
|
||||||
using PosDbContext context = new PosDbContext();
|
using PosDbContext context = new PosDbContext();
|
||||||
//Get the highest index
|
//Get the highest index
|
||||||
ProductEntity highest = context.Products.OrderByDescending(c => c.Index).Take(1).FirstOrDefault();
|
ProductEntity highest = context.Products
|
||||||
|
.Where(c => c.ProductGroupId == productGroupId)
|
||||||
|
.OrderByDescending(c => c.Index)
|
||||||
|
.Take(1)
|
||||||
|
.FirstOrDefault();
|
||||||
if (highest == null)
|
if (highest == null)
|
||||||
{
|
{
|
||||||
highest = new ProductEntity();
|
highest = new ProductEntity();
|
||||||
|
|||||||
@@ -18,12 +18,10 @@
|
|||||||
<None Remove="Icons\settings.png" />
|
<None Remove="Icons\settings.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="RestSharp" Version="108.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Database\Database.csproj" />
|
<ProjectReference Include="..\Database\Database.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Pos.Models\Pos.Models.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Pos.Service\Pos.Service.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Models;
|
using Pos.Models;
|
||||||
using Database.Repository;
|
|
||||||
using Pos.Service;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos
|
namespace Pos
|
||||||
@@ -25,6 +24,9 @@ namespace Pos
|
|||||||
private List<ListReceiptModel> _receiptList = new List<ListReceiptModel>();
|
private List<ListReceiptModel> _receiptList = new List<ListReceiptModel>();
|
||||||
private bool _init = false;
|
private bool _init = false;
|
||||||
private int _saleId = 0;
|
private int _saleId = 0;
|
||||||
|
private readonly SaleHistoryService _saleHistoryService =
|
||||||
|
new SaleHistoryService();
|
||||||
|
private readonly SaleService _saleService = new SaleService();
|
||||||
|
|
||||||
public PrintReceiptWindow()
|
public PrintReceiptWindow()
|
||||||
{
|
{
|
||||||
@@ -38,28 +40,39 @@ namespace Pos
|
|||||||
|
|
||||||
private void Search_OnClick(object sender, RoutedEventArgs e)
|
private void Search_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
DateTime startDate = (DateTime)StartDatePicker.SelectedDate;
|
if (StartDatePicker.SelectedDate is not DateTime startDate ||
|
||||||
DateTime endDate = (DateTime)EndDatePicker.SelectedDate;
|
EndDatePicker.SelectedDate is not DateTime endDate)
|
||||||
SaleRepository saleRepository = new SaleRepository();
|
return;
|
||||||
List<SaleEntity> saleEntities = saleRepository.GetByDateRange(startDate, endDate);
|
|
||||||
foreach (SaleEntity entity in saleEntities)
|
|
||||||
{
|
|
||||||
List<SaleLineEntity> saleLineBySaleId = saleRepository.GetSaleLineBySaleId(entity.Id);
|
|
||||||
decimal total = 0;
|
|
||||||
foreach (SaleLineEntity lineEntity in saleLineBySaleId)
|
|
||||||
{
|
|
||||||
total += lineEntity.Total;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
List<ReceiptSummaryModel> receipts;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
receipts = _saleHistoryService.Search(startDate, endDate);
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldigt datointerval",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_receiptList.Clear();
|
||||||
|
foreach (ReceiptSummaryModel receipt in receipts)
|
||||||
|
{
|
||||||
ListReceiptModel receiptModel = new ListReceiptModel
|
ListReceiptModel receiptModel = new ListReceiptModel
|
||||||
{
|
{
|
||||||
Id = entity.Id,
|
Id = receipt.SaleId,
|
||||||
Content = $"{entity.Time:dd-MM-yyyy HH:mm} - Pris: {total:0.00}"
|
Content =
|
||||||
|
$"{receipt.SaleTime:dd-MM-yyyy HH:mm} - Pris: {receipt.Total:0.00}"
|
||||||
};
|
};
|
||||||
_receiptList.Add(receiptModel);
|
_receiptList.Add(receiptModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
_init = true;
|
_init = true;
|
||||||
|
ListReciept.ItemsSource = null;
|
||||||
ListReciept.ItemsSource = _receiptList;
|
ListReciept.ItemsSource = _receiptList;
|
||||||
_init = false;
|
_init = false;
|
||||||
}
|
}
|
||||||
@@ -78,23 +91,21 @@ namespace Pos
|
|||||||
|
|
||||||
private void ListReciept_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void ListReciept_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_init)
|
if (_init || e.AddedItems.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ListReceiptModel data = (ListReceiptModel) e.AddedItems[0];
|
ListReceiptModel data = (ListReceiptModel) e.AddedItems[0];
|
||||||
_saleId = data.Id;
|
_saleId = data.Id;
|
||||||
SaleRepository saleRepository = new SaleRepository();
|
ReceiptDetailModel receipt =
|
||||||
List<SaleLineEntity> saleLineBySaleId = saleRepository.GetSaleLineBySaleId(data.Id);
|
_saleHistoryService.GetReceipt(data.Id);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
decimal total = 0;
|
foreach (ReceiptLineModel saleLine in receipt.Lines)
|
||||||
foreach (SaleLineEntity saleLine in saleLineBySaleId)
|
|
||||||
{
|
{
|
||||||
total += saleLine.Total;
|
|
||||||
sb.AppendLine(
|
sb.AppendLine(
|
||||||
$"{saleLine.Product} - {saleLine.Pieces} stk. a' {saleLine.Price.ToString("0.00")} = {saleLine.Total.ToString("0.00")}");
|
$"{saleLine.Product} - {saleLine.Pieces} stk. a' {saleLine.Price:0.00} = {saleLine.Total:0.00}");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.AppendLine($"Total: {total.ToString("0.00")} kr.");
|
sb.AppendLine($"Total: {receipt.Total:0.00} kr.");
|
||||||
PrintReceipt.Visibility = Visibility.Visible;
|
PrintReceipt.Visibility = Visibility.Visible;
|
||||||
SaleLines.Clear();
|
SaleLines.Clear();
|
||||||
SaleLines.Text = sb.ToString();
|
SaleLines.Text = sb.ToString();
|
||||||
@@ -102,8 +113,7 @@ namespace Pos
|
|||||||
|
|
||||||
private void PrintReceipt_OnClick(object sender, RoutedEventArgs e)
|
private void PrintReceipt_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
SaleService saleService = new SaleService();
|
_saleService.PrintReceipt(_saleId);
|
||||||
saleService.PrintReceipt(_saleId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ namespace Pos
|
|||||||
{
|
{
|
||||||
private bool _initialLoad = true;
|
private bool _initialLoad = true;
|
||||||
private TotalSaleDetail totalSaleDetail;
|
private TotalSaleDetail totalSaleDetail;
|
||||||
|
private readonly SaleService _saleService = new SaleService();
|
||||||
public SaleOfDay()
|
public SaleOfDay()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
SaleService saleService = new SaleService();
|
totalSaleDetail = _saleService.TotalSale(DateTime.Now);
|
||||||
totalSaleDetail = saleService.TotalSale(DateTime.Now);
|
|
||||||
TotalSale.Content = $"Dagens salg: kr. {totalSaleDetail.TotalSale:0.00}";
|
TotalSale.Content = $"Dagens salg: kr. {totalSaleDetail.TotalSale:0.00}";
|
||||||
StartDatePicker.SelectedDate = DateTime.Now;
|
StartDatePicker.SelectedDate = DateTime.Now;
|
||||||
GridSaleDetail.ItemsSource = totalSaleDetail.TotalSaleCategories;
|
GridSaleDetail.ItemsSource = totalSaleDetail.TotalSaleCategories;
|
||||||
@@ -29,18 +29,20 @@ namespace Pos
|
|||||||
if (_initialLoad)
|
if (_initialLoad)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_initialLoad = false;
|
if (StartDatePicker.SelectedDate is not DateTime selectedDate)
|
||||||
DateTime selectedDate = DateTime.Parse(sender.ToString());
|
return;
|
||||||
SaleService saleService = new SaleService();
|
|
||||||
totalSaleDetail = saleService.TotalSale(selectedDate);
|
totalSaleDetail = _saleService.TotalSale(selectedDate);
|
||||||
TotalSale.Content = $"Dagens salg: kr. {totalSaleDetail.TotalSale:0.00}";
|
TotalSale.Content = $"Dagens salg: kr. {totalSaleDetail.TotalSale:0.00}";
|
||||||
GridSaleDetail.ItemsSource = totalSaleDetail.TotalSaleCategories;
|
GridSaleDetail.ItemsSource = totalSaleDetail.TotalSaleCategories;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintSale_OnClick(object sender, RoutedEventArgs e)
|
private void PrintSale_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
SaleService saleService = new SaleService();
|
if (StartDatePicker.SelectedDate is not DateTime selectedDate)
|
||||||
saleService.PrintSaleOfDay(StartDatePicker.SelectedDate.Value,totalSaleDetail);
|
return;
|
||||||
|
|
||||||
|
_saleService.PrintSaleOfDay(selectedDate, totalSaleDetail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ namespace Pos
|
|||||||
private ObservableCollection<ProductGroupEntity> _productGroups;
|
private ObservableCollection<ProductGroupEntity> _productGroups;
|
||||||
private ObservableCollection<SaleGridModel> _saleGridModels;
|
private ObservableCollection<SaleGridModel> _saleGridModels;
|
||||||
private ObservableCollection<AmountGridModel> _paymentGridModels;
|
private ObservableCollection<AmountGridModel> _paymentGridModels;
|
||||||
private List<PriceLineModel> _priceLineModels;
|
private readonly SalesTransactionService _salesTransactionService =
|
||||||
|
new SalesTransactionService();
|
||||||
|
|
||||||
private ProductEntity _selectedProduct;
|
private ProductEntity _selectedProduct;
|
||||||
private ProductGroupEntity _selectedProductGroup;
|
private ProductGroupEntity _selectedProductGroup;
|
||||||
@@ -37,14 +38,10 @@ namespace Pos
|
|||||||
private int _employeeId = -1;
|
private int _employeeId = -1;
|
||||||
private int _productGroupId = -1;
|
private int _productGroupId = -1;
|
||||||
private int _productId = -1;
|
private int _productId = -1;
|
||||||
private int _numberOfProducts = 1;
|
|
||||||
private int _selectedSaleGridIndex = -1;
|
private int _selectedSaleGridIndex = -1;
|
||||||
|
|
||||||
private int _maxCharOfName = 0;
|
private int _maxCharOfName = 0;
|
||||||
|
|
||||||
private decimal _price = 0;
|
|
||||||
private decimal _totalPrice = 0;
|
|
||||||
|
|
||||||
private Button _prevEmpButton = new Button();
|
private Button _prevEmpButton = new Button();
|
||||||
private Button _prevProductGroupButton = new Button();
|
private Button _prevProductGroupButton = new Button();
|
||||||
private Button _prevProduct = new Button();
|
private Button _prevProduct = new Button();
|
||||||
@@ -61,7 +58,6 @@ namespace Pos
|
|||||||
_employees = CacheService.GetEmployee() as ObservableCollection<EmployeeEntity>;
|
_employees = CacheService.GetEmployee() as ObservableCollection<EmployeeEntity>;
|
||||||
_productGroups = CacheService.GetProductGroupsIncludeProducts() as ObservableCollection<ProductGroupEntity>;
|
_productGroups = CacheService.GetProductGroupsIncludeProducts() as ObservableCollection<ProductGroupEntity>;
|
||||||
_saleGridModels = new ObservableCollection<SaleGridModel>();
|
_saleGridModels = new ObservableCollection<SaleGridModel>();
|
||||||
_priceLineModels = new List<PriceLineModel>();
|
|
||||||
_paymentGridModels = new ObservableCollection<AmountGridModel>();
|
_paymentGridModels = new ObservableCollection<AmountGridModel>();
|
||||||
SaleGrid.ItemsSource = _saleGridModels;
|
SaleGrid.ItemsSource = _saleGridModels;
|
||||||
PaymentGrid.ItemsSource = _paymentGridModels;
|
PaymentGrid.ItemsSource = _paymentGridModels;
|
||||||
@@ -150,11 +146,25 @@ namespace Pos
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
decimal price = Convert.ToDecimal(Price.Text);
|
decimal price = Convert.ToDecimal(Price.Text);
|
||||||
int number = Convert.ToInt32(NumberOfProducts.Text);
|
int numberOfProducts = Convert.ToInt32(NumberOfProducts.Text);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BuildPrice(numberOfProducts, price);
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig salgslinje",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NumberOfProducts.Text = "1";
|
NumberOfProducts.Text = "1";
|
||||||
Price.Text = string.Empty;
|
Price.Text = string.Empty;
|
||||||
TotalPrice.Content = "0";
|
TotalPrice.Content = "0";
|
||||||
BuildPrice(false);
|
|
||||||
_productId = -1;
|
_productId = -1;
|
||||||
_productGroupId = -1;
|
_productGroupId = -1;
|
||||||
ManipulateBuySection();
|
ManipulateBuySection();
|
||||||
@@ -162,16 +172,36 @@ namespace Pos
|
|||||||
|
|
||||||
private void Payment_Click(object sender, RoutedEventArgs e)
|
private void Payment_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
//bool isValid = ValidateAmountInput();
|
decimal? amount = null;
|
||||||
//if (!isValid)
|
|
||||||
// return;
|
|
||||||
decimal amount = -1;
|
|
||||||
if (!string.IsNullOrEmpty(Amount.Text))
|
if (!string.IsNullOrEmpty(Amount.Text))
|
||||||
|
{
|
||||||
|
bool isValid = ValidateAmountInput();
|
||||||
|
if (!isValid)
|
||||||
|
return;
|
||||||
|
|
||||||
amount = Convert.ToDecimal(Amount.Text);
|
amount = Convert.ToDecimal(Amount.Text);
|
||||||
|
}
|
||||||
|
|
||||||
Amount.Text = string.Empty;
|
Amount.Text = string.Empty;
|
||||||
Button button = sender as Button;
|
Button button = sender as Button;
|
||||||
BuildAmuntDataGrid(amount,(string)button.Tag);
|
string paymentMethodName =
|
||||||
|
((string)button.Tag).Replace("PaymentMethod.", string.Empty);
|
||||||
|
|
||||||
|
if (!Enum.TryParse(paymentMethodName, out PaymentMethod paymentMethod))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BuildAmuntDataGrid(amount, paymentMethod);
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig betaling",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NumberOfProducts_LostFocus(object sender, RoutedEventArgs e)
|
private void NumberOfProducts_LostFocus(object sender, RoutedEventArgs e)
|
||||||
@@ -249,61 +279,69 @@ namespace Pos
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private void BuildPrice(bool returnProduct)
|
private void BuildPrice(int numberOfProducts, decimal price)
|
||||||
{
|
{
|
||||||
PriceLineModel pModel = new PriceLineModel();
|
PriceLineModel priceLineModel;
|
||||||
pModel.NumberProducts = _numberOfProducts;
|
|
||||||
pModel.Price = _price;
|
|
||||||
if (_selectedProduct != null)
|
if (_selectedProduct != null)
|
||||||
{
|
{
|
||||||
pModel.Id = _selectedProduct.Id;
|
priceLineModel = _salesTransactionService.AddSaleLine(
|
||||||
pModel.Name = _selectedProduct.Name;
|
_selectedProduct.Id,
|
||||||
pModel.IsProductGroup = false;
|
_selectedProduct.Name,
|
||||||
|
numberOfProducts,
|
||||||
|
price,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pModel.Id = _selectedProductGroup.Id;
|
priceLineModel = _salesTransactionService.AddSaleLine(
|
||||||
pModel.Name = _selectedProductGroup.Name;
|
_selectedProductGroup.Id,
|
||||||
pModel.IsProductGroup = true;
|
_selectedProductGroup.Name,
|
||||||
|
numberOfProducts,
|
||||||
|
price,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildPriceDataGrid(pModel);
|
BuildPriceDataGrid(priceLineModel);
|
||||||
//BuildEmployee();
|
//BuildEmployee();
|
||||||
BuildProductGroup();
|
BuildProductGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CalculateSubPrice()
|
private void CalculateSubPrice()
|
||||||
{
|
{
|
||||||
_price = 0;
|
bool isValid = decimal.TryParse(Price.Text, out decimal price);
|
||||||
bool isValid = decimal.TryParse(Price.Text, out _price);
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
isValid = Int32.TryParse(NumberOfProducts.Text, out _numberOfProducts);
|
isValid = Int32.TryParse(
|
||||||
|
NumberOfProducts.Text,
|
||||||
|
out int numberOfProducts);
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TotalPrice.Content = _price * _numberOfProducts;
|
try
|
||||||
|
{
|
||||||
|
TotalPrice.Content =
|
||||||
|
_salesTransactionService.CalculateLineTotal(
|
||||||
|
price,
|
||||||
|
numberOfProducts);
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
TotalPrice.Content = "0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CalculateTotalLine()
|
private void CalculateTotalLine()
|
||||||
{
|
{
|
||||||
_totalPrice = 0;
|
Total.Content =
|
||||||
foreach (PriceLineModel model in _priceLineModels)
|
$"At betale: Kr. {_salesTransactionService.TotalPrice}";
|
||||||
{
|
|
||||||
_totalPrice += model.Price * model.NumberProducts;
|
|
||||||
}
|
|
||||||
|
|
||||||
Total.Content = $"At betale: Kr. {_totalPrice}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildPriceDataGrid(PriceLineModel priceLineModel)
|
private void BuildPriceDataGrid(PriceLineModel priceLineModel)
|
||||||
{
|
{
|
||||||
_selectedProduct = null;
|
_selectedProduct = null;
|
||||||
_selectedProductGroup = null;
|
_selectedProductGroup = null;
|
||||||
_numberOfProducts = 1;
|
|
||||||
|
|
||||||
_priceLineModels.Add(priceLineModel);
|
|
||||||
CalculateTotalLine();
|
CalculateTotalLine();
|
||||||
|
|
||||||
SaleGridModel model = new SaleGridModel();
|
SaleGridModel model = new SaleGridModel();
|
||||||
@@ -399,38 +437,14 @@ namespace Pos
|
|||||||
TotalPrice.IsEnabled = enabled;
|
TotalPrice.IsEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildAmuntDataGrid(decimal amount, string paymentMethod)
|
private void BuildAmuntDataGrid(
|
||||||
|
decimal? amount,
|
||||||
|
PaymentMethod paymentMethod)
|
||||||
{
|
{
|
||||||
if (amount == -1)
|
AmountGridModel amountGridModel =
|
||||||
{
|
_salesTransactionService.AddPayment(paymentMethod, amount);
|
||||||
amount = 0;
|
|
||||||
foreach (PriceLineModel lineModel in _priceLineModels)
|
|
||||||
{
|
|
||||||
amount += (lineModel.Price * lineModel.NumberProducts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AmountGridModel amountGridModel = new AmountGridModel();
|
amountGridModel.AmountText = $"Kr. {amountGridModel.Amount}";
|
||||||
amountGridModel.Amount = amount;
|
|
||||||
amountGridModel.AmountText = $"Kr. {amount}";
|
|
||||||
switch (paymentMethod)
|
|
||||||
{
|
|
||||||
case "PaymentMethod.Card":
|
|
||||||
amountGridModel.PaymentMethodText = "Kort";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "PaymentMethod.Cash":
|
|
||||||
amountGridModel.PaymentMethodText = "Kontant";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "PaymentMethod.GiftCard":
|
|
||||||
amountGridModel.PaymentMethodText = "Gavekort";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "PaymentMethod.MobilePay":
|
|
||||||
amountGridModel.PaymentMethodText = "MobilePay";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_paymentGridModels.Add(amountGridModel);
|
_paymentGridModels.Add(amountGridModel);
|
||||||
|
|
||||||
AmountPayed();
|
AmountPayed();
|
||||||
@@ -438,28 +452,25 @@ namespace Pos
|
|||||||
|
|
||||||
private void AmountPayed()
|
private void AmountPayed()
|
||||||
{
|
{
|
||||||
decimal amountPayed = 0;
|
if (_salesTransactionService.AmountPaid ==
|
||||||
foreach (AmountGridModel paymentGridModel in _paymentGridModels)
|
_salesTransactionService.TotalPrice)
|
||||||
{
|
|
||||||
amountPayed += paymentGridModel.Amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amountPayed == _totalPrice)
|
|
||||||
{
|
{
|
||||||
btnFinish_Click(null,null);
|
btnFinish_Click(null,null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amountPayed > _totalPrice)
|
if (_salesTransactionService.Change > 0)
|
||||||
{
|
{
|
||||||
lblRecived.Content = $"Byttepenge: Kr. {amountPayed - _totalPrice}";
|
lblRecived.Content =
|
||||||
|
$"Byttepenge: Kr. {_salesTransactionService.Change}";
|
||||||
Style style = this.FindResource("BoldLabelWarningNoMargin") as Style;
|
Style style = this.FindResource("BoldLabelWarningNoMargin") as Style;
|
||||||
lblRecived.Style = style;
|
lblRecived.Style = style;
|
||||||
btnFinish.IsEnabled = true;
|
btnFinish.IsEnabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lblRecived.Content = $"At betale: Kr. {_totalPrice - amountPayed}";
|
lblRecived.Content =
|
||||||
|
$"At betale: Kr. {_salesTransactionService.RemainingAmount}";
|
||||||
Style style = this.FindResource("BoldLabelNoMargin") as Style;
|
Style style = this.FindResource("BoldLabelNoMargin") as Style;
|
||||||
lblRecived.Style = style;
|
lblRecived.Style = style;
|
||||||
}
|
}
|
||||||
@@ -473,21 +484,37 @@ namespace Pos
|
|||||||
if (_selectedSaleGridIndex == -1)
|
if (_selectedSaleGridIndex == -1)
|
||||||
return;
|
return;
|
||||||
int index = _selectedSaleGridIndex;
|
int index = _selectedSaleGridIndex;
|
||||||
//_saleGridModels.RemoveAt(_selectedSaleGridIndex);
|
_salesTransactionService.RemoveSaleLineAt(index);
|
||||||
_priceLineModels.RemoveAt(index);
|
_saleGridModels.RemoveAt(index);
|
||||||
_selectedSaleGridIndex = -1;
|
_selectedSaleGridIndex = -1;
|
||||||
CalculateTotalLine();
|
CalculateTotalLine();
|
||||||
|
|
||||||
|
if (_salesTransactionService.AmountPaid > 0)
|
||||||
|
AmountPayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnFinish_Click(object sender, RoutedEventArgs e)
|
private void btnFinish_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_salesTransactionService.EnsureCanComplete();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Salget kan ikke afsluttes",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SaleService saleService = new SaleService();
|
SaleService saleService = new SaleService();
|
||||||
saleService.Save(_saleGridModels.ToList(),_paymentGridModels.ToList(),_employeeId);
|
saleService.Save(_saleGridModels.ToList(),_paymentGridModels.ToList(),_employeeId);
|
||||||
_paymentGridModels.Clear();
|
_paymentGridModels.Clear();
|
||||||
_priceLineModels.Clear();
|
_salesTransactionService.Reset();
|
||||||
UpdateWindowTitle();
|
UpdateWindowTitle();
|
||||||
_totalPrice = 0;
|
|
||||||
_saleGridModels.Clear();
|
_saleGridModels.Clear();
|
||||||
lblRecived.Content = string.Empty;
|
lblRecived.Content = string.Empty;
|
||||||
_selectedSaleGridIndex = -1;
|
_selectedSaleGridIndex = -1;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting
|
namespace Pos.Setting
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,9 @@ namespace Pos.Setting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AddEmployeeWindow : Window
|
public partial class AddEmployeeWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly EmployeeService _employeeService =
|
||||||
|
new EmployeeService();
|
||||||
|
|
||||||
public AddEmployeeWindow()
|
public AddEmployeeWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -27,9 +30,19 @@ namespace Pos.Setting
|
|||||||
|
|
||||||
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
EmployeeRepository employeeRepository = new EmployeeRepository();
|
try
|
||||||
employeeRepository.Add(txtStaff.Text);
|
{
|
||||||
this.Close();
|
_employeeService.AddEmployee(txtStaff.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig medarbejder",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting
|
namespace Pos.Setting
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,8 @@ namespace Pos.Setting
|
|||||||
public partial class DeleteEmployeeWindow : Window
|
public partial class DeleteEmployeeWindow : Window
|
||||||
{
|
{
|
||||||
private int _employeeId;
|
private int _employeeId;
|
||||||
|
private readonly EmployeeService _employeeService =
|
||||||
|
new EmployeeService();
|
||||||
|
|
||||||
public DeleteEmployeeWindow(int employeeId, string staffName)
|
public DeleteEmployeeWindow(int employeeId, string staffName)
|
||||||
{
|
{
|
||||||
@@ -31,9 +33,8 @@ namespace Pos.Setting
|
|||||||
|
|
||||||
private void btnYes_Click(object sender, RoutedEventArgs e)
|
private void btnYes_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
EmployeeRepository employeeRepository = new EmployeeRepository();
|
_employeeService.ArchiveEmployee(_employeeId);
|
||||||
employeeRepository.Delete(_employeeId);
|
Close();
|
||||||
this.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnNo_Click(object sender, RoutedEventArgs e)
|
private void btnNo_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting
|
namespace Pos.Setting
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,8 @@ namespace Pos.Setting
|
|||||||
public partial class EditEmployeeWindow : Window
|
public partial class EditEmployeeWindow : Window
|
||||||
{
|
{
|
||||||
private int _employeeId;
|
private int _employeeId;
|
||||||
|
private readonly EmployeeService _employeeService =
|
||||||
|
new EmployeeService();
|
||||||
|
|
||||||
public EditEmployeeWindow(int employeeId, string staffName)
|
public EditEmployeeWindow(int employeeId, string staffName)
|
||||||
{
|
{
|
||||||
@@ -31,9 +33,21 @@ namespace Pos.Setting
|
|||||||
|
|
||||||
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
EmployeeRepository employeeRepository = new EmployeeRepository();
|
try
|
||||||
employeeRepository.Edit(_employeeId,txtEmployee.Text);
|
{
|
||||||
this.Close();
|
_employeeService.RenameEmployee(
|
||||||
|
_employeeId,
|
||||||
|
txtEmployee.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig medarbejder",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Models;
|
using Database.Models;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting
|
namespace Pos.Setting
|
||||||
{
|
{
|
||||||
@@ -24,6 +24,8 @@ namespace Pos.Setting
|
|||||||
{
|
{
|
||||||
private int _selectedEmployee = -1;
|
private int _selectedEmployee = -1;
|
||||||
private string _employeeName = string.Empty;
|
private string _employeeName = string.Empty;
|
||||||
|
private readonly EmployeeService _employeeService =
|
||||||
|
new EmployeeService();
|
||||||
public EmployeeWindow()
|
public EmployeeWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -62,15 +64,14 @@ namespace Pos.Setting
|
|||||||
deleteEmployeeWindow.Show();
|
deleteEmployeeWindow.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WindowClosed(object? sender, EventArgs e)
|
private void WindowClosed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
LoadData();
|
LoadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
using EmployeeRepository employeeRepository = new EmployeeRepository();
|
List<EmployeeEntity> allStaff = _employeeService.GetEmployees();
|
||||||
List<EmployeeEntity> allStaff = employeeRepository.GetAll();
|
|
||||||
LstStaff.Items.Clear();
|
LstStaff.Items.Clear();
|
||||||
foreach (EmployeeEntity staff in allStaff)
|
foreach (EmployeeEntity staff in allStaff)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Database.Repository;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.ProductGroup
|
namespace Pos.Setting.ProductGroup
|
||||||
{
|
{
|
||||||
@@ -11,6 +11,11 @@ namespace Pos.Setting.ProductGroup
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AddProductWindow : Window
|
public partial class AddProductWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
private readonly ProductService _productService =
|
||||||
|
new ProductService();
|
||||||
|
|
||||||
public AddProductWindow()
|
public AddProductWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -19,13 +24,16 @@ namespace Pos.Setting.ProductGroup
|
|||||||
|
|
||||||
private void LoadData(int selectedIndex)
|
private void LoadData(int selectedIndex)
|
||||||
{
|
{
|
||||||
ProductGroupRepository productGroupRepository = new ProductGroupRepository();
|
List<Database.Models.ProductGroupEntity> productGroups =
|
||||||
List<Database.Models.ProductGroupEntity> products = productGroupRepository.GetAll();
|
_productGroupService.GetProductGroups();
|
||||||
foreach (Database.Models.ProductGroupEntity productGroup in products)
|
|
||||||
|
foreach (Database.Models.ProductGroupEntity productGroup in productGroups)
|
||||||
{
|
{
|
||||||
ComboBoxItem comboBoxItem = new ComboBoxItem();
|
ComboBoxItem comboBoxItem = new ComboBoxItem
|
||||||
comboBoxItem.Tag = productGroup.Id;
|
{
|
||||||
comboBoxItem.Content = productGroup.Name;
|
Tag = productGroup.Id,
|
||||||
|
Content = productGroup.Name
|
||||||
|
};
|
||||||
cmbProductGroup.Items.Add(comboBoxItem);
|
cmbProductGroup.Items.Add(comboBoxItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,12 +42,23 @@ namespace Pos.Setting.ProductGroup
|
|||||||
|
|
||||||
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ComboBoxItem item = (ComboBoxItem) cmbProductGroup.SelectedItem;
|
ComboBoxItem item = (ComboBoxItem)cmbProductGroup.SelectedItem;
|
||||||
string name = txtProduct.Text;
|
|
||||||
int id = Convert.ToInt32(item.Tag);
|
try
|
||||||
ProductRepository productRepository = new ProductRepository();
|
{
|
||||||
productRepository.Add(name,id);
|
_productService.AddProduct(
|
||||||
this.Close();
|
txtProduct.Text,
|
||||||
|
Convert.ToInt32(item.Tag));
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldigt produkt",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Product
|
namespace Pos.Setting.Product
|
||||||
{
|
{
|
||||||
@@ -21,20 +21,21 @@ namespace Pos.Setting.Product
|
|||||||
public partial class ArchiveProductWindow : Window
|
public partial class ArchiveProductWindow : Window
|
||||||
{
|
{
|
||||||
private int _productId;
|
private int _productId;
|
||||||
|
private readonly ProductService _productService =
|
||||||
|
new ProductService();
|
||||||
public ArchiveProductWindow(int productId)
|
public ArchiveProductWindow(int productId)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_productId = productId;
|
_productId = productId;
|
||||||
ProductRepository productRepository = new ProductRepository();
|
Database.Models.ProductEntity product =
|
||||||
Database.Models.ProductEntity product = productRepository.GetById(_productId);
|
_productService.GetProduct(_productId);
|
||||||
txtDelProduct.Text = product.Name;
|
txtDelProduct.Text = product.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnYes_Click(object sender, RoutedEventArgs e)
|
private void btnYes_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductRepository productRepository = new ProductRepository();
|
_productService.ArchiveProduct(_productId);
|
||||||
productRepository.Archive(_productId);
|
Close();
|
||||||
this.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnNo_Click(object sender, RoutedEventArgs e)
|
private void btnNo_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Product
|
namespace Pos.Setting.Product
|
||||||
{
|
{
|
||||||
@@ -23,6 +23,8 @@ namespace Pos.Setting.Product
|
|||||||
{
|
{
|
||||||
ObservableCollection<Database.Models.ProductEntity> _productList = new ObservableCollection<Database.Models.ProductEntity>();
|
ObservableCollection<Database.Models.ProductEntity> _productList = new ObservableCollection<Database.Models.ProductEntity>();
|
||||||
private int _productGroupId;
|
private int _productGroupId;
|
||||||
|
private readonly ProductService _productService =
|
||||||
|
new ProductService();
|
||||||
public ChangeProductOrderWindow(int productGroupId)
|
public ChangeProductOrderWindow(int productGroupId)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -32,8 +34,8 @@ namespace Pos.Setting.Product
|
|||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
ProductRepository productRepository = new ProductRepository();
|
List<Database.Models.ProductEntity> products =
|
||||||
List<Database.Models.ProductEntity> products = productRepository.GetByProductGroup(_productGroupId);
|
_productService.GetProducts(_productGroupId);
|
||||||
foreach (Database.Models.ProductEntity product in products)
|
foreach (Database.Models.ProductEntity product in products)
|
||||||
{
|
{
|
||||||
_productList.Add(product);
|
_productList.Add(product);
|
||||||
@@ -86,13 +88,10 @@ namespace Pos.Setting.Product
|
|||||||
|
|
||||||
private void btnSave_Click(object sender, RoutedEventArgs e)
|
private void btnSave_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductRepository productRepository = new ProductRepository();
|
_productService.UpdateOrder(
|
||||||
for (int i = 0; i < _productList.Count; i++)
|
_productGroupId,
|
||||||
{
|
_productList.Select(product => product.Id).ToList());
|
||||||
Database.Models.ProductEntity product = _productList[i];
|
Close();
|
||||||
productRepository.SetIndex(product.Id, i);
|
|
||||||
}
|
|
||||||
this.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Product
|
namespace Pos.Setting.Product
|
||||||
{
|
{
|
||||||
@@ -23,6 +23,10 @@ namespace Pos.Setting.Product
|
|||||||
private int _productId;
|
private int _productId;
|
||||||
private int _selectedProductGroupId;
|
private int _selectedProductGroupId;
|
||||||
private Database.Models.ProductEntity _product;
|
private Database.Models.ProductEntity _product;
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
private readonly ProductService _productService =
|
||||||
|
new ProductService();
|
||||||
|
|
||||||
public EditProductWindow(int productId, int selectedProductGroupId)
|
public EditProductWindow(int productId, int selectedProductGroupId)
|
||||||
{
|
{
|
||||||
@@ -34,8 +38,8 @@ namespace Pos.Setting.Product
|
|||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
List<Database.Models.ProductGroupEntity> productGroups =
|
||||||
List<Database.Models.ProductGroupEntity> productGroups = categoryRepository.GetAll();
|
_productGroupService.GetProductGroups();
|
||||||
foreach (Database.Models.ProductGroupEntity productGroup in productGroups)
|
foreach (Database.Models.ProductGroupEntity productGroup in productGroups)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -46,17 +50,29 @@ namespace Pos.Setting.Product
|
|||||||
}
|
}
|
||||||
cmbProductGroup.SelectedIndex = _selectedProductGroupId;
|
cmbProductGroup.SelectedIndex = _selectedProductGroupId;
|
||||||
|
|
||||||
ProductRepository productRepository = new ProductRepository();
|
_product = _productService.GetProduct(_productId);
|
||||||
_product = productRepository.GetById(_productId);
|
|
||||||
txtProduct.Text = _product.Name;
|
txtProduct.Text = _product.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ComboBoxItem item = (ComboBoxItem)cmbProductGroup.SelectedItem;
|
ComboBoxItem item = (ComboBoxItem)cmbProductGroup.SelectedItem;
|
||||||
ProductRepository productRepository = new ProductRepository();
|
try
|
||||||
productRepository.Update(_product.Id,(int)item.Tag,txtProduct.Text);
|
{
|
||||||
this.Close();
|
_productService.UpdateProduct(
|
||||||
|
_product.Id,
|
||||||
|
(int)item.Tag,
|
||||||
|
txtProduct.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldigt produkt",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
using Pos.Setting.Product;
|
using Pos.Setting.Product;
|
||||||
|
|
||||||
namespace Pos.Setting.ProductGroup
|
namespace Pos.Setting.ProductGroup
|
||||||
@@ -14,7 +14,10 @@ namespace Pos.Setting.ProductGroup
|
|||||||
public partial class ProductWindow : Window
|
public partial class ProductWindow : Window
|
||||||
{
|
{
|
||||||
private List<Database.Models.ProductGroupEntity> _productGroups;
|
private List<Database.Models.ProductGroupEntity> _productGroups;
|
||||||
private int _productId;
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
private readonly ProductService _productService =
|
||||||
|
new ProductService();
|
||||||
|
|
||||||
public ProductWindow()
|
public ProductWindow()
|
||||||
{
|
{
|
||||||
@@ -26,8 +29,7 @@ namespace Pos.Setting.ProductGroup
|
|||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
_productGroups = _productGroupService.GetProductGroups();
|
||||||
_productGroups = categoryRepository.GetAll();
|
|
||||||
cmbCat.Items.Clear();
|
cmbCat.Items.Clear();
|
||||||
foreach (Database.Models.ProductGroupEntity productGroup in _productGroups)
|
foreach (Database.Models.ProductGroupEntity productGroup in _productGroups)
|
||||||
{
|
{
|
||||||
@@ -38,14 +40,19 @@ namespace Pos.Setting.ProductGroup
|
|||||||
cmbCat.Items.Add(comboBoxItem);
|
cmbCat.Items.Add(comboBoxItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmbCat.SelectedIndex = 0;
|
if (_productGroups.Count > 0)
|
||||||
|
cmbCat.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
|
|
||||||
ProductRepository productRepository = new ProductRepository();
|
if (cmbCat.SelectedIndex < 0)
|
||||||
List<Database.Models.ProductEntity> products = productRepository.GetByProductGroup(_productGroups[cmbCat.SelectedIndex].Id);
|
return;
|
||||||
|
|
||||||
|
List<Database.Models.ProductEntity> products =
|
||||||
|
_productService.GetProducts(
|
||||||
|
_productGroups[cmbCat.SelectedIndex].Id);
|
||||||
lstProductGroup.Items.Clear();
|
lstProductGroup.Items.Clear();
|
||||||
foreach (Database.Models.ProductEntity product in products)
|
foreach (Database.Models.ProductEntity product in products)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Category
|
namespace Pos.Setting.Category
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,9 @@ namespace Pos.Setting.Category
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AddProductGroupWindow : Window
|
public partial class AddProductGroupWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
|
||||||
public AddProductGroupWindow()
|
public AddProductGroupWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -27,9 +30,19 @@ namespace Pos.Setting.Category
|
|||||||
|
|
||||||
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
private void btnAdd_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
try
|
||||||
categoryRepository.Add(txtProductGroup.Text);
|
{
|
||||||
this.Close();
|
_productGroupService.AddProductGroup(txtProductGroup.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig produktgruppe",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Category
|
namespace Pos.Setting.Category
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,8 @@ namespace Pos.Setting.Category
|
|||||||
public partial class ArchiveProductGroupWindow : Window
|
public partial class ArchiveProductGroupWindow : Window
|
||||||
{
|
{
|
||||||
private readonly int _id;
|
private readonly int _id;
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
public ArchiveProductGroupWindow(string name, int id)
|
public ArchiveProductGroupWindow(string name, int id)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -36,9 +38,8 @@ namespace Pos.Setting.Category
|
|||||||
|
|
||||||
private void btnYes_Click(object sender, RoutedEventArgs e)
|
private void btnYes_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
_productGroupService.ArchiveProductGroup(_id);
|
||||||
categoryRepository.Archive(_id);
|
Close();
|
||||||
this.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Category
|
namespace Pos.Setting.Category
|
||||||
{
|
{
|
||||||
@@ -22,6 +22,8 @@ namespace Pos.Setting.Category
|
|||||||
public partial class ChangeProductGroupOrderWindow : Window
|
public partial class ChangeProductGroupOrderWindow : Window
|
||||||
{
|
{
|
||||||
ObservableCollection<Database.Models.ProductGroupEntity> _prodGroupList = new ObservableCollection<Database.Models.ProductGroupEntity>();
|
ObservableCollection<Database.Models.ProductGroupEntity> _prodGroupList = new ObservableCollection<Database.Models.ProductGroupEntity>();
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
public ChangeProductGroupOrderWindow()
|
public ChangeProductGroupOrderWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -30,8 +32,8 @@ namespace Pos.Setting.Category
|
|||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
List<Database.Models.ProductGroupEntity> categories =
|
||||||
List<Database.Models.ProductGroupEntity> categories = categoryRepository.GetAll();
|
_productGroupService.GetProductGroups();
|
||||||
foreach (Database.Models.ProductGroupEntity category in categories)
|
foreach (Database.Models.ProductGroupEntity category in categories)
|
||||||
{
|
{
|
||||||
_prodGroupList.Add(category);
|
_prodGroupList.Add(category);
|
||||||
@@ -84,13 +86,9 @@ namespace Pos.Setting.Category
|
|||||||
|
|
||||||
private void btnSave_Click(object sender, RoutedEventArgs e)
|
private void btnSave_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
_productGroupService.UpdateOrder(
|
||||||
for (int i = 0; i < _prodGroupList.Count; i++)
|
_prodGroupList.Select(productGroup => productGroup.Id).ToList());
|
||||||
{
|
Close();
|
||||||
Database.Models.ProductGroupEntity productGroup = _prodGroupList[i];
|
|
||||||
categoryRepository.SetIndex(productGroup.Id,i);
|
|
||||||
}
|
|
||||||
this.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
|
|
||||||
namespace Pos.Setting.Category
|
namespace Pos.Setting.Category
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,8 @@ namespace Pos.Setting.Category
|
|||||||
public partial class EditProductGroupWindow : Window
|
public partial class EditProductGroupWindow : Window
|
||||||
{
|
{
|
||||||
private readonly int _id;
|
private readonly int _id;
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
|
||||||
public EditProductGroupWindow(string name, int id)
|
public EditProductGroupWindow(string name, int id)
|
||||||
{
|
{
|
||||||
@@ -31,9 +33,21 @@ namespace Pos.Setting.Category
|
|||||||
|
|
||||||
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
try
|
||||||
categoryRepository.Edit(txtProductGroup.Text,_id);
|
{
|
||||||
this.Close();
|
_productGroupService.RenameProductGroup(
|
||||||
|
_id,
|
||||||
|
txtProductGroup.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (ArgumentException exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
exception.Message,
|
||||||
|
"Ugyldig produktgruppe",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
using Pos.Service;
|
||||||
using Pos.Setting.Category;
|
using Pos.Setting.Category;
|
||||||
|
|
||||||
namespace Pos.Category
|
namespace Pos.Category
|
||||||
@@ -23,6 +23,8 @@ namespace Pos.Category
|
|||||||
{
|
{
|
||||||
private int _id = -1;
|
private int _id = -1;
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
|
||||||
public ProductGroupWindow()
|
public ProductGroupWindow()
|
||||||
{
|
{
|
||||||
@@ -53,8 +55,8 @@ namespace Pos.Category
|
|||||||
|
|
||||||
private void LoadData()
|
private void LoadData()
|
||||||
{
|
{
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
List<Database.Models.ProductGroupEntity> categories =
|
||||||
List<Database.Models.ProductGroupEntity> categories = categoryRepository.GetAll();
|
_productGroupService.GetProductGroups();
|
||||||
LstCategory.Items.Clear();
|
LstCategory.Items.Clear();
|
||||||
foreach (Database.Models.ProductGroupEntity category in categories)
|
foreach (Database.Models.ProductGroupEntity category in categories)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Database.Repository;
|
|
||||||
using Pos.Category;
|
using Pos.Category;
|
||||||
|
using Pos.Service;
|
||||||
using Pos.Setting.ProductGroup;
|
using Pos.Setting.ProductGroup;
|
||||||
|
|
||||||
namespace Pos.Setting
|
namespace Pos.Setting
|
||||||
@@ -22,6 +22,9 @@ namespace Pos.Setting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class SettingWindow : Window
|
public partial class SettingWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly ProductGroupService _productGroupService =
|
||||||
|
new ProductGroupService();
|
||||||
|
|
||||||
public SettingWindow()
|
public SettingWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -42,10 +45,8 @@ namespace Pos.Setting
|
|||||||
|
|
||||||
private void btnProductGroups_Click(object sender, RoutedEventArgs e)
|
private void btnProductGroups_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProductWindow productWindow = new ProductWindow();
|
|
||||||
//Check if there is any categories, if not close this window with a message.
|
//Check if there is any categories, if not close this window with a message.
|
||||||
ProductGroupRepository categoryRepository = new ProductGroupRepository();
|
bool anyExist = _productGroupService.HasProductGroups();
|
||||||
bool anyExist = categoryRepository.Any();
|
|
||||||
if (!anyExist)
|
if (!anyExist)
|
||||||
{
|
{
|
||||||
MessageBox.Show("Der er ingen kategorier, opret dem først", "Kategorier", MessageBoxButton.OK,
|
MessageBox.Show("Der er ingen kategorier, opret dem først", "Kategorier", MessageBoxButton.OK,
|
||||||
@@ -53,6 +54,7 @@ namespace Pos.Setting
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ProductWindow productWindow = new ProductWindow();
|
||||||
productWindow.Show();
|
productWindow.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
|
|
||||||
//public class Rootobject
|
|
||||||
//{
|
|
||||||
// public string logoBase64 { get; set; }
|
|
||||||
// public Header[] header { get; set; }
|
|
||||||
// public Bodymodel bodyModel { get; set; }
|
|
||||||
// public Footer[] footer { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Bodymodel
|
|
||||||
//{
|
|
||||||
// public Product[] products { get; set; }
|
|
||||||
// public int totalPrice { get; set; }
|
|
||||||
// public int totalVat { get; set; }
|
|
||||||
// public int receiptNumber { get; set; }
|
|
||||||
// public string receiptTime { get; set; }
|
|
||||||
// public string staff { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Product
|
|
||||||
//{
|
|
||||||
// public string product { get; set; }
|
|
||||||
// public string noOfProduct { get; set; }
|
|
||||||
// public float price { get; set; }
|
|
||||||
// public float totalPrice { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Header
|
|
||||||
//{
|
|
||||||
// public string value { get; set; }
|
|
||||||
// public Printstyles printStyles { get; set; }
|
|
||||||
// public int textAlignment { get; set; }
|
|
||||||
// public int feedingLines { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Printstyles
|
|
||||||
//{
|
|
||||||
// public bool fontB { get; set; }
|
|
||||||
// public bool bold { get; set; }
|
|
||||||
// public bool doubleHeight { get; set; }
|
|
||||||
// public bool doubleWidth { get; set; }
|
|
||||||
// public bool underline { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Footer
|
|
||||||
//{
|
|
||||||
// public string value { get; set; }
|
|
||||||
// public Printstyles1 printStyles { get; set; }
|
|
||||||
// public int textAlignment { get; set; }
|
|
||||||
// public int feedingLines { get; set; }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public class Printstyles1
|
|
||||||
//{
|
|
||||||
// public bool fontB { get; set; }
|
|
||||||
// public bool bold { get; set; }
|
|
||||||
// public bool doubleHeight { get; set; }
|
|
||||||
// public bool doubleWidth { get; set; }
|
|
||||||
// public bool underline { get; set; }
|
|
||||||
//}
|
|
||||||
23
PointOfSale/Pos.Web/Components/App.razor
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<base href="/" />
|
||||||
|
<ResourcePreloader />
|
||||||
|
<link rel="stylesheet" href="@Assets["app.css"]" />
|
||||||
|
<link rel="stylesheet" href="@Assets["Pos.Web.styles.css"]" />
|
||||||
|
<ImportMap />
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
|
<HeadOutlet @rendermode="InteractiveServer" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Routes @rendermode="InteractiveServer" />
|
||||||
|
<ReconnectModal />
|
||||||
|
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
16
PointOfSale/Pos.Web/Components/Layout/MainLayout.razor
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
<FluentLayout>
|
||||||
|
<FluentLayoutItem Area="LayoutArea.Content" Class="main">
|
||||||
|
<div class="content">
|
||||||
|
@Body
|
||||||
|
</div>
|
||||||
|
</FluentLayoutItem>
|
||||||
|
</FluentLayout>
|
||||||
|
<FluentDialogProvider />
|
||||||
|
|
||||||
|
<div id="blazor-error-ui" data-nosnippet>
|
||||||
|
An unhandled error has occurred.
|
||||||
|
<a href="." class="reload">Reload</a>
|
||||||
|
<span class="dismiss">🗙</span>
|
||||||
|
</div>
|
||||||
31
PointOfSale/Pos.Web/Components/Layout/ReconnectModal.razor
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script type="module" src="@Assets["Components/Layout/ReconnectModal.razor.js"]"></script>
|
||||||
|
|
||||||
|
<dialog id="components-reconnect-modal" data-nosnippet>
|
||||||
|
<div class="components-reconnect-container">
|
||||||
|
<div class="components-rejoining-animation" aria-hidden="true">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<p class="components-reconnect-first-attempt-visible">
|
||||||
|
Rejoining the server...
|
||||||
|
</p>
|
||||||
|
<p class="components-reconnect-repeated-attempt-visible">
|
||||||
|
Rejoin failed... trying again in <span id="components-seconds-to-next-attempt"></span> seconds.
|
||||||
|
</p>
|
||||||
|
<p class="components-reconnect-failed-visible">
|
||||||
|
Failed to rejoin.<br />Please retry or reload the page.
|
||||||
|
</p>
|
||||||
|
<button id="components-reconnect-button" class="components-reconnect-failed-visible">
|
||||||
|
Retry
|
||||||
|
</button>
|
||||||
|
<p class="components-pause-visible">
|
||||||
|
The session has been paused by the server.
|
||||||
|
</p>
|
||||||
|
<p class="components-resume-failed-visible">
|
||||||
|
Failed to resume the session.<br />Please retry or reload the page.
|
||||||
|
</p>
|
||||||
|
<button id="components-resume-button" class="components-pause-visible components-resume-failed-visible">
|
||||||
|
Resume
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
157
PointOfSale/Pos.Web/Components/Layout/ReconnectModal.razor.css
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
.components-reconnect-first-attempt-visible,
|
||||||
|
.components-reconnect-repeated-attempt-visible,
|
||||||
|
.components-reconnect-failed-visible,
|
||||||
|
.components-pause-visible,
|
||||||
|
.components-resume-failed-visible,
|
||||||
|
.components-rejoining-animation {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
|
||||||
|
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
|
||||||
|
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
|
||||||
|
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
|
||||||
|
#components-reconnect-modal.components-reconnect-retrying,
|
||||||
|
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
|
||||||
|
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
|
||||||
|
#components-reconnect-modal.components-reconnect-failed,
|
||||||
|
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#components-reconnect-modal {
|
||||||
|
background-color: white;
|
||||||
|
width: 20rem;
|
||||||
|
margin: 20vh auto;
|
||||||
|
padding: 2rem;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
|
||||||
|
opacity: 0;
|
||||||
|
transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
|
||||||
|
animation: components-reconnect-modal-fadeOutOpacity 0.5s both;
|
||||||
|
&[open]
|
||||||
|
|
||||||
|
{
|
||||||
|
animation: components-reconnect-modal-slideUp 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity 0.5s ease-in-out 0.3s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal::backdrop {
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
animation: components-reconnect-modal-fadeInOpacity 0.5s ease-in-out;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes components-reconnect-modal-slideUp {
|
||||||
|
0% {
|
||||||
|
transform: translateY(30px) scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes components-reconnect-modal-fadeInOpacity {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes components-reconnect-modal-fadeOutOpacity {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-reconnect-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal p {
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal button {
|
||||||
|
border: 0;
|
||||||
|
background-color: #6b9ed2;
|
||||||
|
color: white;
|
||||||
|
padding: 4px 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal button:hover {
|
||||||
|
background-color: #3b6ea2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-reconnect-modal button:active {
|
||||||
|
background-color: #6b9ed2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-rejoining-animation {
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-rejoining-animation div {
|
||||||
|
position: absolute;
|
||||||
|
border: 3px solid #0087ff;
|
||||||
|
opacity: 1;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.components-rejoining-animation div:nth-child(2) {
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes components-rejoining-animation {
|
||||||
|
0% {
|
||||||
|
top: 40px;
|
||||||
|
left: 40px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
4.9% {
|
||||||
|
top: 40px;
|
||||||
|
left: 40px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
5% {
|
||||||
|
top: 40px;
|
||||||
|
left: 40px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// Set up event handlers
|
||||||
|
const reconnectModal = document.getElementById("components-reconnect-modal");
|
||||||
|
reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged);
|
||||||
|
|
||||||
|
const retryButton = document.getElementById("components-reconnect-button");
|
||||||
|
retryButton.addEventListener("click", retry);
|
||||||
|
|
||||||
|
const resumeButton = document.getElementById("components-resume-button");
|
||||||
|
resumeButton.addEventListener("click", resume);
|
||||||
|
|
||||||
|
function handleReconnectStateChanged(event) {
|
||||||
|
if (event.detail.state === "show") {
|
||||||
|
reconnectModal.showModal();
|
||||||
|
} else if (event.detail.state === "hide") {
|
||||||
|
reconnectModal.close();
|
||||||
|
} else if (event.detail.state === "failed") {
|
||||||
|
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
||||||
|
} else if (event.detail.state === "rejected") {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retry() {
|
||||||
|
document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Reconnect will asynchronously return:
|
||||||
|
// - true to mean success
|
||||||
|
// - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID)
|
||||||
|
// - exception to mean we didn't reach the server (this can be sync or async)
|
||||||
|
const successful = await Blazor.reconnect();
|
||||||
|
if (!successful) {
|
||||||
|
// We have been able to reach the server, but the circuit is no longer available.
|
||||||
|
// We'll reload the page so the user can continue using the app as quickly as possible.
|
||||||
|
const resumeSuccessful = await Blazor.resumeCircuit();
|
||||||
|
if (!resumeSuccessful) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
reconnectModal.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// We got an exception, server is currently unavailable
|
||||||
|
document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resume() {
|
||||||
|
try {
|
||||||
|
const successful = await Blazor.resumeCircuit();
|
||||||
|
if (!successful) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
reconnectModal.classList.replace("components-reconnect-paused", "components-reconnect-resume-failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retryWhenDocumentBecomesVisible() {
|
||||||
|
if (document.visibilityState === "visible") {
|
||||||
|
await retry();
|
||||||
|
}
|
||||||
|
}
|
||||||
36
PointOfSale/Pos.Web/Components/Pages/Error.razor
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
@page "/Error"
|
||||||
|
@using System.Diagnostics
|
||||||
|
|
||||||
|
<PageTitle>Error</PageTitle>
|
||||||
|
|
||||||
|
<h1 class="text-danger">Error.</h1>
|
||||||
|
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||||
|
|
||||||
|
@if (ShowRequestId)
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h3>Development Mode</h3>
|
||||||
|
<p>
|
||||||
|
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||||
|
It can result in displaying sensitive information from exceptions to end users.
|
||||||
|
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||||
|
and restarting the app.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
@code{
|
||||||
|
[CascadingParameter]
|
||||||
|
private HttpContext? HttpContext { get; set; }
|
||||||
|
|
||||||
|
private string? RequestId { get; set; }
|
||||||
|
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||||
|
|
||||||
|
protected override void OnInitialized() =>
|
||||||
|
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||||
|
}
|
||||||
21
PointOfSale/Pos.Web/Components/Pages/Home.razor
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@rendermode InteractiveServer
|
||||||
|
@inject NavigationManager Nav
|
||||||
|
@page "/"
|
||||||
|
|
||||||
|
<Header/>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="home-container">
|
||||||
|
<FluentButton Class="menu-button" Size="ButtonSize.Large">
|
||||||
|
Kassesalg
|
||||||
|
</FluentButton>
|
||||||
|
<FluentButton Class="menu-button" Size="ButtonSize.Large">
|
||||||
|
Dagens salg
|
||||||
|
</FluentButton>
|
||||||
|
<FluentButton Class="menu-button" Size="ButtonSize.Large">
|
||||||
|
Print Bon
|
||||||
|
</FluentButton>
|
||||||
|
<FluentButton Class="menu-button" Size="ButtonSize.Large" onclick="@(() => Nav.NavigateTo("/settings"))">
|
||||||
|
Indstillinger
|
||||||
|
</FluentButton>
|
||||||
|
</div>
|
||||||
14
PointOfSale/Pos.Web/Components/Pages/Home.razor.css
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.home-container {
|
||||||
|
width: min(100%, 1100px);
|
||||||
|
margin: 32px auto;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-container ::deep .menu-button {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 220px;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
5
PointOfSale/Pos.Web/Components/Pages/NotFound.razor
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@page "/not-found"
|
||||||
|
@layout MainLayout
|
||||||
|
|
||||||
|
<h3>Not Found</h3>
|
||||||
|
<p>Sorry, the content you are looking for does not exist.</p>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
@using Pos.Service
|
||||||
|
@inject EmployeeService EmployeeService
|
||||||
|
|
||||||
|
@if (IsOpen)
|
||||||
|
{
|
||||||
|
<div class="dialog-overlay">
|
||||||
|
<div class="employee-dialog" role="dialog" aria-modal="true" aria-labelledby="create-employee-title">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h2 id="create-employee-title">Opret medarbejder</h2>
|
||||||
|
<button class="close-button"
|
||||||
|
type="button"
|
||||||
|
aria-label="Luk"
|
||||||
|
@onclick="CloseAsync">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-content">
|
||||||
|
<label for="employee-name">Navn</label>
|
||||||
|
<input id="employee-name"
|
||||||
|
class="name-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="Indtast navn"
|
||||||
|
@bind="_name"
|
||||||
|
@bind:event="oninput" />
|
||||||
|
<p>Medarbejderen bliver aktiv med det samme.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<button class="cancel-button"
|
||||||
|
type="button"
|
||||||
|
@onclick="CloseAsync">
|
||||||
|
Annuller
|
||||||
|
</button>
|
||||||
|
<button class="create-button"
|
||||||
|
type="button"
|
||||||
|
disabled="@string.IsNullOrWhiteSpace(_name)"
|
||||||
|
@onclick="CreateEmployeeAsync">
|
||||||
|
Opret medarbejder
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Database.Models;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Pos.Service;
|
||||||
|
|
||||||
|
namespace Pos.Web.Components.Pages.Settings
|
||||||
|
{
|
||||||
|
public partial class CreateEmployeeDialog
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public bool IsOpen { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<bool> IsOpenChanged { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<EmployeeEntity> EmployeeCreated { get; set; }
|
||||||
|
|
||||||
|
private string _name = string.Empty;
|
||||||
|
|
||||||
|
private async Task CreateEmployeeAsync()
|
||||||
|
{
|
||||||
|
EmployeeEntity employee =
|
||||||
|
await EmployeeService.AddEmployeeAsync(_name);
|
||||||
|
|
||||||
|
await EmployeeCreated.InvokeAsync(employee);
|
||||||
|
await CloseAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CloseAsync()
|
||||||
|
{
|
||||||
|
_name = string.Empty;
|
||||||
|
await IsOpenChanged.InvokeAsync(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
.dialog-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
background: rgb(15 23 42 / 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.employee-dialog {
|
||||||
|
width: min(100%, 650px);
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: white;
|
||||||
|
color: #242424;
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 28px 40px 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: #334155;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 36px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 18px 40px 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content label {
|
||||||
|
color: #242424;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border: 1px solid #8a8a8a;
|
||||||
|
border-radius: 6px;
|
||||||
|
outline: none;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #242424;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input::placeholder {
|
||||||
|
color: #707070;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input:focus {
|
||||||
|
border-color: #0f6cbd;
|
||||||
|
box-shadow: 0 0 0 1px #0f6cbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content p {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 24px 40px;
|
||||||
|
border-top: 1px solid #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button,
|
||||||
|
.create-button {
|
||||||
|
min-height: 42px;
|
||||||
|
padding: 0 22px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
border: 1px solid #616161;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #242424;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-button {
|
||||||
|
border: 1px solid #0f6cbd;
|
||||||
|
background: #0f6cbd;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-button:hover:not(:disabled) {
|
||||||
|
background: #115ea3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-button:disabled {
|
||||||
|
border-color: #d1d1d1;
|
||||||
|
background: #e0e0e0;
|
||||||
|
color: #707070;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.dialog-header,
|
||||||
|
.dialog-content,
|
||||||
|
.dialog-actions {
|
||||||
|
padding-right: 24px;
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
@page "/settings/employees"
|
||||||
|
@inject IDialogService DialogService
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
@using Database.Models
|
||||||
|
@using Pos.Service
|
||||||
|
@inject EmployeeService EmployeeService
|
||||||
|
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<div class="employees-page">
|
||||||
|
<div class="employees-header">
|
||||||
|
<h1>Medarbejdere</h1>
|
||||||
|
|
||||||
|
<FluentButton Appearance="@ButtonAppearance.Primary"
|
||||||
|
OnClick="@(() => _showCreateDialog = true)">
|
||||||
|
Opret medarbejder
|
||||||
|
</FluentButton>
|
||||||
|
</div>
|
||||||
|
@if (_isLoading)
|
||||||
|
{
|
||||||
|
<FluentProgressRing />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<FluentDataGrid TGridItem="EmployeeEntity"
|
||||||
|
Items="@_employees.AsQueryable()"
|
||||||
|
GridTemplateColumns="1fr 180px">
|
||||||
|
|
||||||
|
<PropertyColumn Property="@(item => item.Name)"
|
||||||
|
Title="Navn"
|
||||||
|
Sortable="true" />
|
||||||
|
|
||||||
|
<TemplateColumn Title="Handling" Context="employee">
|
||||||
|
<FluentButton Class="deactivate-button"
|
||||||
|
Appearance="@ButtonAppearance.Outline"
|
||||||
|
OnClick="@(() => ConfirmDeactivation(employee))">
|
||||||
|
Deaktivér
|
||||||
|
</FluentButton>
|
||||||
|
</TemplateColumn>
|
||||||
|
</FluentDataGrid>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CreateEmployeeDialog @bind-IsOpen="_showCreateDialog"
|
||||||
|
EmployeeCreated="EmployeeCreated" />
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Database.Models;
|
||||||
|
using Microsoft.FluentUI.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace Pos.Web.Components.Pages.Settings
|
||||||
|
{
|
||||||
|
public partial class Employees
|
||||||
|
{
|
||||||
|
private List<EmployeeEntity> _employees = [];
|
||||||
|
private bool _isLoading = true;
|
||||||
|
private bool _showCreateDialog;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
_employees = await EmployeeService.GetEmployeesAsync();
|
||||||
|
_isLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadEmployees()
|
||||||
|
{
|
||||||
|
_employees = EmployeeService.GetEmployees();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConfirmDeactivation(EmployeeEntity employee)
|
||||||
|
{
|
||||||
|
DialogResult result = await DialogService.ShowConfirmationAsync(
|
||||||
|
$"Er du sikker på, at du vil deaktivere {employee.Name}?",
|
||||||
|
"Bekræft deaktivering",
|
||||||
|
"Annuller",
|
||||||
|
"Deaktivér");
|
||||||
|
|
||||||
|
if (result.Cancelled)
|
||||||
|
{
|
||||||
|
DeactivateEmployee(employee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeactivateEmployee(EmployeeEntity employee)
|
||||||
|
{
|
||||||
|
EmployeeService.ArchiveEmployee(employee.Id);
|
||||||
|
LoadEmployees();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EmployeeRow
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmployeeCreated(EmployeeEntity employee)
|
||||||
|
{
|
||||||
|
_employees.Add(employee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* CSS for Employees component */
|
||||||
|
.employees-page {
|
||||||
|
width: min(100%, 1100px);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.employees-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.employees-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.employees-page ::deep fluent-data-grid {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.employees-page ::deep .deactivate-button {
|
||||||
|
color: #b10e1e;
|
||||||
|
border-color: #b10e1e;
|
||||||
|
}
|
||||||
20
PointOfSale/Pos.Web/Components/Pages/Settings/Settings.razor
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@rendermode InteractiveServer
|
||||||
|
@inject NavigationManager Nav
|
||||||
|
@page "/settings"
|
||||||
|
|
||||||
|
<Header />
|
||||||
|
<div class="settings-page">
|
||||||
|
<h1>Indstillinger</h1>
|
||||||
|
|
||||||
|
<p>Administrer data, der bruges i kassesalget.</p>
|
||||||
|
|
||||||
|
<div class="settings-grid">
|
||||||
|
<FluentButton Class="settings-button" onclick="@(() => Nav.NavigateTo("/settings/employees"))">
|
||||||
|
Medarbejder
|
||||||
|
</FluentButton>
|
||||||
|
|
||||||
|
<FluentButton Class="settings-button">
|
||||||
|
Vare
|
||||||
|
</FluentButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
.settings-page {
|
||||||
|
width: min(100%, 1100px);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-page h1 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 24px;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-grid ::deep .settings-button {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 220px;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
5
PointOfSale/Pos.Web/Components/Routes.razor
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
|
||||||
|
<Found Context="routeData">
|
||||||
|
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||||
|
</Found>
|
||||||
|
</Router>
|
||||||
12
PointOfSale/Pos.Web/Components/Shared/Header.razor
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
@rendermode InteractiveServer
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
|
<header class="top-nav">
|
||||||
|
<div class="brand">Blomster POS</div>
|
||||||
|
|
||||||
|
<time datetime="@_currentTime.ToString("O")">
|
||||||
|
@_currentTime.ToString(
|
||||||
|
"dddd d. MMMM yyyy · HH:mm",
|
||||||
|
_danishCulture)
|
||||||
|
</time>
|
||||||
|
</header>
|
||||||
33
PointOfSale/Pos.Web/Components/Shared/Header.razor.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Pos.Web.Components.Shared
|
||||||
|
{
|
||||||
|
public partial class Header
|
||||||
|
{
|
||||||
|
private readonly CultureInfo _danishCulture =
|
||||||
|
CultureInfo.GetCultureInfo("da-DK");
|
||||||
|
|
||||||
|
private readonly Timer _timer;
|
||||||
|
private DateTime _currentTime = DateTime.Now;
|
||||||
|
|
||||||
|
public Header()
|
||||||
|
{
|
||||||
|
_timer = new Timer(
|
||||||
|
UpdateTime,
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(1),
|
||||||
|
TimeSpan.FromMinutes(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTime(object? state)
|
||||||
|
{
|
||||||
|
_currentTime = DateTime.Now;
|
||||||
|
_ = InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_timer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
PointOfSale/Pos.Web/Components/Shared/Header.razor.css
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/* CSS for Header component */
|
||||||
|
.top-nav {
|
||||||
|
min-height: 72px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 0 32px;
|
||||||
|
background: var(--colorNeutralBackground1);
|
||||||
|
border-bottom: 1px solid var(--colorNeutralStroke2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
color: var(--colorNeutralForeground2);
|
||||||
|
font-size: 18px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
14
PointOfSale/Pos.Web/Components/_Imports.razor
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@using System.Net.Http
|
||||||
|
@using System.Net.Http.Json
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
|
@using Microsoft.FluentUI.AspNetCore.Components
|
||||||
|
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons
|
||||||
|
@using Microsoft.JSInterop
|
||||||
|
@using Pos.Web
|
||||||
|
@using Pos.Web.Components
|
||||||
|
@using Pos.Web.Components.Layout
|
||||||
|
@using Pos.Web.Components.Shared
|
||||||
21
PointOfSale/Pos.Web/Pos.Web.csproj
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="5.0.0-rc.4-26180.1" />
|
||||||
|
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="4.14.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Pos.Models\Pos.Models.csproj" />
|
||||||
|
<ProjectReference Include="..\Pos.ServiceDefaults\Pos.ServiceDefaults.csproj" />
|
||||||
|
<ProjectReference Include="..\Pos.Service\Pos.Service.csproj" />
|
||||||
|
<ProjectReference Include="..\Pos.Ui\Database\Database.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
35
PointOfSale/Pos.Web/Program.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Microsoft.FluentUI.AspNetCore.Components;
|
||||||
|
using Pos.Web.Components;
|
||||||
|
using Pos.Service;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.AddServiceDefaults();
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
builder.Services.AddRazorComponents()
|
||||||
|
.AddInteractiveServerComponents();
|
||||||
|
builder.Services.AddFluentUIComponents();
|
||||||
|
builder.Services.AddScoped<EmployeeService>();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.MapDefaultEndpoints();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (!app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||||
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||||
|
app.UseHsts();
|
||||||
|
}
|
||||||
|
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAntiforgery();
|
||||||
|
|
||||||
|
app.MapStaticAssets();
|
||||||
|
app.MapRazorComponents<App>()
|
||||||
|
.AddInteractiveServerRenderMode();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
23
PointOfSale/Pos.Web/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "http://localhost:5281",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "https://localhost:7102;http://localhost:5281",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
PointOfSale/Pos.Web/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
PointOfSale/Pos.Web/appsettings.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"SqlServer": "Server=(localdb)\\MSSQLLocalDB;Database=pointofsale;Trusted_Connection=True;TrustServerCertificate=True;",
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
89
PointOfSale/Pos.Web/wwwroot/app.css
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@import '/_content/Microsoft.FluentUI.AspNetCore.Components/css/reboot.css';
|
||||||
|
|
||||||
|
body {
|
||||||
|
--body-font: "Segoe UI Variable", "Segoe UI", sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
font-family: var(--body-font);
|
||||||
|
font-size: var(--type-ramp-base-font-size);
|
||||||
|
line-height: var(--type-ramp-base-line-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
min-height: 100dvh;
|
||||||
|
color: var(--neutral-foreground-rest);
|
||||||
|
align-items: stretch !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 1.5rem;
|
||||||
|
align-self: stretch !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#blazor-error-ui {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.6rem 1.25rem 0.7rem;
|
||||||
|
background: lightyellow;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#blazor-error-ui .dismiss {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0.75rem;
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blazor-error-boundary {
|
||||||
|
padding: 1rem 1rem 1rem 3.7rem;
|
||||||
|
color: white;
|
||||||
|
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blazor-error-boundary::before {
|
||||||
|
content: "An error has occurred. ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 8rem;
|
||||||
|
height: 8rem;
|
||||||
|
margin: 20vh auto 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress circle {
|
||||||
|
fill: none;
|
||||||
|
stroke: #e0e0e0;
|
||||||
|
stroke-width: 0.6rem;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress circle:last-child {
|
||||||
|
stroke: #1b6ec2;
|
||||||
|
stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
|
||||||
|
transition: stroke-dasharray 0.05s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress-text {
|
||||||
|
position: absolute;
|
||||||
|
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress-text::after {
|
||||||
|
content: var(--blazor-load-percentage-text, "Loading");
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: #c02d76;
|
||||||
|
}
|
||||||
BIN
PointOfSale/Pos.Web/wwwroot/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -13,12 +13,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EpsonPrinter", "EpsonPrinte
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.AppHost", "Pos.AppHost\Pos.AppHost.csproj", "{53EFB4EB-931D-419B-8399-4E389011076C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.AppHost", "Pos.AppHost\Pos.AppHost.csproj", "{53EFB4EB-931D-419B-8399-4E389011076C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.ServiceDefaults", "Pos.ServiceDefaults\Pos.ServiceDefaults.csproj", "{EDC882E6-4983-35BD-3357-E433A3E64369}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9051E89F-15CC-40A4-8C60-82C98151139E}"
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Pos.Test", "Pos.Test", "{9051E89F-15CC-40A4-8C60-82C98151139E}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "IntegrationTests\IntegrationTests.csproj", "{04551552-086E-4CF4-AFD3-A4E51CD36182}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "IntegrationTests\IntegrationTests.csproj", "{04551552-086E-4CF4-AFD3-A4E51CD36182}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.Web", "Pos.Web\Pos.Web.csproj", "{81AEF9BF-15E9-414D-9F18-345631896022}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.Service", "Pos.Service\Pos.Service.csproj", "{563C2EC1-B243-4A66-BE53-88A0BA216706}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.Models", "Pos.Models\Pos.Models.csproj", "{D6EA5236-CEFB-4889-9E67-4983D1A016FA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pos.ServiceDefaults", "Pos.ServiceDefaults\Pos.ServiceDefaults.csproj", "{EDC882E6-4983-35BD-3357-E433A3E64369}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -41,14 +47,26 @@ Global
|
|||||||
{53EFB4EB-931D-419B-8399-4E389011076C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{53EFB4EB-931D-419B-8399-4E389011076C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{53EFB4EB-931D-419B-8399-4E389011076C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{53EFB4EB-931D-419B-8399-4E389011076C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{53EFB4EB-931D-419B-8399-4E389011076C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{53EFB4EB-931D-419B-8399-4E389011076C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{EDC882E6-4983-35BD-3357-E433A3E64369}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{EDC882E6-4983-35BD-3357-E433A3E64369}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{EDC882E6-4983-35BD-3357-E433A3E64369}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EDC882E6-4983-35BD-3357-E433A3E64369}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Release|Any CPU.Build.0 = Release|Any CPU
|
{04551552-086E-4CF4-AFD3-A4E51CD36182}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{81AEF9BF-15E9-414D-9F18-345631896022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{81AEF9BF-15E9-414D-9F18-345631896022}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{81AEF9BF-15E9-414D-9F18-345631896022}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{81AEF9BF-15E9-414D-9F18-345631896022}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{563C2EC1-B243-4A66-BE53-88A0BA216706}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{563C2EC1-B243-4A66-BE53-88A0BA216706}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{563C2EC1-B243-4A66-BE53-88A0BA216706}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{563C2EC1-B243-4A66-BE53-88A0BA216706}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D6EA5236-CEFB-4889-9E67-4983D1A016FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D6EA5236-CEFB-4889-9E67-4983D1A016FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D6EA5236-CEFB-4889-9E67-4983D1A016FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D6EA5236-CEFB-4889-9E67-4983D1A016FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EDC882E6-4983-35BD-3357-E433A3E64369}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EDC882E6-4983-35BD-3357-E433A3E64369}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EDC882E6-4983-35BD-3357-E433A3E64369}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EDC882E6-4983-35BD-3357-E433A3E64369}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
BIN
layout/DagensSalg.png
Normal file
|
After Width: | Height: | Size: 887 KiB |
BIN
layout/Forside.png
Normal file
|
After Width: | Height: | Size: 852 KiB |
BIN
layout/Indstillinger.png
Normal file
|
After Width: | Height: | Size: 864 KiB |
BIN
layout/Indstillinger/Medarbejder.png
Normal file
|
After Width: | Height: | Size: 922 KiB |
BIN
layout/Indstillinger/OpretMedarbejder.png
Normal file
|
After Width: | Height: | Size: 1011 KiB |
BIN
layout/Indstillinger/Vare.png
Normal file
|
After Width: | Height: | Size: 1019 KiB |
BIN
layout/PrintBon.png
Normal file
|
After Width: | Height: | Size: 931 KiB |
BIN
layout/Salg/BetalingByttepenge.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |