Compare commits
12 Commits
7cc59e329a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 275eb1ad42 | |||
| 45d2b0fd29 | |||
| 209298cfb2 | |||
| 9ac47ab052 | |||
| 98c7157b0c | |||
| ab75b98571 | |||
| 9d2a9af98a | |||
| 4c603cb648 | |||
| 76ffaa6910 | |||
| a12595b3cf | |||
| 8f2ab38ba2 | |||
| a296bc9b4f |
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# .NET
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist/installers/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/settings.json
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
.DS_Store
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
set m=Unknown error
|
set m=Unknown error
|
||||||
|
|
||||||
@echo ****************** CLEAN ALL OUTPUT FOLDERS **********
|
@echo ****************** CLEAN ALL OUTPUT FOLDERS ***********
|
||||||
rmdir c:\data\code\sockeye\server\wwwroot /s/q
|
rmdir c:\data\code\sockeye\server\wwwroot /s/q
|
||||||
mkdir c:\data\code\sockeye\server\wwwroot
|
mkdir c:\data\code\sockeye\server\wwwroot
|
||||||
rmdir C:\data\code\sockeye\dist\installers /s/q
|
rmdir C:\data\code\sockeye\dist\installers /s/q
|
||||||
|
|||||||
@@ -211,6 +211,9 @@ namespace Sockeye.Biz
|
|||||||
case 20:
|
case 20:
|
||||||
sb.AppendLine("Up to 20");
|
sb.AppendLine("Up to 20");
|
||||||
break;
|
break;
|
||||||
|
case 25://case 4576
|
||||||
|
sb.AppendLine("Up to 25");
|
||||||
|
break;
|
||||||
case 50:
|
case 50:
|
||||||
sb.AppendLine("Up to 50");
|
sb.AppendLine("Up to 50");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ namespace Sockeye.Biz
|
|||||||
case "300740324"://PTI
|
case "300740324"://PTI
|
||||||
case "300740325"://OLI
|
case "300740325"://OLI
|
||||||
case "300807973"://Up to 15
|
case "300807973"://Up to 15
|
||||||
|
case "301091845"://Up to 25 //case 4576
|
||||||
case "300740326"://Outlook Schedule Export
|
case "300740326"://Outlook Schedule Export
|
||||||
case "300740316"://AyaNova LITE
|
case "300740316"://AyaNova LITE
|
||||||
case "999"://Up to 999
|
case "999"://Up to 999
|
||||||
|
|||||||
@@ -590,23 +590,23 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
//Add Handlebars JS for compiling and presenting
|
//Add Handlebars JS for compiling and presenting
|
||||||
//https://handlebarsjs.com/
|
//https://handlebarsjs.com/
|
||||||
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "sock-hb.js") });
|
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "ay-hb.js") });
|
||||||
|
|
||||||
//add Marked for markdown processing
|
//add Marked for markdown processing
|
||||||
//https://github.com/markedjs/marked
|
//https://github.com/markedjs/marked
|
||||||
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "sock-md.js") });
|
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "ay-md.js") });
|
||||||
|
|
||||||
//add DOM Purify for markdown template sanitization processing
|
//add DOM Purify for markdown template sanitization processing
|
||||||
//https://github.com/cure53/DOMPurify
|
//https://github.com/cure53/DOMPurify
|
||||||
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "sock-pf.js") });
|
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "ay-pf.js") });
|
||||||
|
|
||||||
//add Bar code library if our bar code helper is referenced
|
//add Bar code library if our bar code helper is referenced
|
||||||
//https://github.com/metafloor/bwip-js
|
//https://github.com/metafloor/bwip-js
|
||||||
if (report.Template.Contains("ayBC ") || report.JsHelpers.Contains("ayBC "))
|
if (report.Template.Contains("ayBC ") || report.JsHelpers.Contains("ayBC "))
|
||||||
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "sock-bc.js") });
|
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "ay-bc.js") });
|
||||||
|
|
||||||
//add stock helpers
|
//add stock helpers
|
||||||
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "sock-report.js") });
|
await page.AddScriptTagAsync(new AddTagOptions() { Path = Path.Combine(ReportJSFolderPath, "ay-report.js") });
|
||||||
|
|
||||||
//execute to add to handlebars
|
//execute to add to handlebars
|
||||||
await page.EvaluateExpressionAsync("ayRegisterHelpers();");
|
await page.EvaluateExpressionAsync("ayRegisterHelpers();");
|
||||||
|
|||||||
@@ -66,11 +66,12 @@ namespace Sockeye.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//GET
|
//GET
|
||||||
//
|
//
|
||||||
internal async Task<Subscription> GetAsync(long id, bool logTheGetEvent = true, bool populateForReporting = false)
|
internal async Task<Subscription> GetAsync(long id, bool logTheGetEvent = true)
|
||||||
{
|
{
|
||||||
var ret = await ct.Subscription.Include(z => z.Items.OrderByDescending(x=>x.Active).ThenBy(x => x.ExpireDate)).AsNoTracking().SingleOrDefaultAsync(z => z.Id == id);
|
var ret = await ct.Subscription.Include(z => z.Items.OrderByDescending(x => x.Active).ThenBy(x => x.ExpireDate)).AsNoTracking().SingleOrDefaultAsync(z => z.Id == id);
|
||||||
if (logTheGetEvent && ret != null)
|
if (logTheGetEvent && ret != null)
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, SockEvent.Retrieved), ct);
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, SockEvent.Retrieved), ct);
|
||||||
|
|
||||||
await PopulateVizFields(ret);
|
await PopulateVizFields(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -237,45 +238,88 @@ namespace Sockeye.Biz
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//REPORTING
|
//REPORTING
|
||||||
//
|
//
|
||||||
public async Task<JArray> GetReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
public async Task<JArray> GetReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
||||||
|
{
|
||||||
|
if (dataListSelectedRequest.SockType == SockType.Subscription)
|
||||||
|
return await GetSubscriptionsReportData(dataListSelectedRequest, jobId);
|
||||||
|
else
|
||||||
|
//subscription items
|
||||||
|
return await GetSubscriptionItemsReportData(dataListSelectedRequest, jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<JArray> GetSubscriptionsReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
||||||
{
|
{
|
||||||
var idList = dataListSelectedRequest.SelectedRowIds;
|
var idList = dataListSelectedRequest.SelectedRowIds;
|
||||||
JArray ReportData = new JArray();
|
JArray ReportData = new JArray();
|
||||||
|
|
||||||
|
List<Subscription> batchResults = new List<Subscription>();
|
||||||
while (idList.Any())
|
while (idList.Any())
|
||||||
{
|
{
|
||||||
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
|
|
||||||
var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
|
var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
|
||||||
idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
|
idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
|
||||||
|
batchResults.Clear();
|
||||||
//query for this batch, comes back in db natural order unfortunately
|
foreach (long batchId in batch)
|
||||||
var batchResults = await ct.Subscription.AsNoTracking().Where(z => batch.Contains(z.Id)).ToArrayAsync();
|
{
|
||||||
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
//order the results back into original
|
//var subId = await ct.SubscriptionItem.AsNoTracking().Where(z => z.Id == id).Select(z => z.SubscriptionId).FirstOrDefaultAsync();
|
||||||
//What is happening here:
|
batchResults.Add(await GetAsync(batchId, false));
|
||||||
//for performance the query is batching a bunch at once by fetching a block of items from the sql server
|
}
|
||||||
//however it's returning in db order which is often not the order the id list is in
|
|
||||||
//so it needs to be sorted back into the same order as the ide list
|
//these are individually fetched so there's no need to re-order like most other object types
|
||||||
//This would not be necessary if just fetching each one at a time individually (like in workorder get report data)
|
|
||||||
|
foreach (Subscription w in batchResults)
|
||||||
var orderedList = from id in batch join z in batchResults on id equals z.Id select z;
|
|
||||||
batchResults = null;
|
|
||||||
|
|
||||||
foreach (Subscription w in orderedList)
|
|
||||||
{
|
{
|
||||||
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
await PopulateVizFields(w);
|
|
||||||
var jo = JObject.FromObject(w);
|
var jo = JObject.FromObject(w);
|
||||||
if (!JsonUtil.JTokenIsNullOrEmpty(jo["CustomFields"]))
|
|
||||||
jo["CustomFields"] = JObject.Parse((string)jo["CustomFields"]);
|
|
||||||
ReportData.Add(jo);
|
ReportData.Add(jo);
|
||||||
}
|
}
|
||||||
orderedList = null;
|
|
||||||
}
|
}
|
||||||
vc.Clear();
|
vc.Clear();
|
||||||
return ReportData;
|
return ReportData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<JArray> GetSubscriptionItemsReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
||||||
|
{
|
||||||
|
var idList = dataListSelectedRequest.SelectedRowIds;
|
||||||
|
JArray ReportData = new JArray();
|
||||||
|
|
||||||
|
List<SubscriptionItem> batchResults = new List<SubscriptionItem>();
|
||||||
|
while (idList.Any())
|
||||||
|
{
|
||||||
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
|
|
||||||
|
var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
|
||||||
|
idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
|
||||||
|
batchResults.Clear();
|
||||||
|
foreach (long batchId in batch)
|
||||||
|
{
|
||||||
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
|
//var subId = .Select(z => z.SubscriptionId).FirstOrDefaultAsync();
|
||||||
|
var subItem = await ct.SubscriptionItem.AsNoTracking().Where(z => z.Id == batchId).FirstOrDefaultAsync();
|
||||||
|
await PopulateItemVizFields(subItem);
|
||||||
|
batchResults.Add(subItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
//these are individually fetched so there's no need to re-order like most other object types
|
||||||
|
|
||||||
|
foreach (SubscriptionItem w in batchResults)
|
||||||
|
{
|
||||||
|
if (!ReportRenderManager.KeepGoing(jobId)) return null;
|
||||||
|
var jo = JObject.FromObject(w);
|
||||||
|
ReportData.Add(jo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vc.Clear();
|
||||||
|
return ReportData;
|
||||||
|
}
|
||||||
|
|
||||||
private VizCache vc = new VizCache();
|
private VizCache vc = new VizCache();
|
||||||
|
|
||||||
|
|
||||||
@@ -290,12 +334,50 @@ namespace Sockeye.Biz
|
|||||||
|
|
||||||
foreach (var item in o.Items)//some subscriptions have a bunch of the same monthly or yearly raven user in them so this will save in that case
|
foreach (var item in o.Items)//some subscriptions have a bunch of the same monthly or yearly raven user in them so this will save in that case
|
||||||
{
|
{
|
||||||
if (!vc.Has("productname", item.ProductId))
|
await PopulateItemVizFields(item, o);
|
||||||
|
// if (!vc.Has("productname", item.ProductId))
|
||||||
|
// {
|
||||||
|
// var productInfo = await ct.Product.AsNoTracking().Where(x => x.Id == item.ProductId).FirstOrDefaultAsync();
|
||||||
|
// vc.Add(productInfo.Name, "productname", item.ProductId);
|
||||||
|
// vc.Add(productInfo.InitialPrice.ToString(), "productinitialprice", item.ProductId);
|
||||||
|
// vc.Add(productInfo.RenewPrice.ToString(), "productrenewprice", item.ProductId);
|
||||||
|
|
||||||
|
// }
|
||||||
|
// item.ProductViz = vc.Get("productname", item.ProductId);
|
||||||
|
// item.RenewPriceViz = vc.GetAsDecimal("productrenewprice", item.ProductId) ?? 0;
|
||||||
|
// item.InitialPriceViz = vc.GetAsDecimal("productinitialprice", item.ProductId) ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//populate viz fields from provided object
|
||||||
|
private async Task PopulateItemVizFields(SubscriptionItem o, Subscription sub = null)
|
||||||
{
|
{
|
||||||
vc.Add(await ct.Product.AsNoTracking().Where(x => x.Id == item.ProductId).Select(x => x.Name).FirstOrDefaultAsync(), "productname", item.ProductId);
|
|
||||||
|
if (sub == null)
|
||||||
|
sub = await ct.Subscription.AsNoTracking().Where(z => z.Id == o.SubscriptionId).FirstOrDefaultAsync();
|
||||||
|
o.SubscriptionEmailViz = sub.FetchEmail;
|
||||||
|
|
||||||
|
if (!vc.Has("customername", sub.CustomerId))
|
||||||
|
{
|
||||||
|
var custInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == sub.CustomerId).FirstOrDefaultAsync();
|
||||||
|
vc.Add(custInfo.Name, "customername", sub.CustomerId);
|
||||||
|
vc.Add(custInfo.EmailAddress, "customeremail", sub.CustomerId);
|
||||||
}
|
}
|
||||||
item.ProductViz = vc.Get("productname", item.ProductId);
|
o.CustomerViz = vc.Get("customername", sub.CustomerId);
|
||||||
|
o.CustomerEmailViz = vc.Get("customeremail", sub.CustomerId);
|
||||||
|
|
||||||
|
|
||||||
|
if (!vc.Has("productname", o.ProductId))
|
||||||
|
{
|
||||||
|
var productInfo = await ct.Product.AsNoTracking().Where(x => x.Id == o.ProductId).FirstOrDefaultAsync();
|
||||||
|
vc.Add(productInfo.Name, "productname", o.ProductId);
|
||||||
|
vc.Add(productInfo.InitialPrice.ToString(), "productinitialprice", o.ProductId);
|
||||||
|
vc.Add(productInfo.RenewPrice.ToString(), "productrenewprice", o.ProductId);
|
||||||
}
|
}
|
||||||
|
o.ProductViz = vc.Get("productname", o.ProductId);
|
||||||
|
o.RenewPriceViz = vc.GetAsDecimal("productrenewprice", o.ProductId) ?? 0;
|
||||||
|
o.InitialPriceViz = vc.GetAsDecimal("productinitialprice", o.ProductId) ?? 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ namespace Sockeye.Biz
|
|||||||
License newLicense = new License();
|
License newLicense = new License();
|
||||||
//Get last license if any, set up some basic stuff common to all license types
|
//Get last license if any, set up some basic stuff common to all license types
|
||||||
var firstPurchase = purchaseGroup.First();
|
var firstPurchase = purchaseGroup.First();
|
||||||
License lastLicense=null;
|
License lastLicense = null;
|
||||||
|
|
||||||
newLicense.CustomerId = firstPurchase.CustomerId;
|
newLicense.CustomerId = firstPurchase.CustomerId;
|
||||||
newLicense.Active = false;
|
newLicense.Active = false;
|
||||||
@@ -207,6 +207,8 @@ namespace Sockeye.Biz
|
|||||||
21 Single AyaNova service techncian perpetual license 301028314 135 100
|
21 Single AyaNova service techncian perpetual license 301028314 135 100
|
||||||
22 Single AyaNova service techncian 1 year maintenance plan - new 301028317 135 100
|
22 Single AyaNova service techncian 1 year maintenance plan - new 301028317 135 100
|
||||||
23 Single AyaNova service techncian 1 year maintenance plan - active 301028315 100 100
|
23 Single AyaNova service techncian 1 year maintenance plan - active 301028315 100 100
|
||||||
|
case 4576
|
||||||
|
25 Up to 25 AyaNova schedulable resource 1 year subscription license
|
||||||
*/
|
*/
|
||||||
var dtOneYear = DateTime.UtcNow.AddYears(1);
|
var dtOneYear = DateTime.UtcNow.AddYears(1);
|
||||||
switch (product.VendorCode)
|
switch (product.VendorCode)
|
||||||
@@ -280,6 +282,10 @@ namespace Sockeye.Biz
|
|||||||
newLicense.Users = 15;
|
newLicense.Users = 15;
|
||||||
newLicense.MaintenanceExpire = dtOneYear;
|
newLicense.MaintenanceExpire = dtOneYear;
|
||||||
break;
|
break;
|
||||||
|
case "301091845": //case 4576
|
||||||
|
newLicense.Users = 25;
|
||||||
|
newLicense.MaintenanceExpire = dtOneYear;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has product not part of v7 group expected: {product.Name}-{product.VendorCode}";
|
var err = $"SockBotProcessPurchasesIntoLicenses purchase: {purchase.Id} has product not part of v7 group expected: {product.Name}-{product.VendorCode}";
|
||||||
//serious issue requires immediate notification
|
//serious issue requires immediate notification
|
||||||
@@ -299,17 +305,17 @@ namespace Sockeye.Biz
|
|||||||
//it's a RAVEN license
|
//it's a RAVEN license
|
||||||
|
|
||||||
|
|
||||||
//get last license for this dbid, if active then take all it's value and update it with this
|
//get last license for this dbid, if active then take all it's value and update it with this
|
||||||
lastLicense = await ct.License.AsNoTracking().OrderByDescending(z => z.Id).FirstOrDefaultAsync(z => z.CustomerId == firstPurchase.CustomerId && z.PGroup == firstPurchase.PGroup);
|
lastLicense = await ct.License.AsNoTracking().OrderByDescending(z => z.Id).FirstOrDefaultAsync(z => z.CustomerId == firstPurchase.CustomerId && z.PGroup == firstPurchase.PGroup);
|
||||||
|
|
||||||
|
|
||||||
//If renewal and there is no last license then it's a problem -> THROW EXCEPTION
|
//If renewal and there is no last license then it's a problem -> THROW EXCEPTION
|
||||||
|
|
||||||
//If no last license and not renewal then it's a new purchase -> GENERATE NEW
|
//If no last license and not renewal then it's a new purchase -> GENERATE NEW
|
||||||
|
|
||||||
//If last license and renewal then it's a renewal -> UPDATE LAST LICENSE DATES SAVE NEW
|
//If last license and renewal then it's a renewal -> UPDATE LAST LICENSE DATES SAVE NEW
|
||||||
|
|
||||||
//If last license and NEW then it's an additional add on count
|
//If last license and NEW then it's an additional add on count
|
||||||
//if dbid matches -> ADD TO COUNT PUT THAT IN NOTES OF LICENSE
|
//if dbid matches -> ADD TO COUNT PUT THAT IN NOTES OF LICENSE
|
||||||
//if no dbid match then -> THROW EXCEPTION
|
//if no dbid match then -> THROW EXCEPTION
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ namespace Sockeye.Models
|
|||||||
[Required]
|
[Required]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public decimal InitialPrice { get; set; } = 0;
|
||||||
|
public decimal RenewPrice { get; set; } = 0;
|
||||||
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public ProductGroup PGroup {get;set;}
|
public ProductGroup PGroup { get; set; }
|
||||||
public long VendorId { get; set; }
|
public long VendorId { get; set; }
|
||||||
public TimeSpan LicenseInterval { get; set; }
|
public TimeSpan LicenseInterval { get; set; }
|
||||||
public TimeSpan MaintInterval { get; set; }
|
public TimeSpan MaintInterval { get; set; }
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ namespace Sockeye.Models
|
|||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public long ProductId { get; set; }
|
public long ProductId { get; set; }
|
||||||
[NotMapped]
|
|
||||||
public string ProductViz { get; set; }
|
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime ExpireDate { get; set; }
|
public DateTime ExpireDate { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
@@ -30,6 +29,23 @@ namespace Sockeye.Models
|
|||||||
[Required]
|
[Required]
|
||||||
public DateTime OriginalOrderDate { get; set; }
|
public DateTime OriginalOrderDate { get; set; }
|
||||||
|
|
||||||
|
public bool Renewal { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public decimal RenewPriceViz { get; set; } = 0;
|
||||||
|
[NotMapped]
|
||||||
|
public decimal InitialPriceViz { get; set; } = 0;
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string ProductViz { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string CustomerViz { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public string CustomerEmailViz { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public string SubscriptionEmailViz { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public List<string> Tags { get; set; } = new List<string>();
|
public List<string> Tags { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateFullPaths>true</GenerateFullPaths>
|
<GenerateFullPaths>true</GenerateFullPaths>
|
||||||
<Version>8.0.13</Version>
|
<Version>8.0.16</Version>
|
||||||
<FileVersion>8.0.13.0</FileVersion>
|
<FileVersion>8.0.16.0</FileVersion>
|
||||||
<ApplicationIcon>sockeye.ico</ApplicationIcon>
|
<ApplicationIcon>sockeye.ico</ApplicationIcon>
|
||||||
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||||
<noWarn>1591</noWarn>
|
<noWarn>1591</noWarn>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Sockeye.Util
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class SockeyeVersion
|
internal static class SockeyeVersion
|
||||||
{
|
{
|
||||||
public const string VersionString = "8.0.13";
|
public const string VersionString = "8.0.17";
|
||||||
public const string FullNameAndVersion = "Sockeye server " + VersionString;
|
public const string FullNameAndVersion = "Sockeye server " + VersionString;
|
||||||
public const string CurrentApiVersion="v8";
|
public const string CurrentApiVersion="v8";
|
||||||
}//eoc
|
}//eoc
|
||||||
|
|||||||
10
todo.txt
10
todo.txt
@@ -15,18 +15,16 @@ TODO:
|
|||||||
|
|
||||||
TODO: make a filter showing expired but not set to inactive subscription items
|
TODO: make a filter showing expired but not set to inactive subscription items
|
||||||
|
|
||||||
TODO: dashboard items related to subscriptions
|
|
||||||
- revenue per month for next 12 months graph
|
|
||||||
- overdue expired subs list
|
|
||||||
- active count of each product subscription bar graph
|
|
||||||
|
|
||||||
todo: build email address list by active subscription product no dupes
|
todo: build email address list by active subscription product no dupes
|
||||||
maybe in a report?
|
maybe in a report?
|
||||||
This is for alerting subscribers to update or non subscribers to update separately
|
This is for alerting subscribers to update or non subscribers to update separately
|
||||||
maybe it's a full on feature?
|
maybe it's a full on feature?
|
||||||
|
|
||||||
|
|
||||||
|
TODO: dashboard items related to subscriptions
|
||||||
|
- revenue per month for next 12 months graph
|
||||||
|
- overdue expired subs list
|
||||||
|
- active count of each product subscription bar graph
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user