@fayz-ai/db 0.30.0 → 0.31.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.
@@ -0,0 +1,38 @@
1
+ -- ============================================================================
2
+ -- 225_a_task_can_be_a_call — the one task list carries calls and knows what
3
+ -- record it is about.
4
+ --
5
+ -- The feira campaign's touch 3 wrote 105 calls as CRM activities, out of the
6
+ -- tasks drawer, and the CRM grew its own list over them: two places for the
7
+ -- same to-do (11-03). `tasks` stays the single store, with what a call needs:
8
+ --
9
+ -- * `kind` — 'todo' (the default, what the drawer always had) or 'call';
10
+ -- * `subject_type` / `subject_id` — the record it is about ('crm.deal', <id>),
11
+ -- so the deal shows its open tasks and a done call lands on its timeline;
12
+ -- * `phones` — [{ "label", "number" }], the numbers to try, in order;
13
+ -- * `outcome` — what happened when it was done ('connected', 'no_answer',
14
+ -- 'left_message', 'scheduled', 'replied'), the vocabulary of CRM activities.
15
+ --
16
+ -- Idempotent and replay-safe.
17
+ -- ============================================================================
18
+
19
+ ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS kind text NOT NULL DEFAULT 'todo';
20
+ ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS subject_type text;
21
+ ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS subject_id uuid;
22
+ ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS phones jsonb NOT NULL DEFAULT '[]'::jsonb;
23
+ ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS outcome text;
24
+
25
+ DO $$
26
+ BEGIN
27
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'tasks_kind_check') THEN
28
+ ALTER TABLE public.tasks ADD CONSTRAINT tasks_kind_check CHECK (kind IN ('todo', 'call'));
29
+ END IF;
30
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'tasks_outcome_check') THEN
31
+ ALTER TABLE public.tasks ADD CONSTRAINT tasks_outcome_check
32
+ CHECK (outcome IS NULL OR outcome IN ('connected', 'no_answer', 'left_message', 'replied', 'scheduled'));
33
+ END IF;
34
+ END $$;
35
+
36
+ CREATE INDEX IF NOT EXISTS tasks_subject_idx ON public.tasks (tenant_id, subject_type, subject_id);
37
+ CREATE INDEX IF NOT EXISTS tasks_open_assignee_idx ON public.tasks (tenant_id, assigned_to_id, due_date)
38
+ WHERE status IN ('todo', 'in_progress');
@@ -0,0 +1,49 @@
1
+ -- ============================================================================
2
+ -- 225 — stock can go below zero when the house says so
3
+ --
4
+ -- stock_apply refused any on_hand below zero. A house that sells before it
5
+ -- produces (Artorius, with no production module yet) switches «Permitir estoque
6
+ -- negativo» on in Configurações › Estoque, so a sale of a product it does not
7
+ -- have yet is recorded, and the negative balance tells it what to produce.
8
+ --
9
+ -- The core does not read the inventory's settings. The inventory, which does,
10
+ -- marks its own transaction with `fayz.stock_allow_negative = on` before it
11
+ -- calls stock_apply (plugin-inventory 037); only then is a negative on_hand
12
+ -- accepted. Every other caller is refused as before.
13
+ --
14
+ -- Idempotent and replay-safe: CREATE OR REPLACE, same signature.
15
+ -- ============================================================================
16
+
17
+ CREATE OR REPLACE FUNCTION public.stock_apply(p_tenant uuid, p_variant uuid, p_unit uuid, p_on_hand numeric DEFAULT 0, p_reserved numeric DEFAULT 0, p_source text DEFAULT 'inventory'::text)
18
+ RETURNS jsonb
19
+ LANGUAGE plpgsql
20
+ SECURITY DEFINER
21
+ SET search_path TO ''
22
+ AS $function$
23
+ DECLARE
24
+ v_on_hand numeric;
25
+ v_reserved numeric;
26
+ BEGIN
27
+ IF p_tenant IS NULL OR p_variant IS NULL THEN
28
+ RAISE EXCEPTION 'stock_apply: tenant and variant are required' USING ERRCODE = '22023';
29
+ END IF;
30
+
31
+ INSERT INTO public.stock_balances (tenant_id, variant_id, unit_id, on_hand, reserved, updated_by)
32
+ VALUES (p_tenant, p_variant, p_unit, coalesce(p_on_hand, 0), greatest(coalesce(p_reserved, 0), 0), p_source)
33
+ ON CONFLICT (tenant_id, variant_id, coalesce(unit_id, '00000000-0000-0000-0000-000000000000'::uuid)) DO UPDATE
34
+ SET on_hand = public.stock_balances.on_hand + coalesce(p_on_hand, 0),
35
+ reserved = greatest(public.stock_balances.reserved + coalesce(p_reserved, 0), 0),
36
+ updated_at = now(),
37
+ updated_by = p_source
38
+ RETURNING on_hand, reserved INTO v_on_hand, v_reserved;
39
+
40
+ -- Below zero is a data question, not a rounding one: the caller that asked for
41
+ -- it is the one that has to answer — unless the inventory, following the
42
+ -- house's «estoque negativo» switch, said it may (225).
43
+ IF v_on_hand < 0 AND coalesce(current_setting('fayz.stock_allow_negative', true), 'off') <> 'on' THEN
44
+ RAISE EXCEPTION 'stock_apply: % would take variant % below zero (%)', p_source, p_variant, v_on_hand
45
+ USING ERRCODE = '23514';
46
+ END IF;
47
+
48
+ RETURN jsonb_build_object('on_hand', v_on_hand, 'reserved', v_reserved, 'available', v_on_hand - v_reserved);
49
+ END $function$;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.30.0",
6
+ "version": "0.31.0",
7
7
  "description": "Fayz SDK database layer — Drizzle schema primitives, spine references, and migration helpers shared across plugins.",
8
8
  "type": "module",
9
9
  "sideEffects": false,