public async Task Should_send_correct_data() { InitializeMock(); var service = CreateService(); var(account, chargeAmount) = CreateAccountAndAmount(10000, 9943, 1, 1); AccountBalanceManagementNotificationData actualMailData = null; SaveMailData(); await service.SendNotificationIfRequired(account, chargeAmount); Assert.Equal(1, actualMailData.AgencyAccountId); Assert.Equal(1, actualMailData.AgencyId); Assert.Equal("AgencyName1", actualMailData.AgencyName); Assert.Equal(EnumFormatters.FromDescription(Currencies.USD), actualMailData.Currency); Assert.Equal(MoneyFormatter.ToCurrencyString(57, Currencies.USD), actualMailData.NewAmount); void SaveMailData() => _notificationServiceMock .Setup(x => x.Send(It.IsAny <DataWithCompanyInfo>(), It.IsAny <NotificationTypes>(), It.IsAny <string>())) .Callback <DataWithCompanyInfo, NotificationTypes, string>((data, _, _) => actualMailData = (AccountBalanceManagementNotificationData)data); }
/// <summary> /// Метод вызывается платежной системой после оплаты и после сообщения нам о платеже(см. метод Result <see cref="Result"/>) /// </summary> /// <returns></returns> //[HttpPost] public ActionResult Success() { RobokassaApi robokassaApi = ApiFactory.GetRobokassaApi(WebSettingsConfig.Instance); RobokassaPaymentResult paymentResult = robokassaApi.ProcessSuccess(Request.Params); if (paymentResult == null) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Success. PaymentResult is null. Params={0}", HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(GetFailView()); } var purchasedGoogsQuery = new PurchasedGoodsQuery(); PurchasedGoods purchasedGoods = purchasedGoogsQuery.Get(paymentResult.PaymentId); if (purchasedGoods == null) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Success. GetUniqueDownloadId не вернул уникальный идентификатор скачивания. PaymentId={0}, Price={1}, Params={2}", paymentResult.PaymentId, paymentResult.Price, HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(GetFailView()); } LoggerWrapper.RemoteMessage(LoggingType.Info, "PaymentController.Success. Перед тем как сообщить пользователю об успешном платеже на сумму {0} с идентификатором {1}", MoneyFormatter.ToRubles(paymentResult.Price), paymentResult.PaymentId); return(GetSuccessView(purchasedGoods)); }
void UpdateInfo() { int diff = ammoItem.MaxAmount - ammoItem.CurrentAmount; if (diff > ammoItem.AmountToBuy) { diff = ammoItem.AmountToBuy; } int diffAll = ammoItem.MaxAmount - ammoItem.CurrentAmount; buyText.text = GetBuyText(diff); buyAllText.text = GetBuyAllText(diffAll); priceText.text = MoneyFormatter.FormatMoney(shop.GetAmmoPrice(ammoItem, diff)); priceAllText.text = MoneyFormatter.FormatMoney(shop.GetAmmoPrice(ammoItem, diffAll)); currentAmountText.text = GetAmountText(ammoItem.CurrentAmount, ammoItem.MaxAmount); SetAmountPercentage((float)ammoItem.CurrentAmount / ammoItem.MaxAmount); buyButton.interactable = diff != 0 && shop.EnoughMoneyToBuy(ammoItem, diff); buyAllButton.interactable = diffAll != 0 && shop.EnoughMoneyToBuy(ammoItem, diffAll); }
public ActionResult Result() { RobokassaApi robokassaApi = ApiFactory.GetRobokassaApi(WebSettingsConfig.Instance); RobokassaPaymentResult paymentResult = robokassaApi.ProcessResult(Request.Params); if (paymentResult == null) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Result. PaymentResult is null. Params={0}", HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(Content(ERROR_MESSAGE)); } var purchasedGoogsQuery = new PurchasedGoodsQuery(); bool isSuccess = purchasedGoogsQuery.SuccessfullyPurchased(paymentResult.PaymentId, paymentResult.Price); if (!isSuccess) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Result. SuccessfullyPurchased вернул false. PaymentId={0}, Price={1}, Params={2}", paymentResult.PaymentId, paymentResult.Price, HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(Content(ERROR_MESSAGE)); } LoggerWrapper.RemoteMessage(LoggingType.Info, "PaymentController.Result. Прошла оплата на сумму {0} с идентификатором {1}", MoneyFormatter.ToRubles(paymentResult.Price), paymentResult.PaymentId); string response = robokassaApi.GetResponseResultOk(paymentResult.PaymentId); return(Content(response)); }
/// <summary> /// Метод вызывается платежной системой если платеж не удался /// </summary> /// <returns></returns> //[HttpPost] public ActionResult Fail() { RobokassaApi robokassaApi = ApiFactory.GetRobokassaApi(WebSettingsConfig.Instance); RobokassaPaymentResult paymentResult = robokassaApi.ProcessFail(Request.Params); if (paymentResult == null) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Fail. PaymentResult is null. Params={0}", HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(GetCancelView()); } var purchasedGoogsQuery = new PurchasedGoodsQuery(); bool isSuccess = purchasedGoogsQuery.FailedPurchased(paymentResult.PaymentId); if (!isSuccess) { LoggerWrapper.RemoteMessage(LoggingType.Error, "PaymentController.Fail. FailedPurchased вернул false. PaymentId={0}, Price={1}, Params={2}", paymentResult.PaymentId, paymentResult.Price, HttpContextHelper.ParamsToString(Request.Params, RobokassaApi.IsValidParamName)); return(GetCancelView()); } LoggerWrapper.RemoteMessage(LoggingType.Info, "PaymentController.Fail. Перед тем как сообщить пользователю об отменене платежа на сумму {0} с идентификатором {1}", MoneyFormatter.ToRubles(paymentResult.Price), paymentResult.PaymentId); return(GetCancelView()); }
static BookingSummaryNotificationData.BookingData CreateBookingData(Booking booking) => new BookingSummaryNotificationData.BookingData { ReferenceCode = booking.ReferenceCode, Accommodation = booking.AccommodationName, Location = $"{booking.Location.Country}, {booking.Location.Locality}", LeadingPassenger = booking.GetLeadingPassengerFormattedName(), Amount = MoneyFormatter.ToCurrencyString(booking.TotalPrice, booking.Currency), DeadlineDate = DateTimeFormatters.ToDateString(booking.DeadlineDate), CheckInDate = DateTimeFormatters.ToDateString(booking.CheckInDate), CheckOutDate = DateTimeFormatters.ToDateString(booking.CheckOutDate), Status = EnumFormatters.FromDescription(booking.Status), PaymentType = EnumFormatters.FromDescription(booking.PaymentType) };
string GetRepairText(int price) { if (repairTranslation == null) { repairTranslation = repairText.GetComponent <TranslatedText>(); } string translated; try { translated = repairTranslation.GetValue(); } catch { translated = "Repair {0}"; } return(string.Format(translated, MoneyFormatter.FormatMoney(price))); }
string GetBuyText(int price) { if (buyTranslation == null) { buyTranslation = buyText.GetComponent <TranslatedText>(); } string translated; try { translated = buyTranslation.GetValue(); } catch { translated = "Buy {0}"; } return(string.Format(translated, MoneyFormatter.FormatMoney(price))); }
public async Task SendNotificationIfRequired(AgencyAccount account, MoneyAmount chargedAmount) { var resultingBalance = account.Balance - chargedAmount.Amount; var(_, isFailure, setting, _) = await _balanceNotificationsManagementService.Get(account.Id); if (isFailure || !setting.Thresholds.Any(t => account.Balance >= t && resultingBalance < t)) { return; } var(_, isAgencyFailure, agency, _) = await _adminAgencyManagementService.Get(account.AgencyId); if (isAgencyFailure) { return; } var lowestThreshold = setting.Thresholds .Where(t => account.Balance >= t && resultingBalance < t) .OrderBy(t => t) .First(); var messageData = new AccountBalanceManagementNotificationData { AgencyAccountId = account.Id, AgencyId = agency.Id ?? 0, AgencyName = agency.Name, Currency = EnumFormatters.FromDescription(account.Currency), Threshold = lowestThreshold, NewAmount = MoneyFormatter.ToCurrencyString(resultingBalance, account.Currency) }; await _notificationService.Send(messageData : messageData, notificationType : NotificationTypes.AccountBalanceManagementNotification, email : _options.AccountsEmail); }
public UILotPage() { var script = RenderScript("housepage.uis"); BackgroundNumOccupantsImage = script.Create <UIImage>("BackgroundNumOccupantsImage"); AddAt(0, BackgroundNumOccupantsImage); BackgroundHouseCategoryThumbImage = script.Create <UIImage>("BackgroundHouseCategoryThumbImage"); AddAt(0, BackgroundHouseCategoryThumbImage); BackgroundHouseLeaderThumbImage = script.Create <UIImage>("BackgroundHouseLeaderThumbImage"); AddAt(0, BackgroundHouseLeaderThumbImage); BackgroundDescriptionEditImage = script.Create <UIImage>("BackgroundDescriptionEditImage"); AddAt(0, BackgroundDescriptionEditImage); BackgroundDescriptionImage = script.Create <UIImage>("BackgroundDescriptionImage"); AddAt(0, BackgroundDescriptionImage); BackgroundContractedImage = new UIImage(); BackgroundContractedImage.Texture = ContractedBackgroundImage; this.AddAt(0, BackgroundContractedImage); BackgroundExpandedImage = new UIImage(); BackgroundExpandedImage.Texture = ExpandedBackgroundImage; this.AddAt(0, BackgroundExpandedImage); ContractButton.OnButtonClick += (x) => Open = false; ExpandButton.OnButtonClick += (x) => Open = true; ExpandedCloseButton.OnButtonClick += Close; ContractedCloseButton.OnButtonClick += Close; LotThumbnail = script.Create <UILotThumbButton>("HouseThumbSetup"); LotThumbnail.Init(RoommateThumbButtonImage, VisitorThumbButtonImage); DefaultThumb = TextureUtils.TextureFromFile(GameFacade.GraphicsDevice, GameFacade.GameFilePath("userdata/houses/defaulthouse.bmp")); TextureUtils.ManualTextureMask(ref DefaultThumb, new uint[] { 0xFF000000 }); LotThumbnail.SetThumbnail(DefaultThumb, 0); Add(LotThumbnail); RoommateList = script.Create <UIRoommateList>("RoommateList"); Add(RoommateList); SkillGameplayLabel = new UIClickableLabel(); SkillGameplayLabel.Position = RoommateList.Position + new Vector2(-1, 24); SkillGameplayLabel.Size = new Vector2(180, 18); SkillGameplayLabel.Alignment = TextAlignment.Center; SkillGameplayLabel.OnButtonClick += SkillGameplayLabel_OnButtonClick; SkillGameplayLabel.CaptionStyle = SkillGameplayLabel.CaptionStyle.Clone(); SkillGameplayLabel.CaptionStyle.Size = 9; Add(SkillGameplayLabel); OwnerButton = script.Create <UIPersonButton>("HouseLeaderThumbSetup"); OwnerButton.FrameSize = UIPersonButtonSize.LARGE; Add(OwnerButton); /** Drag **/ UIUtils.MakeDraggable(BackgroundContractedImage, this, true); UIUtils.MakeDraggable(BackgroundExpandedImage, this, true); /** Description scroll **/ HouseDescriptionSlider.AttachButtons(HouseDescriptionScrollUpButton, HouseDescriptionScrollDownButton, 1); HouseDescriptionTextEdit.AttachSlider(HouseDescriptionSlider); HouseLinkButton.OnButtonClick += JoinLot; HouseCategoryButton.OnButtonClick += ChangeCategory; HouseNameButton.OnButtonClick += ChangeName; LotThumbnail.OnLotClick += JoinLot; NeighborhoodNameButton.OnButtonClick += (btn) => { if (CurrentLot != null && CurrentLot.Value != null && CurrentLot.Value.Lot_NeighborhoodID != 0) { FindController <CoreGameScreenController>().ShowNeighPage(CurrentLot.Value.Lot_NeighborhoodID); } }; var ui = Content.Content.Get().CustomUI; HouseCategory_CommunityButtonImage = ui.Get("lotp_community_small.png").Get(GameFacade.GraphicsDevice); CurrentLot = new Binding <Lot>() .WithBinding(HouseNameButton, "Caption", "Lot_Name") .WithBinding(NeighborhoodNameButton, "Caption", "Lot_NeighborhoodName") .WithBinding(HouseValueLabel, "Caption", "Lot_Price", x => MoneyFormatter.Format((uint)x)) .WithBinding(OccupantsNumberLabel, "Caption", "Lot_NumOccupants", x => x.ToString()) .WithBinding(OwnerButton, "AvatarId", "Lot_LeaderID") .WithBinding(HouseCategoryButton, "Texture", "Lot_Category", x => { var category = (LotCategory)Enum.Parse(typeof(LotCategory), x.ToString()); switch (category) { case LotCategory.none: return(HouseCategory_NoCategoryButtonImage); case LotCategory.welcome: return(HouseCategory_WelcomeButtonImage); case LotCategory.money: return(HouseCategory_MoneyButtonImage); case LotCategory.entertainment: return(HouseCategory_EntertainmentButtonImage); case LotCategory.games: return(HouseCategory_GamesButtonImage); case LotCategory.offbeat: return(HouseCategory_OffbeatButtonImage); case LotCategory.residence: return(HouseCategory_ResidenceButtonImage); case LotCategory.romance: return(HouseCategory_RomanceButtonImage); case LotCategory.services: return(HouseCategory_ServicesButtonImage); case LotCategory.shopping: return(HouseCategory_ShoppingButtonImage); case LotCategory.skills: return(HouseCategory_SkillsButtonImage); case LotCategory.community: return(HouseCategory_CommunityButtonImage); default: return(HouseCategory_CommunityButtonImage); } }).WithBinding(HouseCategoryButton, "Position", "Lot_Category", x => { return(new Vector2(69 + 11 - HouseCategoryButton.Texture.Width / 8, 164 + 11 - HouseCategoryButton.Texture.Height / 2)); }) .WithMultiBinding(x => RefreshUI(), "Lot_LeaderID", "Lot_IsOnline", "Lot_Thumbnail", "Lot_Description", "Lot_RoommateVec"); RefreshUI(); //NeighborhoodNameButton.Visible = false; Size = BackgroundExpandedImage.Size.ToVector2(); SendToFront(ExpandButton, ContractButton); }
void SetMoneyAmount(int amount) { moneyAmountText.text = MoneyFormatter.FormatMoney(amount); }
protected void ConvertToEntityRecord(Entity entity, EntityMetadata entityMetadata = null, OrganizationServiceContext serviceContext = null, OrganizationMoneyFormatInfo organizationMoneyFormatInfo = null, int?crmLcid = null) { var recordAttributes = new List <EntityRecordAttribute>(); var attributes = entity.Attributes; var formattedAttributes = entity.FormattedValues; if (serviceContext == null) { serviceContext = PortalCrmConfigurationManager.CreateServiceContext(); } organizationMoneyFormatInfo = organizationMoneyFormatInfo ?? new OrganizationMoneyFormatInfo(serviceContext); var recordMoneyFormatInfo = new EntityRecordMoneyFormatInfo(serviceContext, entity); foreach (var attribute in attributes) { var aliasedValue = attribute.Value as AliasedValue; var value = aliasedValue != null ? aliasedValue.Value : attribute.Value; var type = value.GetType().ToString(); var formattedValue = string.Empty; var displayValue = value; DateTimeFormat format = DateTimeFormat.DateAndTime; DateTimeBehavior behavior = null; AttributeMetadata attributeMetadata = null; if (formattedAttributes.Contains(attribute.Key)) { formattedValue = formattedAttributes[attribute.Key]; displayValue = formattedValue; } if (aliasedValue != null) { var aliasedEntityMetadata = serviceContext.GetEntityMetadata(aliasedValue.EntityLogicalName, EntityFilters.Attributes); if (aliasedEntityMetadata != null) { attributeMetadata = aliasedEntityMetadata.Attributes.FirstOrDefault(a => a.LogicalName == aliasedValue.AttributeLogicalName); } } else { if (entityMetadata != null) { attributeMetadata = entityMetadata.Attributes.FirstOrDefault(a => a.LogicalName == attribute.Key); } } if (attributeMetadata != null) { switch (attributeMetadata.AttributeType) { case AttributeTypeCode.State: case AttributeTypeCode.Status: case AttributeTypeCode.Picklist: var optionSetValue = (OptionSetValue)value; formattedValue = Adxstudio.Xrm.Core.OrganizationServiceContextExtensions.GetOptionSetValueLabel(attributeMetadata, optionSetValue.Value, crmLcid.GetValueOrDefault(CultureInfo.CurrentCulture.LCID)); displayValue = formattedValue; break; case AttributeTypeCode.Customer: case AttributeTypeCode.Lookup: case AttributeTypeCode.Owner: var entityReference = value as EntityReference; if (entityReference != null) { displayValue = entityReference.Name ?? string.Empty; } break; case AttributeTypeCode.DateTime: var datetimeAttributeMetadata = attributeMetadata as DateTimeAttributeMetadata; behavior = datetimeAttributeMetadata.DateTimeBehavior; format = datetimeAttributeMetadata.Format.GetValueOrDefault(DateTimeFormat.DateAndTime); if (datetimeAttributeMetadata != null) { if (format != DateTimeFormat.DateOnly && behavior == DateTimeBehavior.UserLocal) { // Don't use the formatted value, as the connection user's timezone is used to format the datetime value. Use the UTC value for display. var date = (DateTime)value; displayValue = date.ToString(DateTimeClientFormat); } if (behavior == DateTimeBehavior.TimeZoneIndependent || behavior == DateTimeBehavior.DateOnly) { // JSON serialization converts the time from server local to UTC automatically // to avoid this we can convert to UTC before serialization value = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); } } break; case AttributeTypeCode.BigInt: case AttributeTypeCode.Integer: displayValue = string.Format("{0}", value); break; case AttributeTypeCode.Decimal: var decimalAttributeMetadata = attributeMetadata as DecimalAttributeMetadata; if (decimalAttributeMetadata != null && value is decimal) { displayValue = ((decimal)value).ToString("N{0}".FormatWith(decimalAttributeMetadata.Precision.GetValueOrDefault(2))); } break; case AttributeTypeCode.Money: var moneyAttributeMetadata = attributeMetadata as MoneyAttributeMetadata; if (moneyAttributeMetadata != null && value is Money) { var moneyFormatter = new MoneyFormatter(organizationMoneyFormatInfo, recordMoneyFormatInfo, moneyAttributeMetadata); displayValue = string.Format(moneyFormatter, "{0}", (Money)value); } break; } } else { if (attribute.Value is EntityReference) { var entityReference = (EntityReference)attribute.Value; if (entityReference != null) { displayValue = entityReference.Name ?? string.Empty; } } else if (attribute.Value is DateTime) { format = DateTimeFormat.DateAndTime; var dtAttributeValue = (DateTime)attribute.Value; // Don't use the formatted value, as the connection user's timezone is used to format the datetime value. Use the UTC value for display. if (dtAttributeValue.Kind == DateTimeKind.Utc) // Indicates this is not a date only attribute { var date = (DateTime)value; displayValue = date.ToString(DateTimeClientFormat); behavior = DateTimeBehavior.UserLocal; } // This below logic fails in one condition: when DateTimeBehavior = TimeZoneIndependent and DateTimeFormat = DateAndTime with value having ex: 20-01-2017 12:00 AM else if (dtAttributeValue.TimeOfDay.TotalSeconds == 0) { behavior = DateTimeBehavior.DateOnly; format = DateTimeFormat.DateOnly; value = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); } else { behavior = DateTimeBehavior.TimeZoneIndependent; // JSON serialization converts the time from server local to UTC automatically // to avoid this we can convert to UTC before serialization value = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); } } } recordAttributes.Add(new EntityRecordAttribute { Name = attribute.Key, Value = value, FormattedValue = formattedValue, DisplayValue = displayValue, DateTimeBehavior = behavior, DateTimeFormat = format.ToString(), Type = type, AttributeMetadata = attributeMetadata }); } Id = entity.Id; EntityName = entity.LogicalName; Attributes = recordAttributes; }
public async Task <Result <string> > SendBookingReports(int agencyId) { var reportBeginTime = _dateTimeProvider.UtcNow(); var reportEndTime = reportBeginTime.AddDays(1); return(await GetEmailsAndSettings() .Map(GetBookings) .Bind(CreateMailData) .Bind(SendMails)); async Task <Result <List <EmailAndSetting> > > GetEmailsAndSettings() { var rolesWithPermission = await _context.AgentRoles .Where(x => x.Permissions.HasFlag(InAgencyPermissions.ReceiveBookingSummary)) .Select(x => x.Id) .ToListAsync(); var emailsAndSettings = await (from relation in _context.AgentAgencyRelations join agent in _context.Agents on relation.AgentId equals agent.Id where relation.AgencyId == agencyId && relation.IsActive && relation.AgentRoleIds.Any(rolesWithPermission.Contains) select new EmailAndSetting { AgentId = relation.AgentId, AgencyId = relation.AgencyId, Email = agent.Email, ReportDaysSetting = _agentSettingsManager.GetUserSettings(agent).BookingReportDays }).ToListAsync(); return(emailsAndSettings.Any() ? Result.Success(emailsAndSettings) : Result.Failure <List <EmailAndSetting> >($"Couldn't find any agents in agency with id {agencyId} to send summary to")); } async Task <(List <EmailAndSetting>, List <Booking>)> GetBookings(List <EmailAndSetting> emailsAndSettings) { var bookings = await _context.Bookings .Where(b => b.AgencyId == agencyId && b.PaymentType == PaymentTypes.VirtualAccount && b.PaymentStatus != BookingPaymentStatuses.Captured && BookingStatusesForSummary.Contains(b.Status) && ((b.DeadlineDate != null) ? b.DeadlineDate : b.CheckInDate) > reportBeginTime && ((b.DeadlineDate != null) ? b.DeadlineDate : b.CheckInDate) <= reportEndTime) .ToListAsync(); return(emailsAndSettings, bookings); } async Task <Result <List <(BookingSummaryNotificationData, EmailAndSetting)> > > CreateMailData( (List <EmailAndSetting> emailsAndSettings, List <Booking> bookings) values) { var(_, isFailure, balanceInfo, error) = await _accountPaymentService.GetAccountBalance(Currencies.USD, agencyId); if (isFailure) { return(Result.Failure <List <(BookingSummaryNotificationData, EmailAndSetting)> >( $"Couldn't retrieve account balance for agency with id {agencyId}. Error: {error}")); } var agencyBalance = balanceInfo.Balance; return(values.emailsAndSettings.Select(emailAndSetting => { var resultingBalance = agencyBalance - values.bookings.Sum(b => b.TotalPrice); return (new BookingSummaryNotificationData { Bookings = values.bookings.OrderBy(b => b.DeadlineDate).Select(CreateBookingData).ToList(), CurrentBalance = MoneyFormatter.ToCurrencyString(agencyBalance, Currencies.USD), ResultingBalance = MoneyFormatter.ToCurrencyString(resultingBalance, Currencies.USD), ShowAlert = resultingBalance < 0m, ReportDate = DateTimeFormatters.ToDateString(reportBeginTime) }, emailAndSetting); }).Where(t => t.Item1.Bookings.Any()).ToList());
protected override void InstantiateControlIn(Control container) { var textbox = new TextBox { ID = ControlID, TextMode = TextBoxMode.SingleLine, CssClass = string.Join(" ", "text", CssClass, Metadata.CssClass), ToolTip = Metadata.ToolTip }; if (Metadata.IsRequired || Metadata.WebFormForceFieldIsRequired) { textbox.Attributes.Add("required", string.Empty); } if (Metadata.ReadOnly) { textbox.CssClass += " readonly"; textbox.Attributes["readonly"] = "readonly"; } textbox.Attributes["onchange"] = "setIsDirty(this.id);"; var inputGroup = new HtmlGenericControl("div"); var inputGroupAddonFirst = new HtmlGenericControl("span") { Visible = false }; var inputGroupAddonLast = new HtmlGenericControl("span") { Visible = false }; inputGroupAddonFirst.Attributes["class"] = "input-group-addon"; inputGroupAddonLast.Attributes["class"] = "input-group-addon"; inputGroup.Controls.Add(inputGroupAddonFirst); inputGroup.Controls.Add(textbox); inputGroup.Controls.Add(inputGroupAddonLast); container.Controls.Add(inputGroup); RegisterClientSideDependencies(container); Bindings[Metadata.DataFieldName] = new CellBinding { Get = () => { decimal value; return(decimal.TryParse(textbox.Text, out value) ? new decimal?(value) : null); }, Set = obj => { var data = obj as Tuple <Entity, Money>; if (data == null) { textbox.Text = ((Money)obj).Value.ToString("N{0}".FormatWith(Metadata.Precision)); return; } using (var serviceContext = CrmConfigurationManager.CreateContext(ContextName)) { var moneyFormatter = new MoneyFormatter( new OrganizationMoneyFormatInfo(serviceContext), new EntityRecordMoneyFormatInfo(serviceContext, data.Item1), Metadata.Precision, Metadata.PrecisionSource, Metadata.IsBaseCurrency); // Include the currency symbol in the field value if it's read-only (for nicer display, as // it won't need to be parsed later. textbox.Text = string.Format(moneyFormatter, Metadata.ReadOnly ? "{0}" : "{0:N}", data.Item2); if (!(Metadata.ReadOnly || string.IsNullOrEmpty(moneyFormatter.CurrencySymbol))) { inputGroup.Attributes["class"] = "input-group"; var addon = moneyFormatter.CurrencySymbolComesFirst ? inputGroupAddonFirst : inputGroupAddonLast; addon.InnerText = moneyFormatter.CurrencySymbol; addon.Visible = true; } } } }; }