From a66350d8f4a0b5c9409d69806d869fb66140eeac Mon Sep 17 00:00:00 2001 From: 15168347908 <296778233@qq.com> Date: Fri, 30 Aug 2024 18:10:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=9A=E5=8A=A1=E9=94=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Entitys/XDepreciationConfig.cs | 84 ++++++++++++++++++++++--- Providers/DataProvider.cs | 20 +++++- Services/ThingDepreciationService.cs | 34 +++++++++- Services/ThingLockService.cs | 94 ++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 Services/ThingLockService.cs diff --git a/Entitys/XDepreciationConfig.cs b/Entitys/XDepreciationConfig.cs index 3637c15..7766910 100644 --- a/Entitys/XDepreciationConfig.cs +++ b/Entitys/XDepreciationConfig.cs @@ -9,6 +9,7 @@ namespace anydata.Models public List Dimensions { get; set; } public XProperty DepreciationMethod { get; set; } public string YearAverageMethod { get; set; } + public string? YearAverageMethod2 { get; set; } public XProperty DepreciationStatus { get; set; } public string AccruingStatus { get; set; } public string AccruedStatus { get; set; } @@ -19,12 +20,20 @@ namespace anydata.Models public XProperty AccruedMonths { get; set; } public XProperty UsefulLife { get; set; } public XProperty StartDate { get; set; } + public XProperty? ResidualRate { get; set; } + public XProperty? ResidualVal { get; set; } public List Fields { get; set; } + public bool Check() { - return Dimensions is null || Dimensions.Count == 0 || DepreciationMethod is null || YearAverageMethod is null || DepreciationStatus is null || AccruingStatus is null || AccruedStatus is null - || OriginalValue is null || AccumulatedDepreciation is null || MonthlyDepreciationAmount is null || NetWorth is null || AccruedMonths is null || StartDate is null || UsefulLife is null; + var success = Dimensions is null || Dimensions.Count == 0 || DepreciationMethod is null || YearAverageMethod is null || DepreciationStatus is null || AccruingStatus is null || AccruedStatus is null + || OriginalValue is null || AccumulatedDepreciation is null || MonthlyDepreciationAmount is null || NetWorth is null || AccruedMonths is null || StartDate is null || UsefulLife is null; + if (YearAverageMethod2 is not null) + { + success = ResidualRate is null || ResidualVal is null; + } + return success; } public XDepreciationConfig Initialize() @@ -39,6 +48,8 @@ namespace anydata.Models AccruedMonths.Initialize(); StartDate.Initialize(); UsefulLife.Initialize(); + ResidualRate?.Initialize(); + ResidualVal?.Initialize(); Fields = new List { DepreciationStatus.field, OriginalValue.field, AccumulatedDepreciation.field, MonthlyDepreciationAmount.field, NetWorth.field }; Dimensions.ForEach(item => Fields.Add(item.field)); return this; @@ -56,7 +67,8 @@ namespace anydata.Models { ["_in_"] = new JArray { - YearAverageMethod + YearAverageMethod, + YearAverageMethod2 } }, [OriginalValue.field.code] = new JObject @@ -114,7 +126,7 @@ namespace anydata.Models } } else - { + { var monthlyDepreciationAmount = Math.Round(afterNetWorth / remainderMonth, 2); after[MonthlyDepreciationAmount.field.code] = Math.Round(monthlyDepreciationAmount, 2); if (monthlyDepreciationAmount > afterNetWorth) @@ -122,7 +134,7 @@ namespace anydata.Models monthlyDepreciationAmount = afterNetWorth; } afterAccumulated += monthlyDepreciationAmount; - afterNetWorth -= monthlyDepreciationAmount; + afterNetWorth -= monthlyDepreciationAmount; remainderMonth -= 1; if (Math.Round(afterAccumulated, 2) != Math.Round(accumulated, 2)) @@ -131,7 +143,65 @@ namespace anydata.Models change.SetChangeDimension(after, context.SourceFields); changes.Add(change); } - } + } + after[AccumulatedDepreciation.field.code] = Math.Round(afterAccumulated, 2); + after[NetWorth.field.code] = Math.Round(afterNetWorth, 2); + after[AccruedMonths.field.code] = usefulLife - remainderMonth; + after[DepreciationStatus.field.code] = remainderMonth == 0 ? AccruedStatus : AccruingStatus; + + return (after, changes); + } + else if (method?.ToString() == YearAverageMethod2) + { + var originalValue = before.GetDoubleValue(OriginalValue.field); + var accumulated = before.GetDoubleValue(AccumulatedDepreciation.field); + var afterAccumulated = accumulated; + var netWorth = originalValue - accumulated; + var afterNetWorth = netWorth; + var usefulLife = before.GetIntValue(UsefulLife.field); + var startDate = before.GetDateValue(StartDate.field); + var residualRate = ResidualRate is null ? 0 : before.GetDoubleValue(ResidualRate.field) / 100; + var residualVal = residualRate * originalValue; + var diffVal = originalValue - residualVal; + + if (netWorth <= 0 || startDate is null) + { + return (null, changes); + } + startDate = startDate.Value.AddMonths(1); + var after = before.Clone(); + var rightAccruedMonths = MonthBetween((DateTime)startDate, current); + var remainderMonth = usefulLife - rightAccruedMonths; + if (remainderMonth <= 0) + { + afterAccumulated = originalValue; + afterNetWorth = 0; + if (Math.Round(afterAccumulated, 2) != Math.Round(accumulated, 2)) + { + var change = new XChange(context, before.id, AccumulatedDepreciation.field.code, accumulated, afterAccumulated, snapshot.id); + change.SetChangeDimension(after, context.SourceFields); + changes.Add(change); + } + } + else + { + var monthlyDepreciationAmount = Math.Round(diffVal / remainderMonth, 2); + after[MonthlyDepreciationAmount.field.code] = Math.Round(monthlyDepreciationAmount, 2); + if (monthlyDepreciationAmount > afterNetWorth) + { + monthlyDepreciationAmount = afterNetWorth; + } + afterAccumulated += monthlyDepreciationAmount; + afterNetWorth -= monthlyDepreciationAmount; + remainderMonth -= 1; + + if (Math.Round(afterAccumulated, 2) != Math.Round(accumulated, 2)) + { + var change = new XChange(context, before.id, AccumulatedDepreciation.field.code, accumulated, afterAccumulated, snapshot.id); + change.SetChangeDimension(after, context.SourceFields); + changes.Add(change); + } + } after[AccumulatedDepreciation.field.code] = Math.Round(afterAccumulated, 2); after[NetWorth.field.code] = Math.Round(afterNetWorth, 2); after[AccruedMonths.field.code] = usefulLife - remainderMonth; @@ -144,7 +214,7 @@ namespace anydata.Models public (FilterDefinition, UpdateDefinition)? BuildFilterUpdate(EntityBase after) { var method = after[DepreciationMethod.field.code]; - if (method?.ToString() == YearAverageMethod) + if (method?.ToString() == YearAverageMethod || method?.ToString() == YearAverageMethod2) { var filter = Builders.Filter.Eq(i => i.id, after.id); var update = Builders.Update.CurrentDate(i => i.updateTime) diff --git a/Providers/DataProvider.cs b/Providers/DataProvider.cs index 4801c57..c1a9d48 100644 --- a/Providers/DataProvider.cs +++ b/Providers/DataProvider.cs @@ -6,6 +6,7 @@ using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json.Linq; using System.Text.RegularExpressions; +using YamlDotNet.Core.Tokens; namespace anydata.Providers { @@ -160,6 +161,14 @@ namespace anydata.Providers var list = EntityBase.FromJToken(data, token.UserId.ToString(), out var isArray); if (list.Count > 0) { + if (collectName == "work-instance") + { + var lockService = services.GetRequiredService(); + foreach (var item in list) + { + await lockService.Locking(token, item, item.status); + } + } var ids = list.Select(i => i.id).ToArray(); var filter = Builders.Filter.In(i => i.id, ids); await collection.DeleteManyAsync(filter); @@ -184,6 +193,15 @@ namespace anydata.Providers } if (!string.IsNullOrWhiteSpace(data.Id)) { + if (collectName == "work-instance") + { + var lockService = services.GetRequiredService(); + var instanceStatus = data.Update.SelectToken("_set_.status"); + if (instanceStatus is not null && instanceStatus.Type == JTokenType.Integer) + { + await lockService.Locking(token, data.Id, instanceStatus.Value()); + } + } var filter = Builders.Filter.Eq(i => i.id, data.Id); return OperateResult.Success(await collection.FindOneAndUpdateAsync(filter, data.Update.ToBDocument(), new FindOneAndUpdateOptions() { ReturnDocument = ReturnDocument.After })); } @@ -305,7 +323,7 @@ namespace anydata.Providers update = update.Set((i) => i.isDeleted, thing.isDeleted == true); foreach (var kp in thing.extensions) { - if (kp.Key != "archives") + if (kp.Key != "archives" && kp.Key != "locks") { update = update.Set(kp.Key, kp.Value); } diff --git a/Services/ThingDepreciationService.cs b/Services/ThingDepreciationService.cs index b0d54e8..a845c65 100644 --- a/Services/ThingDepreciationService.cs +++ b/Services/ThingDepreciationService.cs @@ -2,7 +2,10 @@ using anydata.Loaders.ResponseModel; using anydata.Models; using Microsoft.Extensions.Logging; +using Microsoft.VisualBasic; +using MongoDB.Bson; using MongoDB.Bson.IO; +using MongoDB.Driver; using Newtonsoft.Json.Linq; using StackExchange.Redis; using System.Threading.Channels; @@ -15,11 +18,13 @@ public class ThingDepreciationService : ITransient { private readonly ILogger _logger; private readonly DataProvider provider; + private readonly ThingLockService lockService; - public ThingDepreciationService(DataProvider _provider, ILogger logger) + public ThingDepreciationService(DataProvider _provider, ThingLockService _lockService, ILogger logger) { _logger = logger; this.provider = _provider; + this.lockService = _lockService; } /// @@ -61,10 +66,10 @@ public class ThingDepreciationService : ITransient var options = BuildOptions(context, things.Select(item => item.id).ToList()); var result = await provider.LoadAsync(context.Token, DataProvider.ThingCollName, options); if (!result.success) - { + { return (changes, snapshots); } - var oldThings = ((result.data as LoadResult)?.data as List) ?? new List(); + var oldThings = ((result.data as LoadResult)?.data as List) ?? new List(); foreach (var newThing in things) { var oldThing = oldThings.Find(a => a.id == newThing.id); @@ -124,6 +129,27 @@ public class ThingDepreciationService : ITransient { return OperateResult.Faild($"{period.Period} 已折旧!"); } + if (args.Type == "Confirm") + { + var coll = provider.TryGetCollection(token, "_system-things"); + if (coll.success) + { + var filter = Builders.Filter.And( + Builders.Filter.Eq("belongId", token.BelongId.ToString()), + Builders.Filter.Eq("isDeleted", false), + Builders.Filter.Exists("locks") + ); + var count = await coll.data.Find(filter).Limit(1).CountDocumentsAsync(); + if (count > 0) + { + return OperateResult.Faild($"存在锁定中资产,业务完结后可确认折旧!"); + } + } + else + { + return OperateResult.Faild($"获取 _system-things 集合失败!"); + } + } break; case "Revoke": if (!(period.depreciated ?? false)) @@ -281,6 +307,7 @@ public class ThingDepreciationService : ITransient if (confirm) { await UpdateThings(context, endThings); + await lockService.LockThings(context.Token, context.Instance, DataProvider.ThingCollName, endThings); } if (oldThings.Count < take) { @@ -316,6 +343,7 @@ public class ThingDepreciationService : ITransient oldThings.ForEach(thing => thing.id = thing["thingId"].ToString()); await UpdateThings(context, oldThings); + await lockService.UnLockThings(context.Token, DataProvider.ThingCollName, oldThings); onSkip(skip); } diff --git a/Services/ThingLockService.cs b/Services/ThingLockService.cs new file mode 100644 index 0000000..77bda5b --- /dev/null +++ b/Services/ThingLockService.cs @@ -0,0 +1,94 @@ +using anydata.Entitys; +using MongoDB.Driver; + +namespace anydata.Services +{ + public class ThingLockService : ITransient + { + private readonly DataProvider provider; + + public ThingLockService(DataProvider _provider) + { + provider = _provider; + } + + public async Task Locking(TokenModel token, EntityBase instanceObj, int status) + { + var instance = new XWorkInstance(instanceObj); + if (instance?.InstanceData is not null) + { + var formMap = instance.InstanceData.FormCollectionNameMap; + foreach (var (formId, things) in instance.InstanceData.GetThings()) + { + if (formMap.ContainsKey(formId)) + { + var collName = formMap[formId]; + if (status < 100) + { + await LockThings(token, instance, collName, things); + } + else + { + await UnLockThings(token, collName, things); + } + } + } + } + } + + public async Task Locking(TokenModel token, string id, int status) + { + try + { + var result = provider.TryGetCollection(token, DataProvider.InstanceCollName); + if (!result.success) + { + Console.WriteLine("获取流程实例集合失败!"); + return; + } + var instanceObj = await result.data.Find(i => i.id == id).FirstOrDefaultAsync(); + await Locking(token, instanceObj, status); + } + catch (Exception error) + { + Console.WriteLine("加解锁失败:", error.Message); + } + } + + public async Task LockThings(TokenModel token, XWorkInstance instance, string collName, List things) + { + var coll = provider.TryGetCollection(token, collName); + if (coll.success) + { + try + { + var filter = Builders.Filter.In(item => item.id, things.Select(item => item.id).ToList()); + var update = Builders.Update.Set("locks.exclusion.id", instance.id).Set("locks.exclusion.name", instance.title); + await coll.data.UpdateManyAsync(filter, update); + } + catch (Exception error) + { + Console.WriteLine("锁定失败:" + error.ToString()); + } + } + } + + public async Task UnLockThings(TokenModel token, string collName, List things) + { + var coll = provider.TryGetCollection(token, collName); + if (coll.success) + { + try + { + var filter = Builders.Filter.In(item => item.id, things.Select(item => item.id).ToList()); + var update = Builders.Update.Unset("locks"); + await coll.data.UpdateManyAsync(filter, update); + } + catch (Exception error) + { + Console.WriteLine("解锁失败:" + error.ToString()); + } + } + } + } +} -- Gitee