1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetCustomerTaxIdsById } from "@distilled.cloud/stripe/stripe";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9import { isMissingStripeResource } from "@/Stripe/missing.ts";
10
11const { test } = Test.make({ providers: Stripe.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const isMissing = isMissingStripeResource;
19
20const waitUntilGone = (customer: string, id: string) =>
21 GetCustomerTaxIdsById({ customer, id }).pipe(
22 Effect.as("found" as const),
23 Effect.catchIf(isMissing, () => Effect.succeed("gone" as const)),
24 Effect.repeat({
25 schedule: Schedule.spaced("1 second"),
26 until: (status) => status === "gone",
27 times: 10,
28 }),
29 );
30
31test.provider(
32 "create, update, and delete a customer tax id",
33 (stack) =>
34 Effect.gen(function* () {
35 yield* stack.destroy();
36
37 const created = yield* stack.deploy(
38 Effect.gen(function* () {
39 const customer = yield* Stripe.Customer("TaxIdLifecycleCustomer", {
40 email: "alchemy.taxid.lifecycle@example.com",
41 name: "Alchemy Tax ID Lifecycle",
42 });
43 const taxId = yield* Stripe.CustomerTaxId("LifecycleVat", {
44 customer: customer.id,
45 type: "eu_vat",
46 value: "DE123456789",
47 });
48 return { customer, taxId };
49 }),
50 );
51
52 expect(created.taxId.id).toMatch(/^txi_/);
53 expect(created.taxId.customer).toEqual(created.customer.id);
54 expect(created.taxId.type).toEqual("eu_vat");
55 expect(created.taxId.value).toEqual("DE123456789");
56 expect(created.taxId.country).toEqual("DE");
57 expect(created.taxId.livemode).toEqual(false);
58 expect(created.taxId.created).toEqual(expect.any(Number));
59
60 const fetched = yield* GetCustomerTaxIdsById({
61 customer: created.taxId.customer,
62 id: created.taxId.id,
63 });
64 expect(fetched.id).toEqual(created.taxId.id);
65 expect(fetched.type).toEqual("eu_vat");
66 expect(fetched.value).toEqual("DE123456789");
67 expect(fetched.livemode).toEqual(false);
68
69 const updated = yield* stack.deploy(
70 Effect.gen(function* () {
71 const customer = yield* Stripe.Customer("TaxIdLifecycleCustomer", {
72 email: "alchemy.taxid.lifecycle@example.com",
73 name: "Alchemy Tax ID Lifecycle",
74 });
75 const taxId = yield* Stripe.CustomerTaxId("LifecycleVat", {
76 customer: customer.id,
77 type: "eu_vat",
78 value: "DE123456789",
79 });
80 return { customer, taxId };
81 }),
82 );
83
84 expect(updated.taxId.id).toEqual(created.taxId.id);
85 expect(updated.taxId.customer).toEqual(created.customer.id);
86 expect(updated.taxId.type).toEqual("eu_vat");
87 expect(updated.taxId.value).toEqual("DE123456789");
88
89 yield* stack.destroy();
90
91 const gone = yield* waitUntilGone(
92 created.taxId.customer,
93 created.taxId.id,
94 );
95 expect(gone).toEqual("gone");
96 }).pipe(logLevel),
97 {
98 tags: [
99 "provider:stripe",
100 "provider:stripe:customer",
101 "provider:stripe:customertaxid",
102 "live",
103 ],
104 timeout: 120_000,
105 },
106);
107
108test.provider(
109 "list enumerates the deployed customer tax id",
110 (stack) =>
111 Effect.gen(function* () {
112 yield* stack.destroy();
113
114 const deployed = yield* stack.deploy(
115 Effect.gen(function* () {
116 const customer = yield* Stripe.Customer("TaxIdListCustomer", {
117 email: "alchemy.taxid.list@example.com",
118 name: "Alchemy Tax ID List",
119 });
120 const taxId = yield* Stripe.CustomerTaxId("ListVat", {
121 customer: customer.id,
122 type: "eu_vat",
123 value: "ATU12345678",
124 });
125 return { customer, taxId };
126 }),
127 );
128
129 const provider = yield* Provider.findProvider(Stripe.CustomerTaxId);
130 const all = yield* provider.list();
131 const found = all.find((taxId) => taxId.id === deployed.taxId.id);
132 expect(found).toBeDefined();
133 expect(found?.customer).toEqual(deployed.customer.id);
134 expect(found?.type).toEqual("eu_vat");
135 expect(found?.value).toEqual("ATU12345678");
136
137 yield* stack.destroy();
138
139 const gone = yield* waitUntilGone(
140 deployed.taxId.customer,
141 deployed.taxId.id,
142 );
143 expect(gone).toEqual("gone");
144
145 const after = yield* provider.list();
146 expect(
147 after.find((taxId) => taxId.id === deployed.taxId.id),
148 ).toBeUndefined();
149 }).pipe(logLevel),
150 {
151 tags: [
152 "provider:stripe",
153 "provider:stripe:customer",
154 "provider:stripe:customertaxid",
155 "live",
156 ],
157 timeout: 120_000,
158 },
159);
160
161test.provider(
162 "replace when the tax id value changes",
163 (stack) =>
164 Effect.gen(function* () {
165 yield* stack.destroy();
166
167 const created = yield* stack.deploy(
168 Effect.gen(function* () {
169 const customer = yield* Stripe.Customer("TaxIdReplaceCustomer", {
170 email: "alchemy.taxid.replace@example.com",
171 name: "Alchemy Tax ID Replace",
172 });
173 const taxId = yield* Stripe.CustomerTaxId("ReplaceVat", {
174 customer: customer.id,
175 type: "eu_vat",
176 value: "DE123456789",
177 });
178 return { customer, taxId };
179 }),
180 );
181
182 expect(created.taxId.value).toEqual("DE123456789");
183
184 const replaced = yield* stack.deploy(
185 Effect.gen(function* () {
186 const customer = yield* Stripe.Customer("TaxIdReplaceCustomer", {
187 email: "alchemy.taxid.replace@example.com",
188 name: "Alchemy Tax ID Replace",
189 });
190 const taxId = yield* Stripe.CustomerTaxId("ReplaceVat", {
191 customer: customer.id,
192 type: "eu_vat",
193 value: "DE000000000",
194 });
195 return { customer, taxId };
196 }),
197 );
198
199 expect(replaced.taxId.id).not.toEqual(created.taxId.id);
200 expect(replaced.taxId.customer).toEqual(created.customer.id);
201 expect(replaced.taxId.value).toEqual("DE000000000");
202
203 const newFetched = yield* GetCustomerTaxIdsById({
204 customer: replaced.taxId.customer,
205 id: replaced.taxId.id,
206 });
207 expect(newFetched.value).toEqual("DE000000000");
208
209 const oldGone = yield* waitUntilGone(
210 created.taxId.customer,
211 created.taxId.id,
212 );
213 expect(oldGone).toEqual("gone");
214
215 yield* stack.destroy();
216
217 const gone = yield* waitUntilGone(
218 replaced.taxId.customer,
219 replaced.taxId.id,
220 );
221 expect(gone).toEqual("gone");
222 }).pipe(logLevel),
223 {
224 tags: [
225 "provider:stripe",
226 "provider:stripe:customer",
227 "provider:stripe:customertaxid",
228 "live",
229 ],
230 timeout: 120_000,
231 },
232);