realtimex-crm 0.3.1 → 0.4.0
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/dist/assets/{DealList-o0rCTPLg.js → DealList-C7t7lLe9.js} +2 -2
- package/dist/assets/{DealList-o0rCTPLg.js.map → DealList-C7t7lLe9.js.map} +1 -1
- package/dist/assets/{index-oof5vcGm.js → index-IQ-gFBbx.js} +32 -32
- package/dist/assets/{index-oof5vcGm.js.map → index-IQ-gFBbx.js.map} +1 -1
- package/dist/index.html +1 -1
- package/dist/setup.sql +976 -0
- package/dist/stats.html +1 -1
- package/package.json +1 -1
- package/public/setup.sql +976 -0
- package/src/components/atomic-crm/login/StartPage.tsx +1 -3
- package/src/components/atomic-crm/root/DatabaseHealthCheck.tsx +2 -4
- package/src/components/atomic-crm/setup/DatabaseSetupGuide.tsx +73 -21
- package/src/lib/database-health-check.ts +27 -18
package/dist/setup.sql
ADDED
|
@@ -0,0 +1,976 @@
|
|
|
1
|
+
create table "public"."companies" (
|
|
2
|
+
"id" bigint generated by default as identity not null,
|
|
3
|
+
"created_at" timestamp with time zone not null default now(),
|
|
4
|
+
"name" text not null,
|
|
5
|
+
"sector" text,
|
|
6
|
+
"size" smallint,
|
|
7
|
+
"linkedin_url" text,
|
|
8
|
+
"website" text,
|
|
9
|
+
"phone_number" text,
|
|
10
|
+
"address" text,
|
|
11
|
+
"zipcode" text,
|
|
12
|
+
"city" text,
|
|
13
|
+
"stateAbbr" text,
|
|
14
|
+
"sales_id" bigint,
|
|
15
|
+
"context_links" json,
|
|
16
|
+
"country" text,
|
|
17
|
+
"description" text,
|
|
18
|
+
"revenue" text,
|
|
19
|
+
"tax_identifier" text,
|
|
20
|
+
"logo" jsonb
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
alter table "public"."companies" enable row level security;
|
|
25
|
+
|
|
26
|
+
create table "public"."contactNotes" (
|
|
27
|
+
"id" bigint generated by default as identity not null,
|
|
28
|
+
"contact_id" bigint not null,
|
|
29
|
+
"text" text,
|
|
30
|
+
"date" timestamp with time zone default now(),
|
|
31
|
+
"sales_id" bigint,
|
|
32
|
+
"status" text,
|
|
33
|
+
"attachments" jsonb[]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
alter table "public"."contactNotes" enable row level security;
|
|
38
|
+
|
|
39
|
+
create table "public"."contacts" (
|
|
40
|
+
"id" bigint generated by default as identity not null,
|
|
41
|
+
"first_name" text,
|
|
42
|
+
"last_name" text,
|
|
43
|
+
"gender" text,
|
|
44
|
+
"title" text,
|
|
45
|
+
"email" text,
|
|
46
|
+
"phone_1_number" text,
|
|
47
|
+
"phone_1_type" text,
|
|
48
|
+
"phone_2_number" text,
|
|
49
|
+
"phone_2_type" text,
|
|
50
|
+
"background" text,
|
|
51
|
+
"acquisition" text,
|
|
52
|
+
"avatar" jsonb,
|
|
53
|
+
"first_seen" timestamp with time zone,
|
|
54
|
+
"last_seen" timestamp with time zone,
|
|
55
|
+
"has_newsletter" boolean,
|
|
56
|
+
"status" text,
|
|
57
|
+
"tags" bigint[],
|
|
58
|
+
"company_id" bigint,
|
|
59
|
+
"sales_id" bigint,
|
|
60
|
+
"linkedin_url" text
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
alter table "public"."contacts" enable row level security;
|
|
65
|
+
|
|
66
|
+
create table "public"."dealNotes" (
|
|
67
|
+
"id" bigint generated by default as identity not null,
|
|
68
|
+
"deal_id" bigint not null,
|
|
69
|
+
"type" text,
|
|
70
|
+
"text" text,
|
|
71
|
+
"date" timestamp with time zone default now(),
|
|
72
|
+
"sales_id" bigint,
|
|
73
|
+
"attachments" jsonb[]
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
alter table "public"."dealNotes" enable row level security;
|
|
78
|
+
|
|
79
|
+
create table "public"."deals" (
|
|
80
|
+
"id" bigint generated by default as identity not null,
|
|
81
|
+
"name" text not null,
|
|
82
|
+
"company_id" bigint,
|
|
83
|
+
"contact_ids" bigint[],
|
|
84
|
+
"category" text,
|
|
85
|
+
"stage" text not null,
|
|
86
|
+
"description" text,
|
|
87
|
+
"amount" bigint,
|
|
88
|
+
"created_at" timestamp with time zone not null default now(),
|
|
89
|
+
"updated_at" timestamp with time zone not null default now(),
|
|
90
|
+
"archived_at" timestamp with time zone default null,
|
|
91
|
+
"expected_closing_date" timestamp with time zone default null,
|
|
92
|
+
"sales_id" bigint,
|
|
93
|
+
"index" smallint
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
alter table "public"."deals" enable row level security;
|
|
98
|
+
|
|
99
|
+
create table "public"."sales" (
|
|
100
|
+
"id" bigint generated by default as identity not null,
|
|
101
|
+
"first_name" text not null,
|
|
102
|
+
"last_name" text not null,
|
|
103
|
+
"email" text not null,
|
|
104
|
+
"administrator" boolean not null,
|
|
105
|
+
"user_id" uuid not null,
|
|
106
|
+
"avatar" jsonb,
|
|
107
|
+
"disabled" boolean not null default FALSE
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
alter table "public"."sales" enable row level security;
|
|
112
|
+
|
|
113
|
+
create table "public"."tags" (
|
|
114
|
+
"id" bigint generated by default as identity not null,
|
|
115
|
+
"name" text not null,
|
|
116
|
+
"color" text not null
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
alter table "public"."tags" enable row level security;
|
|
121
|
+
|
|
122
|
+
create table "public"."tasks" (
|
|
123
|
+
"id" bigint generated by default as identity not null,
|
|
124
|
+
"contact_id" bigint not null,
|
|
125
|
+
"type" text,
|
|
126
|
+
"text" text,
|
|
127
|
+
"due_date" timestamp with time zone not null,
|
|
128
|
+
"done_date" timestamp with time zone
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
alter table "public"."tasks" enable row level security;
|
|
133
|
+
|
|
134
|
+
CREATE UNIQUE INDEX companies_pkey ON public.companies USING btree (id);
|
|
135
|
+
|
|
136
|
+
CREATE UNIQUE INDEX "contactNotes_pkey" ON public."contactNotes" USING btree (id);
|
|
137
|
+
|
|
138
|
+
CREATE UNIQUE INDEX contacts_pkey ON public.contacts USING btree (id);
|
|
139
|
+
|
|
140
|
+
CREATE UNIQUE INDEX "dealNotes_pkey" ON public."dealNotes" USING btree (id);
|
|
141
|
+
|
|
142
|
+
CREATE UNIQUE INDEX deals_pkey ON public.deals USING btree (id);
|
|
143
|
+
|
|
144
|
+
CREATE UNIQUE INDEX sales_pkey ON public.sales USING btree (id);
|
|
145
|
+
|
|
146
|
+
CREATE UNIQUE INDEX tags_pkey ON public.tags USING btree (id);
|
|
147
|
+
|
|
148
|
+
CREATE UNIQUE INDEX tasks_pkey ON public.tasks USING btree (id);
|
|
149
|
+
|
|
150
|
+
alter table "public"."companies" add constraint "companies_pkey" PRIMARY KEY using index "companies_pkey";
|
|
151
|
+
|
|
152
|
+
alter table "public"."contactNotes" add constraint "contactNotes_pkey" PRIMARY KEY using index "contactNotes_pkey";
|
|
153
|
+
|
|
154
|
+
alter table "public"."contacts" add constraint "contacts_pkey" PRIMARY KEY using index "contacts_pkey";
|
|
155
|
+
|
|
156
|
+
alter table "public"."dealNotes" add constraint "dealNotes_pkey" PRIMARY KEY using index "dealNotes_pkey";
|
|
157
|
+
|
|
158
|
+
alter table "public"."deals" add constraint "deals_pkey" PRIMARY KEY using index "deals_pkey";
|
|
159
|
+
|
|
160
|
+
alter table "public"."sales" add constraint "sales_pkey" PRIMARY KEY using index "sales_pkey";
|
|
161
|
+
|
|
162
|
+
alter table "public"."tags" add constraint "tags_pkey" PRIMARY KEY using index "tags_pkey";
|
|
163
|
+
|
|
164
|
+
alter table "public"."tasks" add constraint "tasks_pkey" PRIMARY KEY using index "tasks_pkey";
|
|
165
|
+
|
|
166
|
+
alter table "public"."companies" add constraint "companies_sales_id_fkey" FOREIGN KEY (sales_id) REFERENCES sales(id) not valid;
|
|
167
|
+
|
|
168
|
+
alter table "public"."companies" validate constraint "companies_sales_id_fkey";
|
|
169
|
+
|
|
170
|
+
alter table "public"."contactNotes" add constraint "contactNotes_contact_id_fkey" FOREIGN KEY (contact_id) REFERENCES contacts(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
171
|
+
|
|
172
|
+
alter table "public"."contactNotes" validate constraint "contactNotes_contact_id_fkey";
|
|
173
|
+
|
|
174
|
+
alter table "public"."contactNotes" add constraint "contactNotes_sales_id_fkey" FOREIGN KEY (sales_id) REFERENCES sales(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
175
|
+
|
|
176
|
+
alter table "public"."contactNotes" validate constraint "contactNotes_sales_id_fkey";
|
|
177
|
+
|
|
178
|
+
alter table "public"."contacts" add constraint "contacts_company_id_fkey" FOREIGN KEY (company_id) REFERENCES companies(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
179
|
+
|
|
180
|
+
alter table "public"."contacts" validate constraint "contacts_company_id_fkey";
|
|
181
|
+
|
|
182
|
+
alter table "public"."contacts" add constraint "contacts_sales_id_fkey" FOREIGN KEY (sales_id) REFERENCES sales(id) not valid;
|
|
183
|
+
|
|
184
|
+
alter table "public"."contacts" validate constraint "contacts_sales_id_fkey";
|
|
185
|
+
|
|
186
|
+
alter table "public"."dealNotes" add constraint "dealNotes_deal_id_fkey" FOREIGN KEY (deal_id) REFERENCES deals(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
187
|
+
|
|
188
|
+
alter table "public"."dealNotes" validate constraint "dealNotes_deal_id_fkey";
|
|
189
|
+
|
|
190
|
+
alter table "public"."dealNotes" add constraint "dealNotes_sales_id_fkey" FOREIGN KEY (sales_id) REFERENCES sales(id) not valid;
|
|
191
|
+
|
|
192
|
+
alter table "public"."dealNotes" validate constraint "dealNotes_sales_id_fkey";
|
|
193
|
+
|
|
194
|
+
alter table "public"."deals" add constraint "deals_company_id_fkey" FOREIGN KEY (company_id) REFERENCES companies(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
195
|
+
|
|
196
|
+
alter table "public"."deals" validate constraint "deals_company_id_fkey";
|
|
197
|
+
|
|
198
|
+
alter table "public"."deals" add constraint "deals_sales_id_fkey" FOREIGN KEY (sales_id) REFERENCES sales(id) not valid;
|
|
199
|
+
|
|
200
|
+
alter table "public"."deals" validate constraint "deals_sales_id_fkey";
|
|
201
|
+
|
|
202
|
+
alter table "public"."sales" add constraint "sales_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid;
|
|
203
|
+
|
|
204
|
+
alter table "public"."sales" validate constraint "sales_user_id_fkey";
|
|
205
|
+
|
|
206
|
+
alter table "public"."tasks" add constraint "tasks_contact_id_fkey" FOREIGN KEY (contact_id) REFERENCES contacts(id) ON UPDATE CASCADE ON DELETE CASCADE not valid;
|
|
207
|
+
|
|
208
|
+
alter table "public"."tasks" validate constraint "tasks_contact_id_fkey";
|
|
209
|
+
|
|
210
|
+
set check_function_bodies = off;
|
|
211
|
+
|
|
212
|
+
grant delete on table "public"."companies" to "authenticated";
|
|
213
|
+
grant insert on table "public"."companies" to "authenticated";
|
|
214
|
+
grant select on table "public"."companies" to "authenticated";
|
|
215
|
+
grant update on table "public"."companies" to "authenticated";
|
|
216
|
+
|
|
217
|
+
grant delete on table "public"."companies" to "service_role";
|
|
218
|
+
grant insert on table "public"."companies" to "service_role";
|
|
219
|
+
grant references on table "public"."companies" to "service_role";
|
|
220
|
+
grant select on table "public"."companies" to "service_role";
|
|
221
|
+
grant trigger on table "public"."companies" to "service_role";
|
|
222
|
+
grant truncate on table "public"."companies" to "service_role";
|
|
223
|
+
grant update on table "public"."companies" to "service_role";
|
|
224
|
+
|
|
225
|
+
grant delete on table "public"."contactNotes" to "authenticated";
|
|
226
|
+
grant insert on table "public"."contactNotes" to "authenticated";
|
|
227
|
+
grant select on table "public"."contactNotes" to "authenticated";
|
|
228
|
+
grant update on table "public"."contactNotes" to "authenticated";
|
|
229
|
+
|
|
230
|
+
grant delete on table "public"."contactNotes" to "service_role";
|
|
231
|
+
grant insert on table "public"."contactNotes" to "service_role";
|
|
232
|
+
grant references on table "public"."contactNotes" to "service_role";
|
|
233
|
+
grant select on table "public"."contactNotes" to "service_role";
|
|
234
|
+
grant trigger on table "public"."contactNotes" to "service_role";
|
|
235
|
+
grant truncate on table "public"."contactNotes" to "service_role";
|
|
236
|
+
grant update on table "public"."contactNotes" to "service_role";
|
|
237
|
+
|
|
238
|
+
grant delete on table "public"."contacts" to "authenticated";
|
|
239
|
+
grant insert on table "public"."contacts" to "authenticated";
|
|
240
|
+
grant select on table "public"."contacts" to "authenticated";
|
|
241
|
+
grant update on table "public"."contacts" to "authenticated";
|
|
242
|
+
|
|
243
|
+
grant delete on table "public"."contacts" to "service_role";
|
|
244
|
+
grant insert on table "public"."contacts" to "service_role";
|
|
245
|
+
grant references on table "public"."contacts" to "service_role";
|
|
246
|
+
grant select on table "public"."contacts" to "service_role";
|
|
247
|
+
grant trigger on table "public"."contacts" to "service_role";
|
|
248
|
+
grant truncate on table "public"."contacts" to "service_role";
|
|
249
|
+
grant update on table "public"."contacts" to "service_role";
|
|
250
|
+
|
|
251
|
+
grant delete on table "public"."dealNotes" to "authenticated";
|
|
252
|
+
grant insert on table "public"."dealNotes" to "authenticated";
|
|
253
|
+
grant select on table "public"."dealNotes" to "authenticated";
|
|
254
|
+
grant update on table "public"."dealNotes" to "authenticated";
|
|
255
|
+
|
|
256
|
+
grant delete on table "public"."dealNotes" to "service_role";
|
|
257
|
+
grant insert on table "public"."dealNotes" to "service_role";
|
|
258
|
+
grant references on table "public"."dealNotes" to "service_role";
|
|
259
|
+
grant select on table "public"."dealNotes" to "service_role";
|
|
260
|
+
grant trigger on table "public"."dealNotes" to "service_role";
|
|
261
|
+
grant truncate on table "public"."dealNotes" to "service_role";
|
|
262
|
+
grant update on table "public"."dealNotes" to "service_role";
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
grant delete on table "public"."deals" to "authenticated";
|
|
266
|
+
grant insert on table "public"."deals" to "authenticated";
|
|
267
|
+
grant select on table "public"."deals" to "authenticated";
|
|
268
|
+
grant update on table "public"."deals" to "authenticated";
|
|
269
|
+
|
|
270
|
+
grant delete on table "public"."deals" to "service_role";
|
|
271
|
+
grant insert on table "public"."deals" to "service_role";
|
|
272
|
+
grant references on table "public"."deals" to "service_role";
|
|
273
|
+
grant select on table "public"."deals" to "service_role";
|
|
274
|
+
grant trigger on table "public"."deals" to "service_role";
|
|
275
|
+
grant truncate on table "public"."deals" to "service_role";
|
|
276
|
+
grant update on table "public"."deals" to "service_role";
|
|
277
|
+
|
|
278
|
+
grant delete on table "public"."sales" to "authenticated";
|
|
279
|
+
grant insert on table "public"."sales" to "authenticated";
|
|
280
|
+
grant select on table "public"."sales" to "authenticated";
|
|
281
|
+
grant update on table "public"."sales" to "authenticated";
|
|
282
|
+
|
|
283
|
+
grant delete on table "public"."sales" to "service_role";
|
|
284
|
+
grant insert on table "public"."sales" to "service_role";
|
|
285
|
+
grant references on table "public"."sales" to "service_role";
|
|
286
|
+
grant select on table "public"."sales" to "service_role";
|
|
287
|
+
grant trigger on table "public"."sales" to "service_role";
|
|
288
|
+
grant truncate on table "public"."sales" to "service_role";
|
|
289
|
+
grant update on table "public"."sales" to "service_role";
|
|
290
|
+
|
|
291
|
+
grant delete on table "public"."tags" to "authenticated";
|
|
292
|
+
grant insert on table "public"."tags" to "authenticated";
|
|
293
|
+
grant select on table "public"."tags" to "authenticated";
|
|
294
|
+
grant update on table "public"."tags" to "authenticated";
|
|
295
|
+
|
|
296
|
+
grant delete on table "public"."tags" to "service_role";
|
|
297
|
+
grant insert on table "public"."tags" to "service_role";
|
|
298
|
+
grant references on table "public"."tags" to "service_role";
|
|
299
|
+
grant select on table "public"."tags" to "service_role";
|
|
300
|
+
grant trigger on table "public"."tags" to "service_role";
|
|
301
|
+
grant truncate on table "public"."tags" to "service_role";
|
|
302
|
+
grant update on table "public"."tags" to "service_role";
|
|
303
|
+
|
|
304
|
+
grant delete on table "public"."tasks" to "authenticated";
|
|
305
|
+
grant insert on table "public"."tasks" to "authenticated";
|
|
306
|
+
grant select on table "public"."tasks" to "authenticated";
|
|
307
|
+
grant update on table "public"."tasks" to "authenticated";
|
|
308
|
+
|
|
309
|
+
grant delete on table "public"."tasks" to "service_role";
|
|
310
|
+
grant insert on table "public"."tasks" to "service_role";
|
|
311
|
+
grant references on table "public"."tasks" to "service_role";
|
|
312
|
+
grant select on table "public"."tasks" to "service_role";
|
|
313
|
+
grant trigger on table "public"."tasks" to "service_role";
|
|
314
|
+
grant truncate on table "public"."tasks" to "service_role";
|
|
315
|
+
grant update on table "public"."tasks" to "service_role";
|
|
316
|
+
|
|
317
|
+
create policy "Enable insert for authenticated users only"
|
|
318
|
+
on "public"."companies"
|
|
319
|
+
as permissive
|
|
320
|
+
for insert
|
|
321
|
+
to authenticated
|
|
322
|
+
with check (true);
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
create policy "Enable read access for authenticated users"
|
|
326
|
+
on "public"."companies"
|
|
327
|
+
as permissive
|
|
328
|
+
for select
|
|
329
|
+
to authenticated
|
|
330
|
+
using (true);
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
create policy "Enable update for authenticated users only"
|
|
334
|
+
on "public"."companies"
|
|
335
|
+
as permissive
|
|
336
|
+
for update
|
|
337
|
+
to authenticated
|
|
338
|
+
using (true)
|
|
339
|
+
with check (true);
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
create policy "Enable insert for authenticated users only"
|
|
343
|
+
on "public"."contactNotes"
|
|
344
|
+
as permissive
|
|
345
|
+
for insert
|
|
346
|
+
to authenticated
|
|
347
|
+
with check (true);
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
create policy "Enable read access for authenticated users"
|
|
351
|
+
on "public"."contactNotes"
|
|
352
|
+
as permissive
|
|
353
|
+
for select
|
|
354
|
+
to authenticated
|
|
355
|
+
using (true);
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
create policy "Enable insert for authenticated users only"
|
|
359
|
+
on "public"."contacts"
|
|
360
|
+
as permissive
|
|
361
|
+
for insert
|
|
362
|
+
to authenticated
|
|
363
|
+
with check (true);
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
create policy "Enable read access for authenticated users"
|
|
367
|
+
on "public"."contacts"
|
|
368
|
+
as permissive
|
|
369
|
+
for select
|
|
370
|
+
to authenticated
|
|
371
|
+
using (true);
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
create policy "Enable update for authenticated users only"
|
|
375
|
+
on "public"."contacts"
|
|
376
|
+
as permissive
|
|
377
|
+
for update
|
|
378
|
+
to authenticated
|
|
379
|
+
using (true)
|
|
380
|
+
with check (true);
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
create policy "Enable insert for authenticated users only"
|
|
384
|
+
on "public"."dealNotes"
|
|
385
|
+
as permissive
|
|
386
|
+
for insert
|
|
387
|
+
to authenticated
|
|
388
|
+
with check (true);
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
create policy "Enable read access for authenticated users"
|
|
392
|
+
on "public"."dealNotes"
|
|
393
|
+
as permissive
|
|
394
|
+
for select
|
|
395
|
+
to authenticated
|
|
396
|
+
using (true);
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
create policy "Enable insert for authenticated users only"
|
|
400
|
+
on "public"."deals"
|
|
401
|
+
as permissive
|
|
402
|
+
for insert
|
|
403
|
+
to authenticated
|
|
404
|
+
with check (true);
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
create policy "Enable read access for authenticated users"
|
|
408
|
+
on "public"."deals"
|
|
409
|
+
as permissive
|
|
410
|
+
for select
|
|
411
|
+
to authenticated
|
|
412
|
+
using (true);
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
create policy "Enable update for authenticated users only"
|
|
416
|
+
on "public"."deals"
|
|
417
|
+
as permissive
|
|
418
|
+
for update
|
|
419
|
+
to authenticated
|
|
420
|
+
using (true)
|
|
421
|
+
with check (true);
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
create policy "Enable insert for authenticated users only"
|
|
425
|
+
on "public"."sales"
|
|
426
|
+
as permissive
|
|
427
|
+
for insert
|
|
428
|
+
to authenticated
|
|
429
|
+
with check (true);
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
create policy "Enable update for authenticated users only"
|
|
433
|
+
on "public"."sales"
|
|
434
|
+
as permissive
|
|
435
|
+
for update
|
|
436
|
+
to authenticated
|
|
437
|
+
using (true)
|
|
438
|
+
with check (true);
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
create policy "Enable read access for authenticated users"
|
|
442
|
+
on "public"."sales"
|
|
443
|
+
as permissive
|
|
444
|
+
for select
|
|
445
|
+
to authenticated
|
|
446
|
+
using (true);
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
create policy "Enable insert for authenticated users only"
|
|
450
|
+
on "public"."tags"
|
|
451
|
+
as permissive
|
|
452
|
+
for insert
|
|
453
|
+
to authenticated
|
|
454
|
+
with check (true);
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
create policy "Enable read access for authenticated users"
|
|
458
|
+
on "public"."tags"
|
|
459
|
+
as permissive
|
|
460
|
+
for select
|
|
461
|
+
to authenticated
|
|
462
|
+
using (true);
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
create policy "Enable insert for authenticated users only"
|
|
466
|
+
on "public"."tasks"
|
|
467
|
+
as permissive
|
|
468
|
+
for insert
|
|
469
|
+
to authenticated
|
|
470
|
+
with check (true);
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
create policy "Enable read access for authenticated users"
|
|
474
|
+
on "public"."tasks"
|
|
475
|
+
as permissive
|
|
476
|
+
for select
|
|
477
|
+
to authenticated
|
|
478
|
+
using (true);
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
create policy "Company Delete Policy"
|
|
482
|
+
on "public"."companies"
|
|
483
|
+
as permissive
|
|
484
|
+
for delete
|
|
485
|
+
to authenticated
|
|
486
|
+
using (true);
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
create policy "Contact Notes Delete Policy"
|
|
490
|
+
on "public"."contactNotes"
|
|
491
|
+
as permissive
|
|
492
|
+
for delete
|
|
493
|
+
to authenticated
|
|
494
|
+
using (true);
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
create policy "Contact Notes Update policy"
|
|
498
|
+
on "public"."contactNotes"
|
|
499
|
+
as permissive
|
|
500
|
+
for update
|
|
501
|
+
to authenticated
|
|
502
|
+
using (true);
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
create policy "Contact Delete Policy"
|
|
506
|
+
on "public"."contacts"
|
|
507
|
+
as permissive
|
|
508
|
+
for delete
|
|
509
|
+
to authenticated
|
|
510
|
+
using (true);
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
create policy "Deal Notes Delete Policy"
|
|
514
|
+
on "public"."dealNotes"
|
|
515
|
+
as permissive
|
|
516
|
+
for delete
|
|
517
|
+
to authenticated
|
|
518
|
+
using (true);
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
create policy "Deal Notes Update Policy"
|
|
522
|
+
on "public"."dealNotes"
|
|
523
|
+
as permissive
|
|
524
|
+
for update
|
|
525
|
+
to authenticated
|
|
526
|
+
using (true);
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
create policy "Deals Delete Policy"
|
|
530
|
+
on "public"."deals"
|
|
531
|
+
as permissive
|
|
532
|
+
for delete
|
|
533
|
+
to authenticated
|
|
534
|
+
using (true);
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
create policy "Task Delete Policy"
|
|
538
|
+
on "public"."tasks"
|
|
539
|
+
as permissive
|
|
540
|
+
for delete
|
|
541
|
+
to authenticated
|
|
542
|
+
using (true);
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
create policy "Task Update Policy"
|
|
546
|
+
on "public"."tasks"
|
|
547
|
+
as permissive
|
|
548
|
+
for update
|
|
549
|
+
to authenticated
|
|
550
|
+
using (true);
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
-- Use Postgres to create a bucket.
|
|
554
|
+
|
|
555
|
+
insert into storage.buckets
|
|
556
|
+
(id, name, public)
|
|
557
|
+
values
|
|
558
|
+
('attachments', 'attachments', true);
|
|
559
|
+
|
|
560
|
+
CREATE POLICY "Attachments 1mt4rzk_0" ON storage.objects FOR SELECT TO authenticated USING (bucket_id = 'attachments');
|
|
561
|
+
CREATE POLICY "Attachments 1mt4rzk_1" ON storage.objects FOR INSERT TO authenticated WITH CHECK (bucket_id = 'attachments');
|
|
562
|
+
CREATE POLICY "Attachments 1mt4rzk_3" ON storage.objects FOR DELETE TO authenticated USING (bucket_id = 'attachments');
|
|
563
|
+
|
|
564
|
+
-- Use Postgres to create views for companies.
|
|
565
|
+
|
|
566
|
+
create view "public"."companies_summary"
|
|
567
|
+
with (security_invoker=on)
|
|
568
|
+
as
|
|
569
|
+
select
|
|
570
|
+
c.*,
|
|
571
|
+
count(distinct d.id) as nb_deals,
|
|
572
|
+
count(distinct co.id) as nb_contacts
|
|
573
|
+
from
|
|
574
|
+
"public"."companies" c
|
|
575
|
+
left join
|
|
576
|
+
"public"."deals" d on c.id = d.company_id
|
|
577
|
+
left join
|
|
578
|
+
"public"."contacts" co on c.id = co.company_id
|
|
579
|
+
group by
|
|
580
|
+
c.id;
|
|
581
|
+
|
|
582
|
+
-- Use Postgres to create views for contacts.
|
|
583
|
+
|
|
584
|
+
create view "public"."contacts_summary"
|
|
585
|
+
with (security_invoker=on)
|
|
586
|
+
as
|
|
587
|
+
select
|
|
588
|
+
co.*,
|
|
589
|
+
c.name as company_name,
|
|
590
|
+
count(distinct t.id) as nb_tasks
|
|
591
|
+
from
|
|
592
|
+
"public"."contacts" co
|
|
593
|
+
left join
|
|
594
|
+
"public"."tasks" t on co.id = t.contact_id
|
|
595
|
+
left join
|
|
596
|
+
"public"."companies" c on co.company_id = c.id
|
|
597
|
+
group by
|
|
598
|
+
co.id, c.name;
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
create function public.handle_new_user()
|
|
602
|
+
returns trigger
|
|
603
|
+
language plpgsql
|
|
604
|
+
security definer set search_path = ''
|
|
605
|
+
as $$
|
|
606
|
+
declare
|
|
607
|
+
sales_count int;
|
|
608
|
+
begin
|
|
609
|
+
select count(id) into sales_count
|
|
610
|
+
from public.sales;
|
|
611
|
+
|
|
612
|
+
insert into public.sales (first_name, last_name, email, user_id, administrator)
|
|
613
|
+
values (
|
|
614
|
+
new.raw_user_meta_data ->> 'first_name',
|
|
615
|
+
new.raw_user_meta_data ->> 'last_name',
|
|
616
|
+
new.email,
|
|
617
|
+
new.id,
|
|
618
|
+
case when sales_count > 0 then FALSE else TRUE end
|
|
619
|
+
);
|
|
620
|
+
return new;
|
|
621
|
+
end;
|
|
622
|
+
$$;
|
|
623
|
+
|
|
624
|
+
create function public.handle_update_user()
|
|
625
|
+
returns trigger
|
|
626
|
+
language plpgsql
|
|
627
|
+
security definer set search_path = ''
|
|
628
|
+
as $$
|
|
629
|
+
begin
|
|
630
|
+
update public.sales
|
|
631
|
+
set
|
|
632
|
+
first_name = new.raw_user_meta_data ->> 'first_name',
|
|
633
|
+
last_name = new.raw_user_meta_data ->> 'last_name',
|
|
634
|
+
email = new.email
|
|
635
|
+
where user_id = new.id;
|
|
636
|
+
|
|
637
|
+
return new;
|
|
638
|
+
end;
|
|
639
|
+
$$;
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
create unique index "uq__sales__user_id" on public.sales (user_id);
|
|
643
|
+
|
|
644
|
+
create trigger on_auth_user_created
|
|
645
|
+
after insert on auth.users
|
|
646
|
+
for each row execute procedure public.handle_new_user();
|
|
647
|
+
|
|
648
|
+
create trigger on_auth_user_updated
|
|
649
|
+
after update on auth.users
|
|
650
|
+
for each row execute procedure public.handle_update_user();
|
|
651
|
+
|
|
652
|
+
create view init_state
|
|
653
|
+
with (security_invoker=off)
|
|
654
|
+
as
|
|
655
|
+
select count(id) as is_initialized
|
|
656
|
+
from public.sales
|
|
657
|
+
limit 1;
|
|
658
|
+
alter table "public"."tasks" add column "sales_id" bigint;-- this will drop the `contacts_summary` view as well
|
|
659
|
+
ALTER TABLE "public"."contacts"
|
|
660
|
+
DROP COLUMN acquisition CASCADE;
|
|
661
|
+
|
|
662
|
+
-- We need to recreate the view with the new schema
|
|
663
|
+
|
|
664
|
+
create view "public"."contacts_summary"
|
|
665
|
+
as
|
|
666
|
+
select
|
|
667
|
+
co.*,
|
|
668
|
+
c.name as company_name,
|
|
669
|
+
count(distinct t.id) as nb_tasks
|
|
670
|
+
from
|
|
671
|
+
"public"."contacts" co
|
|
672
|
+
left join
|
|
673
|
+
"public"."tasks" t on co.id = t.contact_id
|
|
674
|
+
left join
|
|
675
|
+
"public"."companies" c on co.company_id = c.id
|
|
676
|
+
group by
|
|
677
|
+
co.id, c.name;
|
|
678
|
+
create or replace view init_state
|
|
679
|
+
with (security_invoker=off)
|
|
680
|
+
as
|
|
681
|
+
select count(id) as is_initialized
|
|
682
|
+
from (
|
|
683
|
+
select id
|
|
684
|
+
from public.sales
|
|
685
|
+
limit 1
|
|
686
|
+
) as sub;
|
|
687
|
+
create policy "Enable delete for authenticated users only"
|
|
688
|
+
on "public"."tags"
|
|
689
|
+
as permissive
|
|
690
|
+
for delete
|
|
691
|
+
to authenticated
|
|
692
|
+
using (true);
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
create policy "Enable update for authenticated users only"
|
|
696
|
+
on "public"."tags"
|
|
697
|
+
as permissive
|
|
698
|
+
for update
|
|
699
|
+
to authenticated
|
|
700
|
+
using (true);
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
create schema if not exists "private";
|
|
706
|
+
|
|
707
|
+
set check_function_bodies = off;
|
|
708
|
+
|
|
709
|
+
drop policy "Enable insert for authenticated users only" on "public"."sales";
|
|
710
|
+
|
|
711
|
+
drop policy "Enable update for authenticated users only" on "public"."sales";
|
|
712
|
+
alter table contacts add column email_jsonb jsonb;
|
|
713
|
+
|
|
714
|
+
update contacts set email_jsonb = ('[{"email": "' || email || '", "type": "Other"}]')::jsonb;
|
|
715
|
+
|
|
716
|
+
drop view contacts_summary;
|
|
717
|
+
|
|
718
|
+
alter table contacts drop column email;
|
|
719
|
+
|
|
720
|
+
create view contacts_summary
|
|
721
|
+
as
|
|
722
|
+
select
|
|
723
|
+
co.id,
|
|
724
|
+
co.first_name,
|
|
725
|
+
co.last_name,
|
|
726
|
+
co.gender,
|
|
727
|
+
co.title,
|
|
728
|
+
co.email_jsonb,
|
|
729
|
+
jsonb_path_query_array(co.email_jsonb, '$[*].email')::text as email_fts,
|
|
730
|
+
co.phone_1_number,
|
|
731
|
+
co.phone_1_type,
|
|
732
|
+
co.phone_2_number,
|
|
733
|
+
co.phone_2_type,
|
|
734
|
+
co.background,
|
|
735
|
+
co.avatar,
|
|
736
|
+
co.first_seen,
|
|
737
|
+
co.last_seen,
|
|
738
|
+
co.has_newsletter,
|
|
739
|
+
co.status,
|
|
740
|
+
co.tags,
|
|
741
|
+
co.company_id,
|
|
742
|
+
co.sales_id,
|
|
743
|
+
co.linkedin_url,
|
|
744
|
+
c.name as company_name,
|
|
745
|
+
count(distinct t.id) as nb_tasks
|
|
746
|
+
from
|
|
747
|
+
contacts co
|
|
748
|
+
left join
|
|
749
|
+
tasks t on co.id = t.contact_id
|
|
750
|
+
left join
|
|
751
|
+
companies c on co.company_id = c.id
|
|
752
|
+
group by
|
|
753
|
+
co.id, c.name;
|
|
754
|
+
|
|
755
|
+
alter table contacts add column phone_jsonb jsonb;
|
|
756
|
+
|
|
757
|
+
update contacts set phone_jsonb =
|
|
758
|
+
concat(
|
|
759
|
+
'[',
|
|
760
|
+
case when phone_1_number is not null then
|
|
761
|
+
concat(
|
|
762
|
+
'{"number":"',
|
|
763
|
+
phone_1_number,
|
|
764
|
+
'","type":"',
|
|
765
|
+
phone_1_type,
|
|
766
|
+
'"}'
|
|
767
|
+
)
|
|
768
|
+
else null end,
|
|
769
|
+
case when phone_2_number is not null then
|
|
770
|
+
concat(
|
|
771
|
+
',',
|
|
772
|
+
'{"number":"',
|
|
773
|
+
phone_2_number,
|
|
774
|
+
'","type":"',
|
|
775
|
+
phone_2_type,
|
|
776
|
+
'"}'
|
|
777
|
+
)
|
|
778
|
+
else null end,
|
|
779
|
+
']'
|
|
780
|
+
)::jsonb;
|
|
781
|
+
|
|
782
|
+
drop view contacts_summary;
|
|
783
|
+
|
|
784
|
+
alter table contacts drop column phone_1_number;
|
|
785
|
+
alter table contacts drop column phone_1_type;
|
|
786
|
+
alter table contacts drop column phone_2_number;
|
|
787
|
+
alter table contacts drop column phone_2_type;
|
|
788
|
+
|
|
789
|
+
create view contacts_summary
|
|
790
|
+
as
|
|
791
|
+
select
|
|
792
|
+
co.id,
|
|
793
|
+
co.first_name,
|
|
794
|
+
co.last_name,
|
|
795
|
+
co.gender,
|
|
796
|
+
co.title,
|
|
797
|
+
co.email_jsonb,
|
|
798
|
+
jsonb_path_query_array(co.email_jsonb, '$[*].email')::text as email_fts,
|
|
799
|
+
co.phone_jsonb,
|
|
800
|
+
jsonb_path_query_array(co.phone_jsonb, '$[*].number')::text as phone_fts,
|
|
801
|
+
co.background,
|
|
802
|
+
co.avatar,
|
|
803
|
+
co.first_seen,
|
|
804
|
+
co.last_seen,
|
|
805
|
+
co.has_newsletter,
|
|
806
|
+
co.status,
|
|
807
|
+
co.tags,
|
|
808
|
+
co.company_id,
|
|
809
|
+
co.sales_id,
|
|
810
|
+
co.linkedin_url,
|
|
811
|
+
c.name as company_name,
|
|
812
|
+
count(distinct t.id) as nb_tasks
|
|
813
|
+
from
|
|
814
|
+
contacts co
|
|
815
|
+
left join
|
|
816
|
+
tasks t on co.id = t.contact_id
|
|
817
|
+
left join
|
|
818
|
+
companies c on co.company_id = c.id
|
|
819
|
+
group by
|
|
820
|
+
co.id, c.name;
|
|
821
|
+
|
|
822
|
+
-- Create function to merge contacts server-side with transaction support
|
|
823
|
+
CREATE OR REPLACE FUNCTION merge_contacts(loser_id bigint, winner_id bigint)
|
|
824
|
+
RETURNS bigint
|
|
825
|
+
LANGUAGE plpgsql
|
|
826
|
+
SECURITY INVOKER
|
|
827
|
+
AS $$
|
|
828
|
+
DECLARE
|
|
829
|
+
winner_contact contacts%ROWTYPE;
|
|
830
|
+
loser_contact contacts%ROWTYPE;
|
|
831
|
+
deal_record RECORD;
|
|
832
|
+
merged_emails jsonb;
|
|
833
|
+
merged_phones jsonb;
|
|
834
|
+
merged_tags bigint[];
|
|
835
|
+
winner_emails jsonb;
|
|
836
|
+
loser_emails jsonb;
|
|
837
|
+
winner_phones jsonb;
|
|
838
|
+
loser_phones jsonb;
|
|
839
|
+
email_map jsonb;
|
|
840
|
+
phone_map jsonb;
|
|
841
|
+
BEGIN
|
|
842
|
+
-- Fetch both contacts
|
|
843
|
+
SELECT * INTO winner_contact FROM contacts WHERE id = winner_id;
|
|
844
|
+
SELECT * INTO loser_contact FROM contacts WHERE id = loser_id;
|
|
845
|
+
|
|
846
|
+
IF winner_contact IS NULL OR loser_contact IS NULL THEN
|
|
847
|
+
RAISE EXCEPTION 'Contact not found';
|
|
848
|
+
END IF;
|
|
849
|
+
|
|
850
|
+
-- 1. Reassign tasks from loser to winner
|
|
851
|
+
UPDATE tasks SET contact_id = winner_id WHERE contact_id = loser_id;
|
|
852
|
+
|
|
853
|
+
-- 2. Reassign contact notes from loser to winner
|
|
854
|
+
UPDATE "contactNotes" SET contact_id = winner_id WHERE contact_id = loser_id;
|
|
855
|
+
|
|
856
|
+
-- 3. Update deals - replace loser with winner in contact_ids array
|
|
857
|
+
FOR deal_record IN
|
|
858
|
+
SELECT id, contact_ids
|
|
859
|
+
FROM deals
|
|
860
|
+
WHERE contact_ids @> ARRAY[loser_id]
|
|
861
|
+
LOOP
|
|
862
|
+
UPDATE deals
|
|
863
|
+
SET contact_ids = (
|
|
864
|
+
SELECT ARRAY(
|
|
865
|
+
SELECT DISTINCT unnest(
|
|
866
|
+
array_remove(deal_record.contact_ids, loser_id) || ARRAY[winner_id]
|
|
867
|
+
)
|
|
868
|
+
)
|
|
869
|
+
)
|
|
870
|
+
WHERE id = deal_record.id;
|
|
871
|
+
END LOOP;
|
|
872
|
+
|
|
873
|
+
-- 4. Merge contact data
|
|
874
|
+
|
|
875
|
+
-- Get email arrays
|
|
876
|
+
winner_emails := COALESCE(winner_contact.email_jsonb, '[]'::jsonb);
|
|
877
|
+
loser_emails := COALESCE(loser_contact.email_jsonb, '[]'::jsonb);
|
|
878
|
+
|
|
879
|
+
-- Merge emails with deduplication by email address
|
|
880
|
+
-- Build a map of email -> email object, then convert back to array
|
|
881
|
+
email_map := '{}'::jsonb;
|
|
882
|
+
|
|
883
|
+
-- Add winner emails to map
|
|
884
|
+
IF jsonb_array_length(winner_emails) > 0 THEN
|
|
885
|
+
FOR i IN 0..jsonb_array_length(winner_emails)-1 LOOP
|
|
886
|
+
email_map := email_map || jsonb_build_object(
|
|
887
|
+
winner_emails->i->>'email',
|
|
888
|
+
winner_emails->i
|
|
889
|
+
);
|
|
890
|
+
END LOOP;
|
|
891
|
+
END IF;
|
|
892
|
+
|
|
893
|
+
-- Add loser emails to map (won't overwrite existing keys)
|
|
894
|
+
IF jsonb_array_length(loser_emails) > 0 THEN
|
|
895
|
+
FOR i IN 0..jsonb_array_length(loser_emails)-1 LOOP
|
|
896
|
+
IF NOT email_map ? (loser_emails->i->>'email') THEN
|
|
897
|
+
email_map := email_map || jsonb_build_object(
|
|
898
|
+
loser_emails->i->>'email',
|
|
899
|
+
loser_emails->i
|
|
900
|
+
);
|
|
901
|
+
END IF;
|
|
902
|
+
END LOOP;
|
|
903
|
+
END IF;
|
|
904
|
+
|
|
905
|
+
-- Convert map back to array
|
|
906
|
+
merged_emails := (SELECT jsonb_agg(value) FROM jsonb_each(email_map));
|
|
907
|
+
merged_emails := COALESCE(merged_emails, '[]'::jsonb);
|
|
908
|
+
|
|
909
|
+
-- Get phone arrays
|
|
910
|
+
winner_phones := COALESCE(winner_contact.phone_jsonb, '[]'::jsonb);
|
|
911
|
+
loser_phones := COALESCE(loser_contact.phone_jsonb, '[]'::jsonb);
|
|
912
|
+
|
|
913
|
+
-- Merge phones with deduplication by number
|
|
914
|
+
phone_map := '{}'::jsonb;
|
|
915
|
+
|
|
916
|
+
-- Add winner phones to map
|
|
917
|
+
IF jsonb_array_length(winner_phones) > 0 THEN
|
|
918
|
+
FOR i IN 0..jsonb_array_length(winner_phones)-1 LOOP
|
|
919
|
+
phone_map := phone_map || jsonb_build_object(
|
|
920
|
+
winner_phones->i->>'number',
|
|
921
|
+
winner_phones->i
|
|
922
|
+
);
|
|
923
|
+
END LOOP;
|
|
924
|
+
END IF;
|
|
925
|
+
|
|
926
|
+
-- Add loser phones to map (won't overwrite existing keys)
|
|
927
|
+
IF jsonb_array_length(loser_phones) > 0 THEN
|
|
928
|
+
FOR i IN 0..jsonb_array_length(loser_phones)-1 LOOP
|
|
929
|
+
IF NOT phone_map ? (loser_phones->i->>'number') THEN
|
|
930
|
+
phone_map := phone_map || jsonb_build_object(
|
|
931
|
+
loser_phones->i->>'number',
|
|
932
|
+
loser_phones->i
|
|
933
|
+
);
|
|
934
|
+
END IF;
|
|
935
|
+
END LOOP;
|
|
936
|
+
END IF;
|
|
937
|
+
|
|
938
|
+
-- Convert map back to array
|
|
939
|
+
merged_phones := (SELECT jsonb_agg(value) FROM jsonb_each(phone_map));
|
|
940
|
+
merged_phones := COALESCE(merged_phones, '[]'::jsonb);
|
|
941
|
+
|
|
942
|
+
-- Merge tags (remove duplicates)
|
|
943
|
+
merged_tags := ARRAY(
|
|
944
|
+
SELECT DISTINCT unnest(
|
|
945
|
+
COALESCE(winner_contact.tags, ARRAY[]::bigint[]) ||
|
|
946
|
+
COALESCE(loser_contact.tags, ARRAY[]::bigint[])
|
|
947
|
+
)
|
|
948
|
+
);
|
|
949
|
+
|
|
950
|
+
-- 5. Update winner with merged data
|
|
951
|
+
UPDATE contacts SET
|
|
952
|
+
avatar = COALESCE(winner_contact.avatar, loser_contact.avatar),
|
|
953
|
+
gender = COALESCE(winner_contact.gender, loser_contact.gender),
|
|
954
|
+
first_name = COALESCE(winner_contact.first_name, loser_contact.first_name),
|
|
955
|
+
last_name = COALESCE(winner_contact.last_name, loser_contact.last_name),
|
|
956
|
+
title = COALESCE(winner_contact.title, loser_contact.title),
|
|
957
|
+
company_id = COALESCE(winner_contact.company_id, loser_contact.company_id),
|
|
958
|
+
email_jsonb = merged_emails,
|
|
959
|
+
phone_jsonb = merged_phones,
|
|
960
|
+
linkedin_url = COALESCE(winner_contact.linkedin_url, loser_contact.linkedin_url),
|
|
961
|
+
background = COALESCE(winner_contact.background, loser_contact.background),
|
|
962
|
+
has_newsletter = COALESCE(winner_contact.has_newsletter, loser_contact.has_newsletter),
|
|
963
|
+
first_seen = LEAST(COALESCE(winner_contact.first_seen, loser_contact.first_seen), COALESCE(loser_contact.first_seen, winner_contact.first_seen)),
|
|
964
|
+
last_seen = GREATEST(COALESCE(winner_contact.last_seen, loser_contact.last_seen), COALESCE(loser_contact.last_seen, winner_contact.last_seen)),
|
|
965
|
+
sales_id = COALESCE(winner_contact.sales_id, loser_contact.sales_id),
|
|
966
|
+
tags = merged_tags
|
|
967
|
+
WHERE id = winner_id;
|
|
968
|
+
|
|
969
|
+
-- 6. Delete loser contact
|
|
970
|
+
DELETE FROM contacts WHERE id = loser_id;
|
|
971
|
+
|
|
972
|
+
RETURN winner_id;
|
|
973
|
+
END;
|
|
974
|
+
$$;
|
|
975
|
+
-- Drop the merge_contacts function (reverting to edge function approach)
|
|
976
|
+
DROP FUNCTION IF EXISTS merge_contacts(bigint, bigint);
|