Porting the Batch Planner
In this lesson, you ported the head roaster’s whole Python planner to JavaScript, line by line,
for tonight’s paste of "37.5", then checked the port against Python’s output.
- The roastery’s order dashboard runs on JavaScript, so the planner moves there and must print the same plan: one wrong line, and tomorrow’s roast starts from the wrong beans or the wrong bill.
- The docstring becomes a JSDoc block, a comment between
/**and*/, not a string the program keeps.import mathgoes, becauseMathis a global in JavaScript. - Each setting keeps its UPPER_SNAKE_CASE name and gains
const: Python’s capitals are only a convention, butconstrefuses any reassignment. The order stays text, as pasted. float()becomesNumber(), because JavaScript has one number type. Wherefloat()raises on a paste with a comma, like"37,5",Number()returnsNaN, so the port checks withNumber.isNaN()on the next line. On a paste like that,console.error()prints a message andprocess.exit(1)stops the run.- In the batches line,
//gives way toMath.floor()of a plain division. Here’s the first place a fast port slips: JavaScript has no floor-division operator, and//starts a comment there. Python needsint()because its//on a float gives a float; JavaScript has one number type, soint()drops away. - The last batch’s
%carries over as it is, because both numbers are positive.math.ceil()becomesMath.ceil(), and the parentheses change nothing. round(x, 2)becomesMath.round(x * 100) / 100. The second slip would be a digits argument:Math.round()has none and rounds to a whole number, so the cost goes to cents and back.- The total adds the delivery charge to a number. The third slip would be
.toFixed()in this line: it returns a string, and+would join the delivery charge onto it. - Template literals have no format specs, so the port builds three formatters once, above the
output lines:
eurosfor amounts,percentfor shares, andkilosfor exactly one decimal, each with its locale named. - Each
print()becomesconsole.log()with a template literal. Long lines split in two: Python joins two strings side by side, and JavaScript doesn’t, so+joins the halves. The last batch’s weight uses.toFixed(1), because Python’s spec there has no thousands separator.eurosadds the euro sign, so the port’s line drops the one Python writes by hand. node --checkreads the file without running it and prints nothing when there’s no syntax error. The port then prints the same four lines as Python: same beans, same bill.
Here’s the Python planner:
"""Plan tomorrow's roast from the evening's big order."""
import math
ORDER_KG_TEXT = "37.5"
WEIGHT_LOSS = 0.15
DRUM_KG = 12
BAG_G = 250
GREEN_PRICE_PER_KG = 7.4
SHIPPING_EUR = 12
order_kg = float(ORDER_KG_TEXT)
green_kg = order_kg / (1 - WEIGHT_LOSS)
full_batches = int(green_kg // DRUM_KG)
last_batch_kg = green_kg % DRUM_KG
bags = math.ceil(order_kg * 1000 / BAG_G)
cost = round(green_kg * GREEN_PRICE_PER_KG, 2)
total = cost + SHIPPING_EUR
print(f"Green beans: {green_kg:,.1f} kg "
f"(roast loss {WEIGHT_LOSS:.0%})")
print(f"Batches: {full_batches} full + {last_batch_kg:.1f} kg "
f"({last_batch_kg / DRUM_KG:.0%} of a drum)")
print(f"Bags: {bags}")
print(f"Green coffee: €{total:,.2f} with delivery")