diff --git a/config.json b/config.json
index 9d5eb722..8b13d701 100644
--- a/config.json
+++ b/config.json
@@ -20,6 +20,19 @@
},
"exercises": {
"concept": [
+ {
+ "slug": "freelancer-rates",
+ "name": "Freelancer Rates",
+ "uuid": "0aff2fa7-55ea-47e9-af4a-78927d916baf",
+ "concepts": [
+ "numbers",
+ "arithmetic-operators"
+ ],
+ "prerequisites": [
+ "basics"
+ ],
+ "status": "beta"
+ },
{
"slug": "lasagna",
"name": "Lucian's Luscious Lasagna",
diff --git a/exercises/concept/freelancer-rates/.docs/hints.md b/exercises/concept/freelancer-rates/.docs/hints.md
new file mode 100644
index 00000000..b1dbf0d9
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.docs/hints.md
@@ -0,0 +1,16 @@
+# Hints
+
+## 1. Calculate the day rate given an hourly rate
+
+- Use the arithmetic operators as mentioned in the introduction of this exercise.
+
+## 2. Calculate the number of workdays given a budget
+
+- First determine the day rate, then calculate the number of days, and finally round that number down.
+
+## 3. Calculate the discounted rate for large projects
+
+- Round down the result from division to get the number of full months.
+- `100% - discount` equals the percentage charged after the discount is applied.
+- Use `%`, the remainder operator, to calculate the number of days exceeding full months.
+- Add the discounted month rates and full day rates and round it up
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/.docs/instructions.md b/exercises/concept/freelancer-rates/.docs/instructions.md
new file mode 100644
index 00000000..25d708de
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.docs/instructions.md
@@ -0,0 +1,45 @@
+# Instructions
+
+In this exercise you will be writing code to help a freelancer communicate with his clients about the prices of certain projects. You will write a few utility functions to quickly calculate the costs for the clients.
+
+## 1. Calculate the day rate given an hourly rate
+
+A client contacts the freelancer to enquire about his rates.
+The freelancer explains that he **_works 8 hours a day._**
+However, the freelancer knows only his hourly rates for the project.
+Help him estimate a day rate given an hourly rate.
+
+```c
+DATA(lcl_freelancer_rates) = new zcl_freelancer_rates( ).
+DATA(lv_day_rate) = lcl_freelancer_rates->day_rate( 16 ).
+WRITE |My Day Rate is: { lv_day_rate }|.
+// => My Day Rate is: 128
+```
+
+The day rate does not need to be rounded or changed to a "fixed" precision.
+
+## 2. Calculate the number of workdays given a fixed budget
+
+Another day, a project manager offers the freelancer to work on a project with a fixed budget.
+Given the fixed budget and the freelancer's hourly rate, help him calculate the number of days he would work until the budget is exhausted.
+The result _must_ be **rounded** to the nearest number with 2 decimal places.
+
+```c
+DATA(lcl_freelancer_rates) = new zcl_freelancer_rates( ).
+DATA(lv_days_in_budget) = lcl_freelancer_rates->DAYS_IN_BUDGET( budget = 1280 rate_per_hour = 16 ).
+WRITE |Budget would last for { lv_days_in_budget } days.|.
+// => Budget would last for 10 days.
+```
+
+## 3. Calculate the discounted rate for large projects
+
+Often, the freelancer's clients hire him for projects spanning over multiple months.
+In these cases, the freelancer decides to offer a discount for every full month, and the remaining days are billed at day rate.
+**_Every month has 22 billable days._**
+Help him estimate his cost for such projects, given an hourly rate, the number of days the project spans, and a monthly discount rate.
+The discount is always passed as a number, where `42%` becomes `0.42`. The result _must_ be **rounded up** to the nearest whole number.
+
+```javascript
+priceWithMonthlyDiscount(89, 230, 0.42);
+// => 97972
+```
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/.docs/introduction.md b/exercises/concept/freelancer-rates/.docs/introduction.md
new file mode 100644
index 00000000..0ab457f7
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.docs/introduction.md
@@ -0,0 +1,84 @@
+# Introduction
+
+## Numbers
+
+Many programming languages have specific numeric types to represent different types of numbers, but JavaScript only has two:
+
+- `number`: a numeric data type in the double-precision 64-bit floating-point format (IEEE 754).
+ Examples are `-6`, `-2.4`, `0`, `0.1`, `1`, `3.14`, `16.984025`, `25`, `976`, `1024.0` and `500000`.
+- `bigint`: a numeric data type that can represent _integers_ in the arbitrary precision format.
+ Examples are `-12n`, `0n`, `4n`, and `9007199254740991n`.
+
+If you require arbitrary precision or work with extremely large numbers, use the `bigint` type.
+Otherwise, the `number` type is likely the better option.
+
+### Rounding
+
+There is a built-in global object called `Math` that provides various [rounding functions][ref-math-object-rounding]. For example, you can round down (`floor`) or round up (`ceil`) decimal numbers to the nearest whole numbers.
+
+```javascript
+Math.floor(234.34); // => 234
+Math.ceil(234.34); // => 235
+```
+
+## Arithmetic Operators
+
+JavaScript provides 6 different operators to perform basic arithmetic operations on numbers.
+
+- `+`: The addition operator is used to find the sum of numbers.
+- `-`: The subtraction operator is used to find the difference between two numbers
+- `*`: The multiplication operator is used to find the product of two numbers.
+- `/`: The division operator is used to divide two numbers.
+
+```javascript
+2 - 1.5; //=> 0.5
+19 / 2; //=> 9.5
+```
+
+- `%`: The remainder operator is used to find the remainder of a division performed.
+
+ ```javascript
+ 40 % 4; // => 0
+ -11 % 4; // => -3
+ ```
+
+- `**`: The exponentiation operator is used to raise a number to a power.
+
+ ```javascript
+ 4 ** 3; // => 64
+ 4 ** 1 / 2; // => 2
+ ```
+
+### Order of Operations
+
+When using multiple operators in a line, JavaScript follows an order of precedence as shown in [this precedence table][mdn-operator-precedence].
+To simplify it to our context, JavaScript uses the PEDMAS (Parentheses, Exponents, Division/Multiplication, Addition/Subtraction) rule we've learnt in elementary math classes.
+
+
+```javascript
+const result = 3 ** 3 + 9 * 4 / (3 - 1);
+// => 3 ** 3 + 9 * 4/2
+// => 27 + 9 * 4/2
+// => 27 + 18
+// => 45
+```
+
+
+### Shorthand Assignment Operators
+
+Shorthand assignment operators are a shorter way of writing code conducting arithmetic operations on a variable, and assigning the new value to the same variable.
+For example, consider two variables `x` and `y`.
+Then, `x += y` is same as `x = x + y`.
+Often, this is used with a number instead of a variable `y`.
+The 5 other operations can also be conducted in a similar style.
+
+```javascript
+let x = 5;
+x += 25; // x is now 30
+
+let y = 31;
+y %= 3; // y is now 1
+```
+
+[mdn-operator-precedence]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table
+[ref-math-object-rounding]: https://javascript.info/number#rounding
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/.meta/config.json b/exercises/concept/freelancer-rates/.meta/config.json
new file mode 100644
index 00000000..6e25b607
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.meta/config.json
@@ -0,0 +1,19 @@
+{
+ "authors": [
+ "marianfoo"
+ ],
+ "contributors": [
+ ],
+ "files": {
+ "solution": [
+ "zcl_freelancer_rates.clas.abap"
+ ],
+ "test": [
+ "zcl_freelancer_rates.clas.testclasses.abap"
+ ],
+ "exemplar": [
+ ".meta/zcl_freelancer_rates.clas.abap"
+ ]
+ },
+ "blurb": "Learn about numbers whilst helping a freelancer communicate with a project manager about day- and month rates."
+ }
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/.meta/design.md b/exercises/concept/freelancer-rates/.meta/design.md
new file mode 100644
index 00000000..d15d70f8
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.meta/design.md
@@ -0,0 +1,24 @@
+# Design
+
+## Learning objectives
+
+- Know how to write floating point literals.
+- Know their underlying type (double precision).
+- Know their basic limitations (not all numbers can be represented, e.g. `0.1 + 0.2`).
+- Know how to truncate floating point numbers to a certain decimal place (`Math.ceil`, `Math.floor`, `Math.round`)
+- Know how to use arithmetic operators (`+`, `-`, `*`, `/`, `%`, `**`)
+- Learn about shorthand assignment operators (`+=`, etc.)
+
+## Out of scope
+
+- Parsing integers and floats from strings.
+- Converting integers and floats to strings.
+
+## Concepts
+
+- `numbers`
+- `arithmetic-operators`
+
+## Prerequisites
+
+- `basics`
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/.meta/zcl_freelancer_rates.clas.abap b/exercises/concept/freelancer-rates/.meta/zcl_freelancer_rates.clas.abap
new file mode 100644
index 00000000..f40f0562
--- /dev/null
+++ b/exercises/concept/freelancer-rates/.meta/zcl_freelancer_rates.clas.abap
@@ -0,0 +1,55 @@
+CLASS zcl_freelancer_rates DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ METHODS day_rate
+ IMPORTING
+ !rate_per_hour TYPE f
+ RETURNING
+ VALUE(result) TYPE f .
+ METHODS days_in_budget
+ IMPORTING
+ !budget TYPE f
+ !rate_per_hour TYPE f
+ RETURNING
+ VALUE(result) TYPE i .
+ METHODS price_with_monthly_discount
+ IMPORTING
+ !rate_per_hour TYPE f
+ !num_days TYPE f
+ !discount TYPE f
+ RETURNING
+ VALUE(result) TYPE f .
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+ENDCLASS.
+
+
+
+CLASS zcl_freelancer_rates IMPLEMENTATION.
+
+
+
+ METHOD day_rate.
+ result = round( val = rate_per_hour * 8 dec = 2 ) .
+ ENDMETHOD.
+
+ METHOD days_in_budget.
+ result = floor( budget / day_rate( rate_per_hour ) ).
+ ENDMETHOD.
+
+
+ METHOD price_with_monthly_discount.
+ DATA(lv_months) = floor( num_days / 22 ).
+ DATA(lv_monthly_rate) = 22 * day_rate( rate_per_hour ).
+ DATA(lv_monthly_discount_rate) = ( 1 - discount ) * lv_monthly_rate.
+
+ DATA(lv_extra_days) = num_days MOD 22.
+ DATA(lv_price_extra_days) = lv_extra_days * day_rate( rate_per_hour ).
+
+ result = ceil( lv_months * lv_monthly_discount_rate + lv_price_extra_days ).
+ ENDMETHOD.
+ENDCLASS.
\ No newline at end of file
diff --git a/exercises/concept/freelancer-rates/package.devc.xml b/exercises/concept/freelancer-rates/package.devc.xml
new file mode 100644
index 00000000..541b613d
--- /dev/null
+++ b/exercises/concept/freelancer-rates/package.devc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+ Exercism: Freelancer Rates
+
+
+
+
diff --git a/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.abap b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.abap
new file mode 100644
index 00000000..d9e38e06
--- /dev/null
+++ b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.abap
@@ -0,0 +1,51 @@
+CLASS zcl_freelancer_rates DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+
+ METHODS day_rate
+ IMPORTING
+ !rate_per_hour TYPE f
+ RETURNING
+ VALUE(result) TYPE f.
+
+ METHODS days_in_budget
+ IMPORTING
+ !budget TYPE f
+ !rate_per_hour TYPE f
+ RETURNING
+ VALUE(result) TYPE i.
+
+ METHODS price_with_monthly_discount
+ IMPORTING
+ !rate_per_hour TYPE f
+ !num_days TYPE f
+ !discount TYPE f
+ RETURNING
+ VALUE(result) TYPE f.
+
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+ENDCLASS.
+
+
+
+CLASS zcl_freelancer_rates IMPLEMENTATION.
+
+
+ METHOD days_in_budget.
+* add solution here
+ ENDMETHOD.
+
+
+ METHOD day_rate.
+* add solution here
+ ENDMETHOD.
+
+
+ METHOD price_with_monthly_discount.
+* add solution here
+ ENDMETHOD.
+ENDCLASS.
diff --git a/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.testclasses.abap b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.testclasses.abap
new file mode 100644
index 00000000..654e90b1
--- /dev/null
+++ b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.testclasses.abap
@@ -0,0 +1,118 @@
+CLASS ltcl_freelancer_rates DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL.
+
+ PRIVATE SECTION.
+
+ DATA cut TYPE REF TO zcl_freelancer_rates.
+ METHODS setup.
+ METHODS test_dayrate16 FOR TESTING RAISING cx_static_check.
+ METHODS test_dayrate25 FOR TESTING RAISING cx_static_check.
+ METHODS test_dayrate3140 FOR TESTING RAISING cx_static_check.
+ METHODS test_dayrate8989 FOR TESTING RAISING cx_static_check.
+ METHODS test_dayrate9765 FOR TESTING RAISING cx_static_check.
+ METHODS test_daysinbudget_1280_16 FOR TESTING RAISING cx_static_check.
+ METHODS test_daysinbudget_1280_25 FOR TESTING RAISING cx_static_check.
+ METHODS test_daysinbudget_835_12 FOR TESTING RAISING cx_static_check.
+ METHODS test_discount_16_70_0 FOR TESTING RAISING cx_static_check.
+ METHODS test_discount_16_130_15 FOR TESTING RAISING cx_static_check.
+ METHODS test_discount_29_220_112 FOR TESTING RAISING cx_static_check.
+ METHODS test_discount_29_155_25 FOR TESTING RAISING cx_static_check.
+
+ENDCLASS.
+
+CLASS ltcl_freelancer_rates IMPLEMENTATION.
+
+ METHOD setup.
+ cut = NEW zcl_freelancer_rates( ).
+ ENDMETHOD.
+
+ METHOD test_dayrate16.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->day_rate( 16 )
+ exp = 128 ).
+ ENDMETHOD.
+
+ METHOD test_dayrate25.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->day_rate( 25 )
+ exp = 200 ).
+ ENDMETHOD.
+
+ METHOD test_dayrate3140.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->day_rate( '31.4' )
+ exp = '251.2' ).
+ ENDMETHOD.
+
+ METHOD test_dayrate8989.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->day_rate( '89.89' )
+ exp = '719.12' ).
+ ENDMETHOD.
+
+ METHOD test_dayrate9765.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->day_rate( '97.654321' )
+ exp = '781.23' ).
+ ENDMETHOD.
+
+ METHOD test_daysinbudget_1280_16.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->days_in_budget(
+ budget = 1280
+ rate_per_hour = 16 )
+ exp = 10 ).
+ ENDMETHOD.
+
+ METHOD test_daysinbudget_1280_25.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->days_in_budget(
+ budget = 1280
+ rate_per_hour = 16 )
+ exp = 10 ).
+ ENDMETHOD.
+
+ METHOD test_daysinbudget_835_12.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->days_in_budget(
+ budget = 1280
+ rate_per_hour = 16 )
+ exp = 10 ).
+ ENDMETHOD.
+
+ METHOD test_discount_16_70_0.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->price_with_monthly_discount(
+ rate_per_hour = 16
+ num_days = 70
+ discount = 0 )
+ exp = 8960 ).
+ ENDMETHOD.
+
+ METHOD test_discount_16_130_15.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->price_with_monthly_discount(
+ rate_per_hour = 16
+ num_days = 130
+ discount = '0.15' )
+ exp = 14528 ).
+ ENDMETHOD.
+
+ METHOD test_discount_29_220_112.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->price_with_monthly_discount(
+ rate_per_hour = '29.654321'
+ num_days = 220
+ discount = '0.112' )
+ exp = 46346 ).
+ ENDMETHOD.
+
+ METHOD test_discount_29_155_25.
+ cl_abap_unit_assert=>assert_equals(
+ act = cut->price_with_monthly_discount(
+ rate_per_hour = '29.654321'
+ num_days = 155
+ discount = '0.2547' )
+ exp = 27466 ).
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.xml b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.xml
new file mode 100644
index 00000000..c526fa66
--- /dev/null
+++ b/exercises/concept/freelancer-rates/zcl_freelancer_rates.clas.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ ZCL_FREELANCER_RATES
+ E
+ Exercism: Freelancer Rates
+ 1
+ X
+ X
+ X
+ X
+
+
+
+