public async Task UpdateFxDealAsync(FxDeal fxDeal, string company) { var queryParameters = new DynamicParameters(); queryParameters.Add("@iCompanyId", company); queryParameters.Add("@iFxDeals", ConvertToFxDealUDTT(new[] { fxDeal })); queryParameters.Add("@iDataVersionId", null); await ExecuteNonQueryAsync(StoredProcedureNames.UpdateFxDeals, queryParameters, true); }
public async Task <FxDealReference> CreateFxDealAsync(FxDeal fxDeal, string company) { var queryParameters = new DynamicParameters(); queryParameters.Add("@iCompanyId", company); queryParameters.Add("@iFxDeals", ConvertToFxDealUDTT(new[] { fxDeal })); queryParameters.Add("@iDataVersionId", null); var result = await ExecuteQueryFirstOrDefaultAsync <FxDealReference>(StoredProcedureNames.CreateFxDeals, queryParameters, true); return(result); }
public async Task <Unit> Handle(DeleteFxDealCommand request, CancellationToken cancellationToken) { _unitOfWork.BeginTransaction(); try { // Load fx deal from DB FxDeal fxDeal = new FxDeal { FxDealStatusId = (int)FxDealStatus.Open }; if (fxDeal == null) { throw new NotFoundException("fxDeal", request.FxDealId); } // Check fx deal status if (fxDeal.FxDealStatusId == (int)FxDealStatus.Open || (fxDeal.FxDealStatusId == (int)FxDealStatus.Settled && !fxDeal.Sections.Any())) { await _fxDealRepository.DeleteFxDealAsync(request.FxDealId, request.Company); if (fxDeal.FxDealStatusId == (int)FxDealStatus.Settled) { _logger.LogWarning("Settled Fx deal with id {Atlas_FxDealId} deleted.", request.FxDealId); } else { _logger.LogInformation("Fx deal with id {Atlas_FxDealId} deleted.", request.FxDealId); } _unitOfWork.Commit(); } else { throw new AtlasBusinessException("This Fx deal cannot be deleted."); } } catch { _unitOfWork.Rollback(); throw; } return(Unit.Value); }
public async Task <Unit> Handle(UpdateFxDealSectionsCommand request, CancellationToken cancellationToken) { _unitOfWork.BeginTransaction(); try { // Load fx deal from DB var fxDealDto = await _fxDealQueries.GetFxDealByIdAsync(request.FxDealId, request.CompanyId); if (fxDealDto == null) { throw new NotFoundException("fxDeal", request.FxDealId); } FxDeal fxDealToUpdate = new FxDeal { FxDealId = request.FxDealId, FxDealStatusId = fxDealDto.FxDealStatusId, CurrencyCode = fxDealDto.CurrencyCode, DepartmentId = fxDealDto.DepartmentId, Sections = new List <Entities.FxDealSection>() }; // Check fx deal status if (fxDealDto.FxDealStatusId == (int)FxDealStatus.Open || fxDealDto.FxDealStatusId == (int)FxDealStatus.Linked) { // Match existing section with updated ones var matchedSections = (from ori in fxDealDto.Sections join upd in request.Sections on ori.SectionId equals upd.SectionId into updatedSections from s in updatedSections select new { OriginalSection = ori, UpdatedSection = s, }).ToList(); // Update existing section with new values foreach (var item in matchedSections) { fxDealToUpdate.Sections.Add(new Entities.FxDealSection { SectionId = item.OriginalSection.SectionId, CoverApplied = item.UpdatedSection.CoverApplied, UncoveredAmount = item.OriginalSection.UncoveredAmount }); item.OriginalSection.CoverApplied = item.UpdatedSection.CoverApplied; } // List of sections added (sections from request that do not match existing ones) var addedSections = request.Sections.Except(matchedSections.Select(s => s.UpdatedSection)).ToList(); // If new sections have been added if (addedSections.Any()) { // Load information about the new sections IEnumerable <SectionInformationFxDeal> sectionInfo = await _fxDealRepository.GetSectionInformationForFxDealAsync(addedSections.Select(s => s.SectionId), request.CompanyId); // Check if new sections can be associated to the fx deal (same currency, same department) if (sectionInfo.Any(s => s.CurrencyCode != fxDealToUpdate.CurrencyCode)) { throw new AtlasBusinessException($"The associated sections must have the same currency as the fx deal ({fxDealDto.CurrencyCode})."); } if (sectionInfo.Any(s => s.DepartmentId != fxDealToUpdate.DepartmentId)) { throw new AtlasBusinessException($"The associated sections must have the same department as the fx deal."); } // Match added section with information from DB var matchedAddedSections = (from a in addedSections join s in sectionInfo on a.SectionId equals s.SectionId into sectionsInfo from si in sectionsInfo.DefaultIfEmpty() // DefaultIfEmpty preserves left-hand elements that have no matches on the right side select new { AddedSection = a, SectionInformation = si, }).ToList(); // Associate the new sections to fx deal foreach (var item in matchedAddedSections) { if (item.SectionInformation == null) { throw new AtlasBusinessException($"Cannot found section {item.AddedSection.SectionId}."); } fxDealToUpdate.Sections.Add( new Entities.FxDealSection { SectionId = item.AddedSection.SectionId, CoverApplied = item.AddedSection.CoverApplied, UncoveredAmount = item.SectionInformation.UncoveredAmount }); } } // A control must be applied on the "Cover applied" field to prevent the user to enter a value higher than “Amount uncovered” field’s value. foreach (var section in fxDealToUpdate.Sections) { if (section.CoverApplied > section.UncoveredAmount) { throw new AtlasBusinessException($"The cover applied ({section.CoverApplied}) of the physical trade {section.SectionId} cannot be greather that the amount uncovered ({section.UncoveredAmount})."); } } var totalCoverApplied = fxDealDto.Sections.Sum(s => s.CoverApplied); if (fxDealDto.Amount < totalCoverApplied) { throw new AtlasBusinessException("The sum of the amount of the physical trade covered by the FX deal cannot be greather that the dealt amount."); } // Update fx deal status to Linked if (fxDealDto.Sections.Any() || fxDealToUpdate.Sections.Any()) { fxDealToUpdate.FxDealStatusId = (int)FxDealStatus.Linked; } //await _fxDealRepository.UpdateFxDealAsync(fxDeal, request.CompanyId); await _fxDealRepository.UpdateFxDealSectionsAsync(fxDealDto.FxDealId, fxDealToUpdate.Sections, request.CompanyId); _logger.LogInformation("Fx deal with id {Atlas_FxDealId} updated.", fxDealDto.FxDealId); _unitOfWork.Commit(); } else { throw new AtlasBusinessException("This Fx deal is not editable."); } return(Unit.Value); } catch { _unitOfWork.Rollback(); throw; } }
internal static async Task ValidateFxDeal(FxDeal fxDeal, IIdentityService identityService, IMasterDataService masterDataService, IUserService userService, ISystemDateTimeService systemDateTimeService) { var departments = await masterDataService.GetDepartmentsAsync(fxDeal.CompanyId); if (!departments.Any(d => d.DepartmentId == fxDeal.DepartmentId)) { throw new AtlasBusinessException($"The department {fxDeal.DepartmentId} does not belong to the {fxDeal.CompanyId} company."); } var trader = await userService.GetUserByIdAsync(fxDeal.TraderId); if (trader == null) { throw new NotFoundException("User", fxDeal.TraderId); } if (!trader.Permissions.Any(p => p.CompanyId == fxDeal.CompanyId && p.IsTrader)) { throw new AtlasBusinessException($"The user {fxDeal.TraderId} is not configured as a trader for company {fxDeal.CompanyId}."); } var companyDate = await systemDateTimeService.GetCompanyDate(fxDeal.CompanyId); // The date entered in the Contract date field by the user is not in the future. if (fxDeal.ContractDate.Date > companyDate.Date) { throw new AtlasBusinessException($"The contract date cannot be in the future. Company date: {companyDate.Date}"); } // The department code must belong to the list of departments attached to the user’s account. var user = await userService.GetUserByIdAsync(identityService.GetUserAtlasId()); var companyPermissions = user.Permissions .FirstOrDefault(p => p.CompanyId == fxDeal.CompanyId); var userDepartments = companyPermissions.Departments .Select(department => department.DepartmentId).ToList(); if (!companyPermissions.AllDepartments && !userDepartments.Contains(fxDeal.DepartmentId)) { throw new AtlasBusinessException($"The department {fxDeal.DepartmentId} does not belong to the list of departments attached to the user’s account."); } // The FX Deal type must belong to the Deal type master data var fxTradeTypes = await masterDataService.GetFxTradeTypes(fxDeal.CompanyId); if (!fxTradeTypes.Any(n => n.FxTradeTypeId == fxDeal.FxTradeTypeId)) { throw new AtlasBusinessException($"The FX Deal type {fxDeal.FxTradeTypeId} does not belong to the company {fxDeal.CompanyId}."); } // Settled amount calculation // The value is calculated by multiplying or dividing (depending on M/D field) the “Dealt amount” field’s value by the “Spot ROE” field’s value. var settledAmount = fxDeal.Amount * (fxDeal.SpotRateType == "D" ? 1 / fxDeal.SpotRate : fxDeal.SpotRate); // TODO: tolerance band on Spot ROE // Traded ROE field is the sum of the “Spot ROE” and “FW Points” var tradedRoe = fxDeal.SpotRate + fxDeal.FwPoints; // The Nominal account (Deal) must belong to the Nominal account master data assigned to the company. var nominalAccounts = await masterDataService.GetNominalAccountsAsync(fxDeal.CompanyId); if (!nominalAccounts.Any(n => n.NominalAccountId == fxDeal.NominalAccountId)) { throw new AtlasBusinessException($"The Nominal account (Deal) {fxDeal.NominalAccountId} does not belong to the company {fxDeal.CompanyId}."); } // The Nominal account (Settlement) must belong to the Nominal account master data assigned to the company. if (!nominalAccounts.Any(n => n.NominalAccountId == fxDeal.SettlementNominalAccountId)) { throw new AtlasBusinessException($"The Nominal account (Settlement) {fxDeal.NominalAccountId} does not belong to the company {fxDeal.CompanyId}."); } // The Bank/broker” must belong to the the list of counterparties assigned to the company and having the value “Bank” in “Account type” field var counterparties = await masterDataService.GetCounterpartiesAsync(fxDeal.CompanyId); if (!counterparties.Any(c => c.CounterpartyID == fxDeal.CounterpartyId)) { throw new AtlasBusinessException($"The counterparty {fxDeal.CounterpartyId} does not belong to the company {fxDeal.CounterpartyId}."); } }