FeeAuditRepository.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. using EyeSoft.Logging;
  2. using NPOI.SS.Formula.Functions;
  3. using OASystem.Domain;
  4. using OASystem.Domain.Entities.Groups;
  5. using OASystem.Domain.Entities.Resource;
  6. using OASystem.Domain.ViewModels.Groups;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. namespace OASystem.Infrastructure.Repositories.Groups
  13. {
  14. /// <summary>
  15. /// 费用审核仓储
  16. /// </summary>
  17. public class FeeAuditRepository:BaseRepository<EntityBase,ViewBase>
  18. {
  19. public FeeAuditRepository(SqlSugarClient sqlSugar) : base(sqlSugar)
  20. {
  21. }
  22. /// <summary>
  23. /// 费用自动审核
  24. /// </summary>
  25. /// <param name="feeType">
  26. /// 1.酒店 76
  27. /// 2.op 79
  28. /// 3.其他费用-出行物资 98
  29. /// 4.保险 82
  30. /// </param>
  31. /// <param name="diId">团组Id</param>
  32. /// <param name="dataId">数据Id(模块类型主表Id)</param>
  33. /// <returns></returns>
  34. public async Task<JsonView> FeeAutomaticAudit(int feeType, int diId, int dataId)
  35. {
  36. var _view = new JsonView() { Code = 201, Msg = "自动审核操作失败" };
  37. if (diId < 1) { _view.Msg = MsgTips.DiId; return _view; }
  38. if (dataId < 1) { _view.Msg = MsgTips.Id; return _view; }
  39. var stids = new List<int>() { 17, 66, 91 };
  40. var setData = _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && stids.Contains(x.STid)).ToList();
  41. string _teamCurrency = string.Empty;
  42. decimal _teamRate = 0.00M;
  43. var costContents = new List<GroupCostAuditView>();
  44. if (feeType != 4)
  45. {
  46. var groupInfo = _sqlSugar.Queryable<Grp_GroupCostParameter>().Where(x => x.IsDel == 0 && x.DiId == diId).First();
  47. if (groupInfo == null) { _view.Msg = $"团组成本信息未填写!"; return _view; }
  48. _teamCurrency = groupInfo.Currency;
  49. _teamRate = groupInfo.Rate;
  50. //币种验证 统一为currencycode三字码
  51. if (int.TryParse(_teamCurrency, out int currency)) _teamCurrency = setData.Find(x => x.Id == currency)?.Name ?? "";
  52. string costContentSql = $"Select * From Grp_GroupCost";
  53. costContents = _sqlSugar.SqlQueryable<GroupCostAuditView>(costContentSql).Where(x => x.IsDel == 0 && x.Diid == diId).ToList();
  54. if (costContents.Count < 1) { _view.Msg = $"团组成本信息未填写!"; return _view; }
  55. //处理 成本详细信息 日期为空
  56. for (int i = 0; i < costContents.Count; i++)
  57. {
  58. if (string.IsNullOrEmpty(costContents[i].Date))
  59. {
  60. int index = i - 1;
  61. if (index >= 0)
  62. {
  63. costContents[i].Date = costContents[index].Date;
  64. var dtBool = DateTime.TryParse(costContents[i].Date, out DateTime _dateTime);
  65. if (dtBool)
  66. {
  67. costContents[i].CurrTime = _dateTime;
  68. }
  69. }
  70. }
  71. else
  72. {
  73. var dtBool = DateTime.TryParse(costContents[i].Date, out DateTime _dateTime);
  74. if (dtBool)
  75. {
  76. costContents[i].CurrTime = _dateTime;
  77. }
  78. }
  79. }
  80. }
  81. if (feeType == 1)
  82. {
  83. //1089 对冲账或其他 不在审核范围
  84. var hotelCostInfo = _sqlSugar.Queryable<Grp_HotelReservations>().Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId && x.CheckType != 1089).First();
  85. var hotelCostDetails = _sqlSugar.Queryable<Grp_HotelReservationsContent>().Where(x => x.IsDel == 0 && x.DiId == diId && x.HrId == dataId).ToList();
  86. if (hotelCostInfo == null)
  87. {
  88. _view.Msg = $"酒店费用数据未填写";
  89. QuashAudit(76, diId, dataId);
  90. return _view;
  91. }
  92. //酒店费用金额 == 0 不自动审核
  93. if (hotelCostInfo.CardPrice == 0.0000M)
  94. {
  95. _view.Msg = $"酒店费用金额 == 0 不自动审核";
  96. QuashAudit(76, diId, dataId);
  97. return _view;
  98. }
  99. //获取C表汇率
  100. decimal _rate = 1.0000M;
  101. var roomFeeInfo = hotelCostDetails.Where(x => x.PriceType == 1).First();
  102. if (roomFeeInfo == null)
  103. {
  104. _view.Msg = $"酒店房间费用付款数据未填写";
  105. return _view;
  106. }
  107. _rate = roomFeeInfo.Rate == 0.0000M ? 1.0000M : roomFeeInfo.Rate;
  108. bool isAutoAudit = true; //是否自动审核
  109. DateTime checkIn = Convert.ToDateTime(hotelCostInfo.CheckInDate),
  110. checkOut = Convert.ToDateTime(hotelCostInfo.CheckOutDate);
  111. if (checkOut > checkIn) checkOut = checkOut.AddDays(-1); //房费计算,结束日期为前一天
  112. var hotelCostInfos = costContents.Where(x => x.CurrTime >= checkIn && x.CurrTime <= checkOut).ToList();
  113. if (hotelCostInfos.Count < 1) isAutoAudit = false;
  114. decimal otherFee = hotelCostDetails.Where(x => x.PriceType != 1).Sum(x => x.Price * (x.Rate == 0.0000M ? 1.0000M : x.Rate));
  115. if (otherFee > 0) { otherFee /= (checkOut - checkIn).Days; }
  116. var hotelCostInfosGroup = hotelCostInfos.GroupBy(x => x.Date);
  117. foreach (var item in hotelCostInfosGroup)
  118. {
  119. var hotelSingleRoomFee = item.Sum(x => x.HotelSingleRoomFee) * _teamRate; //成本单间费用
  120. var hotelDoubleRoomFee = item.Sum(x => x.HotelDoubleRoomFee) * _teamRate; //成本双人间费用
  121. var hotelSuiteFee = item.Sum(x => x.HotelSuiteFee) * _teamRate; //成本套房费用
  122. var hotelSuiteRoomFee = item.Sum(x => x.HotelSuiteRoomFee) * _teamRate; //成本其他房型间费用
  123. //1.判断费用是否 <= 成本费用
  124. //1.1 判断单间费用
  125. decimal singleRoomPrice = (hotelCostInfo.SingleRoomPrice + otherFee) * _rate; //酒店录入费用
  126. if (singleRoomPrice > 0) if (singleRoomPrice > hotelSingleRoomFee) isAutoAudit = false;
  127. //1.2 判断双人间费用
  128. decimal doubleRoomPrice = (hotelCostInfo.DoubleRoomPrice + otherFee) * _rate;//酒店录入费用
  129. if (doubleRoomPrice > 0) if (doubleRoomPrice > hotelDoubleRoomFee) isAutoAudit = false;
  130. //1.3 判断套房费用
  131. decimal suiteRoomPrice = (hotelCostInfo.SuiteRoomPrice + otherFee) * _rate;//酒店录入费用
  132. if (suiteRoomPrice > 0) if (suiteRoomPrice > hotelSuiteFee) isAutoAudit = false;
  133. //1.4 判断其他房型费用
  134. decimal otherRoomPrice = (hotelCostInfo.OtherRoomPrice + otherFee) * _rate;//酒店录入费用
  135. if (otherRoomPrice > 0) if (otherRoomPrice > hotelSuiteRoomFee) isAutoAudit = false;
  136. }
  137. //2.判断是否自动审核
  138. if (isAutoAudit)
  139. {
  140. var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  141. .SetColumns(it => it.IsAuditGM == 3)
  142. .SetColumns(it => it.AuditGMOperate == 4)
  143. .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  144. .Where(s => s.DIId == diId && s.CTable == 76 && s.CId == dataId)
  145. .ExecuteCommand();
  146. if (ccpUpdate > 0)
  147. {
  148. _view.Code = 200;
  149. _view.Msg = "自动审核执行成功";
  150. return _view;
  151. }
  152. }
  153. else
  154. {
  155. //撤销该条数据的自动审核 --> 该条数据的审核状态是自动审核 3 --> 0
  156. var quashStatus = QuashAudit(76, diId, dataId);
  157. if (quashStatus)
  158. {
  159. _view.Code = 200;
  160. _view.Msg = "费用超团组成本,自动审核撤销成功!";
  161. return _view;
  162. }
  163. }
  164. }
  165. else if (feeType == 2)
  166. {
  167. //1.基础数据参数验证
  168. var priceType = new List<int>() {
  169. 1062 //1062 尾款
  170. };
  171. var opinfos = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservations>()
  172. .Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId && !priceType.Contains(x.PriceType))
  173. .First();
  174. //var opinfos = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservations>()
  175. // .Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId )
  176. // .First();
  177. if (opinfos == null)
  178. {
  179. _view.Msg = $"OP费用费用类型属于“尾款”或者 内容未填写";
  180. return _view;
  181. }
  182. //1.含超时费用/超支费用 手动审核
  183. if (opinfos.SelectCheck.Contains("超时") || opinfos.SelectCheck.Contains("超支") || opinfos.SelectCheck.Contains("尾款"))
  184. {
  185. _view.Msg = @$"OP费用含尾款/超支/超时费用,请手动审核";
  186. return _view;
  187. }
  188. //1.参数验证
  189. var opCheckPriceTyeps = opinfos.SelectCheck.Split(',');
  190. var opCheckPriceTyepIds = setData.Where(x => opinfos.SelectCheck.Split(',').Contains(x.Name)).Select(x => x.Id).ToList();
  191. var opContents = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservationsContent>()
  192. .Where(x => x.IsDel == 0 && x.DiId == diId && x.CTGGRId == dataId && opCheckPriceTyepIds.Contains(x.SId))
  193. .OrderBy(x => x.DatePrice, OrderByType.Asc)
  194. .ToList();
  195. if (opContents.Count < 1)
  196. {
  197. _view.Msg = $"OP费用费用内容未填写";
  198. return _view;
  199. }
  200. //获取C表汇率
  201. decimal _opRate = 1.0000M;
  202. var payInfo = _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.IsDel == 0 && x.DIId == diId && x.CTable == 79 && x.CId == dataId).First();
  203. if (payInfo == null)
  204. {
  205. _view.Msg = $"OP费用付款数据未填写";
  206. return _view;
  207. }
  208. _opRate = payInfo.DayRate;
  209. string opCurrencyName = setData.Find(x => x.Id == opContents[0].Currency)?.Name ?? "";
  210. //团组、OP币种 验证是否一致
  211. if (opCurrencyName.Equals(_teamCurrency))
  212. {
  213. _opRate = payInfo.DayRate;
  214. _teamRate = payInfo.DayRate;
  215. }
  216. var opBasicDatas = setData.Where(x => x.STid == 17).ToList(); //费用类型基础数据
  217. bool isAutoAudit = true;
  218. if (!DateTime.TryParse(opinfos.ServiceStartTime, out DateTime startDt1) || !DateTime.TryParse(opinfos.ServiceEndTime, out DateTime endDt1))
  219. {
  220. _view.Msg = $"OP费用服务起止日期格式不正确!";
  221. return _view;
  222. }
  223. DateTime startDt = startDt1;
  224. DateTime endDt = endDt1;
  225. var opCostDatas = costContents.Where(it => Convert.ToDateTime(it.Date) >= startDt && Convert.ToDateTime(it.Date) <= endDt).ToList();
  226. if (opCostDatas.Count < 1)
  227. {
  228. _view.Msg = $"该时间段内团组成本未填写!";
  229. return _view;
  230. }
  231. var noAuditFeeTypeIds = new List<int> {
  232. 982 ,//982 车超时费 -- 暂无
  233. 96 ,//96 接送机费 -- 暂无
  234. 97 ,//97 其他费用 -- 暂无
  235. 992 ,//992 住补费用 -- 暂无
  236. 1059,//1059 导游超时费用 -- 暂无
  237. 1070,//1070 尾款金额 -- 暂无
  238. 1071,//1071 其他额外费用 -- 暂无
  239. 1073,//1073 翻译超时费 -- 暂无
  240. 1074,//1074 早餐超支费用 -- 暂无
  241. 1075,//1075 午餐超支费用 -- 暂无
  242. 1076,//1076 晚餐超支费用 -- 暂无
  243. };
  244. //费用类型筛选 包含 feeTypeIds && 包含这些类型费用大于0
  245. var noAuditFeeContents = opContents.Where(x => x.Price > 0 && noAuditFeeTypeIds.Contains(x.SId)).ToList();
  246. if (noAuditFeeContents.Count > 0)
  247. {
  248. _view.Msg = @$"OP费用含尾款/超支/超时费用,请手动审核";
  249. return _view;
  250. }
  251. //2.按天按项 检查费用是否超过预算
  252. var opDayContent = opContents.GroupBy(x => x.DatePrice);
  253. foreach (var item in opDayContent)
  254. {
  255. var opCostInfo = opCostDatas.Where(x => Convert.ToDateTime(x.Date) == item.Key).ToList();
  256. if (opCostInfo.Count < 1) continue;
  257. //车费 91
  258. var opCarCost = item.FirstOrDefault(x => x.SId == 91);
  259. if (opCarCost != null) if (opCarCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.CarFee)) isAutoAudit = false;
  260. //982 车超时费 -- 暂无
  261. //92 导游费
  262. var opGuideCost = item.FirstOrDefault(x => x.SId == 92);
  263. if (opGuideCost != null) if (opGuideCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideFee)) isAutoAudit = false;
  264. //94 导游景点费
  265. var opGuideScenicCost = item.FirstOrDefault(x => x.SId == 94);
  266. if (opGuideScenicCost != null) if (opGuideScenicCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideScenicFee)) isAutoAudit = false;
  267. //95 导游小费
  268. var opGuideTipCost = item.FirstOrDefault(x => x.SId == 95);
  269. if (opGuideTipCost != null) if (opGuideTipCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideTipFee)) isAutoAudit = false;
  270. //983 导游餐补
  271. var opGuideMealCost = item.FirstOrDefault(x => x.SId == 983);
  272. if (opGuideMealCost != null) if (opGuideMealCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideMealFee)) isAutoAudit = false;
  273. //984 导游房补
  274. var opGuideRoomCost = item.FirstOrDefault(x => x.SId == 984);
  275. if (opGuideRoomCost != null) if (opGuideRoomCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideRoomFee)) isAutoAudit = false;
  276. //985 导游交通
  277. var opGuideTrafficCost = item.FirstOrDefault(x => x.SId == 985);
  278. if (opGuideTrafficCost != null) if (opGuideTrafficCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.GuideTrafficFee)) isAutoAudit = false;
  279. //96 接送机费 -- 暂无
  280. //97 其他费用 -- 暂无
  281. //979 司机工资
  282. var opDriverCost = item.FirstOrDefault(x => x.SId == 979);
  283. if (opDriverCost != null) if (opDriverCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverFee)) isAutoAudit = false;
  284. //980 司机小费
  285. var opDriverTipCost = item.FirstOrDefault(x => x.SId == 980);
  286. if (opDriverTipCost != null) if (opDriverTipCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverTipFee)) isAutoAudit = false;
  287. //981 司机餐补
  288. var opDriverMealCost = item.FirstOrDefault(x => x.SId == 981);
  289. if (opDriverMealCost != null) if (opDriverMealCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DriverMealFee)) isAutoAudit = false;
  290. //988 客户早餐费用
  291. var opClientBreakfastCost = item.FirstOrDefault(x => x.SId == 988);
  292. if (opClientBreakfastCost != null) if (opClientBreakfastCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientBreakfastFee)) isAutoAudit = false;
  293. //93 客户午餐费用
  294. var opClientLunchCost = item.FirstOrDefault(x => x.SId == 93);
  295. if (opClientLunchCost != null) if (opClientLunchCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientLunchFee)) isAutoAudit = false;
  296. //989 客户晚餐费用
  297. var opClientDinnerCost = item.FirstOrDefault(x => x.SId == 989);
  298. if (opClientDinnerCost != null) if (opClientDinnerCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ClientDinnerFee)) isAutoAudit = false;
  299. //990 景点门票费
  300. var opScenicTicketCost = item.FirstOrDefault(x => x.SId == 990);
  301. if (opScenicTicketCost != null) if (opScenicTicketCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.ScenicTicketFee)) isAutoAudit = false;
  302. //991 饮料/零食/水果
  303. var opDrinkSnackFruitCost = item.FirstOrDefault(x => x.SId == 991);
  304. if (opDrinkSnackFruitCost != null) if (opDrinkSnackFruitCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.DrinkSnackFruitFee)) isAutoAudit = false;
  305. //992 住补费用 -- 暂无
  306. //994 翻译费
  307. var opTranslatorCost = item.FirstOrDefault(x => x.SId == 994);
  308. if (opTranslatorCost != null) if (opTranslatorCost.Price * _opRate > _teamRate * opCostInfo.Sum(x => x.TranslatorFee)) isAutoAudit = false;
  309. //1059 导游超时费用 -- 暂无
  310. //1070 尾款金额 -- 暂无
  311. //1071 其他额外费用 -- 暂无
  312. //1073 翻译超时费 -- 暂无
  313. //1074 早餐超支费用 -- 暂无
  314. //1075 午餐超支费用 -- 暂无
  315. //1076 晚餐超支费用 -- 暂无
  316. }
  317. //更改审核状态
  318. if (isAutoAudit)
  319. {
  320. var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  321. .SetColumns(it => it.IsAuditGM == 3)
  322. .SetColumns(it => it.AuditGMOperate == 4)
  323. .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  324. .Where(s => s.DIId == diId && s.CTable == 79 && s.CId == dataId)
  325. .ExecuteCommand();
  326. if (ccpUpdate > 0)
  327. {
  328. _view.Code = 200;
  329. _view.Msg = "自动审核执行成功!";
  330. return _view;
  331. }
  332. }
  333. else
  334. {
  335. //撤销该条数据的自动审核 --> 该条数据的审核状态是自动审核 3 --> 0
  336. if (QuashAudit(79, diId, dataId))
  337. {
  338. _view.Code = 200;
  339. _view.Msg = "费用超团组成本,自动审核撤销成功!";
  340. return _view;
  341. }
  342. }
  343. }
  344. else if (feeType == 3)
  345. {
  346. #region 出行物资的功能及相关费用自动审核
  347. var isAutoAudit = false;
  348. var currModule = 98; //其他款项
  349. int groupSize = 0; // 团组人数
  350. var groupDetails = await _sqlSugar.Queryable<Grp_DelegationInfo>().Where(x => x.IsDel == 0 && x.Id == diId).FirstAsync();
  351. if (groupDetails != null) groupSize = groupDetails.VisitPNumber;
  352. decimal groupCostCNYTotal = costContents.Sum(x => x.TeFee) * _teamRate * groupSize; //团组成本出行物资总金额
  353. if (groupCostCNYTotal <= 0.00M)
  354. {
  355. _view.Msg = $"团组成本出行物资费用数据未填写";
  356. QuashAudit(currModule, diId, dataId);
  357. return _view;
  358. }
  359. var teNames = setData.Where(x => x.STid == 91).Select(x => x.Name).ToList();
  360. var otherFeeDatas = _sqlSugar.Queryable<Grp_DecreasePayments>()
  361. .InnerJoin<Grp_CreditCardPayment>((dp, ccp) => dp.Id == ccp.CId && ccp.CTable == 98 && ccp.IsDel == 0)
  362. .Where((dp, ccp) => dp.IsDel == 0 && dp.DiId == diId)
  363. .ToList();
  364. var ids = new List<int>();
  365. foreach (var item in otherFeeDatas)
  366. {
  367. if (item.PriceName.Contains("、"))
  368. {
  369. var priceNames = item.PriceName.Split('、');
  370. foreach (var priceName in priceNames)
  371. {
  372. if (teNames.Contains(priceName))
  373. {
  374. ids.Add(item.Id);
  375. continue;
  376. }
  377. }
  378. }
  379. else if (teNames.Contains(item.PriceName))
  380. {
  381. ids.Add(item.Id);
  382. }
  383. }
  384. ids = ids.Distinct().ToList();
  385. decimal otherFeeCNYTotal = otherFeeDatas.Where(x => ids.Contains(x.Id)).Sum(x => x.FeeTotal); //其他费用出行物资总金额
  386. if (otherFeeCNYTotal <= 0.00M)
  387. {
  388. _view.Msg = $"其他款项出行物资费用数据未填写";
  389. QuashAudit(currModule, diId, dataId);
  390. return _view;
  391. }
  392. if (otherFeeCNYTotal > groupCostCNYTotal)
  393. {
  394. _view.Msg = $"其他款项出行物资费用超出团组成本物资费用";
  395. QuashAudit(currModule, diId, dataId);
  396. return _view;
  397. }
  398. isAutoAudit = true;
  399. //2.判断是否自动审核
  400. if (isAutoAudit)
  401. {
  402. var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  403. .SetColumns(it => it.IsAuditGM == 3)
  404. .SetColumns(it => it.AuditGMOperate == 4)
  405. .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  406. .Where(s => s.DIId == diId && s.CTable == currModule && s.CId == dataId)
  407. .ExecuteCommand();
  408. if (ccpUpdate > 0)
  409. {
  410. _view.Code = 200;
  411. _view.Msg = "自动审核执行成功";
  412. return _view;
  413. }
  414. }
  415. else
  416. {
  417. //撤销该条数据的自动审核 --> 该条数据的审核状态是自动审核 3 --> 0
  418. var quashStatus = QuashAudit(currModule, diId, dataId);
  419. if (quashStatus)
  420. {
  421. _view.Code = 200;
  422. _view.Msg = "费用超团组成本,自动审核撤销成功!";
  423. return _view;
  424. }
  425. }
  426. #endregion
  427. }
  428. else if (feeType == 4)
  429. {
  430. #region 保险费用录入自动审核
  431. var currModule = 82;
  432. var groupDetails = _sqlSugar.Queryable<Grp_DelegationInfo>().Where(x => x.IsDel == 0 && x.Id == diId).First();
  433. if (groupDetails == null)
  434. {
  435. _view.Msg = $"团组信息为空,不可自动审核!";
  436. return _view;
  437. }
  438. var insuranceCountryCostData = _sqlSugar.Queryable<Res_BasicInsuranceCost>().Where(x => x.IsDel == 0).ToList();
  439. if (!insuranceCountryCostData.Any())
  440. {
  441. _view.Msg = $"保险国家费用信息为空,不可自动审核!";
  442. return _view;
  443. }
  444. var insuranceType = _sqlSugar.Queryable<Grp_InsuranceCost>().Where(x => x.IsDel == 0 && x.Id != 2).Select(x => x.Id).ToList();
  445. var insuranceCostData1 = _sqlSugar.Queryable<Grp_Customers>()
  446. .LeftJoin<Grp_CreditCardPayment>((c, ccp) => c.Id == ccp.CId && ccp.CTable == 82)
  447. .Where((c, ccp) => c.IsDel == 0 && c.DiId == diId)
  448. .Select((c, ccp) => new
  449. {
  450. c.Id,
  451. c.Iid,
  452. ccpId = ccp.Id,
  453. CNYPrice = ccp.PayMoney * ccp.DayRate
  454. })
  455. .ToList();
  456. if (!insuranceCostData1.Any())
  457. {
  458. _view.Msg = $"暂无保险数据,不可自动审核!";
  459. return _view;
  460. }
  461. if (insuranceCostData1.Where(x => x.Iid == 2).ToList().Any())
  462. {
  463. _view.Msg = $"保险数据为类型为“新数据请不要选此项”,不可自动审核!";
  464. return _view;
  465. }
  466. #region 处理已审核通过的 “新数据请不要选此项” 数据
  467. var insuranceCostData2 = insuranceCostData1.Where(x => x.Iid == 2).ToList();
  468. if (insuranceCostData2.Any())
  469. {
  470. //_view.Msg = $"保险数据为类型为“新数据请不要选此项”,不可自动审核!";
  471. //return _view;
  472. var ccpIds = insuranceCostData2.Select(x => x.ccpId).ToList();
  473. var auditCcpIds = _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.IsDel == 0 && ccpIds.Contains(x.Id) && x.IsAuditGM == 3).Select(x => x.Id).ToList();
  474. if (auditCcpIds.Any())
  475. {
  476. var ccpUpd = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  477. .SetColumns(it => it.IsAuditGM == 0)
  478. .SetColumns(it => it.AuditGMOperate == 0)
  479. .SetColumns(it => it.AuditGMDate == string.Empty)
  480. .Where(s => auditCcpIds.Contains(s.Id))
  481. .ExecuteCommand();
  482. }
  483. }
  484. #endregion
  485. //var insuranceCostData = insuranceCostData1.Where(x => insuranceType.Contains(x.Iid)).ToList();
  486. var insuranceCostData = insuranceCostData1.ToList();
  487. var currInsuranceInfo = insuranceCostData.Where(x => x.Id == dataId).FirstOrDefault();
  488. if (!insuranceCostData.Any() && currInsuranceInfo == null)
  489. {
  490. _view.Msg = $"暂无保险数据,不可自动审核!";
  491. return _view;
  492. }
  493. if (currInsuranceInfo.CNYPrice == 0.00M)
  494. {
  495. _view.Msg = $"保险数据未录入费用信息,不可自动审核!";
  496. QuashAudit(currModule, diId, dataId);
  497. return _view;
  498. }
  499. var groupPeopleNum = groupDetails.VisitPNumber;
  500. var visitCountrys = groupDetails.VisitCountry.Split("|").ToList();
  501. if (!visitCountrys.Any())
  502. {
  503. _view.Msg = $"出访国家为空,不可自动审核!";
  504. return _view;
  505. }
  506. var basicCountrys = insuranceCountryCostData.Select(x => x.CountryName).ToList();
  507. var schengenCountry = visitCountrys.Intersect(basicCountrys); //申根国
  508. var unSchengenCountry = visitCountrys.Except(basicCountrys); //非申根国
  509. var schengenCost = insuranceCountryCostData.Where(x => schengenCountry.Contains(x.CountryName)).Sum(x => x.Cost); // 申根国费用
  510. var unSchengenCost = unSchengenCountry.Count() * 35; // 非申根国费用
  511. var groupBudgetCost = (schengenCost + unSchengenCost) * groupPeopleNum;
  512. var groupActialCost = insuranceCostData.Sum(x => x.CNYPrice);
  513. if (groupActialCost > groupBudgetCost)
  514. {
  515. _view.Msg = $"保险费用超出团组成本费用";
  516. QuashAudit(currModule, diId, dataId);
  517. return _view;
  518. }
  519. //自动审核
  520. var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  521. .SetColumns(it => it.IsAuditGM == 3)
  522. .SetColumns(it => it.AuditGMOperate == 4)
  523. .SetColumns(it => it.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
  524. .Where(s => s.DIId == diId && s.CTable == currModule && s.CId == dataId)
  525. .ExecuteCommand();
  526. if (ccpUpdate > 0)
  527. {
  528. _view.Code = 200;
  529. _view.Msg = "自动审核执行成功";
  530. }
  531. else _view.Msg = "自动审核执行失败";
  532. return _view;
  533. #endregion
  534. }
  535. else _view.Msg = $"请传入有效的feeType参数";
  536. return _view;
  537. }
  538. /// <summary>
  539. /// hotel、op 撤销自动审核的数据
  540. /// </summary>
  541. /// <param name="type">
  542. /// 酒店 76
  543. /// op 79
  544. /// </param>
  545. /// <param name="diId"></param>
  546. /// <param name="dataId"></param>
  547. /// <returns></returns>
  548. private bool QuashAudit(int type, int diId, int dataId)
  549. {
  550. //撤销该条数据的自动审核 --> 该条数据的审核状态是自动审核 3 --> 0
  551. var ccpInfo = _sqlSugar.Queryable<Grp_CreditCardPayment>()
  552. .Where(s => s.DIId == diId && s.CTable == type && s.CId == dataId && s.IsAuditGM == 3)
  553. .First();
  554. if (ccpInfo != null)
  555. {
  556. var ccpUpdate = _sqlSugar.Updateable<Grp_CreditCardPayment>()
  557. .SetColumns(it => it.IsAuditGM == 0)
  558. .SetColumns(it => it.AuditGMOperate == 0)
  559. .SetColumns(it => it.AuditGMDate == string.Empty)
  560. .Where(s => s.Id == ccpInfo.Id)
  561. .ExecuteCommand();
  562. if (ccpUpdate > 0)
  563. {
  564. return true;
  565. }
  566. }
  567. return false;
  568. }
  569. //
  570. /// <summary>
  571. /// 费用自动审核
  572. /// </summary>
  573. /// <param name="feeType">
  574. /// 1.酒店 76
  575. /// 2.op 79
  576. /// </param>
  577. /// <param name="diId">团组Id</param>
  578. /// <param name="dataId">数据Id(模块类型主表Id)</param>
  579. /// <returns></returns>
  580. public string IsOverBudget(int feeType, int diId, int dataId)
  581. {
  582. string _view ="-";
  583. if (diId < 1) { return _view; }
  584. if (dataId < 1) { return _view; }
  585. List<int> stids = new List<int>() { 17, 66 };
  586. var setData = _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && stids.Contains(x.STid)).ToList();
  587. string _teamCurrency = string.Empty;
  588. var groupInfo = _sqlSugar.Queryable<Grp_GroupCostParameter>().Where(x => x.IsDel == 0 && x.DiId == diId).First();
  589. if (groupInfo == null) { return _view; }
  590. _teamCurrency = groupInfo.Currency;
  591. //币种验证 统一为currencycode三字码
  592. if (int.TryParse(_teamCurrency, out int currency)) _teamCurrency = setData.Find(x => x.Id == currency)?.Name ?? "";
  593. string costContentSql = $"Select * From Grp_GroupCost";
  594. var costContents = _sqlSugar.SqlQueryable<GroupCostAuditView>(costContentSql).Where(x => x.IsDel == 0 && x.Diid == diId).ToList();
  595. if (costContents.Count < 1) { return _view; }
  596. //处理 成本详细信息 日期为空
  597. for (int i = 0; i < costContents.Count; i++)
  598. {
  599. if (string.IsNullOrEmpty(costContents[i].Date))
  600. {
  601. int index = i - 1;
  602. if (index >= 0)
  603. {
  604. costContents[i].Date = costContents[index].Date;
  605. }
  606. }
  607. }
  608. if (feeType == 1)
  609. {
  610. var hotelCostInfo = _sqlSugar.Queryable<Grp_HotelReservations>().Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId).First();
  611. var hotelCostDetails = _sqlSugar.Queryable<Grp_HotelReservationsContent>().Where(x => x.IsDel == 0 && x.DiId == diId && x.HrId == dataId).ToList();
  612. if (hotelCostInfo == null) return _view;
  613. //获取C表汇率
  614. decimal _rate = 1.0000M;
  615. var roomFeeInfo = hotelCostDetails.Where(x => x.PriceType == 1).First();
  616. if (roomFeeInfo == null) return _view;
  617. _rate = roomFeeInfo.Rate == 0.0000M ? 1.0000M : roomFeeInfo.Rate;
  618. bool isAutoAudit = true; //是否自动审核
  619. DateTime checkIn = Convert.ToDateTime(hotelCostInfo.CheckInDate),
  620. checkOut = Convert.ToDateTime(hotelCostInfo.CheckOutDate);
  621. if (checkOut > checkIn) checkOut = checkOut.AddDays(-1); //房费计算,结束日期为前一天
  622. var hotelCostInfos = costContents.Where(x => Convert.ToDateTime(x.Date) >= checkIn && Convert.ToDateTime(x.Date) <= checkOut).ToList();
  623. if (hotelCostInfos.Count < 1) isAutoAudit = false;
  624. decimal otherFee = hotelCostDetails.Where(x => x.PriceType != 1).Sum(x => x.Price * (x.Rate == 0.0000M ? 1.0000M : x.Rate));
  625. if (otherFee > 0) { otherFee /= (checkOut - checkIn).Days; }
  626. var hotelCostInfosGroup = hotelCostInfos.GroupBy(x => x.Date);
  627. foreach (var item in hotelCostInfosGroup)
  628. {
  629. decimal hotelSingleRoomFee = item.Sum(x => x.HotelSingleRoomFee);
  630. decimal hotelDoubleRoomFee = item.Sum(x => x.HotelDoubleRoomFee);
  631. decimal hotelSuiteFee = item.Sum(x => x.HotelSuiteFee);
  632. decimal hotelSuiteRoomFee = item.Sum(x => x.HotelSuiteRoomFee);
  633. //1.判断费用是否 <= 成本费用
  634. //1.1 判断单间费用
  635. decimal singleRoomPrice = (hotelCostInfo.SingleRoomPrice + otherFee) * _rate;
  636. if (singleRoomPrice > 0) if (singleRoomPrice > hotelSingleRoomFee * _rate) isAutoAudit = false;
  637. //1.2 判断双人间费用
  638. decimal doubleRoomPrice = (hotelCostInfo.DoubleRoomPrice + otherFee) * _rate;
  639. if (doubleRoomPrice > 0) if (doubleRoomPrice > hotelDoubleRoomFee * _rate) isAutoAudit = false;
  640. //1.3 判断套房费用
  641. decimal suiteRoomPrice = (hotelCostInfo.SuiteRoomPrice + otherFee) * _rate;
  642. if (suiteRoomPrice > 0) if (suiteRoomPrice > hotelSuiteFee * _rate) isAutoAudit = false;
  643. //1.4 判断其他房型费用
  644. decimal otherRoomPrice = (hotelCostInfo.OtherRoomPrice + otherFee) * _rate;
  645. if (otherRoomPrice > 0) if (otherRoomPrice > hotelSuiteRoomFee * _rate) isAutoAudit = false;
  646. }
  647. //2.判断是否自动审核
  648. if (isAutoAudit)
  649. {
  650. return $"未超预算";
  651. }
  652. }
  653. else if (feeType == 2)
  654. {
  655. //1.基础数据参数验证
  656. var priceType = new List<int>() { 1062 };
  657. var opinfos = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservations>()
  658. .Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId && !priceType.Contains(x.PriceType))
  659. .First();
  660. //var opinfos = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservations>()
  661. // .Where(x => x.IsDel == 0 && x.DiId == diId && x.Id == dataId )
  662. // .First();
  663. if (opinfos == null) return _view;
  664. //1.含超时费用/超支费用 手动审核
  665. if (opinfos.SelectCheck.Contains("超时") || opinfos.SelectCheck.Contains("超支") || opinfos.SelectCheck.Contains("尾款")) return _view;
  666. //1.参数验证
  667. var opCheckPriceTyeps = opinfos.SelectCheck.Split(',');
  668. var opCheckPriceTyepIds = setData.Where(x => opinfos.SelectCheck.Split(',').Contains(x.Name)).Select(x => x.Id).ToList();
  669. var opContents = _sqlSugar.Queryable<Grp_CarTouristGuideGroundReservationsContent>()
  670. .Where(x => x.IsDel == 0 && x.DiId == diId && x.CTGGRId == dataId && opCheckPriceTyepIds.Contains(x.SId))
  671. .OrderBy(x => x.DatePrice, OrderByType.Asc)
  672. .ToList();
  673. if (opContents.Count < 1) return _view;
  674. //获取C表汇率
  675. decimal _rate = 1.0000M;
  676. var payInfo = _sqlSugar.Queryable<Grp_CreditCardPayment>().Where(x => x.IsDel == 0 && x.DIId == diId && x.CTable == 79 && x.Id == dataId).First();
  677. if (payInfo == null) return _view;
  678. _rate = payInfo.DayRate;
  679. string opCurrencyName = setData.Find(x => x.Id == opContents[0].Currency)?.Name ?? "";
  680. var opBasicDatas = setData.Where(x => x.STid == 17).ToList(); //费用类型基础数据
  681. bool isAutoAudit = true;
  682. if (!DateTime.TryParse(opinfos.ServiceStartTime, out DateTime startDt1) || !DateTime.TryParse(opinfos.ServiceEndTime, out DateTime endDt1)) return _view;
  683. DateTime startDt = startDt1;
  684. DateTime endDt = endDt1;
  685. var opCostDatas = costContents.Where(it => Convert.ToDateTime(it.Date) >= startDt && Convert.ToDateTime(it.Date) <= endDt).ToList();
  686. if (opCostDatas.Count < 1) return _view;
  687. var noAuditFeeTypeIds = new List<int> {
  688. 982 ,//982 车超时费 -- 暂无
  689. 96 ,//96 接送机费 -- 暂无
  690. 97 ,//97 其他费用 -- 暂无
  691. 992 ,//992 住补费用 -- 暂无
  692. 1059,//1059 导游超时费用 -- 暂无
  693. 1070,//1070 尾款金额 -- 暂无
  694. 1071,//1071 其他额外费用 -- 暂无
  695. 1073,//1073 翻译超时费 -- 暂无
  696. 1074,//1074 早餐超支费用 -- 暂无
  697. 1075,//1075 午餐超支费用 -- 暂无
  698. 1076,//1076 晚餐超支费用 -- 暂无
  699. };
  700. //费用类型筛选 包含 feeTypeIds && 包含这些类型费用大于0
  701. var noAuditFeeContents = opContents.Where(x => x.Price > 0 && noAuditFeeTypeIds.Contains(x.SId)).ToList();
  702. if (noAuditFeeContents.Count > 0) return _view;
  703. //2.按天按项 检查费用是否超过预算
  704. var opDayContent = opContents.GroupBy(x => x.DatePrice);
  705. foreach (var item in opDayContent)
  706. {
  707. var opCostInfo = opCostDatas.Where(x => Convert.ToDateTime(x.Date) == item.Key).ToList();
  708. if (opCostInfo.Count < 1) continue;
  709. //车费 91
  710. var opCarCost = item.FirstOrDefault(x => x.SId == 91);
  711. if (opCarCost != null) if (opCarCost.Price * _rate > _rate * opCostInfo.Sum(x => x.CarFee)) isAutoAudit = false;
  712. //982 车超时费 -- 暂无
  713. //92 导游费
  714. var opGuideCost = item.FirstOrDefault(x => x.SId == 92);
  715. if (opGuideCost != null) if (opGuideCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideFee)) isAutoAudit = false;
  716. //94 导游景点费
  717. var opGuideScenicCost = item.FirstOrDefault(x => x.SId == 94);
  718. if (opGuideScenicCost != null) if (opGuideScenicCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideScenicFee)) isAutoAudit = false;
  719. //95 导游小费
  720. var opGuideTipCost = item.FirstOrDefault(x => x.SId == 95);
  721. if (opGuideTipCost != null) if (opGuideTipCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideTipFee)) isAutoAudit = false;
  722. //983 导游餐补
  723. var opGuideMealCost = item.FirstOrDefault(x => x.SId == 983);
  724. if (opGuideMealCost != null) if (opGuideMealCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideMealFee)) isAutoAudit = false;
  725. //984 导游房补
  726. var opGuideRoomCost = item.FirstOrDefault(x => x.SId == 984);
  727. if (opGuideRoomCost != null) if (opGuideRoomCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideRoomFee)) isAutoAudit = false;
  728. //985 导游交通
  729. var opGuideTrafficCost = item.FirstOrDefault(x => x.SId == 985);
  730. if (opGuideTrafficCost != null) if (opGuideTrafficCost.Price * _rate > _rate * opCostInfo.Sum(x => x.GuideTrafficFee)) isAutoAudit = false;
  731. //96 接送机费 -- 暂无
  732. //97 其他费用 -- 暂无
  733. //979 司机工资
  734. var opDriverCost = item.FirstOrDefault(x => x.SId == 979);
  735. if (opDriverCost != null) if (opDriverCost.Price * _rate > _rate * opCostInfo.Sum(x => x.DriverFee)) isAutoAudit = false;
  736. //980 司机小费
  737. var opDriverTipCost = item.FirstOrDefault(x => x.SId == 980);
  738. if (opDriverTipCost != null) if (opDriverTipCost.Price * _rate > _rate * opCostInfo.Sum(x => x.DriverTipFee)) isAutoAudit = false;
  739. //981 司机餐补
  740. var opDriverMealCost = item.FirstOrDefault(x => x.SId == 981);
  741. if (opDriverMealCost != null) if (opDriverMealCost.Price * _rate > _rate * opCostInfo.Sum(x => x.DriverMealFee)) isAutoAudit = false;
  742. //988 客户早餐费用
  743. var opClientBreakfastCost = item.FirstOrDefault(x => x.SId == 988);
  744. if (opClientBreakfastCost != null) if (opClientBreakfastCost.Price * _rate > _rate * opCostInfo.Sum(x => x.ClientBreakfastFee)) isAutoAudit = false;
  745. //93 客户午餐费用
  746. var opClientLunchCost = item.FirstOrDefault(x => x.SId == 93);
  747. if (opClientLunchCost != null) if (opClientLunchCost.Price * _rate > _rate * opCostInfo.Sum(x => x.ClientLunchFee)) isAutoAudit = false;
  748. //989 客户晚餐费用
  749. var opClientDinnerCost = item.FirstOrDefault(x => x.SId == 989);
  750. if (opClientDinnerCost != null) if (opClientDinnerCost.Price * _rate > _rate * opCostInfo.Sum(x => x.ClientDinnerFee)) isAutoAudit = false;
  751. //990 景点门票费
  752. var opScenicTicketCost = item.FirstOrDefault(x => x.SId == 990);
  753. if (opScenicTicketCost != null) if (opScenicTicketCost.Price * _rate > _rate * opCostInfo.Sum(x => x.ScenicTicketFee)) isAutoAudit = false;
  754. //991 饮料/零食/水果
  755. var opDrinkSnackFruitCost = item.FirstOrDefault(x => x.SId == 991);
  756. if (opDrinkSnackFruitCost != null) if (opDrinkSnackFruitCost.Price * _rate > _rate * opCostInfo.Sum(x => x.DrinkSnackFruitFee)) isAutoAudit = false;
  757. //992 住补费用 -- 暂无
  758. //994 翻译费
  759. var opTranslatorCost = item.FirstOrDefault(x => x.SId == 994);
  760. if (opTranslatorCost != null) if (opTranslatorCost.Price * _rate > _rate * opCostInfo.Sum(x => x.TranslatorFee)) isAutoAudit = false;
  761. //1059 导游超时费用 -- 暂无
  762. //1070 尾款金额 -- 暂无
  763. //1071 其他额外费用 -- 暂无
  764. //1073 翻译超时费 -- 暂无
  765. //1074 早餐超支费用 -- 暂无
  766. //1075 午餐超支费用 -- 暂无
  767. //1076 晚餐超支费用 -- 暂无
  768. }
  769. //更改审核状态
  770. if (isAutoAudit) return _view;
  771. }
  772. else return _view;
  773. return _view;
  774. }
  775. }
  776. }