diff --git a/MedusaPluginChargeMachine/Handlers/LA9/ChargeEaChargeHandler.cs b/MedusaPluginChargeMachine/Handlers/LA9/ChargeEaChargeHandler.cs index f376e84..63dd6d6 100644 --- a/MedusaPluginChargeMachine/Handlers/LA9/ChargeEaChargeHandler.cs +++ b/MedusaPluginChargeMachine/Handlers/LA9/ChargeEaChargeHandler.cs @@ -1,4 +1,5 @@ -using Abstractions.Entities; +using System.Text.RegularExpressions; +using Abstractions.Entities; using Abstractions.Handlers; using Abstractions.SerializationTypes; using Abstractions.Services; @@ -10,7 +11,7 @@ using ISessionService = MedusaPluginChargeMachine.Services.ISessionService; namespace MedusaPluginChargeMachine.Handlers.LA9; -public class ChargeEaChargeHandler( +public partial class ChargeEaChargeHandler( ICardService cardService, ISessionService sessionService, UserManager userManager, @@ -22,9 +23,20 @@ public class ChargeEaChargeHandler( Method("charge"); } + // chargeid carries the actual denomination as e.g. "N10000P" + // (Note/10000/Paseli) - chargenum is just the quantity of that + // denomination being charged (normally "1" per bill inserted). + [GeneratedRegex(@"^N(\d+)P$")] + private static partial Regex ChargeIdPattern(); + public override async Task HandleAsync(ChargeRequest req, GameModel model) { - var amount = int.Parse(req.ChargeNumber) * 1000; + var match = ChargeIdPattern().Match(req.ChargeId); + if (!match.Success) + throw new InvalidOperationException($"Unrecognized chargeid format: '{req.ChargeId}'"); + + var denomination = int.Parse(match.Groups[1].Value); + var amount = denomination * int.Parse(req.ChargeNumber); var foundSession = sessionService.GetSession(req.SessionId); diff --git a/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs b/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs index f95ac3c..59f9c76 100644 --- a/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs +++ b/MedusaPluginChargeMachine/Handlers/LA9/GetConfigEaChargeHandler.cs @@ -18,13 +18,6 @@ namespace MedusaPluginChargeMachine.Handlers.LA9; { var articles = await db.ArticleContents.ToListAsync(); - // Real server ("automap" capture against services.tablanbass.net) sends - // an EMPTY articledoc for every DOCMT_* type - the disclosure/agreement - // text itself is apparently rendered client-side from a bundled local - // asset, not delivered over the wire. Sending real text for DOCMT_* - // here produced a solid black content area on a real cabinet (working - // touch, live server) instead of the disclosure text, so match the - // real server's (empty) behavior instead of guessing at content. var articleList = articles .Select(a => new EaChargeConfigChargeArticleItem { @@ -38,6 +31,7 @@ namespace MedusaPluginChargeMachine.Handlers.LA9; { Status = 0, Expire = 1200, + ChargeOptions = new XrpcString("multibills"), ChargeArticle = new EaChargeConfigChargeArticle { ArticleRevision = new XrpcString("1"), diff --git a/MedusaPluginChargeMachine/Handlers/LA9/GetLastLogEaChargeHandler.cs b/MedusaPluginChargeMachine/Handlers/LA9/GetLastLogEaChargeHandler.cs index 609f6e7..0c736c2 100644 --- a/MedusaPluginChargeMachine/Handlers/LA9/GetLastLogEaChargeHandler.cs +++ b/MedusaPluginChargeMachine/Handlers/LA9/GetLastLogEaChargeHandler.cs @@ -31,28 +31,80 @@ public class GetLastLogEaChargeHandler(ISessionService sessionService, ChargeMac if (cardId is not null) query = query.Where(h => h.CardId == cardId); - var todayTotal = await query + var todayRows = await query .Where(h => h.OrderDate.Date == today) - .SumAsync(h => (int?)h.ChargeAmount) ?? 0; + .ToListAsync(); + + var todayTotal = todayRows.Sum(h => h.ChargeAmount); + + var headerItems = todayRows + .GroupBy(Denomination) + .Select(g => new GetLastLogChargeItem + { + ChargeId = new XrpcString($"N{g.Key}P"), + ChargeNum = new XrpcInt(g.Sum(h => h.ChargeNum)), + ChargeAmount = new XrpcInt(g.Sum(h => h.ChargeAmount)) + }) + .ToList(); var recentItems = await query .OrderByDescending(h => h.OrderDate) .Take(10) .ToListAsync(); + var resultItems = recentItems + .Select(h => new GetLastLogResultItem + { + OrderDate = new XrpcString(h.OrderDate.ToString("yyyyMMddHHmmss")), + ChargeId = new XrpcString($"N{Denomination(h)}P"), + ChargeNum = new XrpcInt(h.ChargeNum), + CardType = new XrpcInt(1), + CardNo = new XrpcString(MaskCardId(h.CardId)) + }) + .ToList(); + + if (headerItems.Count == 0) + { + headerItems.Add(new GetLastLogChargeItem + { + ChargeId = new XrpcString("N1000P"), + ChargeNum = new XrpcInt(0), + ChargeAmount = new XrpcInt(0) + }); + } + + if (resultItems.Count == 0) + { + resultItems.Add(new GetLastLogResultItem + { + OrderDate = new XrpcString(""), + ChargeId = new XrpcString("N1000P"), + ChargeNum = new XrpcInt(0), + CardType = new XrpcInt(1), + CardNo = new XrpcString("") + }); + } + return new GetLastLogEaChargeResponse { Status = 0, Header = new GetLastLogEaChargeHeader { Chargedaily = new XrpcInt(todayTotal), - Items = recentItems.Select((h, i) => new GetLastLogChargeItem - { - ChargeId = new XrpcString(h.Id.ToString()), - ChargeNum = new XrpcInt(h.ChargeNum), - ChargeAmount = new XrpcInt(h.ChargeAmount) - }).ToList() + Items = headerItems + }, + Result = new GetLastLogEaChargeResult + { + Items = resultItems } }; } + + private static int Denomination(Entities.ChargeHistory h) => + h.ChargeAmount / Math.Max(h.ChargeNum, 1); + + private static string MaskCardId(string cardId) => + cardId.Length <= 4 + ? new string('*', cardId.Length) + : new string('*', cardId.Length - 4) + cardId[^4..]; } diff --git a/MedusaPluginChargeMachine/Handlers/LA9/GetRecentChargeEaChargeHandler.cs b/MedusaPluginChargeMachine/Handlers/LA9/GetRecentChargeEaChargeHandler.cs index 2952984..b51afa6 100644 --- a/MedusaPluginChargeMachine/Handlers/LA9/GetRecentChargeEaChargeHandler.cs +++ b/MedusaPluginChargeMachine/Handlers/LA9/GetRecentChargeEaChargeHandler.cs @@ -21,7 +21,10 @@ public class GetRecentChargeEaChargeHandler(ISessionService sessionService, Char var cardId = ResolveCardId(req); var page = int.TryParse(req.Page, out var p) ? Math.Max(1, p) : 1; - var perPage = int.TryParse(req.PerPage, out var pp) ? Math.Max(1, pp) : 10; + + var perPage = int.TryParse(req.Num, out var n) ? Math.Max(1, n) + : int.TryParse(req.PerPage, out var pp) ? Math.Max(1, pp) + : 10; var query = db.ChargeHistories.AsQueryable(); @@ -31,8 +34,6 @@ public class GetRecentChargeEaChargeHandler(ISessionService sessionService, Char if (req.TargetDate is not null && DateTime.TryParse(req.TargetDate, out var targetDate)) query = query.Where(h => h.OrderDate.Date == targetDate.Date); - var total = await query.CountAsync(); - var rows = await query .OrderByDescending(h => h.OrderDate) .Skip((page - 1) * perPage) @@ -49,10 +50,23 @@ public class GetRecentChargeEaChargeHandler(ISessionService sessionService, Char FontColor = new XrpcString("#FFFFFF") }).ToList(); + if (items.Count == 0) + { + items.Add(new GetRecentChargeItem + { + RcvTime = new XrpcString(""), + ChrgPrice = new XrpcInt(0), + CardNo = new XrpcString(""), + AccCode = new XrpcString(""), + RcvStatus = new XrpcInt(0), + FontColor = new XrpcString("#FFFFFF") + }); + } + return new GetRecentChargeResponse { Status = 0, - Num = new XrpcInt(total), + Num = new XrpcInt(items.Count), Items = items }; } diff --git a/MedusaPluginChargeMachine/Models/Request/ChargeRequest.cs b/MedusaPluginChargeMachine/Models/Request/ChargeRequest.cs index 4c56e65..5d9038c 100644 --- a/MedusaPluginChargeMachine/Models/Request/ChargeRequest.cs +++ b/MedusaPluginChargeMachine/Models/Request/ChargeRequest.cs @@ -8,6 +8,14 @@ public class ChargeRequest [XmlElement("chargenum")] public required string ChargeNumber { get; set; } + // The actual denomination, not chargenum - real traffic (spice2x + // "automap" capture) shows chargenum is always the quantity ("1" for a + // single bill), while chargeid carries the value as e.g. "N10000P" + // (Note/10000/Paseli). chargenum * 1000 alone reports every bill as + // 1000 yen regardless of what was actually inserted. + [XmlElement("chargeid")] + public required string ChargeId { get; set; } + [XmlElement("sessid")] public required string SessionId { get; set; } } \ No newline at end of file diff --git a/MedusaPluginChargeMachine/Models/Request/GetRecentChargeRequest.cs b/MedusaPluginChargeMachine/Models/Request/GetRecentChargeRequest.cs index 333cc5e..6aba4b0 100644 --- a/MedusaPluginChargeMachine/Models/Request/GetRecentChargeRequest.cs +++ b/MedusaPluginChargeMachine/Models/Request/GetRecentChargeRequest.cs @@ -5,6 +5,9 @@ namespace MedusaPluginChargeMachine.Models.Request; [XmlRoot("eacharge")] public class GetRecentChargeRequest { + [XmlElement("num")] + public string? Num { get; set; } + [XmlElement("sessid")] public string? SessionId { get; set; } diff --git a/MedusaPluginChargeMachine/Models/Response/EaChargeConfigResponse.cs b/MedusaPluginChargeMachine/Models/Response/EaChargeConfigResponse.cs index 80a48e4..5d1ae94 100644 --- a/MedusaPluginChargeMachine/Models/Response/EaChargeConfigResponse.cs +++ b/MedusaPluginChargeMachine/Models/Response/EaChargeConfigResponse.cs @@ -12,7 +12,10 @@ public class EaChargeConfigResponse [XmlAttribute("expire")] public required int Expire { get; set; } - + + [XmlElement("chargeoptions")] + public required XrpcString ChargeOptions { get; set; } + [XmlElement("chargearticle")] public required EaChargeConfigChargeArticle ChargeArticle { get; set; } diff --git a/MedusaPluginChargeMachine/Models/Response/GetLastLogEaChargeResponse.cs b/MedusaPluginChargeMachine/Models/Response/GetLastLogEaChargeResponse.cs index 27fb3ce..2f08b71 100644 --- a/MedusaPluginChargeMachine/Models/Response/GetLastLogEaChargeResponse.cs +++ b/MedusaPluginChargeMachine/Models/Response/GetLastLogEaChargeResponse.cs @@ -12,6 +12,9 @@ public class GetLastLogEaChargeResponse [XmlElement("header")] public required GetLastLogEaChargeHeader Header { get; set; } + + [XmlElement("result")] + public required GetLastLogEaChargeResult Result { get; set; } } public record GetLastLogEaChargeHeader @@ -33,4 +36,28 @@ public record GetLastLogChargeItem [XmlElement("chargeamount")] public XrpcInt ChargeAmount { get; set; } -} \ No newline at end of file +} + +public record GetLastLogEaChargeResult +{ + [XmlElement("item")] + public List Items { get; set; } = []; +} + +public record GetLastLogResultItem +{ + [XmlElement("orderdate")] + public XrpcString OrderDate { get; set; } + + [XmlElement("chargeid")] + public XrpcString ChargeId { get; set; } + + [XmlElement("chargenum")] + public XrpcInt ChargeNum { get; set; } + + [XmlElement("cardtype")] + public XrpcInt CardType { get; set; } + + [XmlElement("cardno")] + public XrpcString CardNo { get; set; } +}