# telecoms.roaming-charge Prices a trip abroad against a roaming tariff: which zone the country is in on that date, and what the usage there costs. **The tariff in this package is illustrative. It is not any operator's tariff**, and its prices and dates (including the 2026 price rise in the EUROPE zone) are invented to exercise the calculation. It exists so the function, its vectors and its dated-data handling can be shown working. To bill real customers, publish your own version of this capability with your tariff rows in `data/roaming-tariffs.json`, or add rows under your own tariff name; the code does not change. A tariff is rows of zones. Each row names the countries in the zone (space-separated ISO 3166-1 alpha-2 codes), the currency, and five prices in minor units: a fee per day of use, and prices per MB of data, per minute of calls made, per minute of calls received and per text sent. A daily-pass zone has a daily fee and zero unit prices; a pay-as-you-go zone the opposite. The charge is simply dailyFees = days x dailyFee data = dataMb x dataPerMb calls = callOutMinutes x callOutPerMinute + callInMinutes x callInPerMinute sms = smsOut x smsOut price total = the sum of the four all exact, with no rounding. Minutes are whole minutes already rounded up per call (telecoms.call-rating does per-call rounding), and data is whole MB, so a usage record is priced by one country and one date at a time. Rows are dated with `validFrom` and `validTo` (inclusive; null while in force). The row in force on `onDate` wins, and if two overlap the later `validFrom` wins. A project that installs with `history=current` keeps only the rows still in force; asking such a build about an older date fails with an explanation instead of silently pricing it at today's rates. Home-country use, a country not in any zone of the tariff, an unknown tariff and a date before the tariff's first row are all errors ("no roaming zone"), because pricing unknown usage at zero is how roaming revenue leaks. Other errors: a country that is not two uppercase letters, a malformed or impossible date, and negative usage. What this does not model: fair-use limits inside daily passes, spend caps (see telecoms.data-allowance), and per-country exceptions inside a zone. 1.0.1 fixes Python accepting a trailing newline in country; adds tests.