diff --git a/.gitignore b/.gitignore index cd7bd88..dfcc267 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ ErpNet.FP.Server/appsettings.json ErpNet.FP.Setup/ProductInstallFiles.wxs /UpgradeLog.htm /ErpNet.FP.Setup/HeatWaveConvert.log + +# FashionPoint build artifacts +/publish-win-x64/ +/ErpNet.FP-fashionpoint-* diff --git a/ErpNet.FP.Core/Transports/ComTransport.cs b/ErpNet.FP.Core/Transports/ComTransport.cs index ab39e41..127e124 100644 --- a/ErpNet.FP.Core/Transports/ComTransport.cs +++ b/ErpNet.FP.Core/Transports/ComTransport.cs @@ -14,7 +14,11 @@ public class ComTransport : Transport public override string TransportName => "com"; protected const int DefaultBaudRate = 115200; - protected const int DefaultTimeout = 800; + // FashionPoint patch: 800ms is too aggressive for slow fiscal devices + // (e.g. Daisy PerfectS pauses >800ms between SYN bytes while writing + // to fiscal memory on receipt close), causing E107 "no response", + // automatic receipt aborts (АНУЛИРАН БОН) and false failures. + protected const int DefaultTimeout = 3000; protected const int DefaultTimeoutToClose = 3000; // dispose SerialPort object when specified time after communication is elapsed private readonly IDictionary openedChannels = @@ -22,7 +26,7 @@ public class ComTransport : Transport public override IChannel OpenChannel(string address) { - var (comPort, baudRate) = ParseAddress(address); + var (comPort, baudRate, timeout) = ParseAddress(address); if (openedChannels.TryGetValue(comPort, out Channel? channel)) { if (channel != null) @@ -30,19 +34,22 @@ public override IChannel OpenChannel(string address) else openedChannels.Remove(comPort); } - channel = new Channel(comPort, baudRate); + channel = new Channel(comPort, baudRate, timeout); //
is more specific (:) than and multiple addresses on one port can lead to locking or not finding device (only one can be opened) openedChannels.Add(comPort, channel); return channel; } - protected (string, int) ParseAddress(string address) + // FashionPoint patch: address format is [:[:]], + // e.g. "COM5", "COM5:115200", "COM5:115200:5000". + protected (string, int, int) ParseAddress(string address) { var parts = address.Split(':'); - if (parts.Length == 1) return (address, DefaultBaudRate); + if (parts.Length == 1) return (address, DefaultBaudRate, DefaultTimeout); var hostName = parts[0]; var baudRate = parts.Length > 1 ? int.Parse(parts[1]) : DefaultBaudRate; - return (hostName, baudRate); + var timeout = parts.Length > 2 ? int.Parse(parts[2]) : DefaultTimeout; + return (hostName, baudRate, timeout); } public override void Drop(IChannel channel) @@ -69,6 +76,7 @@ public class Channel : IChannel internal /*readonly*/ SerialPort? serialPort; // can be disposed and created multiple times private string portName; private int baudRate; + private int timeout; protected Timer idleTimer; protected const int MinimalBaudRate = 9600; @@ -88,7 +96,7 @@ public string Descriptor } } - public SerialPort GetNewSerialPort(int timeout = DefaultTimeout) + public SerialPort GetNewSerialPort() { idleTimer.Change(DefaultTimeoutToClose, 0); return new SerialPort @@ -107,6 +115,7 @@ public Channel(string portName, int baudRate = DefaultBaudRate, int timeout = De { this.portName = portName; this.baudRate = baudRate; + this.timeout = timeout; serialPort = null; // GetNewSerialPort(); idleTimer = new Timer(IdleTimerElapsed); diff --git a/README.md b/README.md index e73ecec..4c449db 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,31 @@ +> ## 🔱 FashionPoint Fork +> +> Това е форк на [erpnet/ErpNet.FP](https://github.com/erpnet/ErpNet.FP), поддържан от **FashionPoint** за нашите клиенти (салони/клиники) с фискални устройства. +> +> ### Защо съществува +> Бавни касови апарати (напр. **Daisy PerfectS**) правят пауза от над 800ms между SYN байтовете, докато записват бона във фискалната памет при затваряне. Оригиналният ErpNet.FP има **хардкоднат сериен timeout от 800ms**, което води до: +> - грешка **E107 "no response"**, въпреки че бонът реално се записва; +> - автоматично анулиране на бона от драйвера → **„АНУЛИРАН БОН"** на хартията; +> - фалшиви „провалени" продажби и дублирани УНП в POS системата (проблем по Наредба Н-18). +> +> ### Какво е променено спрямо оригинала +> - **Серийният timeout е вдигнат 800ms → 3000ms** (`ComTransport.DefaultTimeout`); +> - **Per-принтер timeout през адреса**: `com://COM5:115200:5000` (порт : скорост : timeout в ms) — бъдещи бавни устройства се решават с настройка, без ребилд. Напълно обратно съвместимо. +> +> Единственият променен файл е [`ErpNet.FP.Core/Transports/ComTransport.cs`](ErpNet.FP.Core/Transports/ComTransport.cs). +> +> ### Сваляне (нашите билдове) +> Готови билдове за **Windows x64**, **macOS Intel** и **macOS Apple Silicon** — в [**Releases**](https://github.com/fashionpoint-bg/ErpNet.FP/releases). Инструкции за инсталация има във всеки релийз. +> +> ### Статус спрямо оригинала +> Фиксът е предложен upstream: [erpnet/ErpNet.FP#205](https://github.com/erpnet/ErpNet.FP/pull/205). Ако бъде приет, форкът остава само като билд/дистрибуционна точка за нашите клиенти. +> +> Работен бранч: `fashionpoint` (дефолтен). Ъпдейти от оригинала: `git fetch upstream && git merge upstream/master`. + +--- + # ErpNet.FP ErpNet.FP is a light-weight multi-platform Http server facilitating printing to fiscal printers through simple JSON Api. The library provides methods to detect, get status, print receipts, reports and other documents to fiscal printers.