| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- using AutoMapper;
- using Edge.Core.UniversalApi;
- using Gateway.POS.Models;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace Gateway.POS
- {
- public partial class App
- {
- [UniversalApi(Description = "Provide ONE of the paramter to limit the data, and other conditions will be ignorned. Leave all condition null(except page row count and page index) will return data order by timestamp desc.")]
- public async Task<Gateway.POS.MembershipOperationResult> GetMembershipAccountsSummary(int? accountId,
- string accountName, string accountCompanyName, string accountPhoneNumber, string oneOfSubAccountHolderName, string tagName, int pageRowCount, int pageIndex)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- List<MembershipAccount> accounts = null; new List<MembershipAccount>();
- if (accountId.HasValue)
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .Where(acct => acct.Id == accountId.Value)
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- else if (!string.IsNullOrEmpty(accountName))
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)
- .Where(acct => acct.Name.Contains(accountName))
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- else if (!string.IsNullOrEmpty(accountCompanyName))
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)
- .Where(acct => acct.CompanyName.Contains(accountCompanyName))
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- else if (!string.IsNullOrEmpty(accountPhoneNumber))
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)
- .Where(acct => acct.PhoneNumber.Contains(accountPhoneNumber))
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- else if (!string.IsNullOrEmpty(oneOfSubAccountHolderName))
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipSubAccounts
- .Include(sa => sa.Account).ThenInclude(acct => acct.ProfitAccounts)
- .Include(sa => sa.Account).ThenInclude(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(sa => sa.Identities)
- .Include(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(sa => sa.ProfitAccounts)
- .Where(sa => sa.SubAccountHolderName.Contains(oneOfSubAccountHolderName))
- .Select(sa => sa.Account)
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- else if (!string.IsNullOrEmpty(tagName))
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts).Where(acct => acct.AccountTags.Any(at => at.Tag.Name.Contains(tagName)))
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- if (accounts == null)
- {
- using (var db = new PosAppDbContext())
- {
- accounts = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.Identities)
- .Include(acct => acct.SubAccounts).ThenInclude(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .OrderByDescending(acct => acct.ServerSideCreatedTimestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount)
- .ToListAsync();
- }
- }
- var r = new MembershipOperationResult(200, "", mapper.Map<List<MembershipAccountOutputDto>>(accounts));
- return r;
- }
- [UniversalApi(Description = "")]
- public async Task<Gateway.POS.MembershipOperationResult> GetMembershipSubAccountDetail(int subAccountId, int pageRowCount, int pageIndex)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- using (var db = new PosAppDbContext())
- {
- var subAccount = await db.MembershipSubAccounts
- .Include(sa => sa.Account).ThenInclude(acct => acct.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRedeems)
- .Include(sa => sa.Account).ThenInclude(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .Include(sa => sa.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .Include(sa => sa.SubAccountTags).ThenInclude(at => at.Tag)
- .FirstOrDefaultAsync(sa => sa.Id == subAccountId);
- if (subAccount == null)
- return new MembershipOperationResult(404, "", null);
- if (subAccount.ProfitAccounts?.Any() ?? false)
- {
- foreach (var pa in subAccount.ProfitAccounts)
- {
- var latestRecharges = await db.MembershipProfitAccountRecharges.Include(rc => rc.ProfitAccount)
- .Where(rc => rc.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- var latestRedeems = await db.MembershipProfitAccountRedeems.Include(rd => rd.ProfitAccount)
- .Where(rd => rd.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- pa.ProfitRecharges = latestRecharges;
- pa.ProfitRedeems = latestRedeems;
- }
- }
- if (subAccount.Account.AllowSubAccountAccessProfitAccounts)
- {
- if (subAccount.Account.ProfitAccounts?.Any() ?? false)
- {
- foreach (var pa in subAccount.Account.ProfitAccounts)
- {
- var latestRecharges = await db.MembershipProfitAccountRecharges.Include(rc => rc.ProfitAccount)
- .Where(rc => rc.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- var latestRedeems = await db.MembershipProfitAccountRedeems.Include(rd => rd.ProfitAccount)
- .Where(rd => rd.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- pa.ProfitRecharges = latestRecharges;
- pa.ProfitRedeems = latestRedeems;
- }
- }
- }
- else
- {
- subAccount.Account.ProfitAccounts = null;
- }
- return new MembershipOperationResult(200, nameof(MembershipAccount), mapper.Map<MembershipAccountOutputDto>(subAccount.Account));
- }
- }
- [UniversalApi(Description = "")]
- public async Task<Gateway.POS.MembershipOperationResult> GetMembershipAccountDetail(int accountId, int pageRowCount, int pageIndex)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- using (var db = new PosAppDbContext())
- {
- var account = await db.MembershipAccounts
- .Include(acct => acct.SubAccounts).ThenInclude(subAcct => subAcct.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRedeems)
- .Include(acct => acct.SubAccounts).ThenInclude(subAcct => subAcct.SubAccountTags).ThenInclude(at => at.Tag)
- .Include(acct => acct.ProfitAccounts)//.ThenInclude(pa => pa.ProfitRecharges)
- .Include(acct => acct.AccountTags).ThenInclude(at => at.Tag)
- .FirstOrDefaultAsync(acct => acct.Id == accountId);
- if (account == null)
- return new MembershipOperationResult(404, "", null);
- if (account.ProfitAccounts?.Any() ?? false)
- {
- foreach (var pa in account.ProfitAccounts)
- {
- var latestRecharges = await db.MembershipProfitAccountRecharges.Include(rc => rc.ProfitAccount)
- .Where(rc => rc.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- var latestRedeems = await db.MembershipProfitAccountRedeems.Include(rd => rd.ProfitAccount)
- .Where(rd => rd.ProfitAccount.Id == pa.Id)
- .OrderByDescending(rc => rc.Timestamp)
- .Skip(pageRowCount * pageIndex).Take(pageRowCount).ToListAsync();
- pa.ProfitRecharges = latestRecharges;
- pa.ProfitRedeems = latestRedeems;
- }
- }
- return new MembershipOperationResult(200, nameof(MembershipAccount), mapper.Map<MembershipAccountOutputDto>(account));
- }
- }
- [Edge.Core.UniversalApi.UniversalApi(Description = "Get all membership tags, use parameter tagName to limit the scope, or leavel empty or null to return all.")]
- public async Task<Gateway.POS.MembershipOperationResult> GetMembershipTags(string tagName)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- List<MembershipTag> data;
- if (string.IsNullOrEmpty(tagName))
- {
- using (var db = new PosAppDbContext())
- {
- data = await db.MembershipTags.ToListAsync();
- }
- }
- else
- {
- using (var db = new PosAppDbContext())
- {
- data = await db.MembershipTags.ToListAsync();
- }
- }
- return new MembershipOperationResult(200, "", mapper.Map<List<MembershipTagDto>>(data));
- }
- [Edge.Core.UniversalApi.UniversalApi]
- public async Task<Gateway.POS.MembershipOperationResult> UpsertMembershipTag(Gateway.POS.Models.MembershipTagDto input)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var tag = mapper.Map<MembershipTag>(input);
- if (!input.Id.HasValue)
- using (var db = new PosAppDbContext())
- {
- db.MembershipTags.Add(tag);
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when saving to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipTag>(tag));
- }
- else if (!input.MarkForDeletion)
- {
- using (var db = new PosAppDbContext())
- {
- db.MembershipTags.Update(tag);
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when updating to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipTag>(tag));
- }
- }
- else
- {
- using (var db = new PosAppDbContext())
- {
- db.MembershipTags.Remove(tag);
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when removing to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipTag>(tag));
- }
- }
- }
- [Edge.Core.UniversalApi.UniversalApi]
- public async Task<Gateway.POS.MembershipOperationResult> UpsertMembershipAccount(Gateway.POS.Models.MembershipAccountInputDto input)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- //if (input.AccountTags != null)
- //{
- // input.AccountTags.RemoveAll(at => !at.MembershipTagId.HasValue);
- //}
- if (!input.Id.HasValue)
- {
- var newAcct = mapper.Map<MembershipAccount>(input);
- newAcct.ServerSideCreatedTimestamp = System.DateTime.Now;
- using (var db = new PosAppDbContext())
- {
- db.MembershipAccounts.Add(newAcct);
- if (newAcct.AccountTags != null)
- foreach (var t in newAcct.AccountTags)
- {
- t.Account = newAcct;
- if (t.MembershipTagId > 0)
- //dis-allow udpate tag here for make this api slim, should call standard alone api to do this.
- db.Entry(t.Tag).State = EntityState.Unchanged;
- else if (t.MembershipTagId <= 0)
- db.Entry(t.Tag).State = EntityState.Added;
- }
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when saving to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipAccountOutputDto>(newAcct));
- }
- }
- else
- {
- var updateAcct = mapper.Map<MembershipAccount>(input);
- using (var db = new PosAppDbContext())
- {
- db.MembershipAccounts.Update(updateAcct);
- if (updateAcct.AccountTags != null)
- foreach (var t in updateAcct.AccountTags)
- {
- t.Account = updateAcct;
- if (t.MembershipTagId > 0)
- //dis-allow udpate tag here for make this api slim, should call standard alone api to do this.
- db.Entry(t.Tag).State = EntityState.Unchanged;
- else if (t.MembershipTagId <= 0)
- db.Entry(t.Tag).State = EntityState.Added;
- }
- db.Entry(updateAcct.SubAccounts).State = EntityState.Unchanged;
- db.Entry(updateAcct.ProfitAccounts).State = EntityState.Unchanged;
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when updating to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipAccountOutputDto>(updateAcct));
- }
- }
- }
- [Edge.Core.UniversalApi.UniversalApi]
- public async Task<Gateway.POS.MembershipOperationResult> UpsertMembershipProfitAccount(Gateway.POS.Models.MembershipProfitAccountInputDto input)
- {
- if (!input.MembershipAccountId.HasValue && !input.MembershipSubAccountId.HasValue)
- return new MembershipOperationResult(400, "A Profit account must belongs to an account or subAccount, please provide at least one id.");
- var mapper = this.services.GetRequiredService<IMapper>();
- if (!input.Id.HasValue)
- {
- var newProfitAcct = mapper.Map<Gateway.POS.Models.MembershipProfitAccount>(input);
- newProfitAcct.ServerSideCreatedTimestamp = DateTime.Now;
- using (var db = new PosAppDbContext())
- {
- db.MembershipProfitAccounts.Add(newProfitAcct);
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when saving to db.");
- else
- return new MembershipOperationResult(200, "", newProfitAcct);
- }
- }
- else
- {
- var updateProfitAcct = mapper.Map<Gateway.POS.Models.MembershipProfitAccount>(input);
- using (var db = new PosAppDbContext())
- {
- db.MembershipProfitAccounts.Update(updateProfitAcct);
- db.Entry(updateProfitAcct.ProfitRecharges).State = EntityState.Unchanged;
- db.Entry(updateProfitAcct.ProfitRedeems).State = EntityState.Unchanged;
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "The effected row count is < 1 when updating to db.");
- else
- return new MembershipOperationResult(200, "", updateProfitAcct);
- }
- }
- }
- [Edge.Core.UniversalApi.UniversalApi(Description = "Update or insert a sub account to an account.")]
- public async Task<Gateway.POS.MembershipOperationResult> UpsertMembershipSubAccount(
- string cardReaderNameIfIssueCard, Gateway.POS.Models.MembershipSubAccountInputDto input)
- {
- if (input.AccountId == 0)
- return new Gateway.POS.MembershipOperationResult(400, $"Must specify a valid AccountId");
- using (var db = new PosAppDbContext())
- {
- var foundAcct = await db.MembershipAccounts.FirstOrDefaultAsync(acct => acct.Id == input.AccountId);
- if (foundAcct == null)
- return new Gateway.POS.MembershipOperationResult(400, $"Could not find the correlated account with accountId: {input.AccountId}");
- }
- var mapper = this.services.GetRequiredService<IMapper>();
- if (!input.Id.HasValue || input.Id.Value == 0)
- {
- var newSubAcct = mapper.Map<MembershipSubAccount>(input);
- newSubAcct.ServerSideCreatedTimestamp = System.DateTime.Now;
- if (newSubAcct.Identities?.Any(i => i.IdentityCarrierType == MembershipSubAccountIdentityCarrierTypeEnum.Card_DesFireEv1) ?? false)
- {
- var potentialSubAccountIdentity = "";
- if (cardReaderNameIfIssueCard == "fakereader")
- {
- potentialSubAccountIdentity = string.Concat("fake_", System.DateTime.Now.Ticks.ToString());
- }
- else
- {
- var targetDesFireEv1CardModule = this.classicCpuCardApp?.CardReaderModuels?.FirstOrDefault(m => m.Name == cardReaderNameIfIssueCard);
- if (targetDesFireEv1CardModule == null)
- return new Gateway.POS.MembershipOperationResult(404, $"找不到读卡器, 它的名称是: {cardReaderNameIfIssueCard}", null);
- var readCardIdResults = await this.classicCpuCardApp.ReadCardID(cardReaderNameIfIssueCard);
- var readCardIdSucceedResult = readCardIdResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardIdSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(404, $"从读卡器: {cardReaderNameIfIssueCard} 上读取卡片的UID失败, 请确保将卡片靠近读卡器", null);
- potentialSubAccountIdentity = readCardIdSucceedResult.PrettyHexStrData.Replace(" ", "");
- var readCardContentResults = await this.classicCpuCardApp.ReadCardContent(cardReaderNameIfIssueCard, 1, 1);
- var readCardContentSucceedResult = readCardContentResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardContentSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(404, $"从读卡器: {cardReaderNameIfIssueCard} 上读取卡片的内容失败", readCardContentResults);
- /*read a card open id, and the content can be read as well indicates this is a card from our system, otherwise, could be a card just faked the open id*/
- using (var db = new PosAppDbContext())
- {
- var foundSubAcct = await db.MembershipSubAccounts.Include(sa => sa.Account).Include(sa => sa.Identities)
- .FirstOrDefaultAsync(sa =>
- sa.Identities.Any(i => i.IdentityCarrierType == MembershipSubAccountIdentityCarrierTypeEnum.Card_DesFireEv1
- && i.Identity == potentialSubAccountIdentity));
- if (foundSubAcct != null)
- return new Gateway.POS.MembershipOperationResult(409, $"当前卡片已经分配给子帐户: {foundSubAcct.SubAccountHolderName ?? ""} (其属于帐户: {foundSubAcct.Account?.Name ?? ""}), 请换一张新卡片或者将当前卡片与已经绑定的子帐户解除绑定, 然后再试");
- }
- var issueCardWriteContent = string.Format("{0}|{1}|{2}", this.siteId, newSubAcct.Account.Id, potentialSubAccountIdentity);
- var writeCardContentResults = await this.classicCpuCardApp.WriteCardWithTextData(cardReaderNameIfIssueCard, 1, 1, issueCardWriteContent);
- var writeCardContentSucceedResult = writeCardContentResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (writeCardContentSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(500, $"在通过读卡器: {cardReaderNameIfIssueCard} 向卡片中写入内容时失败", writeCardContentResults);
- }
- newSubAcct.Identities.First(i => i.IdentityCarrierType == MembershipSubAccountIdentityCarrierTypeEnum.Card_DesFireEv1).Identity = potentialSubAccountIdentity;
- }
- using (var db = new PosAppDbContext())
- {
- newSubAcct.Account.Id = input.AccountId;
- db.MembershipSubAccounts.Add(newSubAcct);
- if (newSubAcct.SubAccountTags != null)
- foreach (var t in newSubAcct.SubAccountTags)
- {
- t.SubAccount = newSubAcct;
- if (t.MembershipTagId > 0)
- //dis-allow udpate tag here for make this api slim, should call standard alone api to do this.
- db.Entry(t.Tag).State = EntityState.Unchanged;
- else if (t.MembershipTagId <= 0)
- db.Entry(t.Tag).State = EntityState.Added;
- }
- //dis-allow udpate Account
- db.Entry(newSubAcct.Account).State = EntityState.Unchanged;
- try
- {
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "UpsertMembershipSubAccount(Insert), The effected row count is < 1 when saving to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipSubAccountOutputDto>(newSubAcct));
- }
- catch (Exception eee)
- {
- return new MembershipOperationResult(500, $"UpsertMembershipSubAccount(Insert), Saving db exceptioned: {eee}");
- }
- }
- }
- else
- {
- var updateSubAcct = mapper.Map<Gateway.POS.Models.MembershipSubAccount>(input);
- updateSubAcct.ServerSideLastModifiedTimestamp = System.DateTime.Now;
- using (var db = new PosAppDbContext())
- {
- db.MembershipSubAccounts.Update(updateSubAcct);
- if (updateSubAcct.SubAccountTags != null)
- foreach (var t in updateSubAcct.SubAccountTags)
- {
- t.SubAccount = updateSubAcct;
- if (t.MembershipTagId > 0)
- //dis-allow udpate tag here for make this api slim, should call standard alone api to do this.
- db.Entry(t.Tag).State = EntityState.Unchanged;
- else if (t.MembershipTagId <= 0)
- db.Entry(t.Tag).State = EntityState.Added;
- }
- db.Entry(updateSubAcct.Account).State = EntityState.Unchanged;
- db.Entry(updateSubAcct).Collection(p => p.ProfitAccounts).IsModified = false;
- db.Entry(updateSubAcct).Collection(p => p.Identities).IsModified = false;
- try
- {
- var saveResult = await db.SaveChangesAsync();
- if (saveResult < 1)
- return new MembershipOperationResult(500, "UpsertMembershipSubAccount(Update), The effected row count is < 1 when updating to db.");
- else
- return new MembershipOperationResult(200, "", mapper.Map<MembershipSubAccountOutputDto>(updateSubAcct));
- }
- catch (Exception eee)
- {
- return new MembershipOperationResult(500, $"UpsertMembershipSubAccount(Update), Saving db exceptioned: {eee}");
- }
- }
- }
- }
- internal async Task<MembershipOperationResult> InternalRechargeMembershipAccount(int membershipAccountId,
- MembershipProfitAccountProfitTypeEnum rechargeProfitType, MembershipProfitAccountRechargeRequest input, PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var foundAcct = await unitOfWorkDb.MembershipAccounts.Include(acct => acct.ProfitAccounts).FirstOrDefaultAsync(acct => acct.Id == membershipAccountId);
- if (foundAcct == null)
- {
- return new MembershipOperationResult(404, $"Could not find membership account with id: {membershipAccountId}", null);
- }
- var foundProfitAccount = foundAcct.ProfitAccounts.FirstOrDefault(pa => pa.ProfitType == rechargeProfitType);
- if (foundProfitAccount == null)
- {
- /*create a profit account and then recharge it*/
- var newProfitAcct = new MembershipProfitAccount();
- newProfitAcct.MembershipAccountId = membershipAccountId;
- newProfitAcct.ProfitType = rechargeProfitType;
- newProfitAcct.Balance = input.RechargeAmount;
- unitOfWorkDb.MembershipProfitAccounts.Add(newProfitAcct);
- foundProfitAccount = newProfitAcct;
- }
- else
- {
- foundProfitAccount.Balance = (foundProfitAccount.Balance ?? 0) + input.RechargeAmount;
- unitOfWorkDb.MembershipProfitAccounts.Update(foundProfitAccount);
- }
- var recharge = new MembershipProfitAccountRecharge();
- recharge.RechargeAmount = input.RechargeAmount;
- recharge.SourceTrx = input.SourceTrx;
- recharge.Timestamp = DateTime.Now;
- recharge.ProfitAccount = foundProfitAccount;
- recharge.ProfitAccountAmountBalance = foundProfitAccount.Balance;
- unitOfWorkDb.MembershipProfitAccountRecharges.Add(recharge);
- return new MembershipOperationResult(200, "", recharge);
- }
- internal async Task<MembershipOperationResult> InternalRechargeMembershipSubAccount(int membershipSubAccountId,
- MembershipProfitAccountProfitTypeEnum rechargeProfitType, MembershipProfitAccountRechargeRequest input, PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var foundSubAcct = await unitOfWorkDb.MembershipSubAccounts.Include(acct => acct.ProfitAccounts).FirstOrDefaultAsync(subAcct => subAcct.Id == membershipSubAccountId);
- if (foundSubAcct == null)
- {
- return new MembershipOperationResult(404, $"Could not find membership sub account with id: {membershipSubAccountId}", null);
- }
- var foundProfitAccount = foundSubAcct.ProfitAccounts.FirstOrDefault(pa => pa.ProfitType == rechargeProfitType);
- if (foundProfitAccount == null)
- {
- /*create a profit account and then recharge it*/
- var newProfitAcct = new MembershipProfitAccount();
- newProfitAcct.MembershipSubAccountId = membershipSubAccountId;
- newProfitAcct.ProfitType = rechargeProfitType;
- newProfitAcct.Balance = input.RechargeAmount;
- unitOfWorkDb.MembershipProfitAccounts.Add(newProfitAcct);
- foundProfitAccount = newProfitAcct;
- }
- else
- {
- foundProfitAccount.Balance = (foundProfitAccount.Balance ?? 0) + input.RechargeAmount;
- unitOfWorkDb.MembershipProfitAccounts.Update(foundProfitAccount);
- }
- var recharge = new MembershipProfitAccountRecharge();
- recharge.CreateByOperatorId = input.CreateByOperatorId;
- recharge.RechargeAmount = input.RechargeAmount;
- recharge.SourceTrx = input.SourceTrx;
- recharge.Timestamp = DateTime.Now;
- recharge.ProfitAccount = foundProfitAccount;
- recharge.ProfitAccountAmountBalance = foundProfitAccount.Balance;
- unitOfWorkDb.MembershipProfitAccountRecharges.Add(recharge);
- return new MembershipOperationResult(200, "", recharge);
- }
- internal async Task<MembershipOperationResult> InternalRechargeMembershipSubAccountByOpenClassicCpuCardReaderAndReadCard(string cardReaderName,
- MembershipProfitAccountProfitTypeEnum rechargeProfitType, MembershipProfitAccountRechargeRequest input, PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var targetDesFireEv1CardModule = this.classicCpuCardApp?.CardReaderModuels?.FirstOrDefault(m => m.Name == cardReaderName);
- if (targetDesFireEv1CardModule == null)
- return new Gateway.POS.MembershipOperationResult(500, $"找不到读卡器, 它的名称是: {cardReaderName}", null);
- var readCardIdResults = await this.classicCpuCardApp.ReadCardID(cardReaderName);
- var readCardIdSucceedResult = readCardIdResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardIdSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(500, $"Could not read any Card(UID) on card reader: {cardReaderName}, make sure the card is placed near the reader", null);
- /*read a card open id, and the content can be read as well indicates this is a card from our system, otherwise, could be a card just faked the open id*/
- var readCardContentResults = await this.classicCpuCardApp.ReadCardContent(cardReaderName, 1, 1);
- var readCardContentSucceedResult = readCardContentResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardContentSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(500, $"Could not read Card content on card reader: {cardReaderName}", readCardContentResults);
- var potentialSubAccountIdentity = readCardIdSucceedResult.PrettyHexStrData.Replace(" ", "");
- var foundSubAcct =
- await unitOfWorkDb.MembershipSubAccounts
- //.Include(sa => sa.ProfitAccounts)
- //.Include(sa => sa.Account).ThenInclude(acct => acct.ProfitAccounts)
- .Include(sa => sa.Identities)
- .FirstOrDefaultAsync(sa => sa.Identities.Any(i => i.IdentityCarrierType == MembershipSubAccountIdentityCarrierTypeEnum.Card_DesFireEv1 && i.Identity == potentialSubAccountIdentity));
- if (foundSubAcct == null)
- return new Gateway.POS.MembershipOperationResult(404, string.Concat("Could not find sub Account with identity: ", potentialSubAccountIdentity), null);
- var rechargeResult = await this.InternalRechargeMembershipSubAccount(foundSubAcct.Id, rechargeProfitType, input, unitOfWorkDb);
- return rechargeResult;
- }
- internal async Task<Gateway.POS.MembershipOperationResult> InternalRedeemMembershipProfit(MembershipProfitAccountRedeemRequest input,
- PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var foundSubAcct =
- await unitOfWorkDb.MembershipSubAccounts
- //.Include(sa => sa.ProfitAccounts)
- //.Include(sa => sa.Account).ThenInclude(acct => acct.ProfitAccounts)
- .Include(sa => sa.Identities)
- .FirstOrDefaultAsync(sa => sa.Identities.Any(i => i.IdentityCarrierType == input.SubAccountIdentity.IdentityCarrierType && i.Identity == input.SubAccountIdentity.Identity));
- if (foundSubAcct == null)
- return new Gateway.POS.MembershipOperationResult(404, $"找不到拥有标识符为: {input.SubAccountIdentity.Identity} 的子帐户", null);
- var result = await this.InternalRedeemMembershipProfit(foundSubAcct.Id, input, unitOfWorkDb);
- return result;
- }
- internal async Task<Gateway.POS.MembershipOperationResult> InternalRedeemMembershipProfit(int membershipSubAccountId,
- MembershipProfitAccountRedeemRequest input, PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var foundSubAcct =
- await unitOfWorkDb.MembershipSubAccounts
- .Include(sa => sa.ProfitAccounts)
- .Include(sa => sa.Account).ThenInclude(acct => acct.ProfitAccounts)
- .Include(sa => sa.Identities)
- .FirstOrDefaultAsync(sa => sa.Id == membershipSubAccountId);
- if (foundSubAcct == null)
- return new Gateway.POS.MembershipOperationResult(404, $"找不到拥有标识符为: {input.SubAccountIdentity.Identity} 的子帐户", null);
- #region choose profit account, could be from subAcct or acct, subAcct has the priority.
- MembershipProfitAccount targetProfitAccount = null;
- var profitAccountOnSubAcct = foundSubAcct?.ProfitAccounts?.FirstOrDefault(pa => pa.ProfitType == input.ProfitAccountType);
- if (profitAccountOnSubAcct != null)
- targetProfitAccount = profitAccountOnSubAcct;
- else if (profitAccountOnSubAcct == null && foundSubAcct.Account.AllowSubAccountAccessProfitAccounts)
- {
- var profitAccountOnAcct = foundSubAcct.Account?.ProfitAccounts?.FirstOrDefault(pa => pa.ProfitType == input.ProfitAccountType);
- if (profitAccountOnAcct == null)
- return new MembershipOperationResult(404, $"子帐户: {foundSubAcct.SubAccountHolderName} (属于帐户: {foundSubAcct.Account.Name}) 上并未创建任何权益帐户");
- targetProfitAccount = profitAccountOnAcct;
- }
- else
- return new Gateway.POS.MembershipOperationResult(404, $"子帐户: {foundSubAcct.SubAccountHolderName} (id: {foundSubAcct.Id}) 上并未创建类型为: {input.ProfitAccountType} 的权益帐户(且当前子帐户不允许使用帐户上的权益帐户)", null);
- #endregion
- if ((targetProfitAccount.Balance ?? 0) < (input.RedeemProfitAmount ?? 0))
- {
- return new MembershipOperationResult(404, $"当前权益帐户(类型: {targetProfitAccount.ProfitType})中的余额: {targetProfitAccount.Balance ?? 0} 不足以支付当前请求");
- }
- else if (targetProfitAccount.RedeemAuthMode == MembershipProfitAccountRedeemAuthModeEnum.Password)
- {
- if (targetProfitAccount.RedeemAuthPassword != input.RedeemAuthCode)
- {
- return new Gateway.POS.MembershipOperationResult(403, $"当前权益帐户(类型: {targetProfitAccount.ProfitType})的密码输入错误");
- }
- }
- targetProfitAccount.Balance = (targetProfitAccount.Balance ?? 0) - (input.RedeemProfitAmount ?? 0);
- unitOfWorkDb.MembershipProfitAccounts.Update(targetProfitAccount);
- var redeem = new MembershipProfitAccountRedeem();
- redeem.SourceTrx = input.SourceTrx;
- redeem.Timestamp = DateTime.Now;
- redeem.ProfitAccount = targetProfitAccount;
- redeem.Purpose = input.Purpose;
- redeem.RedeemedProfitAmount = input.RedeemProfitAmount;
- redeem.RedeemedProfitComplexData = input.RedeemProfitComplexData;
- redeem.ProfitAccountAmountBalance = targetProfitAccount.Balance;
- redeem.CreateByOperatorId = input.CreateByOperatorId;
- redeem.Description = input.Description;
- unitOfWorkDb.MembershipProfitAccountRedeems.Add(redeem);
- return new MembershipOperationResult(200, "", redeem);
- }
- internal async Task<Gateway.POS.MembershipOperationResult> InternalRedeemMembershipProfitByOpenClassicCpuCardReaderAndReadCard(string cardReaderName,
- MembershipProfitAccountRedeemRequest input, PosAppDbContext unitOfWorkDb)
- {
- var mapper = this.services.GetRequiredService<IMapper>();
- var targetDesFireEv1CardModule = this.classicCpuCardApp?.CardReaderModuels?.FirstOrDefault(m => m.Name == cardReaderName);
- if (targetDesFireEv1CardModule == null)
- return new Gateway.POS.MembershipOperationResult(500, $"找不到读卡器, 它的名称是: {cardReaderName}", null);
- var readCardIdResults = await this.classicCpuCardApp.ReadCardID(cardReaderName);
- var readCardIdSucceedResult = readCardIdResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardIdSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(500, $"从读卡器: {cardReaderName} 上读取卡片的UID失败, 请确保将卡片靠近读卡器", null);
- /*read a card open id, and the content can be read as well indicates this is a card from our system, otherwise, could be a card just faked the open id*/
- var readCardContentResults = await this.classicCpuCardApp.ReadCardContent(cardReaderName, 1, 1);
- var readCardContentSucceedResult = readCardContentResults.FirstOrDefault(r => r.OverallResultCode == 200);
- if (readCardContentSucceedResult == null)
- return new Gateway.POS.MembershipOperationResult(500, $"从读卡器: {cardReaderName} 上读取卡片的内容失败", readCardContentResults);
- var potentialSubAccountIdentity = readCardIdSucceedResult.PrettyHexStrData.Replace(" ", "");
- input.SubAccountIdentity = new MembershipSubAccountIdentityInputDto()
- {
- IdentityCarrierType = MembershipSubAccountIdentityCarrierTypeEnum.Card_DesFireEv1,
- Identity = potentialSubAccountIdentity
- };
- var redeemResult = await this.InternalRedeemMembershipProfit(input, unitOfWorkDb);
- return redeemResult;
- }
- [Edge.Core.UniversalApi.UniversalApi(Description = "Redeem profit from a SubAccount, and SubAccount's Identity will be read by a card reader, thus no need to fill it in input, or it'll get overwriten")]
- public Task<Gateway.POS.MembershipOperationResult> RedeemMembershipProfitByOpenClassicCpuCardReaderAndReadCard(string cardReaderName,
- MembershipProfitAccountRedeemRequest input)
- {
- return this.InternalRedeemMembershipProfitByOpenClassicCpuCardReaderAndReadCard(cardReaderName, input, new PosAppDbContext());
- }
- }
- public class MembershipOperationResult
- {
- public int OverallResultCode { get; set; }
- public string Message { get; }
- public object Data { get; set; }
- public ShengJu_CUT100_DES.GroupHandler.CardOperationResult[] CardOperationResults { get; set; }
- public MembershipOperationResult(int overallResultCode, string message, object data)
- {
- this.OverallResultCode = overallResultCode;
- this.Message = message;
- this.Data = data;
- }
- public MembershipOperationResult(int overallResultCode, string message)
- : this(overallResultCode, message, null)
- {
- }
- public MembershipOperationResult(int overallResultCode)
- : this(overallResultCode, null, null)
- {
- }
- }
- }
|