feat(workshop): add reference implementations for exercises (part1–part3)
Add complete solutions for all workshop exercises covering: - part1: basics (amounts, arithmetic, rounding, formatting, parsing) - part2: operators and queries - part3: integration scenarios Implementations follow JSR-354 best practices and align with exercise tests and workshop structure.
This commit is contained in:
parent
21d835b9ca
commit
4f915afb06
12 changed files with 172 additions and 93 deletions
|
|
@ -21,7 +21,7 @@ public class ArithmeticExercises {
|
|||
* @return sum of both amounts in the same currency
|
||||
*/
|
||||
public MonetaryAmount addAmounts(MonetaryAmount firstAmount, MonetaryAmount secondAmount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return firstAmount.add(secondAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +34,7 @@ public class ArithmeticExercises {
|
|||
* @return difference after subtraction in the same currency
|
||||
*/
|
||||
public MonetaryAmount subtractAmounts(MonetaryAmount minuend, MonetaryAmount subtrahend) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return minuend.subtract(subtrahend);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,7 +47,7 @@ public class ArithmeticExercises {
|
|||
* @return product amount in the same currency
|
||||
*/
|
||||
public MonetaryAmount multiplyAmount(MonetaryAmount amount, int factor) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.multiply(factor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,6 +60,6 @@ public class ArithmeticExercises {
|
|||
* @return {@code true} if first amount is greater, otherwise {@code false}
|
||||
*/
|
||||
public boolean compareAmounts(MonetaryAmount firstAmount, MonetaryAmount secondAmount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return firstAmount.isGreaterThan(secondAmount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package swiss.fihlon.workshop.money.part1;
|
||||
|
||||
import java.util.Locale;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.format.MonetaryAmountFormat;
|
||||
import javax.money.format.MonetaryFormats;
|
||||
|
||||
/**
|
||||
* <p>Part 1 workshop exercises for formatting monetary amounts using JSR-354.</p>
|
||||
|
|
@ -21,7 +24,7 @@ public class FormattingExercises {
|
|||
* @return formatted amount string for Swiss German locale
|
||||
*/
|
||||
public String formatSwissGerman(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return format(amount, "de-CH");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +36,7 @@ public class FormattingExercises {
|
|||
* @return formatted amount string for German locale
|
||||
*/
|
||||
public String formatGerman(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return format(amount, "de-DE");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,6 +48,20 @@ public class FormattingExercises {
|
|||
* @return formatted amount string for US locale
|
||||
*/
|
||||
public String formatUs(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return format(amount, "en-US");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Format the given amount using the specified locale.</p>
|
||||
*
|
||||
* <p>Use the provided language tag to obtain a locale-specific formatter.</p>
|
||||
*
|
||||
* @param amount the amount to format
|
||||
* @param languageTag IETF BCP 47 language tag (e.g. {@code de-CH})
|
||||
* @return formatted amount string
|
||||
*/
|
||||
private String format(MonetaryAmount amount, String languageTag) {
|
||||
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.forLanguageTag(languageTag));
|
||||
return format.format(amount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
package swiss.fihlon.workshop.money.part1;
|
||||
|
||||
import java.util.Locale;
|
||||
import javax.money.Monetary;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.MonetaryOperator;
|
||||
import javax.money.format.MonetaryAmountFormat;
|
||||
import javax.money.format.MonetaryFormats;
|
||||
import org.javamoney.moneta.Money;
|
||||
|
||||
/**
|
||||
* <p>Part 1 workshop exercises for combining parsing, arithmetic, rounding, and formatting with JSR-354.</p>
|
||||
*
|
||||
|
|
@ -22,6 +30,24 @@ public class IntegrationExercises {
|
|||
* @return formatted final price text
|
||||
*/
|
||||
public String calculateFinalPrice(String priceText) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
// setup locale and formatter
|
||||
Locale swissGerman = Locale.forLanguageTag("de-CH");
|
||||
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(swissGerman);
|
||||
|
||||
// parse
|
||||
MonetaryAmount price = format.parse(priceText);
|
||||
|
||||
// constants
|
||||
MonetaryAmount shipping = Money.of(4.95, "CHF");
|
||||
MonetaryAmount discount = Money.of(2.00, "CHF");
|
||||
|
||||
// calculate
|
||||
MonetaryAmount total = price.add(shipping).subtract(discount);
|
||||
|
||||
// round
|
||||
MonetaryAmount roundedTotal = total.with(Monetary.getDefaultRounding());
|
||||
|
||||
// format
|
||||
return format.format(roundedTotal);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package swiss.fihlon.workshop.money.part1;
|
||||
|
||||
import org.javamoney.moneta.Money;
|
||||
|
||||
import javax.money.CurrencyUnit;
|
||||
import javax.money.Monetary;
|
||||
import javax.money.MonetaryAmount;
|
||||
|
||||
/**
|
||||
|
|
@ -19,7 +22,7 @@ public class MoneyExercises {
|
|||
* @return Swiss franc currency unit ({@code CHF})
|
||||
*/
|
||||
public CurrencyUnit createSwissFranc() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return Monetary.getCurrency("CHF");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -29,7 +32,7 @@ public class MoneyExercises {
|
|||
* @return monetary amount {@code 19.95 CHF}
|
||||
*/
|
||||
public MonetaryAmount createSwissFrancAmount() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return Money.of(19.95, "CHF");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -39,7 +42,7 @@ public class MoneyExercises {
|
|||
* @return monetary amount {@code 2500 JPY}
|
||||
*/
|
||||
public MonetaryAmount createJapaneseYenAmount() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return Money.of(2500, "JPY");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,6 +52,6 @@ public class MoneyExercises {
|
|||
* @return monetary amount {@code 12.345 TND}
|
||||
*/
|
||||
public MonetaryAmount createTunisianDinarAmount() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return Money.of(12.345, "TND");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package swiss.fihlon.workshop.money.part1;
|
||||
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.format.MonetaryAmountFormat;
|
||||
import javax.money.format.MonetaryFormats;
|
||||
import javax.money.format.MonetaryParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
|
|
@ -24,7 +27,7 @@ public class ParsingExercises {
|
|||
* @return parsed monetary amount
|
||||
*/
|
||||
public MonetaryAmount parseSwissGerman(String text) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return parse(text, "de-CH");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,7 +39,7 @@ public class ParsingExercises {
|
|||
* @return parsed monetary amount
|
||||
*/
|
||||
public MonetaryAmount parseGerman(String text) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return parse(text, "de-DE");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +51,22 @@ public class ParsingExercises {
|
|||
* @return parsed monetary amount
|
||||
*/
|
||||
public MonetaryAmount parseUs(String text) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return parse(text, "en-US");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Parse the given monetary amount text using the specified locale.</p>
|
||||
*
|
||||
* <p>Use the provided language tag to obtain a locale-specific parser.</p>
|
||||
*
|
||||
* @param text the input text to parse
|
||||
* @param languageTag IETF BCP 47 language tag (e.g. {@code de-CH})
|
||||
* @return parsed monetary amount
|
||||
*/
|
||||
private MonetaryAmount parse(String text, String languageTag) {
|
||||
MonetaryAmountFormat format =
|
||||
MonetaryFormats.getAmountFormat(Locale.forLanguageTag(languageTag));
|
||||
return format.parse(text);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,6 +79,12 @@ public class ParsingExercises {
|
|||
* @return {@code true} if parsing succeeds, otherwise {@code false}
|
||||
*/
|
||||
public boolean parseInvalidInput(String text, Locale locale) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(locale);
|
||||
try {
|
||||
format.parse(text);
|
||||
return true;
|
||||
} catch (MonetaryParseException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package swiss.fihlon.workshop.money.part1;
|
||||
|
||||
import javax.money.Monetary;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.MonetaryOperator;
|
||||
|
||||
/**
|
||||
* <p>Part 1 workshop exercises for currency-aware rounding with JSR-354.</p>
|
||||
|
|
@ -20,7 +22,7 @@ public class RoundingExercises {
|
|||
* @return rounded amount
|
||||
*/
|
||||
public MonetaryAmount applyDefaultRounding(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.with(Monetary.getDefaultRounding());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,6 +35,7 @@ public class RoundingExercises {
|
|||
* @return divided and rounded amount
|
||||
*/
|
||||
public MonetaryAmount divideAndRound(MonetaryAmount amount, int divisor) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.divide(divisor)
|
||||
.with(Monetary.getDefaultRounding());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package swiss.fihlon.workshop.money.part2;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.convert.CurrencyConversion;
|
||||
import javax.money.convert.MonetaryConversions;
|
||||
|
||||
/**
|
||||
* <p>Part 2 workshop exercises for currency conversion using JSR-354.</p>
|
||||
|
|
@ -21,7 +21,7 @@ public class CurrencyConversionExercises {
|
|||
* @return currency conversion to EUR
|
||||
*/
|
||||
public CurrencyConversion getEurConversion() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return MonetaryConversions.getConversion("EUR", "ECB");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,31 +33,7 @@ public class CurrencyConversionExercises {
|
|||
* @return converted amount in EUR
|
||||
*/
|
||||
public MonetaryAmount convertChfToEur(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a currency conversion to EUR using a timestamp-based conversion query.</p>
|
||||
*
|
||||
* <p>Include the given {@link LocalDateTime} in the query.</p>
|
||||
*
|
||||
* @param timestamp timestamp used in the conversion query
|
||||
* @return currency conversion to EUR for the given timestamp
|
||||
*/
|
||||
public CurrencyConversion getEurConversionForTimestamp(LocalDateTime timestamp) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convert a CHF amount to EUR using a timestamp-based conversion query.</p>
|
||||
*
|
||||
* <p>Build the conversion query with the given timestamp and return the converted amount.</p>
|
||||
*
|
||||
* @param amount amount in CHF
|
||||
* @param timestamp timestamp used in the conversion query
|
||||
* @return converted amount in EUR
|
||||
*/
|
||||
public MonetaryAmount convertChfToEurAt(MonetaryAmount amount, LocalDateTime timestamp) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
CurrencyConversion conversion = getEurConversion();
|
||||
return amount.with(conversion);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class MonetaryContextExercises {
|
|||
* @return monetary context of the amount
|
||||
*/
|
||||
public MonetaryContext getMonetaryContext(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +34,7 @@ public class MonetaryContextExercises {
|
|||
* @return maximum scale from the monetary context
|
||||
*/
|
||||
public int getMaxScale(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.getContext().getMaxScale();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -47,7 +47,7 @@ public class MonetaryContextExercises {
|
|||
* @return {@code true} if both contexts are equal, otherwise {@code false}
|
||||
*/
|
||||
public boolean compareContexts(MonetaryAmount firstAmount, MonetaryAmount secondAmount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return firstAmount.getContext().equals(secondAmount.getContext());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,6 +59,7 @@ public class MonetaryContextExercises {
|
|||
* @return formatted context description
|
||||
*/
|
||||
public String describeContext(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryContext context = amount.getContext();
|
||||
return "precision=" + context.getPrecision() + ", maxScale=" + context.getMaxScale();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
package swiss.fihlon.workshop.money.part2;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.MonetaryOperator;
|
||||
|
||||
/**
|
||||
* <p>Part 2 workshop exercises for encapsulating domain logic with MonetaryOperator.</p>
|
||||
*
|
||||
* <p>The exercises focus on applying reusable monetary operations such as discounts and VAT.</p>
|
||||
*
|
||||
* <p>The methods are intentionally incomplete and should be implemented by making tests pass.</p>
|
||||
* <p>The examples focus on applying reusable monetary operations such as discounts and VAT.</p>
|
||||
*/
|
||||
public class MonetaryOperatorExercises {
|
||||
|
||||
|
|
@ -21,7 +20,8 @@ public class MonetaryOperatorExercises {
|
|||
* @return discounted amount
|
||||
*/
|
||||
public MonetaryAmount applyDiscount(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator discount = createDiscountOperator();
|
||||
return amount.with(discount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +33,8 @@ public class MonetaryOperatorExercises {
|
|||
* @return amount after VAT
|
||||
*/
|
||||
public MonetaryAmount applyVat(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator vat = createVatOperator();
|
||||
return amount.with(vat);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +46,18 @@ public class MonetaryOperatorExercises {
|
|||
* @return amount after discount and VAT
|
||||
*/
|
||||
public MonetaryAmount applyDiscountThenVat(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator discount = createDiscountOperator();
|
||||
MonetaryOperator vat = createVatOperator();
|
||||
return amount.with(discount).with(vat);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a reusable 7.7% VAT monetary operator.</p>
|
||||
*
|
||||
* @return a reusable VAT operator
|
||||
*/
|
||||
public MonetaryOperator createVatOperator() {
|
||||
return monetaryAmount -> monetaryAmount.multiply(new BigDecimal("1.077"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -56,6 +68,6 @@ public class MonetaryOperatorExercises {
|
|||
* @return reusable discount operator
|
||||
*/
|
||||
public MonetaryOperator createDiscountOperator() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return monetaryAmount -> monetaryAmount.multiply(new BigDecimal("0.90"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ import javax.money.MonetaryQuery;
|
|||
/**
|
||||
* <p>Part 2 workshop exercises for extracting information from monetary amounts with MonetaryQuery.</p>
|
||||
*
|
||||
* <p>The exercises focus on encapsulating reusable query logic for monetary values and currencies.</p>
|
||||
*
|
||||
* <p>The methods are intentionally incomplete and should be implemented by making tests pass.</p>
|
||||
* <p>The examples focus on encapsulating reusable query logic for monetary values and currencies.</p>
|
||||
*/
|
||||
public class MonetaryQueryExercises {
|
||||
|
||||
|
|
@ -22,7 +20,7 @@ public class MonetaryQueryExercises {
|
|||
* @return currency code
|
||||
*/
|
||||
public String queryCurrencyCode(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.query(createCurrencyCodeQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +32,9 @@ public class MonetaryQueryExercises {
|
|||
* @return default fraction digits of the currency
|
||||
*/
|
||||
public int queryDefaultFractionDigits(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryQuery<Integer> query =
|
||||
monetaryAmount -> monetaryAmount.getCurrency().getDefaultFractionDigits();
|
||||
return amount.query(query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +46,9 @@ public class MonetaryQueryExercises {
|
|||
* @return numeric value as BigDecimal
|
||||
*/
|
||||
public BigDecimal queryNumberAsBigDecimal(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryQuery<BigDecimal> query =
|
||||
monetaryAmount -> monetaryAmount.getNumber().numberValueExact(BigDecimal.class);
|
||||
return amount.query(query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -57,6 +59,6 @@ public class MonetaryQueryExercises {
|
|||
* @return reusable query returning a currency code
|
||||
*/
|
||||
public MonetaryQuery<String> createCurrencyCodeQuery() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return monetaryAmount -> monetaryAmount.getCurrency().getCurrencyCode();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
package swiss.fihlon.workshop.money.part2;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import javax.money.Monetary;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.MonetaryOperator;
|
||||
|
||||
/**
|
||||
* <p>Part 2 workshop exercises for applying different rounding strategies with JSR-354.</p>
|
||||
* <p>Part 2 workshop examples for applying different rounding strategies with JSR-354.</p>
|
||||
*
|
||||
* <p>The exercises focus on treating rounding as an explicit domain decision that depends on the use case.</p>
|
||||
*
|
||||
* <p>The methods are intentionally incomplete and should be implemented by making tests pass.</p>
|
||||
* <p>The examples focus on treating rounding as an explicit domain decision that depends on the use case.</p>
|
||||
*/
|
||||
public class RoundingStrategyExercises {
|
||||
|
||||
|
|
@ -21,19 +22,8 @@ public class RoundingStrategyExercises {
|
|||
* @return amount rounded with default currency rounding
|
||||
*/
|
||||
public MonetaryAmount applyDefaultRounding(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Apply explicit default rounding to a VAT amount.</p>
|
||||
*
|
||||
* <p>Use rounding as a separate, explicit step.</p>
|
||||
*
|
||||
* @param taxAmount tax amount to round
|
||||
* @return rounded tax amount
|
||||
*/
|
||||
public MonetaryAmount roundVatAmount(MonetaryAmount taxAmount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator rounding = Monetary.getDefaultRounding();
|
||||
return amount.with(rounding);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +35,8 @@ public class RoundingStrategyExercises {
|
|||
* @return CHF amount rounded to the nearest 0.05
|
||||
*/
|
||||
public MonetaryAmount applySwissCashRounding(MonetaryAmount amount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator swissCashRounding = createSwissCashRounding();
|
||||
return amount.with(swissCashRounding);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -56,6 +47,19 @@ public class RoundingStrategyExercises {
|
|||
* @return reusable Swiss cash rounding operator
|
||||
*/
|
||||
public MonetaryOperator createSwissCashRounding() {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return monetaryAmount -> {
|
||||
if (!"CHF".equals(monetaryAmount.getCurrency().getCurrencyCode())) {
|
||||
throw new IllegalArgumentException("Swiss cash rounding only supports CHF.");
|
||||
}
|
||||
|
||||
BigDecimal increment = new BigDecimal("0.05");
|
||||
BigDecimal value = monetaryAmount.getNumber().numberValueExact(BigDecimal.class);
|
||||
BigDecimal rounded = value.divide(increment, 0, RoundingMode.HALF_UP).multiply(increment);
|
||||
|
||||
return monetaryAmount.getFactory()
|
||||
.setCurrency(monetaryAmount.getCurrency())
|
||||
.setNumber(rounded)
|
||||
.create();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
package swiss.fihlon.workshop.money.part3;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
import javax.money.CurrencyUnit;
|
||||
import javax.money.Monetary;
|
||||
import javax.money.MonetaryAmount;
|
||||
import javax.money.MonetaryOperator;
|
||||
import javax.money.convert.MonetaryConversions;
|
||||
import javax.money.format.MonetaryAmountFormat;
|
||||
import javax.money.format.MonetaryFormats;
|
||||
|
||||
/**
|
||||
* <p>Part 3 workshop exercises for integrating monetary calculations into a small order workflow.</p>
|
||||
* <p>Part 3 workshop examples for integrating monetary calculations into a small order workflow.</p>
|
||||
*
|
||||
* <p>The exercises focus on combining subtotal calculation, discount, VAT, rounding, and formatting.</p>
|
||||
*
|
||||
* <p>The methods are intentionally incomplete and should be implemented by making tests pass.</p>
|
||||
* <p>The examples focus on combining subtotal calculation, discount, VAT, rounding, and formatting.</p>
|
||||
*/
|
||||
public class OrderExercises {
|
||||
|
||||
|
|
@ -22,7 +27,7 @@ public class OrderExercises {
|
|||
* @return subtotal amount
|
||||
*/
|
||||
public MonetaryAmount calculateSubtotal(MonetaryAmount unitPrice, int quantity) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return unitPrice.multiply(quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +39,8 @@ public class OrderExercises {
|
|||
* @return discounted amount
|
||||
*/
|
||||
public MonetaryAmount applyDiscount(MonetaryAmount subtotal) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryOperator discount = amount -> amount.multiply(new BigDecimal("0.90"));
|
||||
return subtotal.with(discount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +52,9 @@ public class OrderExercises {
|
|||
* @return VAT-inclusive amount
|
||||
*/
|
||||
public MonetaryAmount applyVat(MonetaryAmount discountedAmount) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryAmount vatInclusiveAmount = discountedAmount.multiply(new BigDecimal("1.077"));
|
||||
MonetaryOperator rounding = Monetary.getDefaultRounding();
|
||||
return vatInclusiveAmount.with(rounding);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,7 +67,9 @@ public class OrderExercises {
|
|||
* @return final total amount
|
||||
*/
|
||||
public MonetaryAmount calculateTotal(MonetaryAmount unitPrice, int quantity) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryAmount subtotal = calculateSubtotal(unitPrice, quantity);
|
||||
MonetaryAmount discountedAmount = applyDiscount(subtotal);
|
||||
return applyVat(discountedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -71,7 +81,8 @@ public class OrderExercises {
|
|||
* @return formatted total string
|
||||
*/
|
||||
public String formatTotal(MonetaryAmount total) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.forLanguageTag("de-CH"));
|
||||
return format.format(total);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,6 +95,6 @@ public class OrderExercises {
|
|||
* @return amount converted to the target currency
|
||||
*/
|
||||
public MonetaryAmount convertToCurrency(MonetaryAmount amount, CurrencyUnit targetCurrency) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
return amount.with(MonetaryConversions.getConversion(targetCurrency, "ECB"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue