Skip to content

Commit c8ac39b

Browse files
committed
#1424 Added rounding rules for currencies
1 parent c8a63e9 commit c8ac39b

File tree

17 files changed

+373
-12
lines changed

17 files changed

+373
-12
lines changed

src/Libraries/Nop.Core/Domain/Directory/Currency.cs

+20
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,26 @@ public partial class Currency : BaseEntity, ILocalizedEntity, IStoreMappingSuppo
5858
/// Gets or sets the date and time of instance update
5959
/// </summary>
6060
public DateTime UpdatedOnUtc { get; set; }
61+
62+
/// <summary>
63+
/// Gets or sets the rounding type identifier
64+
/// </summary>
65+
public int RoundingTypeId { get; set; }
66+
67+
/// <summary>
68+
/// Gets or sets the rounding type
69+
/// </summary>
70+
public RoundingType RoundingType
71+
{
72+
get
73+
{
74+
return (RoundingType)RoundingTypeId;
75+
}
76+
set
77+
{
78+
RoundingTypeId = (int)value;
79+
}
80+
}
6181
}
6282

6383
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
namespace Nop.Core.Domain.Directory
2+
{
3+
public enum RoundingType
4+
{
5+
/// <summary>
6+
/// Default rounding (Match.Round(num, 2))
7+
/// </summary>
8+
Rounding001 = 0,
9+
/// <summary>
10+
/// Prices are rounded up to the nearest multiple of 5 cents for sales ending in: 3¢ & 4¢ round to 5¢; and, 8¢ & 9¢ round to 10¢
11+
/// </summary>
12+
Rounding005Up = 10,
13+
/// <summary>
14+
/// Prices are rounded down to the nearest multiple of 5 cents for sales ending in: 1¢ & 2¢ to 0¢; and, 6¢ & 7¢ to 5¢
15+
/// </summary>
16+
Rounding005Down = 20,
17+
/// <summary>
18+
/// Round up to the nearest 10 cent value for sales ending in 5¢
19+
/// </summary>
20+
Rounding01Up = 30,
21+
/// <summary>
22+
/// Round down to the nearest 10 cent value for sales ending in 5¢
23+
/// </summary>
24+
Rounding01Down = 40,
25+
/// <summary>
26+
/// Sales ending in 1–24 öre round down to 0 öre
27+
/// Sales ending in 25–49 öre round up to 50 öre
28+
/// Sales ending in 51–74 öre round down to 50 öre
29+
/// Sales ending in 75–99 öre round up to the next whole krona
30+
/// </summary>
31+
Rounding05 = 50,
32+
/// <summary>
33+
/// Sales ending in 1–49 öre/øre round down to 0 öre/øre
34+
/// Sales ending in 50–99 öre/øre round up to the next whole krona/krone
35+
/// </summary>
36+
Rounding1 = 60,
37+
/// <summary>
38+
/// Sales ending in 1–99 öre/øre round up to the next whole krona/krone
39+
/// </summary>
40+
Rounding1Up = 70
41+
}
42+
}

src/Libraries/Nop.Core/Infrastructure/NopEngine.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public T[] ResolveAll<T>()
156156
/// <summary>
157157
/// Container manager
158158
/// </summary>
159-
public ContainerManager ContainerManager
159+
public virtual ContainerManager ContainerManager
160160
{
161161
get { return _containerManager; }
162162
}

src/Libraries/Nop.Core/Nop.Core.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
<Compile Include="Domain\Customers\CustomerLoginResults.cs" />
126126
<Compile Include="Domain\Customers\Events.cs" />
127127
<Compile Include="Domain\Customers\RewardPointsActivatingDelayPeriod.cs" />
128+
<Compile Include="Domain\Directory\RoundingType.cs" />
128129
<Compile Include="Domain\Forums\ForumPostVote.cs" />
129130
<Compile Include="Domain\Messages\MessageDelayPeriod.cs" />
130131
<Compile Include="Domain\Messages\QueuedEmailPriority.cs" />

src/Libraries/Nop.Data/Mapping/Directory/CurrencyMap.cs

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public CurrencyMap()
1313
this.Property(c => c.DisplayLocale).HasMaxLength(50);
1414
this.Property(c => c.CustomFormatting).HasMaxLength(50);
1515
this.Property(c => c.Rate).HasPrecision(18, 4);
16+
17+
this.Ignore(c => c.RoundingType);
1618
}
1719
}
1820
}

src/Libraries/Nop.Services/Catalog/RoundingHelper.cs

+83-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using System;
2+
using Nop.Core;
3+
using Nop.Core.Domain.Directory;
4+
using Nop.Core.Infrastructure;
25

36
namespace Nop.Services.Catalog
47
{
@@ -16,13 +19,88 @@ public static decimal RoundPrice(decimal value)
1619
{
1720
//we use this method because some currencies (e.g. Gungarian Forint or Swiss Franc) use non-standard rules for rounding
1821
//you can implement any rounding logic here
19-
//use EngineContext.Current.Resolve<IWorkContext>() to get current currency
2022

21-
//using Swiss Franc (CHF)? just uncomment the line below
22-
//return Math.Round(value * 20, 0) / 20;
23+
var workContext = EngineContext.Current.Resolve<IWorkContext>();
2324

24-
//default round
25-
return Math.Round(value, 2);
25+
return value.Round(workContext.WorkingCurrency.RoundingType);
26+
}
27+
28+
/// <summary>
29+
/// Round a product or order total for the currency
30+
/// </summary>
31+
/// <param name="value">Value to round</param>
32+
/// <param name="currency">Currency</param>
33+
/// <returns>Rounded value</returns>
34+
public static decimal RoundPrice(decimal value, Currency currency)
35+
{
36+
return value.Round(currency.RoundingType);
37+
}
38+
39+
/// <summary>
40+
/// Round
41+
/// </summary>
42+
/// <param name="value">Value to round</param>
43+
/// <param name="roundingType">The rounding type</param>
44+
/// <returns>Rounded value</returns>
45+
public static decimal Round(this decimal value, RoundingType roundingType)
46+
{
47+
//default round (Rounding001)
48+
var rez = Math.Round(value, 2);
49+
decimal t;
50+
51+
//Cash rounding (details: https://en.wikipedia.org/wiki/Cash_rounding)
52+
switch (roundingType)
53+
{
54+
//rounding with 0.05 or 5 intervals
55+
case RoundingType.Rounding005Up:
56+
case RoundingType.Rounding005Down:
57+
t = (rez - Math.Truncate(rez)) * 10;
58+
t = (t - Math.Truncate(t)) * 10;
59+
60+
if (roundingType == RoundingType.Rounding005Down)
61+
t = t >= 5 ? 5 - t : t * -1;
62+
else
63+
t = t >= 5 ? 10 - t : 5 - t;
64+
65+
rez += t / 100;
66+
break;
67+
//rounding with 0.10 intervals
68+
case RoundingType.Rounding01Up:
69+
case RoundingType.Rounding01Down:
70+
t = (rez - Math.Truncate(rez)) * 10;
71+
t = (t - Math.Truncate(t)) * 10;
72+
73+
if (roundingType == RoundingType.Rounding01Down && t == 5)
74+
t = -5;
75+
else
76+
t = t < 5 ? t * -1 : 10 - t;
77+
78+
rez += t / 100;
79+
break;
80+
//rounding with 0.50 intervals
81+
case RoundingType.Rounding05:
82+
t = (rez - Math.Truncate(rez)) * 100;
83+
t = t < 25 ? t * -1 : t < 50 || t < 75 ? 50 - t : 100 - t;
84+
85+
rez += t / 100;
86+
break;
87+
//rounding with 1.00 intervals
88+
case RoundingType.Rounding1:
89+
case RoundingType.Rounding1Up:
90+
t = (rez - Math.Truncate(rez)) * 100;
91+
92+
if (roundingType == RoundingType.Rounding1Up && t > 0)
93+
rez = Math.Truncate(rez) + 1;
94+
else
95+
rez = t < 50 ? Math.Truncate(rez) : Math.Truncate(rez) + 1;
96+
97+
break;
98+
case RoundingType.Rounding001:
99+
default:
100+
break;
101+
}
102+
103+
return rez;
26104
}
27105
}
28106
}

src/Libraries/Nop.Services/Installation/CodeFirstInstallationService.cs

+13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
using Nop.Core.Domain.Topics;
3232
using Nop.Core.Domain.Vendors;
3333
using Nop.Core.Infrastructure;
34+
using Nop.Services.Catalog;
3435
using Nop.Services.Common;
3536
using Nop.Services.Configuration;
3637
using Nop.Services.Customers;
@@ -395,6 +396,7 @@ protected virtual void InstallCurrencies()
395396
DisplayOrder = 1,
396397
CreatedOnUtc = DateTime.UtcNow,
397398
UpdatedOnUtc = DateTime.UtcNow,
399+
RoundingType = RoundingType.Rounding001
398400
},
399401
new Currency
400402
{
@@ -407,6 +409,7 @@ protected virtual void InstallCurrencies()
407409
DisplayOrder = 2,
408410
CreatedOnUtc = DateTime.UtcNow,
409411
UpdatedOnUtc = DateTime.UtcNow,
412+
RoundingType = RoundingType.Rounding001
410413
},
411414
new Currency
412415
{
@@ -419,6 +422,7 @@ protected virtual void InstallCurrencies()
419422
DisplayOrder = 3,
420423
CreatedOnUtc = DateTime.UtcNow,
421424
UpdatedOnUtc = DateTime.UtcNow,
425+
RoundingType = RoundingType.Rounding001
422426
},
423427
new Currency
424428
{
@@ -431,6 +435,7 @@ protected virtual void InstallCurrencies()
431435
DisplayOrder = 4,
432436
CreatedOnUtc = DateTime.UtcNow,
433437
UpdatedOnUtc = DateTime.UtcNow,
438+
RoundingType = RoundingType.Rounding001
434439
},
435440
new Currency
436441
{
@@ -443,6 +448,7 @@ protected virtual void InstallCurrencies()
443448
DisplayOrder = 5,
444449
CreatedOnUtc = DateTime.UtcNow,
445450
UpdatedOnUtc = DateTime.UtcNow,
451+
RoundingType = RoundingType.Rounding001
446452
},
447453
new Currency
448454
{
@@ -456,6 +462,7 @@ protected virtual void InstallCurrencies()
456462
DisplayOrder = 6,
457463
CreatedOnUtc = DateTime.UtcNow,
458464
UpdatedOnUtc = DateTime.UtcNow,
465+
RoundingType = RoundingType.Rounding001
459466
},
460467
new Currency
461468
{
@@ -468,6 +475,7 @@ protected virtual void InstallCurrencies()
468475
DisplayOrder = 7,
469476
CreatedOnUtc = DateTime.UtcNow,
470477
UpdatedOnUtc = DateTime.UtcNow,
478+
RoundingType = RoundingType.Rounding001
471479
},
472480
new Currency
473481
{
@@ -480,6 +488,7 @@ protected virtual void InstallCurrencies()
480488
DisplayOrder = 8,
481489
CreatedOnUtc = DateTime.UtcNow,
482490
UpdatedOnUtc = DateTime.UtcNow,
491+
RoundingType = RoundingType.Rounding001
483492
},
484493
new Currency
485494
{
@@ -492,6 +501,7 @@ protected virtual void InstallCurrencies()
492501
DisplayOrder = 9,
493502
CreatedOnUtc = DateTime.UtcNow,
494503
UpdatedOnUtc = DateTime.UtcNow,
504+
RoundingType = RoundingType.Rounding001
495505
},
496506
new Currency
497507
{
@@ -504,6 +514,7 @@ protected virtual void InstallCurrencies()
504514
DisplayOrder = 10,
505515
CreatedOnUtc = DateTime.UtcNow,
506516
UpdatedOnUtc = DateTime.UtcNow,
517+
RoundingType = RoundingType.Rounding1
507518
},
508519
new Currency
509520
{
@@ -516,6 +527,7 @@ protected virtual void InstallCurrencies()
516527
DisplayOrder = 11,
517528
CreatedOnUtc = DateTime.UtcNow,
518529
UpdatedOnUtc = DateTime.UtcNow,
530+
RoundingType = RoundingType.Rounding001
519531
},
520532
new Currency
521533
{
@@ -528,6 +540,7 @@ protected virtual void InstallCurrencies()
528540
DisplayOrder = 12,
529541
CreatedOnUtc = DateTime.UtcNow,
530542
UpdatedOnUtc = DateTime.UtcNow,
543+
RoundingType = RoundingType.Rounding001
531544
},
532545
};
533546
_currencyRepository.Insert(currencies);

src/Presentation/Nop.Web/Administration/Infrastructure/Mapper/AdminMapperConfiguration.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ public Action<IMapperConfigurationExpression> GetConfiguration()
375375
cfg.CreateMap<CurrencyModel, Currency>()
376376
.ForMember(dest => dest.CreatedOnUtc, mo => mo.Ignore())
377377
.ForMember(dest => dest.UpdatedOnUtc, mo => mo.Ignore())
378-
.ForMember(dest => dest.LimitedToStores, mo => mo.Ignore());
378+
.ForMember(dest => dest.LimitedToStores, mo => mo.Ignore())
379+
.ForMember(dest => dest.RoundingType, mo => mo.Ignore());
379380
//measure weights
380381
cfg.CreateMap<MeasureWeight, MeasureWeightModel>()
381382
.ForMember(dest => dest.IsPrimaryWeight, mo => mo.Ignore())

src/Presentation/Nop.Web/Administration/Models/Directory/CurrencyModel.cs

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public CurrencyModel()
6161
[UIHint("MultiSelect")]
6262
public IList<int> SelectedStoreIds { get; set; }
6363
public IList<SelectListItem> AvailableStores { get; set; }
64+
65+
[NopResourceDisplayName("Admin.Configuration.Currencies.Fields.RoundingType")]
66+
public int RoundingTypeId { get; set; }
6467
}
6568

6669
public partial class CurrencyLocalizedModel : ILocalizedModelLocal

src/Presentation/Nop.Web/Administration/Views/Currency/_CreateOrUpdate.cshtml

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
@model CurrencyModel
1+
@using Nop.Core.Domain.Directory
2+
@using Nop.Services
3+
@model CurrencyModel
24

35
@Html.ValidationSummary(true)
46
@Html.HiddenFor(model => model.Id)
@@ -120,6 +122,15 @@
120122
</div>
121123
</div>
122124
</div>
125+
<div class="form-group">
126+
<div class="col-md-3">
127+
@Html.NopLabelFor(model => model.RoundingTypeId)
128+
</div>
129+
<div class="col-md-9">
130+
@Html.NopDropDownListFor(model => model.RoundingTypeId, ((RoundingType)Model.RoundingTypeId).ToSelectList())
131+
@Html.ValidationMessageFor(model => model.RoundingTypeId)
132+
</div>
133+
</div>
123134
<div class="form-group">
124135
<div class="col-md-3">
125136
@Html.NopLabelFor(model => model.Published)

src/Presentation/Nop.Web/App_Data/Localization/defaultResources.nopres.xml

+30
Original file line numberDiff line numberDiff line change
@@ -4335,6 +4335,12 @@
43354335
<LocaleResource Name="Admin.Configuration.Currencies.Fields.Rate.Range">
43364336
<Value>Exchange rate must be greater than 0.</Value>
43374337
</LocaleResource>
4338+
<LocaleResource Name="Admin.Configuration.Currencies.Fields.RoundingType">
4339+
<Value>Rounding type</Value>
4340+
</LocaleResource>
4341+
<LocaleResource Name="Admin.Configuration.Currencies.Fields.RoundingType.Hint">
4342+
<Value>The rounding type.</Value>
4343+
</LocaleResource>
43384344
<LocaleResource Name="Admin.Configuration.Currencies.GetLiveRates">
43394345
<Value>Get live rates</Value>
43404346
</LocaleResource>
@@ -13497,6 +13503,30 @@
1349713503
<LocaleResource Name="Enums.Nop.Core.Domain.Customers.RewardPointsActivatingDelayPeriod.Hours">
1349813504
<Value>Hours</Value>
1349913505
</LocaleResource>
13506+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding001">
13507+
<Value>Default rounding</Value>
13508+
</LocaleResource>
13509+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding005Up">
13510+
<Value>Rounding up with 0.05 intervals (0.06 round to 0.10)</Value>
13511+
</LocaleResource>
13512+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding005Down">
13513+
<Value>Rounding down with 0.05 intervals (0.06 round to 0.05)</Value>
13514+
</LocaleResource>
13515+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding01Up">
13516+
<Value>Rounding up with 0.10 intervals (1.05 round to 1.10)</Value>
13517+
</LocaleResource>
13518+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding01Down">
13519+
<Value>Rounding down with 0.10 intervals (1.05 round to 1.00)</Value>
13520+
</LocaleResource>
13521+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding05">
13522+
<Value>Rounding with 0.50 intervals</Value>
13523+
</LocaleResource>
13524+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding1">
13525+
<Value>Rounding with 1.00 intervals (1.01-1.49 round to 1.00, 1.50-1.99 round to 2.00)</Value>
13526+
</LocaleResource>
13527+
<LocaleResource Name="Enums.Nop.Core.Domain.Directory.RoundingType.Rounding1Up">
13528+
<Value>Rounding up with 1.00 intervals (1.01–1.99 round to 2.00)</Value>
13529+
</LocaleResource>
1350013530
<LocaleResource Name="Enums.Nop.Core.Domain.Discounts.DiscountLimitationType.NTimesOnly">
1350113531
<Value>N times only</Value>
1350213532
</LocaleResource>

0 commit comments

Comments
 (0)