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());
- }
- }
- }
|