@fluid-app/fluid-cli-localization 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -70,6 +70,7 @@ and agents use the commands instead.
70
70
  | `list` | The countries the company sells in. |
71
71
  | `plan <iso> --mode <m>` | What `open` would send, with language and agreement status, warehouses and the launch checklist. Read-only. |
72
72
  | `open <iso> --mode <m>` | Adds the country, seeded from the atlas: currency, mode, tax name, tax-inclusive pricing, tax invoices, 3-D Secure, legal settings, address layout and payment method order. |
73
+ | `update <iso>` | Changes only the settings you name on an open country (`--set key=value`, `--warehouse-id`, `--business-id`, `--entity-registered`, `--settlement-currency`), e.g. its entity. Nested settings merge into the current ones. |
73
74
  | `prices <iso>` | Converts each variant's price from another country (`--from-country`, default `US`) into this country's currency. A dry run unless `--write`. |
74
75
  | `languages <iso>` | The market's major languages and whether each is on, with the `fluid translations enable` command for the ones that are off. |
75
76
  | `agreements <iso>` | Atlas agreements matched to the company's by title. `--create` adds the missing ones; `--translate` writes the atlas translations onto ones already on the country. |
@@ -79,7 +80,8 @@ and agents use the commands instead.
79
80
  `--settlement-currency` for what the atlas can't know, and `--set key=value`
80
81
  to override a seeded value. It skips Fluid's generic country agreements and
81
82
  forms (pass `--legacy-defaults` to keep them), and changes nothing on an open
82
- country unless you pass `--reseed`.
83
+ country unless you pass `--reseed`, which writes every atlas value over it.
84
+ To change a few fields on an open country, use `update`.
83
85
 
84
86
  ### Converting prices
85
87
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/countries/commands.ts","../src/translations/commands.ts","../src/index.ts"],"mappings":";;;;iBA6JgB,yBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;iBC/DS,4BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;;AD2DP;;;;;cE9IM,MAAA,EAAQ,WAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/countries/commands.ts","../src/translations/commands.ts","../src/index.ts"],"mappings":";;;;iBAiKgB,yBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;iBCnES,4BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;;AD+DP;;;;;cElJM,MAAA,EAAQ,WAAA"}
package/dist/index.mjs CHANGED
@@ -1087,7 +1087,7 @@ function companyCountryFromAtlas(atlas, options) {
1087
1087
  };
1088
1088
  const tax = atlas.taxSettings;
1089
1089
  if (tax) {
1090
- if (typeof tax.taxName === "string" && tax.taxName !== "") body["tax_name"] = tax.taxName;
1090
+ if (tax.taxInclusive === true && typeof tax.taxName === "string" && tax.taxName !== "") body["tax_name"] = tax.taxName;
1091
1091
  if (typeof tax.taxInclusive === "boolean") body["tax_inclusive_pricing"] = tax.taxInclusive;
1092
1092
  if (typeof tax.invoiceRequired === "boolean") body["tax_invoice_required"] = tax.invoiceRequired;
1093
1093
  }
@@ -1120,6 +1120,18 @@ function applyOverrides(body, overrides) {
1120
1120
  function isPlainObject(value) {
1121
1121
  return typeof value === "object" && value !== null && !Array.isArray(value);
1122
1122
  }
1123
+ /**
1124
+ * The body for changing named fields on an open country, leaving the rest as
1125
+ * they are. A nested override (`legal_settings.x=…`) merges into the
1126
+ * country's current object, so its other keys are kept.
1127
+ */
1128
+ function partialCountryUpdate(current, overrides) {
1129
+ const values = current;
1130
+ if (Object.keys(overrides).length === 0) throw new LocalizationError("Name at least one setting to change, e.g. --set entity_id=12 or --settlement-currency USD.");
1131
+ const base = {};
1132
+ for (const key of Object.keys(overrides)) if (isPlainObject(values[key])) base[key] = values[key];
1133
+ return applyOverrides(base, overrides);
1134
+ }
1123
1135
  //#endregion
1124
1136
  //#region src/countries/status.ts
1125
1137
  function same(a, b) {
@@ -1141,10 +1153,15 @@ function settingsChecks(atlas, cc) {
1141
1153
  });
1142
1154
  const tax = atlas.taxSettings;
1143
1155
  if (tax) {
1144
- checks.push({
1156
+ const inclusive = cc.tax_inclusive_pricing === true;
1157
+ checks.push(inclusive ? {
1145
1158
  id: "tax_name",
1146
1159
  ok: same(cc.tax_name, tax.taxName),
1147
1160
  detail: `Tax name ${cc.tax_name ?? "unset"}; the atlas says ${tax.taxName}.`
1161
+ } : {
1162
+ id: "tax_name",
1163
+ ok: true,
1164
+ detail: `No tax name needed: prices are tax-exclusive, so tax is added at checkout (Fluid stores a tax name only with tax-inclusive pricing).`
1148
1165
  });
1149
1166
  checks.push({
1150
1167
  id: "tax_inclusive_pricing",
@@ -1590,14 +1607,17 @@ async function walkCountry(deps, options = {}) {
1590
1607
  }
1591
1608
  ctx.note(`"${value}" isn't a three-letter currency code, such as EUR.`);
1592
1609
  }
1593
- const taxName = String(seeded["tax_name"] ?? "");
1594
- if (!await keep("Tax name", taxName || "(none)")) overrides["tax_name"] = (await ctx.ask({
1595
- message: "Tax name",
1596
- kind: "text",
1597
- current: taxName
1598
- })).trim() || taxName;
1599
- const inclusive = seeded["tax_inclusive_pricing"] === true;
1600
- if (!await keep("Prices include tax", inclusive ? "yes" : "no")) overrides["tax_inclusive_pricing"] = !inclusive;
1610
+ const seededInclusive = seeded["tax_inclusive_pricing"] === true;
1611
+ if (!await keep("Prices include tax", seededInclusive ? "yes" : "no")) overrides["tax_inclusive_pricing"] = !seededInclusive;
1612
+ if ((overrides["tax_inclusive_pricing"] ?? seededInclusive) === true) {
1613
+ const taxName = String(seeded["tax_name"] ?? draft.atlas?.taxSettings?.taxName ?? "");
1614
+ if (!await keep("Tax name", taxName || "(none)")) overrides["tax_name"] = (await ctx.ask({
1615
+ message: "Tax name",
1616
+ kind: "text",
1617
+ current: taxName
1618
+ })).trim() || taxName;
1619
+ else if (taxName && seeded["tax_name"] === void 0) overrides["tax_name"] = taxName;
1620
+ } else delete overrides["tax_name"];
1601
1621
  const threeDs = seeded["requires_3ds"] === true;
1602
1622
  if (!await keep("Card payments need 3-D Secure", threeDs ? "yes" : "no")) overrides["requires_3ds"] = !threeDs;
1603
1623
  const order = seeded["payment_method_priority"] ?? [];
@@ -3410,6 +3430,24 @@ function registerCountriesCommands(parent, ctx) {
3410
3430
  companyCountry: created
3411
3431
  });
3412
3432
  }));
3433
+ parent.command("update <iso>").description("Change named settings on an open country and leave the rest as they are, e.g. its entity or settlement currency (changes live config)").option("--warehouse-id <id>", "The warehouse that fulfills orders for the country").option("--business-id <id>", "The local tax or business registration number").option("--entity-registered", "The company has a legally registered local entity").option("--settlement-currency <code>", "Settle in this currency, e.g. USD").option("--set <key=value>", "Set a company country field, e.g. entity_id=12 or legal_settings.cooling_off_period_days=30 (repeatable)", collect, []).option("--yes", "Confirm without a prompt", false).action((iso, opts) => run(async () => {
3434
+ const api = await client$1(ctx);
3435
+ const countryCode = countryCodeOf(iso);
3436
+ const existing = await requireCompanyCountry(api, countryCode);
3437
+ const body = partialCountryUpdate(existing, {
3438
+ ...opts.warehouseId ? { warehouse_id: positiveInt(opts.warehouseId, "--warehouse-id") } : {},
3439
+ ...opts.businessId ? { tax_business_id: opts.businessId } : {},
3440
+ ...opts.entityRegistered ? { entity_legally_registered: true } : {},
3441
+ ...opts.settlementCurrency ? { settlement_currency: opts.settlementCurrency.toUpperCase() } : {},
3442
+ ...parseSettingAssignments(opts.set)
3443
+ });
3444
+ await confirmChange(`Change ${Object.keys(body).join(", ")} on ${countryCode}?`, opts.yes);
3445
+ ctx.output({
3446
+ country: countryCode,
3447
+ updated: Object.keys(body),
3448
+ companyCountry: await updateCompanyCountry(api, existing.id, body, existing.revision)
3449
+ });
3450
+ }));
3413
3451
  parent.command("languages <iso>").description("Compare the market's major languages with the company's; `fluid translations enable` turns the missing ones on").action((iso) => run(async () => {
3414
3452
  const api = await client$1(ctx);
3415
3453
  const { countryCode, atlas } = await requireAtlas(api, iso);
@@ -3953,7 +3991,7 @@ function registerTranslationsCommands(parent, ctx) {
3953
3991
  */
3954
3992
  const plugin = {
3955
3993
  name: "@fluid-app/fluid-cli-localization",
3956
- version: "0.1.0",
3994
+ version: "0.1.1",
3957
3995
  register(ctx) {
3958
3996
  ctx.program.addCommand(createDomainCommand("countries", "Open a country from Fluid's Country Atlas: settings, prices in its currency, agreements, and a status check", registerCountriesCommands));
3959
3997
  ctx.program.addCommand(createDomainCommand("translations", "Add a language and translate what shoppers see: storefront, navigation, theme, agreements, and more", registerTranslationsCommands));