@stacksjs/defaults 0.70.353 → 0.70.354

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.
@@ -227,7 +227,6 @@ function concreteApiPath(
227
227
  dynamicPages: string[],
228
228
  modelRoutes: string[],
229
229
  ): string {
230
- // eslint-disable-next-line pickier/no-unused-vars
231
230
  const match = (prefix: string) => dynamicPages
232
231
  .find(route => route.startsWith(`${prefix}/`))
233
232
  ?.slice(prefix.length + 1)
@@ -19,6 +19,10 @@ export interface TaxRateRecord {
19
19
  region: TaxRateRegion
20
20
  status: 'active' | 'inactive'
21
21
  isDefault: boolean
22
+ /** Stable identifier application code matches on, independent of `name`. */
23
+ code: string
24
+ /** Whether a qualifying exemption stops this component being charged. */
25
+ exemptible: boolean
22
26
  createdAt: string
23
27
  }
24
28
 
@@ -50,6 +54,11 @@ export function normalizeTaxRateRecord(record: any): TaxRateRecord {
50
54
  ]),
51
55
  status: commerceEnum(commerceValue(record, 'status'), source, 'status', ['active', 'inactive']),
52
56
  isDefault: commerceBoolean(commerceValue(record, 'is_default', 'isDefault'), source, 'is_default'),
57
+ // Optional, both of them: a rate created before these columns existed has
58
+ // neither, and a dashboard that throws on an older row is worse than one
59
+ // that shows it without a badge.
60
+ code: String(commerceValue(record, 'code') ?? ''),
61
+ exemptible: Boolean(commerceValue(record, 'exemptible') ?? false),
53
62
  createdAt: commerceTimestamp(commerceValue(record, 'created_at', 'createdAt'), source),
54
63
  }
55
64
  }
@@ -9,7 +9,7 @@ export interface AuthorInput {
9
9
  avatar: string
10
10
  }
11
11
 
12
- // eslint-disable-next-line pickier/no-unused-vars
12
+ // eslint-disable-next-line
13
13
  export function parseAuthorInput(inputRequest: RequestInstance): { data: AuthorInput } | { message: string } {
14
14
  const data = {
15
15
  name: str(inputRequest.get('name')).trim(),
@@ -10,7 +10,7 @@ export function parsePublished(value: unknown): boolean {
10
10
  return value === true || value === 1 || value === '1' || value === 'true'
11
11
  }
12
12
 
13
- // eslint-disable-next-line pickier/no-unused-vars
13
+ // eslint-disable-next-line
14
14
  export function parsePageInput(inputRequest: RequestInstance): { data: PageInput } | { message: string } {
15
15
  const data = {
16
16
  title: str(inputRequest.get('title')).trim(),
@@ -58,7 +58,6 @@ export default new Action({
58
58
  const { count: _count, ...metadata } = definition
59
59
  return formatDashboardStat(metadata, results[index])
60
60
  })
61
- // eslint-disable-next-line pickier/no-unused-vars
62
61
  const issues = results.flatMap((result, index) => result.status === 'rejected'
63
62
  ? [{
64
63
  source: definitions[index].title,
@@ -111,6 +111,54 @@ export default defineModel({
111
111
  },
112
112
  factory: () => false,
113
113
  },
114
+
115
+ /**
116
+ * A stable name for this component, for code to reference.
117
+ *
118
+ * `name` is what an operator reads and edits in the dashboard, so it is
119
+ * the wrong thing for an application to branch on — renaming "State sales
120
+ * tax" to "Sales tax (CA)" should not change what gets charged. A code is
121
+ * the identifier that survives the rename.
122
+ *
123
+ * Free-form on purpose. What counts as a component differs by
124
+ * jurisdiction: `vat`, `gst`, `excise`, `city`, `eco-fee`.
125
+ */
126
+ code: {
127
+ order: 8,
128
+ fillable: true,
129
+ default: '',
130
+ validation: {
131
+ rule: schema.string().max(64),
132
+ message: {
133
+ max: 'Code must have a maximum of 64 characters',
134
+ },
135
+ },
136
+ factory: faker => faker.helpers.arrayElement(['vat', 'gst', 'sales', 'excise', 'city']),
137
+ },
138
+
139
+ /**
140
+ * Whether a qualifying exemption removes this component.
141
+ *
142
+ * Most places tax in parts, and an exemption usually lifts some of them
143
+ * and not others: groceries escape VAT but not a deposit levy, and a
144
+ * Californian medical cannabis patient is exempt from sales tax while
145
+ * still paying excise and the city's business tax. Modelling tax as one
146
+ * blended number cannot say that, so an app either over-charges the
147
+ * exempt customer or under-collects tax it owes.
148
+ *
149
+ * What *qualifies* is the application's business — a card, a resale
150
+ * certificate, a charity registration. This only records that the
151
+ * component is the kind that can be lifted.
152
+ */
153
+ exemptible: {
154
+ order: 9,
155
+ fillable: true,
156
+ default: false,
157
+ validation: {
158
+ rule: schema.boolean(),
159
+ },
160
+ factory: () => false,
161
+ },
114
162
  },
115
163
 
116
164
  dashboard: {
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.70.353",
5
+ "version": "0.70.354",
6
6
  "description": "A modern Stacks development environment.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.353",
5
+ "version": "0.70.354",
6
6
  "description": "The complete managed Stacks application scaffold, including runtime defaults, AI guidance, editor metadata, and npm-backed project support files.",
7
7
  "author": "Chris Breuer",
8
8
  "license": "MIT",
@@ -15,6 +15,8 @@ const country = state('')
15
15
  const region = state('North America')
16
16
  const status = state<'active' | 'inactive'>('active')
17
17
  const isDefault = state(false)
18
+ const code = state('')
19
+ const exemptible = state(false)
18
20
  let hydrationKey = ''
19
21
 
20
22
  const regions = ['North America', 'South America', 'Europe', 'Asia', 'Africa', 'Oceania', 'Antarctica'] as const
@@ -36,6 +38,8 @@ effect(() => {
36
38
  region.set(current?.region || 'North America')
37
39
  status.set(current?.status || 'active')
38
40
  isDefault.set(current?.isDefault || false)
41
+ code.set(current?.code || '')
42
+ exemptible.set(current?.exemptible || false)
39
43
  })
40
44
 
41
45
  function submit(): void {
@@ -49,6 +53,8 @@ function submit(): void {
49
53
  region: region(),
50
54
  status: status(),
51
55
  isDefault: isDefault(),
56
+ code: code().trim(),
57
+ exemptible: exemptible(),
52
58
  })
53
59
  }
54
60
 
@@ -105,6 +111,11 @@ function errorMessages(): string[] {
105
111
  </select>
106
112
  </label>
107
113
  </div>
114
+ <label class="block">
115
+ <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Code</span>
116
+ <input x-model="code" type="text" placeholder="sales" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" />
117
+ <span class="block mt-1 text-gray-500 text-xs dark:text-neutral-400">What the application matches on. Renaming the rate above does not change what is charged; changing this can.</span>
118
+ </label>
108
119
  <label class="flex gap-3 items-start p-3 border border-gray-200 rounded-lg dark:border-neutral-700">
109
120
  <input x-model="isDefault" type="checkbox" class="mt-0.5 h-4 w-4 text-blue-600 border-gray-300 rounded" />
110
121
  <span>
@@ -112,6 +123,18 @@ function errorMessages(): string[] {
112
123
  <span class="block mt-0.5 text-gray-500 text-xs dark:text-neutral-400">Selecting this clears the default flag from every other rate.</span>
113
124
  </span>
114
125
  </label>
126
+ {{--
127
+ Spelled out rather than labelled "exempt", because the two read
128
+ alike and mean opposite things: this marks the component as one an
129
+ exemption can lift, not one that is currently unpaid.
130
+ --}}
131
+ <label class="flex gap-3 items-start p-3 border border-gray-200 rounded-lg dark:border-neutral-700">
132
+ <input x-model="exemptible" type="checkbox" class="mt-0.5 h-4 w-4 text-blue-600 border-gray-300 rounded" />
133
+ <span>
134
+ <span class="block font-medium text-gray-700 text-sm dark:text-neutral-200">Can be exempted</span>
135
+ <span class="block mt-0.5 text-gray-500 text-xs dark:text-neutral-400">Customers who qualify for an exemption are not charged this component. Leave off for anything owed regardless — an excise or a city levy is usually still due.</span>
136
+ </span>
137
+ </label>
115
138
  </div>
116
139
  </div>
117
140
  <footer class="flex gap-2 justify-end px-6 py-4 bg-gray-50 dark:bg-neutral-900/50 border-gray-200 border-t dark:border-neutral-700">
@@ -16,6 +16,8 @@ interface TaxRateWritePayload {
16
16
  region: string
17
17
  status: 'active' | 'inactive'
18
18
  isDefault: boolean
19
+ code: string
20
+ exemptible: boolean
19
21
  }
20
22
 
21
23
  const emptySummary: TaxRateSummary = { total: 0, active: 0, countries: 0, averageRate: 0, defaultConflicts: 0 }
@@ -136,6 +138,8 @@ async function saveTax(payload: TaxRateWritePayload): Promise<void> {
136
138
  region: payload.region,
137
139
  status: payload.status,
138
140
  isDefault: payload.isDefault,
141
+ code: payload.code,
142
+ exemptible: payload.exemptible,
139
143
  }
140
144
 
141
145
  saving.set(true)
@@ -39,9 +39,17 @@ function formatDate(value: string): string {
39
39
  <template :for="record in records()" :key="record.id">
40
40
  <tr class="align-top">
41
41
  <td class="px-4 py-4">
42
- <div class="flex gap-2 items-center">
42
+ <div class="flex flex-wrap gap-2 items-center">
43
43
  <p class="font-medium text-gray-900 text-sm dark:text-white">{{ record.name }}</p>
44
44
  <span :if="record.isDefault" class="px-2 py-0.5 font-medium text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40 rounded-full">Default</span>
45
+ {{--
46
+ Both badges change what a customer is charged, so they sit
47
+ next to the name rather than in a column someone has to
48
+ scroll to. The code is what application code matches on;
49
+ renaming the rate must not change the bill.
50
+ --}}
51
+ <span :if="record.code" class="px-2 py-0.5 font-mono text-gray-600 text-xs dark:text-neutral-300 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ record.code }}</span>
52
+ <span :if="record.exemptible" class="px-2 py-0.5 font-medium text-amber-700 text-xs dark:text-amber-300 bg-amber-50 dark:bg-amber-950/40 rounded-full" title="Not charged to a customer who qualifies for an exemption">Exemptible</span>
45
53
  </div>
46
54
  <p class="mt-1 text-gray-500 text-xs dark:text-neutral-400">{{ record.type }}</p>
47
55
  </td>