This commit is contained in:
parent
320af54b3d
commit
4666c1995f
14 changed files with 876 additions and 346 deletions
|
|
@ -228,23 +228,55 @@ export inline constexpr std::string_view kPayCrypto = "crypto";
|
|||
// "quantity=99999999999" before any of that arithmetic runs.
|
||||
export inline constexpr std::int64_t kMaxQuantity = 99;
|
||||
|
||||
// What a buyer in a NoSaleCountries destination is told. Stated as a standing
|
||||
// fact about where the shop sells, not as an apology or an outage: someone
|
||||
// there should close the tab rather than retry tomorrow or hunt for a
|
||||
// workaround. The reason itself (insurance territory) is on the terms page —
|
||||
// a form field is the wrong place for it.
|
||||
// What a buyer outside Money::ShippableCountries is told.
|
||||
//
|
||||
// One definition, three renderings: this error, the note above the form, and
|
||||
// the on-page total preview, so the page can never encourage an order the
|
||||
// server will refuse.
|
||||
export inline constexpr std::string_view kNoSaleMessage =
|
||||
"Catcrafts does not sell or ship to the United States or Canada.";
|
||||
// One sentence for every refusal that is not sanctions, because from the buyer's
|
||||
// side they are all one fact: their country has not been cleared. Merging them is
|
||||
// also the honest shape — the old split between "we are not registered there",
|
||||
// "the handset would not work there" and "our insurer excludes it" described
|
||||
// Catcrafts' internal reasons, not anything the buyer can act on.
|
||||
//
|
||||
// Names the reason as regulatory rather than commercial, because a Dutch shop
|
||||
// that plainly posts worldwide would otherwise read as arbitrary, or worse as
|
||||
// quietly declining someone. The truth is duller and better: selling a phone into
|
||||
// a country means meeting that country's rules first, and doing it in the wrong
|
||||
// order is the illegal part.
|
||||
//
|
||||
// No date is promised. Which country comes next depends on which one people ask
|
||||
// for, and an invented timeline is worse than none — so the address is the point
|
||||
// of the last clause.
|
||||
//
|
||||
// One definition, three renderings: this error, the note above the form, and the
|
||||
// on-page total preview, so the page can never encourage an order the server
|
||||
// will refuse.
|
||||
export inline constexpr std::string_view kRegulatoryMessage =
|
||||
"Catcrafts can't ship there. Selling a phone into a country means meeting "
|
||||
"that country's own rules first — recycling schemes, radio approval, import "
|
||||
"registration — and only a few are cleared so far. Email "
|
||||
"orders@catcrafts.net if you would like yours looked at next.";
|
||||
|
||||
// The sanctions refusal, in different words on purpose: kNoSaleMessage states
|
||||
// a choice, this states a prohibition. Naming the reason here rather than only
|
||||
// on the terms page — unlike the insurance one — because "sanctions" is the
|
||||
// whole answer: nothing about the shop could change it, and a buyer told only
|
||||
// "no" would rightly ask why.
|
||||
// The standing note above the buy form, and the one place the policy is stated
|
||||
// POSITIVELY. With an allow-list that is the only useful phrasing: "we ship to
|
||||
// these five" tells a visitor in one glance what "we cannot ship to two hundred
|
||||
// others" never would, and it stops someone filling in a whole address before
|
||||
// the field error tells them no.
|
||||
//
|
||||
// Prose rather than generated from Money::ShippableCountries because that array
|
||||
// holds ISO codes and a buyer should not have to decode "NZ". The duplication is
|
||||
// real, so ShouldComputeMoney asserts the array's LENGTH — add a country and that
|
||||
// test fails, pointing here. Update both or neither.
|
||||
export inline constexpr std::string_view kShipsToMessage =
|
||||
"Catcrafts currently ships to the Netherlands, Switzerland, Serbia, "
|
||||
"Montenegro, Albania, Kosovo, Georgia, Australia, Hong Kong and "
|
||||
"Singapore. Other "
|
||||
"countries are being worked through one at a time; email "
|
||||
"orders@catcrafts.net if you would like yours looked at next.";
|
||||
|
||||
// The sanctions refusal, in different words on purpose: kRegulatoryMessage
|
||||
// describes paperwork that could be done, this states a prohibition that cannot.
|
||||
// Naming the reason here rather than only on the terms page, because "sanctions"
|
||||
// is the whole answer: nothing about the shop could change it, and a buyer told
|
||||
// only "no" would rightly ask why.
|
||||
export inline constexpr std::string_view kSanctionsMessage =
|
||||
"Catcrafts cannot sell or ship to Russia, Belarus or North Korea: "
|
||||
"EU sanctions prohibit exporting consumer electronics there.";
|
||||
|
|
@ -365,14 +397,15 @@ export CheckoutResult ValidateCheckout(const Fields& f) {
|
|||
} else if (!LooksLikeCountryCode(country)) {
|
||||
r.errors.push_back({ "country", "Country must be a two-letter code." });
|
||||
} else if (Money::IsSanctioned(r.value.country)) {
|
||||
// Checked before the general refusal because SellsTo denies both and
|
||||
// the words differ: this one says the law forbids the sale, not that
|
||||
// the shop chose not to make it.
|
||||
// Sanctions are checked first because both gates deny and only the words
|
||||
// differ: this one says the law forbids the sale, not that the shop has
|
||||
// not got round to that country yet.
|
||||
r.errors.push_back({ "country", std::string(kSanctionsMessage) });
|
||||
} else if (!Money::SellsTo(r.value.country)) {
|
||||
// The refusal happens here, in validation, rather than at the payment
|
||||
// step: no order record, no payment link, nothing charged to undo.
|
||||
r.errors.push_back({ "country", std::string(kNoSaleMessage) });
|
||||
} else if (!Money::ShipsTo(r.value.country)) {
|
||||
// Everything not on the shipping list. The refusal happens here, in
|
||||
// validation, rather than at the payment step: no order record, no
|
||||
// payment link, nothing charged to undo.
|
||||
r.errors.push_back({ "country", std::string(kRegulatoryMessage) });
|
||||
}
|
||||
|
||||
// Colour: shape only (slug-ish, bounded). Whether it names a variant that
|
||||
|
|
|
|||
Loading…
Reference in a new issue