earnrate 0.1.0 → 0.1.1
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
|
@@ -69,7 +69,7 @@ cards:
|
|
|
69
69
|
two-percent: [gas-ev-charging]
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Rule IDs for `activated
|
|
72
|
+
Rule IDs for `activated`, the choice slots for `chosen` and the membership IDs that unlock bonuses (such as `bofa-rewards-premier` for a BofA Rewards tier) are in each card's file. Currencies and their default values are in [`data/currencies.yaml`](data/currencies.yaml). Spending caps fill up as you record purchases from an AI agent or import a statement with `--apply`, and reset with each period.
|
|
73
73
|
|
|
74
74
|
### Merchants earnrate doesn't know
|
|
75
75
|
|
|
@@ -119,7 +119,7 @@ It totals what each card earned against the best card in your wallet for each pu
|
|
|
119
119
|
|
|
120
120
|
## Supported cards
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
57 cards, each modeled from the issuer's own terms and checked weekly against them:
|
|
123
123
|
|
|
124
124
|
- **American Express:** Gold, Platinum, Blue Cash Preferred, Blue Cash Everyday, Blue Business Plus
|
|
125
125
|
- **Chase:** Sapphire Preferred, Sapphire Reserve, Freedom Unlimited, Freedom Flex, Ink Business Cash, Ink Business Preferred, Prime Visa
|
|
@@ -127,7 +127,7 @@ It totals what each card earned against the best card in your wallet for each pu
|
|
|
127
127
|
- **Citi:** Strata Elite, Strata Premier, Double Cash, Custom Cash, My Best Buy Visa, Costco Anywhere Visa (personal and business); AAdvantage MileUp, Platinum Select, Globe, Executive, Business
|
|
128
128
|
- **Capital One:** Venture X, Venture, Savor, Kohl's Card, Kohl's Rewards Visa
|
|
129
129
|
- **Wells Fargo:** Active Cash, Autograph
|
|
130
|
-
- **Bank of America:** Atmos Rewards Ascent, Summit, Business
|
|
130
|
+
- **Bank of America:** Atmos Rewards Ascent, Summit, Business; Customized Cash Rewards
|
|
131
131
|
- **TD Bank:** Target Circle Card, Nordstrom card, Nordstrom Visa
|
|
132
132
|
- **Others:** U.S. Bank Cash+, Bilt Obsidian, SoFi Unlimited 2%
|
|
133
133
|
|
package/data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Every change to card rules, merchants, categories or currencies under `data/`. Bump `data/VERSION` (`YYYY.MM.DD`, plus `.N` for a second release on the same day) and add a section here in the same commit. Each row cites the issuer page the new value came from.
|
|
4
4
|
|
|
5
|
+
## 2026.10.28.2
|
|
6
|
+
|
|
7
|
+
Bank of America Customized Cash Rewards, reviewed by Collin (`verified_by: collin`). Choice options can now be "any online purchase except these categories", and a choice period can be `until_changed` for picks that carry over.
|
|
8
|
+
|
|
9
|
+
| Card | Field | Old → new | Source |
|
|
10
|
+
| --------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| bank-of-america-customized-cash-rewards | new | 3% in a choice category, 2% at grocery stores and wholesale clubs ($2,500 combined a quarter), 1% otherwise; BofA Rewards tiers add 10%–75% | [card page](https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/), [categories](https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/), terms, [BofA Rewards](https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/) |
|
|
12
|
+
|
|
5
13
|
## 2026.10.28.1
|
|
6
14
|
|
|
7
15
|
Collin reviewed the family-cards and offers packets and kept every value as recorded, including the open calls: no Peloton rule on Sapphire Preferred yet, My Best Buy Visa's fee at the top of Citi's $0–59 range, and Amex "as high as" offers at the public figure. All 56 cards are now `verified_by: collin`.
|
package/data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2026.10.28.
|
|
1
|
+
2026.10.28.2
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
id: bank-of-america-customized-cash-rewards
|
|
2
|
+
name: Bank of America Customized Cash Rewards Credit Card
|
|
3
|
+
issuer: bank-of-america
|
|
4
|
+
# Bank of America's terms carry only the Visa and Visa Signature trademark
|
|
5
|
+
# notice, so the network is Visa.
|
|
6
|
+
network: visa
|
|
7
|
+
currency: cash
|
|
8
|
+
last_verified: 2026-10-28
|
|
9
|
+
verified_by: collin
|
|
10
|
+
source_urls:
|
|
11
|
+
- https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/
|
|
12
|
+
- https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
13
|
+
- https://www.bankofamerica.com/credit-cards/terms-and-conditions/?campaignid=4079537&productoffercode=8H&locale=en_US
|
|
14
|
+
- https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
15
|
+
base_rate: 1
|
|
16
|
+
annual_fee: 0
|
|
17
|
+
welcome_offer:
|
|
18
|
+
dollars: 200
|
|
19
|
+
spend: 1000
|
|
20
|
+
months: 3
|
|
21
|
+
note: Online offer; the window is 90 days from account opening, modeled as 3 months. The offer may not be available elsewhere after leaving the page.
|
|
22
|
+
caps:
|
|
23
|
+
- id: three-and-two-percent-combined
|
|
24
|
+
amount: 2500
|
|
25
|
+
period: quarter
|
|
26
|
+
then_rate: 1
|
|
27
|
+
choices:
|
|
28
|
+
# Gas is the default until changed. It can be changed once per calendar
|
|
29
|
+
# month and otherwise carries over.
|
|
30
|
+
- id: three-percent
|
|
31
|
+
pick: 1
|
|
32
|
+
period: until_changed
|
|
33
|
+
default: [gas-ev-charging]
|
|
34
|
+
options:
|
|
35
|
+
gas-ev-charging: [gas, ev_charging]
|
|
36
|
+
# Bank of America also excludes doctors and hospitals, government
|
|
37
|
+
# services and taxes, insurance, schools and other non-retail services,
|
|
38
|
+
# which have no earnrate category.
|
|
39
|
+
online-shopping:
|
|
40
|
+
{ channel: online, exclude: [utilities, shipping, fitness] }
|
|
41
|
+
dining: [dining]
|
|
42
|
+
travel: [travel, transit]
|
|
43
|
+
drug-stores: [drugstore]
|
|
44
|
+
home-improvement-furnishings: [home_improvement, furniture]
|
|
45
|
+
rules:
|
|
46
|
+
- id: three-percent
|
|
47
|
+
match: { choice: three-percent }
|
|
48
|
+
rate: 3
|
|
49
|
+
cap: three-and-two-percent-combined
|
|
50
|
+
note: Gas and EV charging, online shopping, dining, travel, drug stores, or home improvement and furnishings, whichever you picked. Travel includes parking, transit, rideshare and tolls. Online shopping is any purchase paid on a website or app, as reported by the merchant; ordered online but paid in store, in-store mobile wallet and phone or mail orders don't count, and doctors, government, insurance, membership organizations, schools, some utilities and other non-retail services are excluded. The first $2,500 a calendar quarter across the 3% and 2% categories, then 1%.
|
|
51
|
+
- id: two-percent
|
|
52
|
+
match: { categories: [grocery.supermarket, warehouse_club] }
|
|
53
|
+
rate: 2
|
|
54
|
+
cap: three-and-two-percent-combined
|
|
55
|
+
note: Grocery stores, supermarkets, wholesale clubs, and meat and seafood, candy, dairy and bakery stores. Superstores and smaller stores that also sell groceries, like drug stores, are excluded. Shares the $2,500 quarterly cap with the 3% category.
|
|
56
|
+
# BofA Rewards members earn a tier bonus on all cash back: 10% for Member,
|
|
57
|
+
# 25% Preferred Plus, 50% Preferred Honors, 75% Premier.
|
|
58
|
+
- id: three-percent-bofa-rewards-member
|
|
59
|
+
match: { choice: three-percent }
|
|
60
|
+
rate: 3.3
|
|
61
|
+
cap: three-and-two-percent-combined
|
|
62
|
+
requires: { membership: bofa-rewards-member }
|
|
63
|
+
note: 3% plus the 10% BofA Rewards Member bonus.
|
|
64
|
+
- id: two-percent-bofa-rewards-member
|
|
65
|
+
match: { categories: [grocery.supermarket, warehouse_club] }
|
|
66
|
+
rate: 2.2
|
|
67
|
+
cap: three-and-two-percent-combined
|
|
68
|
+
requires: { membership: bofa-rewards-member }
|
|
69
|
+
note: 2% plus the 10% BofA Rewards Member bonus.
|
|
70
|
+
- id: everything-else-bofa-rewards-member
|
|
71
|
+
match: { any: true }
|
|
72
|
+
rate: 1.1
|
|
73
|
+
requires: { membership: bofa-rewards-member }
|
|
74
|
+
note: 1% plus the 10% BofA Rewards Member bonus.
|
|
75
|
+
- id: three-percent-bofa-rewards-preferred-plus
|
|
76
|
+
match: { choice: three-percent }
|
|
77
|
+
rate: 3.75
|
|
78
|
+
cap: three-and-two-percent-combined
|
|
79
|
+
requires: { membership: bofa-rewards-preferred-plus }
|
|
80
|
+
note: 3% plus the 25% BofA Rewards Preferred Plus bonus.
|
|
81
|
+
- id: two-percent-bofa-rewards-preferred-plus
|
|
82
|
+
match: { categories: [grocery.supermarket, warehouse_club] }
|
|
83
|
+
rate: 2.5
|
|
84
|
+
cap: three-and-two-percent-combined
|
|
85
|
+
requires: { membership: bofa-rewards-preferred-plus }
|
|
86
|
+
note: 2% plus the 25% BofA Rewards Preferred Plus bonus.
|
|
87
|
+
- id: everything-else-bofa-rewards-preferred-plus
|
|
88
|
+
match: { any: true }
|
|
89
|
+
rate: 1.25
|
|
90
|
+
requires: { membership: bofa-rewards-preferred-plus }
|
|
91
|
+
note: 1% plus the 25% BofA Rewards Preferred Plus bonus.
|
|
92
|
+
- id: three-percent-bofa-rewards-preferred-honors
|
|
93
|
+
match: { choice: three-percent }
|
|
94
|
+
rate: 4.5
|
|
95
|
+
cap: three-and-two-percent-combined
|
|
96
|
+
requires: { membership: bofa-rewards-preferred-honors }
|
|
97
|
+
note: 3% plus the 50% BofA Rewards Preferred Honors bonus.
|
|
98
|
+
- id: two-percent-bofa-rewards-preferred-honors
|
|
99
|
+
match: { categories: [grocery.supermarket, warehouse_club] }
|
|
100
|
+
rate: 3
|
|
101
|
+
cap: three-and-two-percent-combined
|
|
102
|
+
requires: { membership: bofa-rewards-preferred-honors }
|
|
103
|
+
note: 2% plus the 50% BofA Rewards Preferred Honors bonus.
|
|
104
|
+
- id: everything-else-bofa-rewards-preferred-honors
|
|
105
|
+
match: { any: true }
|
|
106
|
+
rate: 1.5
|
|
107
|
+
requires: { membership: bofa-rewards-preferred-honors }
|
|
108
|
+
note: 1% plus the 50% BofA Rewards Preferred Honors bonus.
|
|
109
|
+
- id: three-percent-bofa-rewards-premier
|
|
110
|
+
match: { choice: three-percent }
|
|
111
|
+
rate: 5.25
|
|
112
|
+
cap: three-and-two-percent-combined
|
|
113
|
+
requires: { membership: bofa-rewards-premier }
|
|
114
|
+
note: 3% plus the 75% BofA Rewards Premier bonus.
|
|
115
|
+
- id: two-percent-bofa-rewards-premier
|
|
116
|
+
match: { categories: [grocery.supermarket, warehouse_club] }
|
|
117
|
+
rate: 3.5
|
|
118
|
+
cap: three-and-two-percent-combined
|
|
119
|
+
requires: { membership: bofa-rewards-premier }
|
|
120
|
+
note: 2% plus the 75% BofA Rewards Premier bonus.
|
|
121
|
+
- id: everything-else-bofa-rewards-premier
|
|
122
|
+
match: { any: true }
|
|
123
|
+
rate: 1.75
|
|
124
|
+
requires: { membership: bofa-rewards-premier }
|
|
125
|
+
note: 1% plus the 75% BofA Rewards Premier bonus.
|
|
126
|
+
# Issuer text backing each rule; `yarn check-sources` checks it weekly.
|
|
127
|
+
evidence:
|
|
128
|
+
- rule: base_rate
|
|
129
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/
|
|
130
|
+
quote: 'Unlimited 1% cash back on all other purchases'
|
|
131
|
+
- rule: three-percent
|
|
132
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
133
|
+
quote: '3% cash back in the category of your choice'
|
|
134
|
+
- rule: three-percent
|
|
135
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
136
|
+
quote: 'You can change it once each calendar month, or make no change and it stays the same.'
|
|
137
|
+
- rule: three-percent
|
|
138
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
139
|
+
quote: 'Until you change your category it will be set to Gas & EV Charging Stations.'
|
|
140
|
+
- rule: three-percent
|
|
141
|
+
url: https://www.bankofamerica.com/credit-cards/terms-and-conditions/?campaignid=4079537&productoffercode=8H&locale=en_US
|
|
142
|
+
quote: 'first $2,500 of combined Net Purchases posted to the account each calendar quarter'
|
|
143
|
+
- rule: three-percent
|
|
144
|
+
url: https://www.bankofamerica.com/credit-cards/terms-and-conditions/?campaignid=4079537&productoffercode=8H&locale=en_US
|
|
145
|
+
quote: 'purchases must be made online via a website or a digital application (an app)'
|
|
146
|
+
- rule: three-percent
|
|
147
|
+
url: https://www.bankofamerica.com/credit-cards/terms-and-conditions/?campaignid=4079537&productoffercode=8H&locale=en_US
|
|
148
|
+
quote: 'doctors and hospitals, government services and taxes, insurances, membership organizations, education/schools, and some utilities'
|
|
149
|
+
- rule: three-percent
|
|
150
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
151
|
+
quote: 'Courier Services (Air and Ground, Freight Forwarders)'
|
|
152
|
+
- rule: three-percent
|
|
153
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
154
|
+
quote: 'Clubs, Country Clubs, Membership (Athletic, Recreation, Sports)'
|
|
155
|
+
- rule: three-percent
|
|
156
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/cash-back-category-choices/
|
|
157
|
+
quote: 'parking, public transit, taxis/ride share'
|
|
158
|
+
- rule: two-percent
|
|
159
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/
|
|
160
|
+
quote: 'Automatic 2% cash back at grocery stores and wholesale clubs'
|
|
161
|
+
- rule: two-percent
|
|
162
|
+
url: https://www.bankofamerica.com/credit-cards/terms-and-conditions/?campaignid=4079537&productoffercode=8H&locale=en_US
|
|
163
|
+
quote: 'Excluded from this Bonus Category are superstores and smaller stores (like drug stores)'
|
|
164
|
+
- rule: three-percent-bofa-rewards-member
|
|
165
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
166
|
+
quote: 'a $100 purchase that earns 3% ($3.00) will actually earn $3.30'
|
|
167
|
+
- rule: two-percent-bofa-rewards-member
|
|
168
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
169
|
+
quote: 'bonus of 10% for the Member tier'
|
|
170
|
+
- rule: everything-else-bofa-rewards-member
|
|
171
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
172
|
+
quote: 'applied after all base and bonus cash rewards have been calculated on a purchase'
|
|
173
|
+
- rule: three-percent-bofa-rewards-preferred-plus
|
|
174
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
175
|
+
quote: 'will actually earn $3.30, $3.75, $4.50 or $5.25 based on your tier'
|
|
176
|
+
- rule: two-percent-bofa-rewards-preferred-plus
|
|
177
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
178
|
+
quote: '25% for the Preferred Plus tier'
|
|
179
|
+
- rule: everything-else-bofa-rewards-preferred-plus
|
|
180
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
181
|
+
quote: '25% for the Preferred Plus tier'
|
|
182
|
+
- rule: three-percent-bofa-rewards-preferred-honors
|
|
183
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
184
|
+
quote: 'will actually earn $3.30, $3.75, $4.50 or $5.25 based on your tier'
|
|
185
|
+
- rule: two-percent-bofa-rewards-preferred-honors
|
|
186
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
187
|
+
quote: '50% for the Preferred Honors tier'
|
|
188
|
+
- rule: everything-else-bofa-rewards-preferred-honors
|
|
189
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
190
|
+
quote: '50% for the Preferred Honors tier'
|
|
191
|
+
- rule: three-percent-bofa-rewards-premier
|
|
192
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
193
|
+
quote: 'will actually earn $3.30, $3.75, $4.50 or $5.25 based on your tier'
|
|
194
|
+
- rule: two-percent-bofa-rewards-premier
|
|
195
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
196
|
+
quote: 'or 75% for the Premier tier'
|
|
197
|
+
- rule: everything-else-bofa-rewards-premier
|
|
198
|
+
url: https://www.bankofamerica.com/bofa-rewards/increasing-bofa-rewards-with-credit-cards/
|
|
199
|
+
quote: 'or 75% for the Premier tier'
|
|
200
|
+
- rule: annual_fee
|
|
201
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/
|
|
202
|
+
quote: 'Annual Fee $0'
|
|
203
|
+
- rule: welcome_offer
|
|
204
|
+
url: https://www.bankofamerica.com/credit-cards/products/cash-back-credit-card/
|
|
205
|
+
quote: 'Online $200 cash rewards bonus after making at least $1,000 in purchases in the first 90 days'
|
|
206
|
+
todo:
|
|
207
|
+
- New accounts earn 6% in the choice category for the first year (an extra 3%, inside the same $2,500 quarterly cap, with no BofA Rewards bonus on the extra 3%). earnrate can't see when an account was opened, so this isn't modeled.
|
|
208
|
+
- 'The BofA Rewards rules use proposed membership ids: bofa-rewards-member, bofa-rewards-preferred-plus, bofa-rewards-preferred-honors and bofa-rewards-premier. Cardholders who joined Preferred Rewards before May 26, 2026 may have an "extended card benefit" that Bank of America doesn''t define.'
|
|
209
|
+
- With a BofA Rewards tier, a purchase that crosses the $2,500 cap counts the part past the cap at 1% instead of the tier's boosted base rate, so it's slightly understated.
|
|
210
|
+
- "Online shopping counts any online purchase earnrate can't place in an excluded category, including unknown merchants. Bank of America also excludes doctors, government, insurance, schools and other non-retail services, which earnrate can't tell apart."
|
package/dist/data/integrity.js
CHANGED
|
@@ -106,7 +106,10 @@ function cardProblems(card, catalog, merchantIds) {
|
|
|
106
106
|
problems.push(`${where} choice ${choice.id}: default '${d}' is not an option`);
|
|
107
107
|
}
|
|
108
108
|
for (const [option, covered] of options) {
|
|
109
|
-
for (const c of
|
|
109
|
+
for (const c of [
|
|
110
|
+
...covered.categories,
|
|
111
|
+
...(covered.online?.exclude ?? []),
|
|
112
|
+
])
|
|
110
113
|
checkCategory(c, `choice ${choice.id}.${option}`);
|
|
111
114
|
for (const m of covered.merchants)
|
|
112
115
|
checkMerchant(m, `choice ${choice.id}.${option}`);
|
package/dist/engine/evaluate.js
CHANGED
|
@@ -30,6 +30,7 @@ export function pickedCategories(card, held, date) {
|
|
|
30
30
|
let picks = chosen?.picks[choice.id];
|
|
31
31
|
if (picks &&
|
|
32
32
|
chosen &&
|
|
33
|
+
choice.period !== 'until_changed' &&
|
|
33
34
|
chosen.period !== periodKey(choice.period, date, null)) {
|
|
34
35
|
staleChoice = chosen.period;
|
|
35
36
|
picks = undefined;
|
|
@@ -41,6 +42,7 @@ export function pickedCategories(card, held, date) {
|
|
|
41
42
|
picked.set(choice.id, {
|
|
42
43
|
categories: options.flatMap((o) => o.categories),
|
|
43
44
|
merchants: options.flatMap((o) => o.merchants),
|
|
45
|
+
online: options.flatMap((o) => (o.online ? [o.online] : [])),
|
|
44
46
|
});
|
|
45
47
|
}
|
|
46
48
|
return { picked, staleChoice };
|
|
@@ -60,7 +62,11 @@ function applicability(rule, ctx, held, picked) {
|
|
|
60
62
|
const covered = picked.get(match.choice);
|
|
61
63
|
const merchantPicked = ctx.merchantId !== null &&
|
|
62
64
|
(covered?.merchants.includes(ctx.merchantId) ?? false);
|
|
63
|
-
|
|
65
|
+
const onlinePicked = ctx.channel === 'online' &&
|
|
66
|
+
(covered?.online.some((o) => !inCategory(o.exclude)) ?? false);
|
|
67
|
+
if (!merchantPicked &&
|
|
68
|
+
!onlinePicked &&
|
|
69
|
+
!inCategory(covered?.categories ?? []))
|
|
64
70
|
return 'no';
|
|
65
71
|
}
|
|
66
72
|
if (exclude?.categories && inCategory(exclude.categories))
|
package/dist/schema/card.js
CHANGED
|
@@ -75,21 +75,40 @@ export const WelcomeOfferSchema = z
|
|
|
75
75
|
export const ChoiceSchema = z.strictObject({
|
|
76
76
|
id: KebabId,
|
|
77
77
|
pick: z.number().int().positive(),
|
|
78
|
-
|
|
78
|
+
// `until_changed`: the pick carries over until the cardholder changes it,
|
|
79
|
+
// so a pick made in an earlier period is still current.
|
|
80
|
+
period: z.enum(['month', 'quarter', 'calendar_year', 'until_changed']),
|
|
79
81
|
// Option ids that apply when the wallet hasn't picked, e.g. Bilt's dining.
|
|
80
82
|
default: z.array(KebabId).min(1).optional(),
|
|
81
|
-
// Option id → what that option covers: a list of categories
|
|
82
|
-
// issuer publishes the only qualifying stores, `{ merchants: [...] }
|
|
83
|
+
// Option id → what that option covers: a list of categories; or, when the
|
|
84
|
+
// issuer publishes the only qualifying stores, `{ merchants: [...] }`; or,
|
|
85
|
+
// for "online shopping" picks, `{ channel: online, exclude: [...] }`, any
|
|
86
|
+
// online purchase outside the excluded categories.
|
|
83
87
|
options: z.record(KebabId, z.union([
|
|
84
88
|
z
|
|
85
89
|
.array(CategoryId)
|
|
86
90
|
.min(1)
|
|
87
|
-
.transform((categories) => ({
|
|
91
|
+
.transform((categories) => ({
|
|
92
|
+
categories,
|
|
93
|
+
merchants: [],
|
|
94
|
+
online: null,
|
|
95
|
+
})),
|
|
88
96
|
z
|
|
89
97
|
.strictObject({ merchants: z.array(KebabId).min(1) })
|
|
90
98
|
.transform(({ merchants }) => ({
|
|
91
99
|
categories: [],
|
|
92
100
|
merchants,
|
|
101
|
+
online: null,
|
|
102
|
+
})),
|
|
103
|
+
z
|
|
104
|
+
.strictObject({
|
|
105
|
+
channel: z.literal('online'),
|
|
106
|
+
exclude: z.array(CategoryId).default([]),
|
|
107
|
+
})
|
|
108
|
+
.transform(({ exclude }) => ({
|
|
109
|
+
categories: [],
|
|
110
|
+
merchants: [],
|
|
111
|
+
online: { exclude },
|
|
93
112
|
})),
|
|
94
113
|
])),
|
|
95
114
|
});
|