| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 | using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using com.sun.xml.@internal.fastinfoset.sax;using Comal.Classes;using GenHTTP.Api.Protocol;using GenHTTP.Modules.IO;using InABox.Clients;using InABox.Core;using NPOI.HSSF.Util;using PRS.Shared;using PRSServices;using RequestMethod = GenHTTP.Api.Protocol.RequestMethod;namespace PRSLicensing;public class LicensingHandler : Handler<LicensingHandlerProperties>{    private LicensingHandlerProperties? _properties;        public override void Init(LicensingHandlerProperties properties)    {        _properties = properties;    }    private IResponseBuilder RetrieveFees(IRequest request)    {        if (_properties == null)            return request.Respond().Status(ResponseStatus.BadRequest);                var lsr = Serialization.Deserialize<LicenseFeeRequest>(request.Content);        if (lsr == null)            return request.Respond().Status(ResponseStatus.BadRequest);                Logger.Send(LogType.Information, "", $"License Enquiry Received ({lsr.RegistrationID})");        var productids = _properties.EngineProperties.Mappings.Select(x => x.Product.ID).ToArray();        if (!productids.Any())        {             Logger.Send(LogType.Error,"","Engine Product Mapping List is Empty");            return request.Respond().Status(ResponseStatus.BadRequest);        }                var query = new MultiQuery();                query.Add(            new Filter<Product>(x=>x.ID).InList(productids),            Columns.None<Product>().Add(x=>x.ID)                .Add(x=>x.NettCost)                .Add(x=>x.Charge.Chargeable)                .Add(x=>x.Charge.PriceType)                .Add(x=>x.Charge.Markup)                .Add(x=>x.Charge.Price)            );                if (lsr.RegistrationID != Guid.Empty)            query.Add(                new Filter<CustomerProduct>(x=>x.Customer.ID).IsEqualTo(lsr.RegistrationID).And(x=>x.Product.ID).InList(productids),                Columns.None<CustomerProduct>().Add(x=>x.Product.ID)                    .Add(x=>x.Product.NettCost)                    .Add(x=>x.Charge.Chargeable)                    .Add(x=>x.Charge.PriceType)                    .Add(x=>x.Charge.Markup)                    .Add(x=>x.Charge.Price)            );                query.Query();        var products = query.Get<Product>().Rows.Select(x => x.ToObject<Product>()).ToArray();                var customerproducts = lsr.RegistrationID != Guid.Empty            ? query.Get<CustomerProduct>().Rows.Select(x => x.ToObject<CustomerProduct>()).ToArray()            : new CustomerProduct[] { };        var result = new LicenseFeeResponse();        foreach (var mapping in _properties.EngineProperties.Mappings)        {            var customer = customerproducts.FirstOrDefault(x => x.Product.ID == mapping.Product.ID);            if (customer != null)            {                result.LicenseFees[mapping.License] = customer.Charge.PriceType == ProductPriceType.CostPlus                    ? customer.Product.NettCost * (100F + customer.Charge.Markup) / 100F                    : customer.Charge.Price;            }            else            {                var product = products.FirstOrDefault(x => x.ID == mapping.Product.ID);                result.LicenseFees[mapping.License] = product != null                    ? product.Charge.PriceType == ProductPriceType.CostPlus                        ? product.NettCost * (100F + product.Charge.Markup) / 100F                        : product.Charge.Price                    : 0.0F;            }        }        foreach (var timediscount in _properties.EngineProperties.TimeDiscounts)            result.TimeDiscounts[timediscount.Months] = timediscount.Discount;                foreach (var userdiscount in _properties.EngineProperties.UserDiscounts)            result.UserDiscounts[userdiscount.Users] = userdiscount.Discount;                return request.Respond().Status(ResponseStatus.OK).Content(Serialization.Serialize(result));    }    private static List<Tuple<int, Func<DateTime, DateTime>>> renewalPeriods = new List<Tuple<int, Func<DateTime, DateTime>>> {        new(1, x => x.AddDays(-7)),        new(3, x => x.AddDays(-14)),        new(6, x => x.AddMonths(-1))    };    private int GetMonthDifference(DateTime date1, DateTime date2){        var months = (date2.Year - date1.Year) * 12 + (date2.Month - date1.Month);                if(date2.Day >= date1.Day){            return months;        }        return months - 1;    }    private LicenseData GenerateLicense(LicenseRenewalRequest renewalRequest){        var renewalPeriodInMonths = GetMonthDifference(renewalRequest.DateRenewed, renewalRequest.NewExpiry);        var renewalAvailable = renewalPeriods            .Where(x => renewalPeriodInMonths >= x.Item1)            .MaxBy(x => x.Item1)            .Item2(renewalRequest.NewExpiry);                var newLicense = LicenseUtils.RenewLicense(renewalRequest.OldLicense, renewalRequest.DateRenewed, renewalRequest.NewExpiry, renewalAvailable, renewalRequest.Addresses);        return newLicense;    }        private string NewCustomerCode(LicenseRenewalRequest renewalRequest)    {        // Try to build a 5 character abbreviation of the company name        // is ACME Incorporated should become ACMIN        // while P T Barnum should become PTBAR and so on        String code = "";        var codecomps = renewalRequest.Company.CompanyName            .ToUpper()            .Split(' ')            .ToList();        while (code.Length < 5 && codecomps.Any())        {            var chunk = new string(codecomps.First().Take(Math.Min(3,5-code.Length)).ToArray());            code += chunk;            codecomps.RemoveAt(0);        }                var codes = new Client<Customer>().Query(            new Filter<Customer>(x => x.Code).BeginsWith(code),            Columns.None<Customer>().Add(x => x.Code))?.Rows.Select(x => x.Get<Customer, string>(x => x.Code)        ).ToList() ?? new List<string>();                var i = 1;        while(codes.Contains($"{code}{i:D3}"))            i++;                            return $"{code}{i:D3}";    }        private Customer CreateNewCustomer(LicenseRenewalRequest renewalRequest){        Logger.Send(LogType.Information, "", "Creating new customer");                var customer = new Customer {            Code = NewCustomerCode(renewalRequest),            Name = renewalRequest.Company.CompanyName,            ABN = renewalRequest.Company.ABN,            Delivery = renewalRequest.Company.DeliveryAddress,            Email = renewalRequest.Company.Email,            Postal = renewalRequest.Company.PostalAddress        };        new Client<Customer>().Save(customer, "Created by License Renewal");        return customer;    }        private CustomerDocument CreateNewCustomerDocument(Guid customerID, string fileName, string data){        var document = new Document {            FileName = fileName,            Private = true,            TimeStamp = DateTime.Now,            Data = Encoding.UTF8.GetBytes(data)        };        document.CRC = CoreUtils.CalculateCRC(document.Data);                new Client<Document>().Save(document, "");                var documentType = new Client<DocumentType>()            .Query(                new Filter<DocumentType>(x => x.Code).IsEqualTo("LICENSE"),                Columns.None<DocumentType>().Add(x => x.ID))            .Rows.FirstOrDefault()?.Get<DocumentType, Guid>(x => x.ID) ?? Guid.Empty;        if(documentType == Guid.Empty){            Logger.Send(LogType.Error, "", "Document Type 'LICENSE' doesn't exist");        }                var customerDocument = new CustomerDocument();        customerDocument.Type.ID = documentType;        customerDocument.EntityLink.ID = customerID;        customerDocument.DocumentLink.ID = document.ID;                new Client<CustomerDocument>().Save(customerDocument, "Created by License Renewal");        return customerDocument;    }        private void CreateInvoice(Guid customerID, LicenseRenewalRequest renewalRequest){        var invoiceLines = new List<InvoiceLine>();        var notes = new List<string>();        foreach(var item in renewalRequest.LicenseTracking){            var invoiceLine = new InvoiceLine {                Description = $"{item.Caption} - {item.Users} Users @ ${item.Rate:F2} per user",                ExTax = item.ExGST            };            invoiceLines.Add(invoiceLine);            notes.Add(invoiceLine.Description);        }        var discountLine = new InvoiceLine {            Description = $"${renewalRequest.Discount:F2} discount",            ExTax = -renewalRequest.Discount        };        invoiceLines.Add(discountLine);        notes.Add(discountLine.Description);                var invoice = new Invoice {            Date = DateTime.Today,            Description = $"PRS License Renewal",        };        invoice.CustomerLink.ID = customerID;                new Client<Invoice>().Save(invoice, "Created by License Renewal");                foreach(var line in invoiceLines){            line.InvoiceLink.ID = invoice.ID;        }        new Client<InvoiceLine>().Save(invoiceLines, "");                var receipt = new Receipt {            Date = DateTime.Today,            Notes = $"PRS Renewal Invoice #{invoice.Number} ({renewalRequest.TransactionID})"        };        new Client<Receipt>().Save(receipt, "");                var invoiceReceipt = new InvoiceReceipt {            Notes = "Receipt for License Renewal",            Amount = renewalRequest.Net        };        invoiceReceipt.InvoiceLink.ID = invoice.ID;        invoiceReceipt.ReceiptLink.ID = receipt.ID;        new Client<InvoiceReceipt>().Save(invoiceReceipt, "");    }        private IResponseBuilder RenewLicense(IRequest request)    {                var renewal = Serialization.Deserialize<LicenseRenewalRequest>(request.Content);        if(renewal == null){            return request.Respond().Status(ResponseStatus.BadRequest);        }                Logger.Send(LogType.Information, "", $"Request for license renewal from {renewal.Company.CompanyName}");                var customerID = renewal.OldLicense.CustomerID;        if(customerID == Guid.Empty){            customerID = CreateNewCustomer(renewal).ID;            renewal.OldLicense.CustomerID = customerID;        }                Logger.Send(LogType.Information, "", "Generating new license");                var newLicense = GenerateLicense(renewal);        var newLicenseData = LicenseUtils.EncryptLicense(newLicense);        if(newLicenseData == null){            Logger.Send(LogType.Error, "", "Encryption of new license failed!");            return request.Respond().Status(ResponseStatus.InternalServerError);        }                Logger.Send(LogType.Information, "", "Generating customer document");        var customerDocument = CreateNewCustomerDocument(customerID, $"{renewal.Company.CompanyName} - PRS License - {DateTime.Now:dd MMM yyyy}.txt", newLicenseData);        Logger.Send(LogType.Information, "", "Creating invoice");        CreateInvoice(customerID, renewal);        LicenseRenewalResult result = new()        {            License = newLicenseData        };        return request.Respond()            .Status(ResponseStatus.OK)            .Content(Serialization.Serialize(result)); // Send just the encrypted data.    }        private IResponseBuilder Ping(IRequest request)    {        return request.Respond().Status(ResponseStatus.OK);    }    private IResponseBuilder HandleGET(IRequest request)    {        var endpoint = request.Target.Current?.Value.ToLower() ?? "";                if (endpoint == nameof(Ping).ToLower())            return Ping(request);                return request.Respond().Status(ResponseStatus.NotFound);    }    private IResponseBuilder HandlePOST(IRequest request)    {        var endpoint = request.Target.Current?.Value.ToLower() ?? "";                if (endpoint.Equals(nameof(LicenseFeeRequest).ToLower()))            return RetrieveFees(request);                if (endpoint.Equals(nameof(LicenseRenewalRequest).ToLower()))            return RenewLicense(request);                return request.Respond().Status(ResponseStatus.NotFound);    }    public override ValueTask<IResponse?> HandleAsync(IRequest request)    {        try        {            switch (request.Method.KnownMethod)            {                case RequestMethod.GET:                    return new ValueTask<IResponse?>(HandleGET(request).Build());                case RequestMethod.POST:                    return new ValueTask<IResponse?>(HandlePOST(request).Build());                default:                    Logger.Send(LogType.Error, ClientFactory.UserID, $"Request method {request.Method.RawMethod} unknown");                    return new ValueTask<IResponse?>(request.Respond().Status(ResponseStatus.MethodNotAllowed).Build());            }        }        catch (Exception eListen)        {            Logger.Send(LogType.Error, ClientFactory.UserID, eListen.Message);            return new ValueTask<IResponse?>(request.Respond().Status(ResponseStatus.InternalServerError).Build());        }    }}
 |