Currency and location
We don't know where a customer is, or what money they want to pay in
Reads the clues it has (number, language, delivery place, a dropped pin), settles the currency by fixed rules, and asks only when the answer is really in doubt
The situation
A quotation needs two things a parts list almost never carries: where the parts are going, and what money the customer wants to pay in. WhatsApp tells us very little. With each message we get the customer's phone number, the name on their WhatsApp profile, and what they typed or sent. We do not get their phone's language, their time zone, their IP address or their country.
Asking every customer "which currency?" and "where to?" is friction, and customers who are asked things they have already said stop answering. Guessing wrong is worse: a quote in the wrong currency has to be redone.
What the app does
It asks for both up front, reads every clue it has, settles what the clues settle, and asks only what is really in doubt.
Up front. When a customer opens a new sales inquiry, the first prompt asks for the parts list and "where the parts are to be delivered (town and country, or drop a pin) and your currency: GBP, EUR or USD".
The clues it reads:
The phone number: its country, and whether that country is in Europe.
The language they write in: only when a message is wholly in the number's own language. One English word turns this off, because a European writing English may well be living in the UK.
Where it ships: a country or a town named in their words ("delivery to Košice"). A town the rules cannot place is placed by the assistant, once per inquiry.
A dropped pin: a WhatsApp location, placed in its country on our own server (nothing is sent to a map service).
A currency they name: in words, a symbol (€, £, $), or a tap on the currency buttons.
The state machine. The quote currency is always in one of six states: Unknown (where every request starts), Asking (the three currency buttons are on the customer's phone), Open (they typed past the buttons, so the default is said with its alternative), or settled in GBP, EUR or USD. The rules that move it, tried in this order:
# | If | Then |
|---|---|---|
1 | They named a currency | That currency, never questioned |
2 | UK number | GBP, whatever they write |
3 | Number from outside Europe | The number's own currency (USD for most of the world, GBP for the Commonwealth set) |
4 | European number, message wholly in its own language | The number's own currency |
5 | European number shipping outside the UK (named, placed, or pinned) | The number's own currency |
6 | Anything else: a European number writing English, nothing abroad | Ask once, with three buttons; the reply names no currency before the buttons arrive |
An interactive version, with the transition table and a customer you can try, is the "Quote Currency States" page.
Where it ships. If the customer has not said, a card asks once, suggesting the number's country as the answer, so confirming costs one tap. A place in their words or a pin answers it without the card.
An example
A Slovak number writes in English, with delivery to Košice. Rule 5 applies: the reply says "…DHL Express shipping to Košice for you in EUR" and no buttons are sent. The same number writing only "please quote the attached" gets rule 6: the reply says "…in the currency you choose below", and the buttons follow.
What it does not do yet
A town written in lower case ("going to leeds") is not placed before the first reply; the buttons may be sent, and the where-to-ship card reads it afterwards.
A pin within a few kilometres of a border can be placed on the wrong side (the outlines are 1:50 million scale).
Turkey and Russia count as outside Europe.
The tests that hold it
tests/unit/test_quote_terms.py, test_written_language.py, test_ships_abroad.py, test_dropped_pin.py, test_inquiry_prompt_copy.py.
Six states. Every request starts at Unknown. GBP, EUR and USD are settled — the quote is in that money and the assistant says so. Asking means the three buttons are on the customer's phone. Open means they typed past the buttons, so the default is said with its alternative and never asked again. The lit path is the customer picked below.
Pick what we know about them. The answer is not worked out here — it was worked out by the app itself, once for each of the 360 combinations, and looked up.
European number shipping outside the UK — rule ships_abroad
The first one that matches settles it. These names are the app's own (app/currency_learning.RULES), and every month each rule is scored against what the customer then did.
| # | if | then | rule |
|---|---|---|---|
| 1 | They named a currency | USD | named |
| 2 | UK number | GBP | uk_number |
| 3 | Number from outside Europe | USD | outside_europe |
| 4 | European number, wholly its own language | EUR | own_language |
| 5 | European number shipping outside the UK | EUR | ships_abroad |
| 6 | Asked: European number, English, nothing abroad | ask, once, with three buttons | asked |
This is the whole of it. No device language, no time zone, no IP address, no country — the number is the only technical signal on every message, which is why the rules above have to work as hard as they do.
| From / WaId | Their phone number, with the country code | used — the default currency, whether the number is European, and the customer's location on the sheet |
| ProfileName | The name on their WhatsApp profile | used — the name on the rep's card and on the sheet |
| Body | What they typed | used — the language they write, a currency they name, where it ships |
| Latitude, Longitude | A location pin, when they drop one | used — placed in its country on our own server, nothing sent to a map service; it settles the currency by rule 5 |
| Referral… | The ad or link they came from | not used — no ads running |
| Language, time zone, IP | Not sent by WhatsApp at all | not available |
