Initial commit
Initial commit til Git. V2 er deployed
This commit is contained in:
362
PointOfSale/.gitignore
vendored
Normal file
362
PointOfSale/.gitignore
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using EpsonPrinter.Services;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PosPrinterController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// PrintReceipt receipt, so far only for all Epson Thermal Printers
|
||||
/// </summary>
|
||||
/// PrintStyle is:
|
||||
/// None
|
||||
/// FontB
|
||||
/// Bold
|
||||
/// DoubleHeight
|
||||
/// DoubleWidth
|
||||
/// Underline
|
||||
/// There is support for any combination of PrintStyles
|
||||
/// ----------------------------------------
|
||||
///
|
||||
///
|
||||
/// <param name="receiptModel"></param>
|
||||
[HttpPost]
|
||||
[Route("Receipt")]
|
||||
public void PrintReceipt([FromServices] EpsonPrintService epsonPrint, ReceiptModel receiptModel)
|
||||
{
|
||||
epsonPrint.PrintReceipt(receiptModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("SaleOfDay")]
|
||||
public void PrintSaleOfDay([FromServices] EpsonPrintService epsonPrint, SaleOfDayModel saleOfDayModel)
|
||||
{
|
||||
epsonPrint.PrintSaleOfDay(saleOfDayModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ValuesController : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("HelloWorld")]
|
||||
public string Get()
|
||||
{
|
||||
return "HelloWorld";
|
||||
}
|
||||
}
|
||||
}
|
||||
9
PointOfSale/EpsonPrinterLinux/Enums/AlignmentEnum.cs
Normal file
9
PointOfSale/EpsonPrinterLinux/Enums/AlignmentEnum.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace EpsonPrinter.Enums
|
||||
{
|
||||
public enum AlignmentEnum
|
||||
{
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
}
|
||||
12
PointOfSale/EpsonPrinterLinux/Enums/PrintStylesEnum.cs
Normal file
12
PointOfSale/EpsonPrinterLinux/Enums/PrintStylesEnum.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace EpsonPrinter.Enums
|
||||
{
|
||||
public enum PrintStylesEnum
|
||||
{
|
||||
None,
|
||||
FontB,
|
||||
Bold,
|
||||
DoubleHeight,
|
||||
DoubleWidth,
|
||||
UnderLine
|
||||
}
|
||||
}
|
||||
22
PointOfSale/EpsonPrinterLinux/EpsonPrinter.csproj
Normal file
22
PointOfSale/EpsonPrinterLinux/EpsonPrinter.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>..\Pos</DockerfileContext>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ESC-POS\**" />
|
||||
<Content Remove="ESC-POS\**" />
|
||||
<EmbeddedResource Remove="ESC-POS\**" />
|
||||
<None Remove="ESC-POS\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
PointOfSale/EpsonPrinterLinux/Model/BodyModel.cs
Normal file
18
PointOfSale/EpsonPrinterLinux/Model/BodyModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class BodyModel
|
||||
{
|
||||
public List<BodyProductModel> Products { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
public decimal TotalVat { get; set; }
|
||||
public int ReceiptNumber { get; set; }
|
||||
public string ReceiptTime { get; set; }
|
||||
public string Staff { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
15
PointOfSale/EpsonPrinterLinux/Model/BodyProductModel.cs
Normal file
15
PointOfSale/EpsonPrinterLinux/Model/BodyProductModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class BodyProductModel
|
||||
{
|
||||
public string Product { get; set; }
|
||||
public int NoOfProduct { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/FooterModel.cs
Normal file
16
PointOfSale/EpsonPrinterLinux/Model/FooterModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class FooterModel
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public PrintStyleModel PrintStyles { get; set; }
|
||||
public AlignmentEnum TextAlignment { get; set; }
|
||||
public int FeedingLines { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/HeaderModel.cs
Normal file
16
PointOfSale/EpsonPrinterLinux/Model/HeaderModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class HeaderModel
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public PrintStyleModel PrintStyles { get; set; }
|
||||
public AlignmentEnum TextAlignment { get; set; }
|
||||
public int FeedingLines { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/PrintStyleModel.cs
Normal file
16
PointOfSale/EpsonPrinterLinux/Model/PrintStyleModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class PrintStyleModel
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
13
PointOfSale/EpsonPrinterLinux/Model/ReceiptModel.cs
Normal file
13
PointOfSale/EpsonPrinterLinux/Model/ReceiptModel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class ReceiptModel
|
||||
{
|
||||
public string LogoBase64 { get; set; }
|
||||
public List<HeaderModel> Header { get; set; }
|
||||
public BodyModel BodyModel { get; set; }
|
||||
public List<FooterModel> Footer { get; set; }
|
||||
}
|
||||
}
|
||||
10
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayDetail.cs
Normal file
10
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayDetail.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class SaleOfDayDetail
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public decimal TotalSale { get; set; }
|
||||
}
|
||||
}
|
||||
14
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayModel.cs
Normal file
14
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class SaleOfDayModel
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public int TotalCustomers { get; set; }
|
||||
public Decimal TotalSale { get; set; }
|
||||
public List<SaleOfDayDetail> SaleOfDayDetail { get; set; } = new();
|
||||
|
||||
}
|
||||
}
|
||||
23
PointOfSale/EpsonPrinterLinux/Program.cs
Normal file
23
PointOfSale/EpsonPrinterLinux/Program.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using EpsonPrinter.Services;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Services
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
builder.Services.AddScoped<EpsonPrintService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Swagger (altid aktiv – vi er på en Pi, ikke i produktion)
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
// Routing
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
31
PointOfSale/EpsonPrinterLinux/Properties/launchSettings.json
Normal file
31
PointOfSale/EpsonPrinterLinux/Properties/launchSettings.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:23653",
|
||||
"sslPort": 44334
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"EpsonPrinter": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
PointOfSale/EpsonPrinterLinux/README_LINUX_USB.txt
Normal file
18
PointOfSale/EpsonPrinterLinux/README_LINUX_USB.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
Linux USB version of the EpsonPrinter API.
|
||||
|
||||
What changed:
|
||||
- Keeps the incoming JSON models for /api/PosPrinter/Receipt and /api/PosPrinter/SaleOfDay
|
||||
- Replaces COM/SerialPrinter transport with raw writes to Linux USB printer device
|
||||
- Uses /dev/usb/lp0 by default from appsettings.json
|
||||
- Builds a standard receipt when parts of the payload are missing
|
||||
- Pulls fallback values from appsettings.json under PrintSettings:Defaults
|
||||
|
||||
Typical run:
|
||||
dotnet restore
|
||||
dotnet run
|
||||
|
||||
Typical endpoint:
|
||||
POST /api/PosPrinter/Receipt
|
||||
|
||||
Important setting:
|
||||
PrintSettings:DevicePath = /dev/usb/lp0
|
||||
248
PointOfSale/EpsonPrinterLinux/Services/EpsonPrintService.cs
Normal file
248
PointOfSale/EpsonPrinterLinux/Services/EpsonPrintService.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using EpsonPrinter.Model;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class EpsonPrintService
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
private readonly string _devicePath;
|
||||
|
||||
public EpsonPrintService(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
_devicePath = _config["PrintSettings:DevicePath"] ?? "/dev/usb/lp0";
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
|
||||
public void PrintReceipt(ReceiptModel model)
|
||||
{
|
||||
ICommandEmitter e = new EPSON();
|
||||
InitAndWrite(e);
|
||||
|
||||
List<byte[][]> printBytes = new List<byte[][]>();
|
||||
PrintHeader printHeader = new PrintHeader(e);
|
||||
PrintBody printBody = new PrintBody(e, _config);
|
||||
PrintFooter printFooter = new PrintFooter(e);
|
||||
|
||||
var header = (model.Header != null && model.Header.Any()) ? model.Header : BuildDefaultHeader();
|
||||
var body = model.BodyModel ?? BuildDefaultBody();
|
||||
if (string.IsNullOrWhiteSpace(body.Staff))
|
||||
{
|
||||
body.Staff = _config["PrintSettings:Defaults:Staff"] ?? "Ukendt";
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(body.ReceiptTime))
|
||||
{
|
||||
body.ReceiptTime = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss");
|
||||
}
|
||||
if (body.ReceiptNumber <= 0)
|
||||
{
|
||||
body.ReceiptNumber = Math.Abs(Environment.TickCount % 1000000);
|
||||
}
|
||||
body.Products ??= new List<BodyProductModel>();
|
||||
if (!body.Products.Any())
|
||||
{
|
||||
body.Products.Add(new BodyProductModel
|
||||
{
|
||||
Product = "Standard vare",
|
||||
NoOfProduct = 1,
|
||||
Price = 99.00m,
|
||||
TotalPrice = 99.00m
|
||||
});
|
||||
}
|
||||
if (body.TotalPrice <= 0)
|
||||
{
|
||||
body.TotalPrice = body.Products.Sum(x => x.TotalPrice <= 0 ? x.Price * x.NoOfProduct : x.TotalPrice);
|
||||
}
|
||||
if (body.TotalVat <= 0)
|
||||
{
|
||||
body.TotalVat = Math.Round(body.TotalPrice * 0.25m, 2);
|
||||
}
|
||||
|
||||
var footer = (model.Footer != null && model.Footer.Any()) ? model.Footer : BuildDefaultFooter();
|
||||
|
||||
printBytes.AddRange(printHeader.Print(header));
|
||||
printBytes.AddRange(printBody.Print(body));
|
||||
printBytes.AddRange(printFooter.Print(footer));
|
||||
|
||||
byte[][] array = printBytes.SelectMany(c => c).ToArray();
|
||||
Write(array);
|
||||
Write(e.FeedLines(5));
|
||||
Write(e.FullCut());
|
||||
}
|
||||
|
||||
public void PrintSaleOfDay(SaleOfDayModel model)
|
||||
{
|
||||
ICommandEmitter e = new EPSON();
|
||||
InitAndWrite(e);
|
||||
PrintSaleOfDay(model, e);
|
||||
}
|
||||
|
||||
private void InitAndWrite(ICommandEmitter e)
|
||||
{
|
||||
Write(e.Initialize());
|
||||
Write(e.Enable());
|
||||
Write(e.CodePage(CodePage.ISO8859_15_LATIN9));
|
||||
Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
|
||||
private void PrintSaleOfDay(SaleOfDayModel model, ICommandEmitter e)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
|
||||
byte[][] dateBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine($"Dato: {model.Date:dd-MM-yyyy}")
|
||||
};
|
||||
data.Add(dateBytes);
|
||||
|
||||
byte[][] seperater =
|
||||
{
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine("-----------------------------------")
|
||||
};
|
||||
data.Add(seperater);
|
||||
|
||||
foreach (SaleOfDayDetail saleOfDayDetail in model.SaleOfDayDetail)
|
||||
{
|
||||
string pS = $"{saleOfDayDetail.Category} : {saleOfDayDetail.TotalSale.ToString("#.#0", CultureInfo.InvariantCulture)}";
|
||||
byte[][] totalPrice =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(pS)
|
||||
};
|
||||
data.Add(totalPrice);
|
||||
}
|
||||
|
||||
data.Add(seperater);
|
||||
|
||||
string totalSale = $"Total salg: {model.TotalSale.ToString("#.#0", CultureInfo.InvariantCulture)}";
|
||||
byte[][] tSBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(totalSale)
|
||||
};
|
||||
data.Add(tSBytes);
|
||||
|
||||
string totalCustomer = $"Antal kunder: {model.TotalCustomers}";
|
||||
byte[][] tCBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(totalCustomer)
|
||||
};
|
||||
data.Add(tCBytes);
|
||||
|
||||
byte[][] array = data.SelectMany(c => c).ToArray();
|
||||
Write(array);
|
||||
Write(e.FeedLines(5));
|
||||
Write(e.FullCut());
|
||||
}
|
||||
|
||||
private List<HeaderModel> BuildDefaultHeader()
|
||||
{
|
||||
return new List<HeaderModel>
|
||||
{
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:StoreName"] ?? "TableTop3D",
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = true, DoubleWidth = true, DoubleHeight = true }
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:AddressLine1"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = true }
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:AddressLine2"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel()
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:Cvr"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 1,
|
||||
PrintStyles = new PrintStyleModel()
|
||||
}
|
||||
}.Where(x => !string.IsNullOrWhiteSpace(x.Value)).ToList();
|
||||
}
|
||||
|
||||
private FooterModel CreateFooterLine(string value, bool bold = false)
|
||||
{
|
||||
return new FooterModel
|
||||
{
|
||||
Value = value,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = bold }
|
||||
};
|
||||
}
|
||||
|
||||
private List<FooterModel> BuildDefaultFooter()
|
||||
{
|
||||
var values = new[]
|
||||
{
|
||||
_config["PrintSettings:Defaults:FooterLine1"] ?? "Tak for dit køb!",
|
||||
_config["PrintSettings:Defaults:FooterLine2"] ?? string.Empty,
|
||||
_config["PrintSettings:Defaults:Phone"] ?? string.Empty
|
||||
}.Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
||||
|
||||
return values.Select((x, i) => CreateFooterLine(x, i == 0)).ToList();
|
||||
}
|
||||
|
||||
private BodyModel BuildDefaultBody()
|
||||
{
|
||||
return new BodyModel
|
||||
{
|
||||
ReceiptNumber = Math.Abs(Environment.TickCount % 1000000),
|
||||
ReceiptTime = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss"),
|
||||
Staff = _config["PrintSettings:Defaults:Staff"] ?? "Ukendt",
|
||||
Products = new List<BodyProductModel>
|
||||
{
|
||||
new BodyProductModel
|
||||
{
|
||||
Product = "Standard vare",
|
||||
NoOfProduct = 1,
|
||||
Price = 99.00m,
|
||||
TotalPrice = 99.00m
|
||||
}
|
||||
},
|
||||
TotalPrice = 99.00m,
|
||||
TotalVat = 24.75m
|
||||
};
|
||||
}
|
||||
|
||||
private void Write(byte[] data)
|
||||
{
|
||||
using var stream = new FileStream(_devicePath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
|
||||
stream.Write(data, 0, data.Length);
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
private void Write(byte[][] data)
|
||||
{
|
||||
foreach (var segment in data)
|
||||
{
|
||||
Write(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
PointOfSale/EpsonPrinterLinux/Services/PrintAlignment.cs
Normal file
24
PointOfSale/EpsonPrinterLinux/Services/PrintAlignment.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using EpsonPrinter.Enums;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintAlignment
|
||||
{
|
||||
public byte[] GetTextAlignment(ICommandEmitter e, AlignmentEnum alignment)
|
||||
{
|
||||
if (alignment == AlignmentEnum.Left)
|
||||
return e.LeftAlign();
|
||||
|
||||
if (alignment == AlignmentEnum.Right)
|
||||
return e.RightAlign();
|
||||
|
||||
return e.CenterAlign();
|
||||
}
|
||||
}
|
||||
}
|
||||
117
PointOfSale/EpsonPrinterLinux/Services/PrintBody.cs
Normal file
117
PointOfSale/EpsonPrinterLinux/Services/PrintBody.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET.Emitters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintBody
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
private IConfiguration _config;
|
||||
|
||||
private int productMaxWidth;
|
||||
|
||||
public PrintBody(ICommandEmitter e, IConfiguration config)
|
||||
{
|
||||
_e = e;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public List<byte[][]> Print(BodyModel model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
|
||||
byte[][] headerModel =
|
||||
{
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
_e.LeftAlign(),
|
||||
_e.PrintLine($"Dato.........: {model.ReceiptTime}"),
|
||||
_e.PrintLine($"Ekspedient...: {model.Staff}"),
|
||||
_e.PrintLine($"Kvittering...: {model.ReceiptNumber}"),
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(headerModel);
|
||||
|
||||
int printWidth = Convert.ToInt32(_config["PrintSettings:PrintWidth"]);
|
||||
foreach (BodyProductModel product in model.Products)
|
||||
{
|
||||
//Size of product is max half of recipt
|
||||
string totalProductLine = MakeProductNameString(product.Product, printWidth);
|
||||
totalProductLine += MakeProductNumber(product.NoOfProduct, product.Price);
|
||||
totalProductLine = MakeTotalProductPrice(totalProductLine, product.TotalPrice,printWidth);
|
||||
|
||||
byte[][] p =
|
||||
{
|
||||
_e.PrintLine(totalProductLine)
|
||||
};
|
||||
data.Add(p);
|
||||
}
|
||||
|
||||
PrintString printString = new PrintString();
|
||||
string totalPricePrint = printString.MakePrintString(printWidth, $"Total: ", $"{model.TotalPrice:F} DKK");
|
||||
byte[][] totalPrice =
|
||||
{
|
||||
_e.FeedLines(1),
|
||||
_e.SetStyles(PrintStyle.Bold | PrintStyle.DoubleHeight),
|
||||
_e.RightAlign(),
|
||||
_e.PrintLine(totalPricePrint)
|
||||
};
|
||||
data.Add(totalPrice);
|
||||
|
||||
byte[][] vat =
|
||||
{
|
||||
_e.FeedLines(1),
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
_e.LeftAlign(),
|
||||
_e.PrintLine(MakeVat(printWidth,model.TotalVat))
|
||||
};
|
||||
data.Add(vat);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private string MakeProductNameString(string product, int totalWidth)
|
||||
{
|
||||
string productString = product;
|
||||
productMaxWidth = (totalWidth / 2) - 5;
|
||||
int productLength = product.Length;
|
||||
if (productLength < productMaxWidth)
|
||||
{
|
||||
|
||||
for (int i = productLength; i < productMaxWidth; i++)
|
||||
{
|
||||
productString += ".";
|
||||
}
|
||||
}
|
||||
|
||||
return productString;
|
||||
}
|
||||
|
||||
private string MakeProductNumber(int noOfProduct, decimal price)
|
||||
{
|
||||
return $"{noOfProduct} á {price:F} DKK :";
|
||||
}
|
||||
|
||||
private string MakeTotalProductPrice(string buffer, decimal totalPrice, int printWidth)
|
||||
{
|
||||
PrintString printString = new PrintString();
|
||||
string p = $"{totalPrice:F} DKK";
|
||||
string makePrintString = printString.MakePrintString(printWidth, buffer, p);
|
||||
return makePrintString;
|
||||
}
|
||||
|
||||
private string MakeVat(int printWidth, decimal vat)
|
||||
{
|
||||
PrintString printString = new PrintString();
|
||||
string vatDesc = $"Moms udgør 25% :";
|
||||
string v = $"{vat:F} DKK";
|
||||
string vatString = printString.MakePrintString(printWidth, vatDesc, v);
|
||||
return vatString;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
PointOfSale/EpsonPrinterLinux/Services/PrintFooter.cs
Normal file
47
PointOfSale/EpsonPrinterLinux/Services/PrintFooter.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintFooter
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
|
||||
public PrintFooter(ICommandEmitter e)
|
||||
{
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public List<byte[][]> Print(List<FooterModel> model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
PrintStyleCombination printStyleCombination = new PrintStyleCombination();
|
||||
PrintAlignment printAlignment = new PrintAlignment();
|
||||
byte[][] feedLines =
|
||||
{
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(feedLines);
|
||||
foreach (FooterModel footerModel in model)
|
||||
{
|
||||
|
||||
PrintStyle printStyle = printStyleCombination.Combine(footerModel.PrintStyles);
|
||||
byte[][] bytes = {
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
printAlignment.GetTextAlignment(_e,footerModel.TextAlignment),
|
||||
_e.SetStyles(printStyle),
|
||||
_e.PrintLine(footerModel.Value),
|
||||
_e.FeedLines(footerModel.FeedingLines)
|
||||
};
|
||||
data.Add(bytes);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
PointOfSale/EpsonPrinterLinux/Services/PrintHeader.cs
Normal file
47
PointOfSale/EpsonPrinterLinux/Services/PrintHeader.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET;
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintHeader
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
|
||||
public PrintHeader(ICommandEmitter e)
|
||||
{
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public List<Byte[][]> Print(List<HeaderModel> model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
PrintStyleCombination printStyleCombination = new PrintStyleCombination();
|
||||
PrintAlignment printAlignment = new PrintAlignment();
|
||||
foreach (HeaderModel headerModel in model)
|
||||
{
|
||||
|
||||
PrintStyle printStyle = printStyleCombination.Combine(headerModel.PrintStyles);
|
||||
byte[][] bytes = {
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
printAlignment.GetTextAlignment(_e,headerModel.TextAlignment),
|
||||
_e.SetStyles(printStyle),
|
||||
_e.PrintLine(headerModel.Value),
|
||||
_e.FeedLines(headerModel.FeedingLines)
|
||||
};
|
||||
data.Add(bytes);
|
||||
}
|
||||
byte[][] feedLines =
|
||||
{
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(feedLines);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
PointOfSale/EpsonPrinterLinux/Services/PrintString.cs
Normal file
44
PointOfSale/EpsonPrinterLinux/Services/PrintString.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintString
|
||||
{
|
||||
/// <summary>
|
||||
/// An appropriate interval is converted into the length of
|
||||
/// the tab about two texts. And make a printing data.
|
||||
/// </summary>
|
||||
/// <param name="iLineChars">
|
||||
/// The width of the territory which it prints on is converted into the number of
|
||||
/// characters, and that value is specified.
|
||||
/// </param>
|
||||
/// <param name="strBuf">
|
||||
/// It is necessary as an information for deciding the interval of the text.
|
||||
/// </param>
|
||||
/// <param name="strPrice">
|
||||
/// It is necessary as an information for deciding the interval of the text, too.
|
||||
/// </param>
|
||||
/// <returns>printing data.
|
||||
/// </returns>
|
||||
public String MakePrintString(int iLineChars, String strBuf, String strPrice)
|
||||
{
|
||||
int iSpaces = 0;
|
||||
String tab = "";
|
||||
try
|
||||
{
|
||||
iSpaces = iLineChars - (strBuf.Length + strPrice.Length);
|
||||
for (int j = 0; j < iSpaces; j++)
|
||||
{
|
||||
tab += " ";
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return strBuf + tab + strPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintStyleCombination
|
||||
{
|
||||
public PrintStyle Combine(PrintStyleModel printStyleModel)
|
||||
{
|
||||
|
||||
//Bold
|
||||
if (printStyleModel.Bold && !printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight;
|
||||
|
||||
if(printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//DoubleHeight
|
||||
if (printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//DoubleWidth
|
||||
if (printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//FontB
|
||||
if (printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.FontB;
|
||||
|
||||
if(printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//Underline
|
||||
if (printStyleModel.Underline)
|
||||
return PrintStyle.Underline;
|
||||
|
||||
return PrintStyle.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
26
PointOfSale/EpsonPrinterLinux/appsettings.json
Normal file
26
PointOfSale/EpsonPrinterLinux/appsettings.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"PrintSettings": {
|
||||
"DevicePath": "/dev/usb/lp0",
|
||||
"PrintWidth": 48,
|
||||
"CodePage": "ISO8859_15_LATIN9",
|
||||
"Defaults": {
|
||||
"StoreName": "Blomster Til Alt",
|
||||
"AddressLine1": "Adelgade 88",
|
||||
"AddressLine2": "5400 Bogense",
|
||||
"Cvr": "CVR: 37144436",
|
||||
"Phone": "Tlf: 41 82 71 66",
|
||||
"FooterLine1": "Tak for dit køb!",
|
||||
"FooterLine2": "Vi håber du bliver glad for dine varer.",
|
||||
"Staff": "Ukendt",
|
||||
"ReceiptPrefix": "BON"
|
||||
}
|
||||
}
|
||||
}
|
||||
73
PointOfSale/EpsonPrinterLinux/testdata.json
Normal file
73
PointOfSale/EpsonPrinterLinux/testdata.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"logoBase64": "string",
|
||||
"header": [
|
||||
{
|
||||
"value": "Første linie med ÆØÅ æøå",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Anden linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Tredje linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Fjerde linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Femte linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
{
|
||||
"value": "string",
|
||||
"printStyles": {
|
||||
"fontB": true,
|
||||
"bold": true,
|
||||
"doubleHeight": true,
|
||||
"doubleWidth": true,
|
||||
"underline": true
|
||||
},
|
||||
"textAlignment": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
7
PointOfSale/Pos.Api/Pos.Api.Database/Class1.cs
Normal file
7
PointOfSale/Pos.Api/Pos.Api.Database/Class1.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Pos.Api.Database
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
162
PointOfSale/Pos.Api/Pos.Api.Database/Data/PosApiContext.cs
Normal file
162
PointOfSale/Pos.Api/Pos.Api.Database/Data/PosApiContext.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Pos.Api.Database.Models;
|
||||
|
||||
namespace Pos.Api.Database.Data;
|
||||
|
||||
public partial class PosApiContext : DbContext
|
||||
{
|
||||
public PosApiContext(DbContextOptions<PosApiContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<Employee> Employees { get; set; }
|
||||
|
||||
public virtual DbSet<LastUpdate> LastUpdates { get; set; }
|
||||
|
||||
public virtual DbSet<Payment> Payments { get; set; }
|
||||
|
||||
public virtual DbSet<Product> Products { get; set; }
|
||||
|
||||
public virtual DbSet<Productgroup> Productgroups { get; set; }
|
||||
|
||||
public virtual DbSet<Sale> Sales { get; set; }
|
||||
|
||||
public virtual DbSet<SaleLine> SaleLines { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.UseCollation("latin1_swedish_ci")
|
||||
.HasCharSet("latin1");
|
||||
|
||||
modelBuilder.Entity<Employee>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("employee")
|
||||
.HasCharSet("utf8mb4")
|
||||
.UseCollation("utf8mb4_general_ci");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnType("int(11)");
|
||||
entity.Property(e => e.IsArchived).HasColumnType("tinyint(4)");
|
||||
entity.Property(e => e.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(50);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<LastUpdate>(entity =>
|
||||
{
|
||||
entity
|
||||
.HasNoKey()
|
||||
.ToTable("LastUpdate");
|
||||
|
||||
entity.Property(e => e.DateTime).HasColumnType("datetime");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Payment>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("payment")
|
||||
.HasCharSet("armscii8")
|
||||
.UseCollation("armscii8_bin");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Amount).HasPrecision(20, 6);
|
||||
entity.Property(e => e.SaleId).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Type)
|
||||
.IsRequired()
|
||||
.HasColumnType("tinytext");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Product>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("product")
|
||||
.HasCharSet("utf8mb4")
|
||||
.UseCollation("utf8mb4_general_ci");
|
||||
|
||||
entity.HasIndex(e => e.ProductGroupId, "FK_Product_Categories");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int(11)");
|
||||
entity.Property(e => e.Description).HasColumnType("mediumtext");
|
||||
entity.Property(e => e.Index).HasColumnType("int(11)");
|
||||
entity.Property(e => e.IsArchived).HasColumnType("tinyint(4)");
|
||||
entity.Property(e => e.Name)
|
||||
.IsRequired()
|
||||
.HasColumnType("tinytext");
|
||||
entity.Property(e => e.Price).HasPrecision(10, 2);
|
||||
entity.Property(e => e.ProductGroupId).HasColumnType("int(11)");
|
||||
|
||||
entity.HasOne(d => d.IdNavigation).WithOne(p => p.Product)
|
||||
.HasForeignKey<Product>(d => d.Id)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_Product_ProductGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Productgroup>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("productgroup")
|
||||
.HasCharSet("utf8mb4")
|
||||
.UseCollation("utf8mb4_general_ci");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Index).HasColumnType("int(11)");
|
||||
entity.Property(e => e.IsArchived).HasColumnType("tinyint(4)");
|
||||
entity.Property(e => e.Name)
|
||||
.IsRequired()
|
||||
.HasColumnType("tinytext");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Sale>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("sale")
|
||||
.HasCharSet("armscii8")
|
||||
.UseCollation("armscii8_bin");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnType("int(11)");
|
||||
entity.Property(e => e.EmployeeId).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Time).HasColumnType("datetime");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SaleLine>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
.ToTable("sale_line")
|
||||
.HasCharSet("armscii8")
|
||||
.UseCollation("armscii8_bin");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Pieces).HasColumnType("smallint(6)");
|
||||
entity.Property(e => e.Price).HasPrecision(20, 6);
|
||||
entity.Property(e => e.Product)
|
||||
.IsRequired()
|
||||
.HasColumnType("tinytext");
|
||||
entity.Property(e => e.SaleId).HasColumnType("int(11)");
|
||||
entity.Property(e => e.Total).HasPrecision(20, 6);
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pos.Api.Database.Data
|
||||
{
|
||||
public partial class PosApiContext
|
||||
{
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
LoadConfig l = new LoadConfig();
|
||||
IConfiguration config = l.ByEnvironment();
|
||||
string connectionString = config["MySQL"].ToString();
|
||||
optionsBuilder
|
||||
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
|
||||
.UseLoggerFactory(LoggerFactory.Create(b => b
|
||||
.AddFilter(level => level >= LogLevel.Information)))
|
||||
.EnableSensitiveDataLogging()
|
||||
.EnableDetailedErrors();
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
PointOfSale/Pos.Api/Pos.Api.Database/LoadConfig.cs
Normal file
55
PointOfSale/Pos.Api/Pos.Api.Database/LoadConfig.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Pos.Api.Database
|
||||
{
|
||||
public class LoadConfig
|
||||
{
|
||||
private string dir;
|
||||
public LoadConfig()
|
||||
{
|
||||
dir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
public IConfiguration ByEnvironment()
|
||||
{
|
||||
//Console.Out.WriteLine($"Json path: {dir}");
|
||||
#if DEBUG
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
|
||||
#else
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
#endif
|
||||
//Running in a environment that not is supported in this setup
|
||||
throw new Exception("HostingEnvironment is not supported! This config setup only supports Development or Production");
|
||||
}
|
||||
|
||||
public IConfiguration DebugConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
|
||||
public IConfiguration ReleaseConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
PointOfSale/Pos.Api/Pos.Api.Database/Models/Employee.cs
Normal file
15
PointOfSale/Pos.Api/Pos.Api.Database/Models/Employee.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class Employee
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public sbyte IsArchived { get; set; }
|
||||
}
|
||||
11
PointOfSale/Pos.Api/Pos.Api.Database/Models/LastUpdate.cs
Normal file
11
PointOfSale/Pos.Api/Pos.Api.Database/Models/LastUpdate.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class LastUpdate
|
||||
{
|
||||
public DateTime? DateTime { get; set; }
|
||||
}
|
||||
17
PointOfSale/Pos.Api/Pos.Api.Database/Models/Payment.cs
Normal file
17
PointOfSale/Pos.Api/Pos.Api.Database/Models/Payment.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class Payment
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int SaleId { get; set; }
|
||||
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
}
|
||||
25
PointOfSale/Pos.Api/Pos.Api.Database/Models/Product.cs
Normal file
25
PointOfSale/Pos.Api/Pos.Api.Database/Models/Product.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class Product
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public int ProductGroupId { get; set; }
|
||||
|
||||
public sbyte IsArchived { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public virtual Productgroup IdNavigation { get; set; }
|
||||
}
|
||||
19
PointOfSale/Pos.Api/Pos.Api.Database/Models/Productgroup.cs
Normal file
19
PointOfSale/Pos.Api/Pos.Api.Database/Models/Productgroup.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class Productgroup
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public sbyte IsArchived { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public virtual Product Product { get; set; }
|
||||
}
|
||||
15
PointOfSale/Pos.Api/Pos.Api.Database/Models/Sale.cs
Normal file
15
PointOfSale/Pos.Api/Pos.Api.Database/Models/Sale.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class Sale
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public DateTime Time { get; set; }
|
||||
|
||||
public int EmployeeId { get; set; }
|
||||
}
|
||||
21
PointOfSale/Pos.Api/Pos.Api.Database/Models/SaleLine.cs
Normal file
21
PointOfSale/Pos.Api/Pos.Api.Database/Models/SaleLine.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pos.Api.Database.Models;
|
||||
|
||||
public partial class SaleLine
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int SaleId { get; set; }
|
||||
|
||||
public string Product { get; set; }
|
||||
|
||||
public short Pieces { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public decimal Total { get; set; }
|
||||
}
|
||||
15
PointOfSale/Pos.Api/Pos.Api.Database/Pos.Api.Database.csproj
Normal file
15
PointOfSale/Pos.Api/Pos.Api.Database/Pos.Api.Database.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
66
PointOfSale/Pos.Api/Pos.Api.Database/efpt.config.json
Normal file
66
PointOfSale/Pos.Api/Pos.Api.Database/efpt.config.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"CodeGenerationMode": 3,
|
||||
"ContextClassName": "PosApiContext",
|
||||
"ContextNamespace": null,
|
||||
"DefaultDacpacSchema": null,
|
||||
"FilterSchemas": false,
|
||||
"IncludeConnectionString": false,
|
||||
"ModelNamespace": null,
|
||||
"OutputContextPath": "Data",
|
||||
"OutputPath": "Models",
|
||||
"PreserveCasingWithRegex": true,
|
||||
"ProjectRootNamespace": "Pos.Api.Database",
|
||||
"Schemas": null,
|
||||
"SelectedHandlebarsLanguage": 0,
|
||||
"SelectedToBeGenerated": 0,
|
||||
"Tables": [
|
||||
{
|
||||
"Name": "employee",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "LastUpdate",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "payment",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "product",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "productgroup",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "sale",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "sale_line",
|
||||
"ObjectType": 0
|
||||
}
|
||||
],
|
||||
"UiHint": "simply.com",
|
||||
"UncountableWords": null,
|
||||
"UseBoolPropertiesWithoutDefaultSql": false,
|
||||
"UseDatabaseNames": false,
|
||||
"UseDateOnlyTimeOnly": false,
|
||||
"UseDbContextSplitting": false,
|
||||
"UseFluentApiOnly": true,
|
||||
"UseHandleBars": false,
|
||||
"UseHierarchyId": false,
|
||||
"UseInflector": true,
|
||||
"UseLegacyPluralizer": false,
|
||||
"UseManyToManyEntity": false,
|
||||
"UseNoDefaultConstructor": false,
|
||||
"UseNoObjectFilter": false,
|
||||
"UseNodaTime": false,
|
||||
"UseNullableReferences": false,
|
||||
"UseSchemaFolders": false,
|
||||
"UseSchemaNamespaces": false,
|
||||
"UseSpatial": false,
|
||||
"UseT4": false
|
||||
}
|
||||
29
PointOfSale/Pos.Api/Pos.Api/BaseController.cs
Normal file
29
PointOfSale/Pos.Api/Pos.Api/BaseController.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Pos.Api.Database;
|
||||
|
||||
namespace Pos.Api
|
||||
{
|
||||
public class BaseController : Controller
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
public BaseController(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
public override async Task OnActionExecutionAsync(ActionExecutingContext context,
|
||||
ActionExecutionDelegate next)
|
||||
{
|
||||
HttpRequest request = Request;
|
||||
string apiKey = request.Headers["ApiKey"].ToString();
|
||||
string? apiKeyRequest = _config["ApiKey"];
|
||||
if (apiKeyRequest == null)
|
||||
{
|
||||
throw new NullReferenceException("ApiKey header is missing");
|
||||
}
|
||||
|
||||
if (!apiKeyRequest.Equals(apiKey))
|
||||
throw new ArgumentException("ApiKey is wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
151
PointOfSale/Pos.Api/Pos.Api/Controllers/PosController.cs
Normal file
151
PointOfSale/Pos.Api/Pos.Api/Controllers/PosController.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Pos.Api.Database.Data;
|
||||
using Pos.Api.Database.Models;
|
||||
|
||||
namespace Pos.Api.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PosController : Controller
|
||||
{
|
||||
private readonly PosApiContext _context;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public PosController(IConfiguration config, PosApiContext context)
|
||||
{
|
||||
_context = context;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
//[HttpGet("/update")]
|
||||
//public DateTime LastUpdate()
|
||||
//{
|
||||
|
||||
// LastUpdate? lastUpdate = _context.LastUpdates.SingleOrDefault();
|
||||
// if (lastUpdate == null)
|
||||
// {
|
||||
// return DateTime.Now;
|
||||
// }
|
||||
|
||||
// DateTime last = lastUpdate.DateTime.Value;
|
||||
// lastUpdate.DateTime = DateTime.Now;
|
||||
// _context.SaveChanges();
|
||||
|
||||
// return last;
|
||||
//}
|
||||
|
||||
[HttpPost("/employee")]
|
||||
public void Employee(Employee employee)
|
||||
{
|
||||
ValidateApiKey();
|
||||
|
||||
Employee? dbEmployee = _context.Employees.SingleOrDefault(c => c.Id == employee.Id);
|
||||
if (dbEmployee == null)
|
||||
{
|
||||
dbEmployee = new Employee();
|
||||
dbEmployee.Id = employee.Id;
|
||||
dbEmployee.IsArchived = employee.IsArchived;
|
||||
_context.Employees.Add(dbEmployee);
|
||||
}
|
||||
dbEmployee.Name = employee.Name;
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
[HttpPost("/productgroup")]
|
||||
public void Product(Productgroup productGroup)
|
||||
{
|
||||
ValidateApiKey();
|
||||
|
||||
Productgroup dbProductGroup = _context.Productgroups.SingleOrDefault(c => c.Id == productGroup.Id);
|
||||
if (dbProductGroup == null)
|
||||
{
|
||||
dbProductGroup = new Productgroup();
|
||||
dbProductGroup.Id = productGroup.Id;
|
||||
_context.Productgroups.Add(dbProductGroup);
|
||||
}
|
||||
dbProductGroup.IsArchived = productGroup.IsArchived;
|
||||
dbProductGroup.Name = productGroup.Name;
|
||||
dbProductGroup.Index = productGroup.Index;
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
[HttpPost("/sale")]
|
||||
public void Sale(Sale sale)
|
||||
{
|
||||
ValidateApiKey();
|
||||
|
||||
Sale? dbSale = _context.Sales.SingleOrDefault(c => c.Id == sale.Id);
|
||||
if (dbSale == null)
|
||||
{
|
||||
dbSale = new Sale();
|
||||
dbSale.Id = sale.Id;
|
||||
_context.Sales.Add(dbSale);
|
||||
}
|
||||
dbSale.EmployeeId = sale.EmployeeId;
|
||||
dbSale.Time = sale.Time;
|
||||
_context.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
[HttpPost("/saleline")]
|
||||
public void SaleLine(SaleLine saleLine)
|
||||
{
|
||||
ValidateApiKey();
|
||||
|
||||
SaleLine? dbSaleLine = _context.SaleLines.SingleOrDefault(c => c.Id == saleLine.Id);
|
||||
if (dbSaleLine == null)
|
||||
{
|
||||
dbSaleLine = new SaleLine();
|
||||
dbSaleLine.Id = saleLine.Id;
|
||||
_context.SaleLines.Add(dbSaleLine);
|
||||
}
|
||||
dbSaleLine.SaleId = saleLine.SaleId;
|
||||
dbSaleLine.Price = saleLine.Price;
|
||||
dbSaleLine.Pieces = saleLine.Pieces;
|
||||
dbSaleLine.Price = saleLine.Price;
|
||||
dbSaleLine.Product = saleLine.Product;
|
||||
dbSaleLine.Total = saleLine.Total;
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
[HttpPost("/payment")]
|
||||
public void Payment(Payment payment)
|
||||
{
|
||||
ValidateApiKey();
|
||||
|
||||
Payment? dbPayment = _context.Payments.SingleOrDefault(c => c.Id == payment.Id);
|
||||
if (dbPayment == null)
|
||||
{
|
||||
dbPayment = new Payment();
|
||||
dbPayment.Id = payment.Id;
|
||||
_context.Payments.Add(dbPayment);
|
||||
}
|
||||
dbPayment.Amount = payment.Amount;
|
||||
dbPayment.SaleId = payment.SaleId;
|
||||
dbPayment.Type = payment.Type;
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
private void ValidateApiKey()
|
||||
{
|
||||
IHeaderDictionary headers = Request.Headers;
|
||||
if (!headers.ContainsKey("ApiKey"))
|
||||
{
|
||||
throw new MissingFieldException("ApiKey missing");
|
||||
}
|
||||
|
||||
StringValues apiKeyHeader = headers["ApiKey"];
|
||||
string? apiKey = _config["ApiKey"];
|
||||
if (!apiKeyHeader.Equals(apiKey))
|
||||
{
|
||||
throw new MissingFieldException("ApiKey is wrong");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Pos.Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetWeatherForecast")]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Pos.Api.Database;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace Pos.Api.Helper
|
||||
{
|
||||
public class ApiKeyHeaderOperationFilter : IOperationFilter
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public ApiKeyHeaderOperationFilter(IConfiguration config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
string? apiKey = _config["ApiKey"];
|
||||
operation.Parameters.Add(new OpenApiParameter
|
||||
{
|
||||
Name = "ApiKey",
|
||||
In = ParameterLocation.Header,
|
||||
Required = true,
|
||||
Schema = new OpenApiSchema
|
||||
{
|
||||
Type = "string",
|
||||
Default = new OpenApiString(apiKey)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
55
PointOfSale/Pos.Api/Pos.Api/Helper/LoadConfig.cs
Normal file
55
PointOfSale/Pos.Api/Pos.Api/Helper/LoadConfig.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Pos.Api.Helper
|
||||
{
|
||||
public class LoadConfig
|
||||
{
|
||||
private string dir;
|
||||
public LoadConfig()
|
||||
{
|
||||
dir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
public IConfiguration ByEnvironment()
|
||||
{
|
||||
//Console.Out.WriteLine($"Json path: {dir}");
|
||||
#if DEBUG
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
|
||||
#else
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
#endif
|
||||
//Running in a environment that not is supported in this setup
|
||||
throw new Exception("HostingEnvironment is not supported! This config setup only supports Development or Production");
|
||||
}
|
||||
|
||||
public IConfiguration DebugConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
|
||||
public IConfiguration ReleaseConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
PointOfSale/Pos.Api/Pos.Api/Pos.Api.csproj
Normal file
24
PointOfSale/Pos.Api/Pos.Api/Pos.Api.csproj
Normal file
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.7" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Pos.Api.Database\Pos.Api.Database.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
32
PointOfSale/Pos.Api/Pos.Api/Program.cs
Normal file
32
PointOfSale/Pos.Api/Pos.Api/Program.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Pos.Api.Database;
|
||||
using Pos.Api.Database.Data;
|
||||
using Pos.Api.Helper;
|
||||
using LoadConfig = Pos.Api.Helper.LoadConfig;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
LoadConfig loadConfig = new LoadConfig();
|
||||
IConfiguration config = loadConfig.ByEnvironment();
|
||||
builder.Services.AddSingleton(config);
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
c.OperationFilter<ApiKeyHeaderOperationFilter>()
|
||||
);
|
||||
builder.Services.AddDbContext<PosApiContext>();
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
31
PointOfSale/Pos.Api/Pos.Api/Properties/launchSettings.json
Normal file
31
PointOfSale/Pos.Api/Pos.Api/Properties/launchSettings.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:53151",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5297",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
PointOfSale/Pos.Api/Pos.Api/WeatherForecast.cs
Normal file
13
PointOfSale/Pos.Api/Pos.Api/WeatherForecast.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Pos.Api
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
||||
8
PointOfSale/Pos.Api/Pos.Api/appsettings.Development.json
Normal file
8
PointOfSale/Pos.Api/Pos.Api/appsettings.Development.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
PointOfSale/Pos.Api/Pos.Api/appsettings.json
Normal file
11
PointOfSale/Pos.Api/Pos.Api/appsettings.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"MySQL": "Data Source=mysql22.unoeuro.com;Initial Catalog=blomstertilalt_dk_db;Persist Security Info=False;User ID=blomstertil_dk;Password=amccpy6l",
|
||||
"ApiKey": "ad0YfMYm5bdVGjmXkJBOdNggQaWtkB9nzyQv68GAcB7mpf9onGBP9j3DJ46S7go30NwaQgoZBNS7hZDOM79KTyU3K2ysMW2x4mWGHOkETJmWadaMXBTGpoWn0ef9KiUN"
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Pos.Dispatcher.Database
|
||||
{
|
||||
public class LoadConfig
|
||||
{
|
||||
private string dir;
|
||||
public LoadConfig()
|
||||
{
|
||||
dir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
public IConfiguration ByEnvironment()
|
||||
{
|
||||
//Console.Out.WriteLine($"Json path: {dir}");
|
||||
#if DEBUG
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
|
||||
#else
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
#endif
|
||||
//Running in a environment that not is supported in this setup
|
||||
throw new Exception("HostingEnvironment is not supported! This config setup only supports Development or Production");
|
||||
}
|
||||
|
||||
public IConfiguration DebugConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
|
||||
public IConfiguration ReleaseConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Pos.Dispatcher.Database.Models;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Model;
|
||||
|
||||
public partial class PosDispatcherContext : DbContext
|
||||
{
|
||||
public PosDispatcherContext(DbContextOptions<PosDispatcherContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<Employee> Employees { get; set; }
|
||||
|
||||
public virtual DbSet<Payment> Payments { get; set; }
|
||||
|
||||
public virtual DbSet<Product> Products { get; set; }
|
||||
|
||||
public virtual DbSet<Productgroup> Productgroups { get; set; }
|
||||
|
||||
public virtual DbSet<Sale> Sales { get; set; }
|
||||
|
||||
public virtual DbSet<SaleLine> SaleLines { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.UseCollation("armscii8_bin")
|
||||
.HasCharSet("armscii8");
|
||||
|
||||
modelBuilder.Entity<Employee>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Payment>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Product>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity.Property(e => e.Id).ValueGeneratedOnAdd();
|
||||
|
||||
entity.HasOne(d => d.IdNavigation).WithOne(p => p.Product)
|
||||
.OnDelete(DeleteBehavior.ClientSetNull)
|
||||
.HasConstraintName("FK_Product_ProductGroup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Productgroup>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Sale>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SaleLine>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Model
|
||||
{
|
||||
public partial class PosDispatcherContext
|
||||
{
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
LoadConfig l = new LoadConfig();
|
||||
IConfiguration config = l.ByEnvironment();
|
||||
string connectionString = config["MariaSqlServer"].ToString();
|
||||
optionsBuilder
|
||||
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
|
||||
.UseLoggerFactory(LoggerFactory.Create(b => b
|
||||
.AddFilter(level => level >= LogLevel.Information)))
|
||||
.EnableSensitiveDataLogging()
|
||||
.EnableDetailedErrors();
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("employee")]
|
||||
[MySqlCharSet("utf8mb4")]
|
||||
[MySqlCollation("utf8mb4_general_ci")]
|
||||
public partial class Employee
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(50)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte IsArchived { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte? IsModified { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("payment")]
|
||||
public partial class Payment
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int SaleId { get; set; }
|
||||
|
||||
[Precision(20, 6)]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column(TypeName = "tinytext")]
|
||||
public string Type { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("product")]
|
||||
[Index("ProductGroupId", Name = "FK_Product_Categories")]
|
||||
[MySqlCharSet("utf8mb4")]
|
||||
[MySqlCollation("utf8mb4_general_ci")]
|
||||
public partial class Product
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column(TypeName = "tinytext")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Precision(10, 2)]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[Column(TypeName = "mediumtext")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int ProductGroupId { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte IsArchived { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Index { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte? IsModified { get; set; }
|
||||
|
||||
[ForeignKey("Id")]
|
||||
[InverseProperty("Product")]
|
||||
public virtual Productgroup IdNavigation { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("productgroup")]
|
||||
[MySqlCharSet("utf8mb4")]
|
||||
[MySqlCollation("utf8mb4_general_ci")]
|
||||
public partial class Productgroup
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column(TypeName = "tinytext")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte IsArchived { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Index { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte? IsModified { get; set; }
|
||||
|
||||
[InverseProperty("IdNavigation")]
|
||||
public virtual Product Product { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("sale")]
|
||||
public partial class Sale
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column(TypeName = "datetime")]
|
||||
public DateTime Time { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int EmployeeId { get; set; }
|
||||
|
||||
[Column(TypeName = "tinyint(4)")]
|
||||
public sbyte? IsModified { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
|
||||
#nullable disable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Pos.Dispatcher.Database.Models;
|
||||
|
||||
[Table("sale_line")]
|
||||
public partial class SaleLine
|
||||
{
|
||||
[Key]
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column(TypeName = "int(11)")]
|
||||
public int SaleId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column(TypeName = "tinytext")]
|
||||
public string Product { get; set; }
|
||||
|
||||
[Column(TypeName = "smallint(6)")]
|
||||
public short Pieces { get; set; }
|
||||
|
||||
[Precision(20, 6)]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[Precision(20, 6)]
|
||||
public decimal Total { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"CodeGenerationMode": 3,
|
||||
"ContextClassName": "PosDispatcherContext",
|
||||
"ContextNamespace": null,
|
||||
"DefaultDacpacSchema": null,
|
||||
"FilterSchemas": false,
|
||||
"IncludeConnectionString": false,
|
||||
"ModelNamespace": null,
|
||||
"OutputContextPath": "Model",
|
||||
"OutputPath": "Models",
|
||||
"PreserveCasingWithRegex": true,
|
||||
"ProjectRootNamespace": "Pos.Dispatcher.Database",
|
||||
"Schemas": null,
|
||||
"SelectedHandlebarsLanguage": 0,
|
||||
"SelectedToBeGenerated": 0,
|
||||
"Tables": [
|
||||
{
|
||||
"Name": "employee",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "payment",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "product",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "productgroup",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "sale",
|
||||
"ObjectType": 0
|
||||
},
|
||||
{
|
||||
"Name": "sale_line",
|
||||
"ObjectType": 0
|
||||
}
|
||||
],
|
||||
"UiHint": "localhost",
|
||||
"UncountableWords": null,
|
||||
"UseBoolPropertiesWithoutDefaultSql": false,
|
||||
"UseDatabaseNames": false,
|
||||
"UseDateOnlyTimeOnly": false,
|
||||
"UseDbContextSplitting": false,
|
||||
"UseFluentApiOnly": false,
|
||||
"UseHandleBars": false,
|
||||
"UseHierarchyId": false,
|
||||
"UseInflector": true,
|
||||
"UseLegacyPluralizer": false,
|
||||
"UseManyToManyEntity": false,
|
||||
"UseNoDefaultConstructor": false,
|
||||
"UseNoObjectFilter": false,
|
||||
"UseNodaTime": false,
|
||||
"UseNullableReferences": false,
|
||||
"UseSchemaFolders": false,
|
||||
"UseSchemaNamespaces": false,
|
||||
"UseSpatial": false,
|
||||
"UseT4": false
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="RestSharp" Version="110.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Pos.Dispatcher.Database\Pos.Dispatcher.Database.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
21
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/Program.cs
Normal file
21
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/Program.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Pomelo.EntityFrameworkCore;
|
||||
using Pos.Dispatcher;
|
||||
using Pos.Dispatcher.Database;
|
||||
using Pos.Dispatcher.Database.Model;
|
||||
|
||||
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
||||
LoadConfig loadConfig = new LoadConfig();
|
||||
IConfiguration config = loadConfig.ByEnvironment();
|
||||
builder.Services.AddSingleton(config);
|
||||
builder.Services.AddDbContext<PosDispatcherContext>();
|
||||
builder.Services.AddScoped<Synchronize>();
|
||||
using IHost host = builder.Build();
|
||||
|
||||
Synchronize synchronize = host.Services.GetRequiredService<Synchronize>();
|
||||
synchronize.Go();
|
||||
103
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/Synchronize.cs
Normal file
103
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/Synchronize.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Pos.Dispatcher.Database.Model;
|
||||
using Pos.Dispatcher.Database.Models;
|
||||
using RestSharp;
|
||||
|
||||
namespace Pos.Dispatcher
|
||||
{
|
||||
public class Synchronize
|
||||
{
|
||||
private readonly PosDispatcherContext _context;
|
||||
private readonly IConfiguration _config;
|
||||
private string _apiUrl;
|
||||
private string _apiKey;
|
||||
|
||||
public Synchronize(PosDispatcherContext context, IConfiguration config)
|
||||
{
|
||||
_context = context;
|
||||
_config = config;
|
||||
_apiUrl = _config["PosApi"];
|
||||
_apiKey = _config["ApiKey"];
|
||||
}
|
||||
|
||||
public void Go()
|
||||
{
|
||||
Employee();
|
||||
ProductGroup();
|
||||
Sale();
|
||||
}
|
||||
|
||||
private void Employee()
|
||||
{
|
||||
List<Employee> employees = _context.Employees.Where(c => c.IsModified == 1).ToList();
|
||||
foreach (Employee employee in employees)
|
||||
{
|
||||
RestClient client = new RestClient(_apiUrl);
|
||||
client.AddDefaultHeader("ApiKey", _apiKey);
|
||||
var request = new RestRequest("/employee", Method.Post);
|
||||
request.AddJsonBody(employee);
|
||||
RestResponse restResponse = client.Post(request);
|
||||
employee.IsModified = 0;
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
private void ProductGroup()
|
||||
{
|
||||
List<Productgroup> productgroups = _context.Productgroups.Where(c => c.IsModified == 1).ToList();
|
||||
foreach (Productgroup product in productgroups)
|
||||
{
|
||||
RestClient client = new RestClient(_apiUrl);
|
||||
client.AddDefaultHeader("ApiKey", _apiKey);
|
||||
var request = new RestRequest("/productgroup", Method.Post);
|
||||
request.AddJsonBody(product);
|
||||
RestResponse response = client.Post(request);
|
||||
product.IsModified = 0;
|
||||
}
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Sale()
|
||||
{
|
||||
List<Sale> sales = _context.Sales.Where(c => c.IsModified == 1).ToList();
|
||||
foreach (Sale sale in sales)
|
||||
{
|
||||
RestClient client = new RestClient(_apiUrl);
|
||||
client.AddDefaultHeader("ApiKey", _apiKey);
|
||||
var request = new RestRequest("/sale", Method.Post);
|
||||
request.AddJsonBody(sale);
|
||||
RestResponse response = client.Post(request);
|
||||
sale.IsModified = 0;
|
||||
|
||||
List<SaleLine> saleLines = _context.SaleLines.Where(c => c.SaleId == sale.Id).ToList();
|
||||
foreach (SaleLine saleLine in saleLines)
|
||||
{
|
||||
client = new RestClient(_apiUrl);
|
||||
client.AddDefaultHeader("ApiKey", _apiKey);
|
||||
request = new RestRequest("/saleline", Method.Post);
|
||||
request.AddJsonBody(saleLine);
|
||||
response = client.Post(request);
|
||||
}
|
||||
|
||||
List<Payment> payments = _context.Payments.Where(c => c.SaleId == sale.Id).ToList();
|
||||
foreach (Payment payment in payments)
|
||||
{
|
||||
client = new RestClient(_apiUrl);
|
||||
client.AddDefaultHeader("ApiKey", _apiKey);
|
||||
request = new RestRequest("/payment", Method.Post);
|
||||
request.AddJsonBody(payment);
|
||||
response = client.Post(request);
|
||||
}
|
||||
|
||||
sale.IsModified = 0;
|
||||
}
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/appsettings.json
Normal file
12
PointOfSale/Pos.Dispatcher/Pos.Dispatcher/appsettings.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"MariaSqlServer": "Data Source=localhost;Initial Catalog=PointOfSale;Persist Security Info=False;User ID=root",
|
||||
"ApiKey": "ad0YfMYm5bdVGjmXkJBOdNggQaWtkB9nzyQv68GAcB7mpf9onGBP9j3DJ46S7go30NwaQgoZBNS7hZDOM79KTyU3K2ysMW2x4mWGHOkETJmWadaMXBTGpoWn0ef9KiUN",
|
||||
"PosApi": "http://localhost:53151"
|
||||
}
|
||||
21
PointOfSale/Pos.EpsonPrinter/EncodingHelper.cs
Normal file
21
PointOfSale/Pos.EpsonPrinter/EncodingHelper.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Text;
|
||||
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public static class EncodingHelper
|
||||
{
|
||||
static EncodingHelper()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
|
||||
public static Encoding GetEncodingForCodePage(PrinterCodePage codePage) =>
|
||||
codePage switch
|
||||
{
|
||||
PrinterCodePage.PC865_Nordic => Encoding.GetEncoding(865),
|
||||
PrinterCodePage.PC850_Multilingual => Encoding.GetEncoding(850),
|
||||
PrinterCodePage.PC858_Euro => Encoding.GetEncoding(858),
|
||||
PrinterCodePage.WPC1252 => Encoding.GetEncoding(1252),
|
||||
_ => Encoding.GetEncoding(865)
|
||||
};
|
||||
}
|
||||
42
PointOfSale/Pos.EpsonPrinter/EpsonNetworkReceiptPrinter.cs
Normal file
42
PointOfSale/Pos.EpsonPrinter/EpsonNetworkReceiptPrinter.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public sealed class EpsonNetworkReceiptPrinter : IReceiptPrinter
|
||||
{
|
||||
private readonly string _host;
|
||||
private readonly int _port;
|
||||
private readonly PrinterCodePage _codePage;
|
||||
|
||||
public EpsonNetworkReceiptPrinter(string host, int port = 9100, PrinterCodePage codePage = PrinterCodePage.PC865_Nordic)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
throw new ArgumentException("Host must be provided.", nameof(host));
|
||||
}
|
||||
|
||||
_host = host;
|
||||
_port = port;
|
||||
_codePage = codePage;
|
||||
}
|
||||
|
||||
public async Task PrintAsync(Receipt receipt, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(receipt);
|
||||
|
||||
var data = ReceiptFormatter.Format(receipt, _codePage);
|
||||
await PrintRawAsync(data, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task PrintRawAsync(byte[] data, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(data);
|
||||
|
||||
using var client = new TcpClient();
|
||||
await client.ConnectAsync(_host, _port, cancellationToken);
|
||||
|
||||
await using var stream = client.GetStream();
|
||||
await stream.WriteAsync(data, cancellationToken);
|
||||
await stream.FlushAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
10
PointOfSale/Pos.EpsonPrinter/EpsonReceiptPrinter.csproj
Normal file
10
PointOfSale/Pos.EpsonPrinter/EpsonReceiptPrinter.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
147
PointOfSale/Pos.EpsonPrinter/EscPosBuilder.cs
Normal file
147
PointOfSale/Pos.EpsonPrinter/EscPosBuilder.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System.Text;
|
||||
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public sealed class EscPosBuilder
|
||||
{
|
||||
private readonly List<byte> _buffer = new();
|
||||
private readonly Encoding _encoding;
|
||||
private PrinterCodePage _codePage;
|
||||
|
||||
public EscPosBuilder(PrinterCodePage codePage = PrinterCodePage.PC865_Nordic, Encoding? encoding = null)
|
||||
{
|
||||
_codePage = codePage;
|
||||
_encoding = encoding ?? EncodingHelper.GetEncodingForCodePage(codePage);
|
||||
}
|
||||
|
||||
public EscPosBuilder Initialize()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.Initialize);
|
||||
_buffer.AddRange(EscPosCommands.SelectCodePage(_codePage));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder SelectCodePage(PrinterCodePage codePage)
|
||||
{
|
||||
_codePage = codePage;
|
||||
_buffer.AddRange(EscPosCommands.SelectCodePage(codePage));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder AlignLeft()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.AlignLeft);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder AlignCenter()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.AlignCenter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder AlignRight()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.AlignRight);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder BoldOn()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.BoldOn);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder BoldOff()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.BoldOff);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder UnderlineOn()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.UnderlineOn);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder UnderlineOff()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.UnderlineOff);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder SetTextSize(TextSize size)
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.TextSize(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder SetTextSize(int widthMultiplier, int heightMultiplier)
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.TextSize(widthMultiplier, heightMultiplier));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder Write(string text)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
_buffer.AddRange(_encoding.GetBytes(text));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder WriteLine(string? text = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
_buffer.AddRange(_encoding.GetBytes(text));
|
||||
}
|
||||
|
||||
_buffer.Add(0x0A);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder Feed(int lines = 1)
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.Feed(lines));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder Cut(bool partial = false)
|
||||
{
|
||||
_buffer.AddRange(partial ? EscPosCommands.CutPartial() : EscPosCommands.CutFull());
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder OpenCashDrawer()
|
||||
{
|
||||
_buffer.AddRange(EscPosCommands.OpenCashDrawer());
|
||||
return this;
|
||||
}
|
||||
|
||||
public EscPosBuilder Separator(int width = 42, char character = '-')
|
||||
{
|
||||
return WriteLine(new string(character, width));
|
||||
}
|
||||
|
||||
public EscPosBuilder WriteColumns(string left, string? right, int totalWidth = 42)
|
||||
{
|
||||
left ??= string.Empty;
|
||||
right ??= string.Empty;
|
||||
|
||||
if (left.Length + right.Length >= totalWidth)
|
||||
{
|
||||
WriteLine(left);
|
||||
WriteLine(right.PadLeft(totalWidth));
|
||||
return this;
|
||||
}
|
||||
|
||||
var spaces = totalWidth - left.Length - right.Length;
|
||||
WriteLine(left + new string(' ', spaces) + right);
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] Build() => _buffer.ToArray();
|
||||
}
|
||||
63
PointOfSale/Pos.EpsonPrinter/EscPosCommands.cs
Normal file
63
PointOfSale/Pos.EpsonPrinter/EscPosCommands.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public static class EscPosCommands
|
||||
{
|
||||
public static readonly byte[] Initialize = [0x1B, 0x40];
|
||||
|
||||
public static readonly byte[] BoldOn = [0x1B, 0x45, 0x01];
|
||||
public static readonly byte[] BoldOff = [0x1B, 0x45, 0x00];
|
||||
|
||||
public static readonly byte[] UnderlineOn = [0x1B, 0x2D, 0x01];
|
||||
public static readonly byte[] UnderlineOff = [0x1B, 0x2D, 0x00];
|
||||
|
||||
public static readonly byte[] AlignLeft = [0x1B, 0x61, 0x00];
|
||||
public static readonly byte[] AlignCenter = [0x1B, 0x61, 0x01];
|
||||
public static readonly byte[] AlignRight = [0x1B, 0x61, 0x02];
|
||||
|
||||
public static readonly byte[] FontA = [0x1B, 0x4D, 0x00];
|
||||
public static readonly byte[] FontB = [0x1B, 0x4D, 0x01];
|
||||
|
||||
public static byte[] Feed(int lines)
|
||||
{
|
||||
if (lines < 0 || lines > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(lines));
|
||||
}
|
||||
|
||||
return [0x1B, 0x64, (byte)lines];
|
||||
}
|
||||
|
||||
public static byte[] CutFull() => [0x1D, 0x56, 0x00];
|
||||
|
||||
public static byte[] CutPartial() => [0x1D, 0x56, 0x01];
|
||||
|
||||
public static byte[] OpenCashDrawer() => [0x1B, 0x70, 0x00, 0x19, 0xFA];
|
||||
|
||||
public static byte[] SelectCodePage(PrinterCodePage codePage) => [0x1B, 0x74, (byte)codePage];
|
||||
|
||||
public static byte[] TextSize(TextSize size) =>
|
||||
size switch
|
||||
{
|
||||
TextSize.Normal => [0x1D, 0x21, 0x00],
|
||||
TextSize.DoubleWidth => [0x1D, 0x21, 0x10],
|
||||
TextSize.DoubleHeight => [0x1D, 0x21, 0x01],
|
||||
TextSize.DoubleWidthAndHeight => [0x1D, 0x21, 0x11],
|
||||
_ => [0x1D, 0x21, 0x00]
|
||||
};
|
||||
|
||||
public static byte[] TextSize(int widthMultiplier, int heightMultiplier)
|
||||
{
|
||||
if (widthMultiplier < 1 || widthMultiplier > 8)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(widthMultiplier));
|
||||
}
|
||||
|
||||
if (heightMultiplier < 1 || heightMultiplier > 8)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(heightMultiplier));
|
||||
}
|
||||
|
||||
var value = (byte)(((widthMultiplier - 1) << 4) | (heightMultiplier - 1));
|
||||
return [0x1D, 0x21, value];
|
||||
}
|
||||
}
|
||||
7
PointOfSale/Pos.EpsonPrinter/IReceiptPrinter.cs
Normal file
7
PointOfSale/Pos.EpsonPrinter/IReceiptPrinter.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public interface IReceiptPrinter
|
||||
{
|
||||
Task PrintAsync(Receipt receipt, CancellationToken cancellationToken = default);
|
||||
Task PrintRawAsync(byte[] data, CancellationToken cancellationToken = default);
|
||||
}
|
||||
13
PointOfSale/Pos.EpsonPrinter/PrinterCodePage.cs
Normal file
13
PointOfSale/Pos.EpsonPrinter/PrinterCodePage.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public enum PrinterCodePage
|
||||
{
|
||||
PC437_USA = 0,
|
||||
Katakana = 1,
|
||||
PC850_Multilingual = 2,
|
||||
PC860_Portuguese = 3,
|
||||
PC863_CanadianFrench = 4,
|
||||
PC865_Nordic = 5,
|
||||
WPC1252 = 16,
|
||||
PC858_Euro = 19
|
||||
}
|
||||
31
PointOfSale/Pos.EpsonPrinter/Receipt.cs
Normal file
31
PointOfSale/Pos.EpsonPrinter/Receipt.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public sealed class Receipt
|
||||
{
|
||||
public string? Header { get; set; }
|
||||
public string? SubHeader { get; set; }
|
||||
public List<ReceiptLine> Lines { get; } = new();
|
||||
public string? Footer { get; set; }
|
||||
public bool CutPaper { get; set; } = true;
|
||||
public int PaperWidthCharacters { get; set; } = 42;
|
||||
}
|
||||
|
||||
public sealed class ReceiptLine
|
||||
{
|
||||
public ReceiptLine()
|
||||
{
|
||||
}
|
||||
|
||||
public ReceiptLine(string left, string? right = null, bool emphasize = false, TextSize textSize = TextSize.Normal)
|
||||
{
|
||||
Left = left;
|
||||
Right = right;
|
||||
Emphasize = emphasize;
|
||||
TextSize = textSize;
|
||||
}
|
||||
|
||||
public string Left { get; set; } = string.Empty;
|
||||
public string? Right { get; set; }
|
||||
public bool Emphasize { get; set; }
|
||||
public TextSize TextSize { get; set; } = TextSize.Normal;
|
||||
}
|
||||
72
PointOfSale/Pos.EpsonPrinter/ReceiptFormatter.cs
Normal file
72
PointOfSale/Pos.EpsonPrinter/ReceiptFormatter.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public static class ReceiptFormatter
|
||||
{
|
||||
public static byte[] Format(Receipt receipt, PrinterCodePage codePage = PrinterCodePage.PC865_Nordic)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(receipt);
|
||||
|
||||
var width = receipt.PaperWidthCharacters <= 0 ? 42 : receipt.PaperWidthCharacters;
|
||||
|
||||
var builder = new EscPosBuilder(codePage)
|
||||
.Initialize()
|
||||
.AlignCenter();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(receipt.Header))
|
||||
{
|
||||
builder
|
||||
.SetTextSize(TextSize.DoubleWidthAndHeight)
|
||||
.BoldOn()
|
||||
.WriteLine(receipt.Header)
|
||||
.BoldOff()
|
||||
.SetTextSize(TextSize.Normal);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(receipt.SubHeader))
|
||||
{
|
||||
builder.WriteLine(receipt.SubHeader);
|
||||
}
|
||||
|
||||
builder
|
||||
.Feed(1)
|
||||
.AlignLeft()
|
||||
.Separator(width);
|
||||
|
||||
foreach (var line in receipt.Lines)
|
||||
{
|
||||
builder.SetTextSize(line.TextSize);
|
||||
|
||||
if (line.Emphasize)
|
||||
{
|
||||
builder.BoldOn();
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.BoldOff();
|
||||
}
|
||||
|
||||
builder.WriteColumns(line.Left, line.Right, width);
|
||||
builder.SetTextSize(TextSize.Normal);
|
||||
builder.BoldOff();
|
||||
}
|
||||
|
||||
builder
|
||||
.Separator(width)
|
||||
.Feed(1)
|
||||
.AlignCenter();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(receipt.Footer))
|
||||
{
|
||||
builder.WriteLine(receipt.Footer);
|
||||
}
|
||||
|
||||
builder.Feed(3);
|
||||
|
||||
if (receipt.CutPaper)
|
||||
{
|
||||
builder.Cut();
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
9
PointOfSale/Pos.EpsonPrinter/TextSize.cs
Normal file
9
PointOfSale/Pos.EpsonPrinter/TextSize.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace EpsonReceiptPrinter;
|
||||
|
||||
public enum TextSize
|
||||
{
|
||||
Normal,
|
||||
DoubleWidth,
|
||||
DoubleHeight,
|
||||
DoubleWidthAndHeight
|
||||
}
|
||||
12
PointOfSale/Pos.Ui/Database/.config/dotnet-tools.json
Normal file
12
PointOfSale/Pos.Ui/Database/.config/dotnet-tools.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.9",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
PointOfSale/Pos.Ui/Database/Database.csproj
Normal file
16
PointOfSale/Pos.Ui/Database/Database.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
60
PointOfSale/Pos.Ui/Database/LoadConfig.cs
Normal file
60
PointOfSale/Pos.Ui/Database/LoadConfig.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Pos
|
||||
{
|
||||
public class LoadConfig
|
||||
{
|
||||
private string dir;
|
||||
public LoadConfig()
|
||||
{
|
||||
dir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
public IConfiguration ByEnvironment()
|
||||
{
|
||||
//Console.Out.WriteLine($"Json path: {dir}");
|
||||
#if DEBUG
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
|
||||
#else
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
#endif
|
||||
//Running in a environment that not is supported in this setup
|
||||
throw new Exception("HostingEnvironment is not supported! This config setup only supports Development or Production");
|
||||
}
|
||||
|
||||
public IConfiguration DebugConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
|
||||
public IConfiguration ReleaseConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
PointOfSale/Pos.Ui/Database/Models/EmployeeEntity.cs
Normal file
20
PointOfSale/Pos.Ui/Database/Models/EmployeeEntity.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("employee")]
|
||||
public class EmployeeEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
}
|
||||
}
|
||||
21
PointOfSale/Pos.Ui/Database/Models/PaymentEntity.cs
Normal file
21
PointOfSale/Pos.Ui/Database/Models/PaymentEntity.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("payment")]
|
||||
public class PaymentEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public int SaleId { get; set; }
|
||||
public decimal Amount { get; set;}
|
||||
public string Type { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/ProductEntity.cs
Normal file
22
PointOfSale/Pos.Ui/Database/Models/ProductEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("product")]
|
||||
public class ProductEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public int Index { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
public int ProductGroupId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ProductGroupId))]
|
||||
public ProductGroupEntity ProductGroup { get; set; }
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/ProductGroupEntity.cs
Normal file
22
PointOfSale/Pos.Ui/Database/Models/ProductGroupEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("productgroup")]
|
||||
public class ProductGroupEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public ICollection<ProductEntity> Products { get; set; }
|
||||
}
|
||||
}
|
||||
20
PointOfSale/Pos.Ui/Database/Models/SaleEntity.cs
Normal file
20
PointOfSale/Pos.Ui/Database/Models/SaleEntity.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("sale")]
|
||||
public class SaleEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public int EmployeeId { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/SaleLineEntity.cs
Normal file
22
PointOfSale/Pos.Ui/Database/Models/SaleLineEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("sale_line")]
|
||||
public class SaleLineEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public int SaleId { get; set; }
|
||||
public string Product { get; set; }
|
||||
public int Pieces { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public decimal Total { get; set; }
|
||||
}
|
||||
}
|
||||
35
PointOfSale/Pos.Ui/Database/PosDbContext.cs
Normal file
35
PointOfSale/Pos.Ui/Database/PosDbContext.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pos;
|
||||
|
||||
|
||||
namespace Database
|
||||
{
|
||||
public class PosDbContext : DbContext
|
||||
{
|
||||
|
||||
public DbSet<EmployeeEntity> Employee { get; set; }
|
||||
public DbSet<ProductGroupEntity> ProductGroups { get; set; }
|
||||
public DbSet<ProductEntity> Products { get; set; }
|
||||
public DbSet<SaleEntity> Sales { get; set; }
|
||||
public DbSet<SaleLineEntity> SalesLines { get; set; }
|
||||
public DbSet<PaymentEntity> Payment { get; set; }
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
LoadConfig l = new LoadConfig();
|
||||
IConfiguration config = l.ByEnvironment();
|
||||
string connectionString = config["MariaSqlServer"].ToString();
|
||||
optionsBuilder
|
||||
.UseMySql(connectionString,ServerVersion.AutoDetect(connectionString))
|
||||
.UseLoggerFactory(LoggerFactory.Create(b => b
|
||||
.AddFilter(level => level >= LogLevel.Information)))
|
||||
.EnableSensitiveDataLogging()
|
||||
.EnableDetailedErrors();
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
PointOfSale/Pos.Ui/Database/Repository/EmployeeRepository.cs
Normal file
62
PointOfSale/Pos.Ui/Database/Repository/EmployeeRepository.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Database.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class EmployeeRepository : IDisposable
|
||||
{
|
||||
|
||||
public void Add(string name)
|
||||
{
|
||||
EmployeeEntity employee = new EmployeeEntity();
|
||||
employee.Name = name;
|
||||
employee.IsModified = true;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.Employee.Add(employee);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public EmployeeEntity Get(int employeeId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employeeEntity = context.Employee.First(c => c.Id == employeeId);
|
||||
return employeeEntity;
|
||||
}
|
||||
|
||||
public List<EmployeeEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<EmployeeEntity> staffs = context.Employee.Where(c => c.IsArchived == false).ToList();
|
||||
|
||||
return staffs;
|
||||
}
|
||||
|
||||
public void Edit(int id, string name)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employee = context.Employee.Single(c => c.Id == id);
|
||||
employee.Name = name;
|
||||
employee.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employee = context.Employee.Single(c => c.Id == id);
|
||||
employee.IsArchived = true;
|
||||
employee.IsModified = true;
|
||||
context.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class ProductGroupRepository
|
||||
{
|
||||
public List<ProductGroupEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductGroupEntity> productGroups = context.ProductGroups
|
||||
.Include(c => c.Products)
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return productGroups;
|
||||
}
|
||||
|
||||
public ProductGroupEntity Get(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity product = context.ProductGroups.Single(c => c.Id == id);
|
||||
return product;
|
||||
}
|
||||
|
||||
public void Add(string name)
|
||||
{
|
||||
ProductGroupEntity productGroup = new ProductGroupEntity();
|
||||
productGroup.Name = name;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
//Get the highest index
|
||||
ProductGroupEntity highest = context.ProductGroups.OrderByDescending(c => c.Index).Take(1).FirstOrDefault();
|
||||
if(highest == null)
|
||||
{
|
||||
highest = new ProductGroupEntity();
|
||||
highest.Index = 0;
|
||||
}
|
||||
productGroup.Index = highest.Index + 1;
|
||||
context.ProductGroups.Add(productGroup);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Edit(string name, int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.Name = name;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Archive(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.IsArchived = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void SetIndex(int id, int index)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.Index = index;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public bool Any()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
bool any = context.ProductGroups.Any();
|
||||
return any;
|
||||
}
|
||||
}
|
||||
}
|
||||
87
PointOfSale/Pos.Ui/Database/Repository/ProductRepository.cs
Normal file
87
PointOfSale/Pos.Ui/Database/Repository/ProductRepository.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Database.Models;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class ProductRepository
|
||||
{
|
||||
public List<ProductEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductEntity> products = context.Products
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return products;
|
||||
}
|
||||
|
||||
public List<ProductEntity> GetByProductGroup(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductEntity> products = context.Products
|
||||
.Where(c => c.ProductGroupId == id)
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return products;
|
||||
}
|
||||
|
||||
public void SetIndex(int id, int index)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity product = context.Products.Single(c => c.Id == id);
|
||||
product.Index = index;
|
||||
product.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public ProductEntity GetById(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity product = context.Products.Single(c => c.Id == id);
|
||||
return product;
|
||||
}
|
||||
|
||||
public void Update(int id, int productGroupId, string name)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity dbProduct = context.Products.Single(c => c.Id == id);
|
||||
dbProduct.ProductGroupId = productGroupId;
|
||||
dbProduct.Name = name;
|
||||
dbProduct.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Archive(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity dbProduct = context.Products.Single(c => c.Id == id);
|
||||
dbProduct.IsArchived = true;
|
||||
dbProduct.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Add(string name, int productGroupId)
|
||||
{
|
||||
|
||||
ProductEntity product = new ProductEntity();
|
||||
product.Name = name;
|
||||
product.ProductGroupId = productGroupId;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
//Get the highest index
|
||||
ProductEntity highest = context.Products.OrderByDescending(c => c.Index).Take(1).FirstOrDefault();
|
||||
if (highest == null)
|
||||
{
|
||||
highest = new ProductEntity();
|
||||
highest.Index = 0;
|
||||
}
|
||||
product.Index = highest.Index + 1;
|
||||
product.IsModified = true;
|
||||
context.Products.Add(product);
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
83
PointOfSale/Pos.Ui/Database/Repository/SaleRepository.cs
Normal file
83
PointOfSale/Pos.Ui/Database/Repository/SaleRepository.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class SaleRepository
|
||||
{
|
||||
public SaleEntity New(int employeeId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = new SaleEntity();
|
||||
saleEntity.Time = DateTime.Now;
|
||||
saleEntity.EmployeeId = employeeId;
|
||||
saleEntity.IsModified = true;
|
||||
context.Sales.Add(saleEntity);
|
||||
context.SaveChanges();
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public SaleLineEntity SaveSaleLine(SaleLineEntity entity)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.SalesLines.Add(entity);
|
||||
context.SaveChanges();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public List<SaleLineEntity> GetSaleLineBySaleId(int saleId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleLineEntity> saleLineEntities = context.SalesLines.Where(c => c.SaleId == saleId).ToList();
|
||||
return saleLineEntities;
|
||||
}
|
||||
|
||||
public PaymentEntity SavePayment(PaymentEntity entity)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.Payment.Add(entity);
|
||||
context.SaveChanges();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public List<PaymentEntity> GetPaymentBySaleId(int saleId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<PaymentEntity> paymentEntities = context.Payment.Where(c => c.SaleId == saleId).ToList();
|
||||
return paymentEntities;
|
||||
}
|
||||
|
||||
public SaleEntity GetLatest()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = context.Sales.OrderByDescending(c => c.Id).Take(1).First();
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public SaleEntity Get(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = context.Sales.Single(c => c.Id == id);
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public List<SaleEntity> GetByDateRange(DateTime start, DateTime end)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleEntity> saleEntities = context.Sales.Where(c => c.Time.Date >= start.Date && c.Time.Date <= end.Date).OrderByDescending(c => c.Time).ToList();
|
||||
return saleEntities;
|
||||
}
|
||||
|
||||
public List<SaleEntity> GetByDateRange(DateTime start)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleEntity> saleEntities = context.Sales.Where(c => c.Time.Date == start.Date.Date).OrderByDescending(c => c.Time).ToList();
|
||||
return saleEntities;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using EpsonPrinter.Services;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PosPrinterController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// PrintReceipt receipt, so far only for all Epson Thermal Printers
|
||||
/// </summary>
|
||||
/// PrintStyle is:
|
||||
/// None
|
||||
/// FontB
|
||||
/// Bold
|
||||
/// DoubleHeight
|
||||
/// DoubleWidth
|
||||
/// Underline
|
||||
/// There is support for any combination of PrintStyles
|
||||
/// ----------------------------------------
|
||||
///
|
||||
///
|
||||
/// <param name="receiptModel"></param>
|
||||
[HttpPost]
|
||||
[Route("Receipt")]
|
||||
public void PrintReceipt([FromServices] EpsonPrintService epsonPrint, ReceiptModel receiptModel)
|
||||
{
|
||||
epsonPrint.PrintReceipt(receiptModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("SaleOfDay")]
|
||||
public void PrintSaleOfDay([FromServices] EpsonPrintService epsonPrint, SaleOfDayModel saleOfDayModel)
|
||||
{
|
||||
epsonPrint.PrintSaleOfDay(saleOfDayModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ValuesController : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("HelloWorld")]
|
||||
public string Get()
|
||||
{
|
||||
return "HelloWorld";
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master.zip
Normal file
BIN
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master.zip
Normal file
Binary file not shown.
1
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitattributes
vendored
Normal file
1
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
12
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.github/FUNDING.yml
vendored
Normal file
12
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: ['lukevp']
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
7
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitignore
vendored
Normal file
7
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.vs/
|
||||
.idea/
|
||||
**/obj/
|
||||
**/bin/
|
||||
push.ps1
|
||||
/push.txt
|
||||
/ESCPOS_NET/ESCPOS_NET.csproj.user
|
||||
@@ -0,0 +1,74 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ESCPOS_NET\ESCPOS_NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="abe-lincoln.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\abe-lincoln.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\kitten.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-100.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-200.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.bmp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.gif">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-400.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-500.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-600.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\Portal_Companion_Cube.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="kitten.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="pd-logo.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="test-files\output-juliogamasso.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,267 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static BasePrinter printer;
|
||||
private static ICommandEmitter e;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
Console.WriteLine("Welcome to the ESCPOS_NET Test Application!");
|
||||
Console.Write("Would you like to see all debug messages? (y/n): ");
|
||||
var response = Console.ReadLine().Trim().ToLowerInvariant();
|
||||
var logLevel = LogLevel.Information;
|
||||
if (response.Length >= 1 && response[0] == 'y')
|
||||
{
|
||||
Console.WriteLine("Debugging enabled!");
|
||||
logLevel = LogLevel.Trace;
|
||||
}
|
||||
var factory = LoggerFactory.Create(b => b.AddConsole().SetMinimumLevel(logLevel));
|
||||
var logger = factory.CreateLogger<Program>();
|
||||
ESCPOS_NET.Logging.Logger = logger;
|
||||
|
||||
Console.WriteLine("1 ) Test Serial Port");
|
||||
Console.WriteLine("2 ) Test Network Printer");
|
||||
Console.Write("Choice: ");
|
||||
string comPort = "";
|
||||
string baudRate;
|
||||
string ip;
|
||||
string networkPort;
|
||||
response = Console.ReadLine();
|
||||
var valid = new List<string> { "1", "2" };
|
||||
if (!valid.Contains(response))
|
||||
{
|
||||
response = "1";
|
||||
}
|
||||
|
||||
int choice = int.Parse(response);
|
||||
|
||||
if (choice == 1)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
while (!comPort.StartsWith("COM"))
|
||||
{
|
||||
Console.Write("COM Port (enter for default COM5): ");
|
||||
comPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(comPort))
|
||||
{
|
||||
comPort = "COM5";
|
||||
}
|
||||
}
|
||||
Console.Write("Baud Rate (enter for default 115200): ");
|
||||
baudRate = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(baudRate))
|
||||
{
|
||||
baudRate = "115200";
|
||||
}
|
||||
printer = new SerialPrinter(portName: comPort, baudRate: 115200);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
Console.Write("File / virtual com path (eg. /dev/usb/lp0): ");
|
||||
comPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(comPort))
|
||||
{
|
||||
comPort = "/dev/usb/lp0";
|
||||
}
|
||||
printer = new FilePrinter(filePath: comPort, false);
|
||||
}
|
||||
}
|
||||
else if (choice == 2)
|
||||
{
|
||||
Console.Write("IP Address (eg. 192.168.1.240): ");
|
||||
ip = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(ip))
|
||||
{
|
||||
ip = "192.168.254.202";
|
||||
}
|
||||
Console.Write("TCP Port (enter for default 9100): ");
|
||||
networkPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(networkPort))
|
||||
{
|
||||
networkPort = "9100";
|
||||
}
|
||||
printer = new NetworkPrinter(settings: new NetworkPrinterSettings() { ConnectionString = $"{ip}:{networkPort}" });
|
||||
}
|
||||
|
||||
bool monitor = false;
|
||||
Thread.Sleep(500);
|
||||
Console.Write("Turn on Live Status Back Monitoring? (y/n): ");
|
||||
response = Console.ReadLine().Trim().ToLowerInvariant();
|
||||
if (response.Length >= 1 && response[0] == 'y')
|
||||
{
|
||||
monitor = true;
|
||||
}
|
||||
|
||||
e = new EPSON();
|
||||
var testCases = new Dictionary<Option, string>()
|
||||
{
|
||||
{ Option.SingleLinePrinting, "Single Line Printing" },
|
||||
{ Option.MultiLinePrinting, "Multi-line Printing" },
|
||||
{ Option.LineSpacing, "Line Spacing" },
|
||||
{ Option.BarcodeStyles, "Barcode Styles" },
|
||||
{ Option.BarcodeTypes, "Barcode Types" },
|
||||
{ Option.TwoDimensionCodes, "2D Codes" },
|
||||
{ Option.TextStyles, "Text Styles" },
|
||||
{ Option.FullReceipt, "Full Receipt" },
|
||||
{ Option.CodePages, "Code Pages (Euro, Katakana, Etc)" },
|
||||
{ Option.Images, "Images" },
|
||||
{ Option.LegacyImages, "Legacy Images" },
|
||||
{ Option.LargeByteArrays, "Large Byte Arrays" },
|
||||
{ Option.CashDrawerPin2, "Cash Drawer Pin2" },
|
||||
{ Option.CashDrawerPin5, "Cash Drawer Pin5" },
|
||||
{ Option.Exit, "Exit" }
|
||||
|
||||
};
|
||||
while (true)
|
||||
{
|
||||
foreach (var item in testCases)
|
||||
{
|
||||
Console.WriteLine($"{(int)item.Key} : {item.Value}");
|
||||
}
|
||||
Console.Write("Execute Test: ");
|
||||
|
||||
if (!int.TryParse(Console.ReadLine(), out choice) || !Enum.IsDefined(typeof(Option), choice))
|
||||
{
|
||||
Console.WriteLine("Invalid entry. Please try again.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var enumChoice = (Option)choice;
|
||||
if (enumChoice == Option.Exit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Clear();
|
||||
|
||||
if (monitor)
|
||||
{
|
||||
printer.Write(e.Initialize());
|
||||
printer.Write(e.Enable());
|
||||
printer.Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
Setup(monitor);
|
||||
|
||||
printer?.Write(e.PrintLine($"== [ Start {testCases[enumChoice]} ] =="));
|
||||
|
||||
switch (enumChoice)
|
||||
{
|
||||
case Option.SingleLinePrinting:
|
||||
printer.Write(Tests.SingleLinePrinting(e));
|
||||
break;
|
||||
case Option.MultiLinePrinting:
|
||||
printer.Write(Tests.MultiLinePrinting(e));
|
||||
break;
|
||||
case Option.LineSpacing:
|
||||
printer.Write(Tests.LineSpacing(e));
|
||||
break;
|
||||
case Option.BarcodeStyles:
|
||||
printer.Write(Tests.BarcodeStyles(e));
|
||||
break;
|
||||
case Option.BarcodeTypes:
|
||||
printer.Write(Tests.BarcodeTypes(e));
|
||||
break;
|
||||
case Option.TwoDimensionCodes:
|
||||
printer.Write(Tests.TwoDimensionCodes(e));
|
||||
break;
|
||||
case Option.TextStyles:
|
||||
printer.Write(Tests.TextStyles(e));
|
||||
break;
|
||||
case Option.FullReceipt:
|
||||
printer.Write(Tests.Receipt(e));
|
||||
break;
|
||||
case Option.Images:
|
||||
printer.Write(Tests.Images(e, false));
|
||||
break;
|
||||
case Option.LegacyImages:
|
||||
printer.Write(Tests.Images(e, true));
|
||||
break;
|
||||
case Option.LargeByteArrays:
|
||||
try
|
||||
{
|
||||
printer.Write(Tests.TestLargeByteArrays(e));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Aborting print due to test failure. Exception: {e?.Message}, Stack Trace: {e?.GetBaseException()?.StackTrace}");
|
||||
}
|
||||
break;
|
||||
case Option.CashDrawerPin2:
|
||||
printer.Write(Tests.CashDrawerOpenPin2(e));
|
||||
break;
|
||||
case Option.CashDrawerPin5:
|
||||
printer.Write(Tests.CashDrawerOpenPin5(e));
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid entry.");
|
||||
break;
|
||||
}
|
||||
|
||||
Setup(monitor);
|
||||
printer?.Write(e.PrintLine($"== [ End {testCases[enumChoice]} ] =="));
|
||||
printer?.Write(e.PartialCutAfterFeed(5));
|
||||
|
||||
// TODO: also make an automatic runner that runs all tests (command line).
|
||||
}
|
||||
}
|
||||
|
||||
public enum Option
|
||||
{
|
||||
SingleLinePrinting = 1,
|
||||
MultiLinePrinting,
|
||||
LineSpacing,
|
||||
BarcodeStyles,
|
||||
BarcodeTypes,
|
||||
TwoDimensionCodes,
|
||||
TextStyles,
|
||||
FullReceipt,
|
||||
CodePages,
|
||||
Images,
|
||||
LegacyImages,
|
||||
LargeByteArrays,
|
||||
CashDrawerPin2,
|
||||
CashDrawerPin5,
|
||||
Exit = 99
|
||||
}
|
||||
|
||||
private static void StatusChanged(object sender, EventArgs ps)
|
||||
{
|
||||
var status = (PrinterStatusEventArgs)ps;
|
||||
if (status == null) { Console.WriteLine("Status was null - unable to read status from printer."); return; }
|
||||
Console.WriteLine($"Printer Online Status: {status.IsPrinterOnline}");
|
||||
Console.WriteLine(JsonConvert.SerializeObject(status));
|
||||
}
|
||||
private static bool _hasEnabledStatusMonitoring = false;
|
||||
|
||||
private static void Setup(bool enableStatusBackMonitoring)
|
||||
{
|
||||
if (printer != null)
|
||||
{
|
||||
// Only register status monitoring once.
|
||||
if (!_hasEnabledStatusMonitoring)
|
||||
{
|
||||
printer.StatusChanged += StatusChanged;
|
||||
_hasEnabledStatusMonitoring = true;
|
||||
}
|
||||
printer?.Write(e.Initialize());
|
||||
printer?.Write(e.Enable());
|
||||
if (enableStatusBackMonitoring)
|
||||
{
|
||||
printer.Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
private const string websiteString = "https://github.com/lukevp/ESC-POS-.NET/";
|
||||
public static byte[][] TwoDimensionCodes(ICommandEmitter e) => new byte[][] {
|
||||
e.PrintLine("PDF417:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("PDF417 (TINY):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString, Size2DCode.TINY),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("PDF417 (LARGE):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString, Size2DCode.LARGE),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 2:"),
|
||||
e.PrintQRCode(websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MICRO:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MICRO, "github.com/lukevp"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1 (TINY):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString, Size2DCode.TINY),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1 (LARGE):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString, Size2DCode.LARGE),
|
||||
e.PrintLine()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] BarcodeStyles(ICommandEmitter e) => new byte[][] {
|
||||
//TODO: test all widths and put bar in front in label
|
||||
e.PrintLine("Thinnest Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thinnest),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thin Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thin),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Default Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Default),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thicker Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thick),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thickest Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thickest),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
|
||||
e.PrintLine("Short (50 dots):"),
|
||||
e.SetBarcodeHeightInDots(50),
|
||||
e.SetBarWidth(BarWidth.Default),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Tall (255 dots):"),
|
||||
e.SetBarcodeHeightInDots(255),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Above:"),
|
||||
e.SetBarcodeHeightInDots(50),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Above),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Above and Below:"),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Both),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Below:"),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Below),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Font B Label Below:"),
|
||||
e.SetBarLabelFontB(true),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905")
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user