@lambda-development/erp-core 0.6.13 → 0.6.14

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/index.js CHANGED
@@ -1,28 +1,28 @@
1
1
  import { jsx as e, jsxs as r, Fragment as Ce } from "react/jsx-runtime";
2
- import { useState as w, useEffect as re, useCallback as Pe, useContext as nn, createContext as an, useRef as oe, useMemo as Ne, useLayoutEffect as pn, StrictMode as Ia } from "react";
3
- import { createRoot as Ba } from "react-dom/client";
4
- import { useQueryClient as He, useQuery as ue, useMutation as me, QueryClientProvider as Ea, QueryClient as La } from "@tanstack/react-query";
5
- import { NavLink as qt, useLocation as vt, useNavigate as Ee, Outlet as Oa, Navigate as qa, Link as ve, useSearchParams as zt, useParams as ut, createBrowserRouter as za, RouterProvider as Ma } from "react-router-dom";
6
- import { useTranslation as X, initReactI18next as Fa } from "react-i18next";
7
- import { BookOpen as $a, ShoppingCart as Wn, CreditCard as Ua, FileText as rn, Package as Hn, BarChart3 as Va, Database as Ka, Settings as ja, MessageCircle as Ga, ChevronDown as Mt, ChevronRight as Dt, Plus as Qn, Trash2 as Yn, LineChart as Wa, ArrowLeft as Ha, TrendingUp as Qa, ArrowDownRight as Ya, ArrowUpRight as Ja, Wallet as Za, Receipt as hn, ChevronLeft as Xa, Info as er } from "lucide-react";
8
- import { createColumnHelper as Jn, useReactTable as Zn, getCoreRowModel as Xn, flexRender as Bt } from "@tanstack/react-table";
9
- import { createPortal as ea } from "react-dom";
10
- import { ResponsiveContainer as tr, LineChart as nr, CartesianGrid as gn, XAxis as fn, YAxis as yn, Tooltip as Vt, Line as ar, PieChart as rr, Pie as sr, Cell as ir, BarChart as or, Bar as lr } from "recharts";
11
- import ta from "i18next";
12
- import { default as rl } from "i18next";
13
- let ct = "/api";
14
- function Go(t) {
15
- ct = t.replace(/\/+$/, "");
16
- }
17
- function cr(t) {
18
- return new URL(`${ct}${t}`, window.location.origin).toString();
2
+ import { useState as w, useEffect as re, useCallback as Pe, useContext as an, createContext as rn, useRef as oe, useMemo as Ne, useLayoutEffect as hn, StrictMode as Ba } from "react";
3
+ import { createRoot as Ea } from "react-dom/client";
4
+ import { useQueryClient as He, useQuery as ue, useMutation as me, QueryClientProvider as La, QueryClient as Oa } from "@tanstack/react-query";
5
+ import { NavLink as qt, useLocation as bt, useNavigate as Ee, Outlet as qa, Navigate as za, Link as ve, useSearchParams as zt, useParams as dt, createBrowserRouter as Ma, RouterProvider as Fa } from "react-router-dom";
6
+ import { useTranslation as X, initReactI18next as $a } from "react-i18next";
7
+ import { BookOpen as Ua, ShoppingCart as Hn, CreditCard as Va, FileText as sn, Package as Qn, BarChart3 as Ka, Database as ja, Settings as Ga, MessageCircle as Wa, ChevronDown as Mt, ChevronRight as Dt, Plus as Yn, Trash2 as Jn, LineChart as Ha, ArrowLeft as Qa, TrendingUp as Ya, ArrowDownRight as Ja, ArrowUpRight as Za, Wallet as Xa, Receipt as gn, ChevronLeft as er, Info as tr } from "lucide-react";
8
+ import { createColumnHelper as Zn, useReactTable as Xn, getCoreRowModel as ea, flexRender as Bt } from "@tanstack/react-table";
9
+ import { createPortal as ta } from "react-dom";
10
+ import { ResponsiveContainer as nr, LineChart as ar, CartesianGrid as fn, XAxis as yn, YAxis as bn, Tooltip as Kt, Line as rr, PieChart as sr, Pie as ir, Cell as or, BarChart as lr, Bar as cr } from "recharts";
11
+ import na from "i18next";
12
+ import { default as il } from "i18next";
13
+ let lt = "/api";
14
+ function Ho(t) {
15
+ lt = t.replace(/\/+$/, "");
16
+ }
17
+ function dr(t) {
18
+ return new URL(`${lt}${t}`, window.location.origin).toString();
19
19
  }
20
20
  class Ue extends Error {
21
21
  constructor(n, a) {
22
22
  super(a), this.status = n;
23
23
  }
24
24
  }
25
- function dr(t) {
25
+ function ur(t) {
26
26
  if (!t) return "Request failed";
27
27
  if (typeof t == "string") return t;
28
28
  if (Array.isArray(t))
@@ -38,7 +38,7 @@ function dr(t) {
38
38
  return String(t);
39
39
  }
40
40
  async function L(t, n) {
41
- const a = await fetch(`${ct}${t}`, {
41
+ const a = await fetch(`${lt}${t}`, {
42
42
  headers: { "Content-Type": "application/json" },
43
43
  credentials: "include",
44
44
  ...n
@@ -47,7 +47,7 @@ async function L(t, n) {
47
47
  if (a.status === 401 && !t.startsWith("/auth/"))
48
48
  throw window.location.href = "/login", new Ue(401, "Session expired");
49
49
  const s = await a.json().catch(() => ({ detail: a.statusText }));
50
- throw new Ue(a.status, dr(s.detail));
50
+ throw new Ue(a.status, ur(s.detail));
51
51
  }
52
52
  return a.json();
53
53
  }
@@ -65,7 +65,7 @@ const I = {
65
65
  uploadChatAttachment: async (t, n) => {
66
66
  const a = new FormData();
67
67
  a.append("file", n), a.append("session_id", t);
68
- const s = await fetch(`${ct}/chat/attachments`, {
68
+ const s = await fetch(`${lt}/chat/attachments`, {
69
69
  method: "POST",
70
70
  credentials: "include",
71
71
  body: a
@@ -78,7 +78,7 @@ const I = {
78
78
  }
79
79
  return s.json();
80
80
  },
81
- getChatAttachmentUrl: (t) => `${ct}/chat/attachments/${encodeURIComponent(t)}`,
81
+ getChatAttachmentUrl: (t) => `${lt}/chat/attachments/${encodeURIComponent(t)}`,
82
82
  // Chat
83
83
  createChatSession: () => L(
84
84
  "/chat/sessions",
@@ -120,7 +120,7 @@ const I = {
120
120
  uploadProposalAppendix: async (t, n) => {
121
121
  const a = new FormData();
122
122
  a.append("file", n);
123
- const s = await fetch(`${ct}/proposals/${encodeURIComponent(t)}/appendix`, {
123
+ const s = await fetch(`${lt}/proposals/${encodeURIComponent(t)}/appendix`, {
124
124
  method: "POST",
125
125
  credentials: "include",
126
126
  body: a
@@ -134,7 +134,7 @@ const I = {
134
134
  return s.json();
135
135
  },
136
136
  deleteProposalAppendix: (t) => L(`/proposals/${encodeURIComponent(t)}/appendix`, { method: "DELETE" }),
137
- proposalPdfUrl: (t) => `${ct}/documents/proposal/${encodeURIComponent(t)}/pdf`,
137
+ proposalPdfUrl: (t) => `${lt}/documents/proposal/${encodeURIComponent(t)}/pdf`,
138
138
  // Masters
139
139
  listMasters: (t, n) => L(
140
140
  `/masters/${t}${Be(n)}`
@@ -202,7 +202,7 @@ const I = {
202
202
  const a = new URLSearchParams();
203
203
  n != null && n.link && a.set("link", "1"), n != null && n.invite && a.set("invite", n.invite);
204
204
  const s = a.toString() ? `?${a.toString()}` : "";
205
- return cr(`/auth/${encodeURIComponent(t)}/login${s}`);
205
+ return dr(`/auth/${encodeURIComponent(t)}/login${s}`);
206
206
  },
207
207
  oauthListIdentities: () => L("/auth/oauth/identities"),
208
208
  authRegister: (t) => L("/auth/register", { method: "POST", body: JSON.stringify(t) }),
@@ -240,8 +240,8 @@ const I = {
240
240
  { method: "DELETE" }
241
241
  ),
242
242
  getDemoSpend: () => L("/admin/demo-spend")
243
- }, na = an(null);
244
- function ur({ children: t }) {
243
+ }, aa = rn(null);
244
+ function mr({ children: t }) {
245
245
  const [n, a] = w(null), [s, o] = w(!0);
246
246
  re(() => {
247
247
  I.authMe().then((d) => a(d)).catch(() => a(null)).finally(() => o(!1));
@@ -265,14 +265,14 @@ function ur({ children: t }) {
265
265
  } catch {
266
266
  }
267
267
  }, []);
268
- return /* @__PURE__ */ e(na.Provider, { value: { user: n, loading: s, login: i, register: l, logout: c, refreshUser: h }, children: t });
268
+ return /* @__PURE__ */ e(aa.Provider, { value: { user: n, loading: s, login: i, register: l, logout: c, refreshUser: h }, children: t });
269
269
  }
270
270
  function st() {
271
- const t = nn(na);
271
+ const t = an(aa);
272
272
  if (!t) throw new Error("useAuth must be used within AuthProvider");
273
273
  return t;
274
274
  }
275
- const aa = an(null), bn = {
275
+ const ra = rn(null), vn = {
276
276
  quotation: { group: "Selling", item: "Quotation" },
277
277
  "sales-order": { group: "Selling", item: "Sales Order" },
278
278
  "sales-invoice": { group: "Selling", item: "Sales Invoice" },
@@ -288,31 +288,31 @@ const aa = an(null), bn = {
288
288
  "delivery-note": { group: "Stock", item: "Delivery Note" },
289
289
  "purchase-receipt": { group: "Stock", item: "Purchase Receipt" },
290
290
  "pricing-rule": { group: "Settings", item: "Pricing Rule" }
291
- }, vn = {
291
+ }, xn = {
292
292
  customer: { group: "Masters", item: "Customer" },
293
293
  supplier: { group: "Masters", item: "Supplier" },
294
294
  item: { group: "Masters", item: "Item" },
295
295
  warehouse: { group: "Masters", item: "Warehouse" },
296
296
  company: { group: "Masters", item: "Company" }
297
297
  };
298
- function Kt(t) {
298
+ function jt(t) {
299
299
  return typeof t != "string" ? null : t.trim().toLowerCase().replace(/\s+/g, "-");
300
300
  }
301
- function mr(t, n) {
301
+ function pr(t, n) {
302
302
  if (t === "create_custom_analytics_report" || t === "update_custom_analytics_report")
303
303
  return { group: "Custom Analytics", item: "" };
304
304
  if (!n) return null;
305
305
  let a = null;
306
- if (t === "create_document" || t === "update_document" || t === "submit_document" || t === "cancel_document" ? a = Kt(n.doctype) : t === "convert_document" && (a = Kt(n.target_doctype)), a && bn[a])
307
- return bn[a];
306
+ if (t === "create_document" || t === "update_document" || t === "submit_document" || t === "cancel_document" ? a = jt(n.doctype) : t === "convert_document" && (a = jt(n.target_doctype)), a && vn[a])
307
+ return vn[a];
308
308
  if (t === "create_master" || t === "update_master") {
309
- const s = Kt(n.master_type);
310
- if (s && vn[s])
311
- return vn[s];
309
+ const s = jt(n.master_type);
310
+ if (s && xn[s])
311
+ return xn[s];
312
312
  }
313
313
  return null;
314
314
  }
315
- function xn(t) {
315
+ function Nn(t) {
316
316
  return {
317
317
  id: t.id,
318
318
  type: t.role === "user" ? "user" : "assistant",
@@ -321,11 +321,11 @@ function xn(t) {
321
321
  attachments: t.attachments
322
322
  };
323
323
  }
324
- const ra = "lambda-erp:known-chat-sessions";
325
- function sn() {
324
+ const sa = "lambda-erp:known-chat-sessions";
325
+ function on() {
326
326
  if (typeof localStorage > "u") return /* @__PURE__ */ new Set();
327
327
  try {
328
- const t = localStorage.getItem(ra);
328
+ const t = localStorage.getItem(sa);
329
329
  if (!t) return /* @__PURE__ */ new Set();
330
330
  const n = JSON.parse(t);
331
331
  return new Set(Array.isArray(n) ? n.filter((a) => typeof a == "string") : []);
@@ -333,22 +333,22 @@ function sn() {
333
333
  return /* @__PURE__ */ new Set();
334
334
  }
335
335
  }
336
- function sa(t) {
336
+ function ia(t) {
337
337
  if (!(typeof localStorage > "u"))
338
338
  try {
339
- localStorage.setItem(ra, JSON.stringify([...t]));
339
+ localStorage.setItem(sa, JSON.stringify([...t]));
340
340
  } catch {
341
341
  }
342
342
  }
343
- function ia(t) {
344
- const n = sn();
345
- n.has(t) || (n.add(t), sa(n));
343
+ function oa(t) {
344
+ const n = on();
345
+ n.has(t) || (n.add(t), ia(n));
346
346
  }
347
- function Nn(t) {
348
- const n = sn();
349
- n.delete(t) && sa(n);
347
+ function wn(t) {
348
+ const n = on();
349
+ n.delete(t) && ia(n);
350
350
  }
351
- function pr() {
351
+ function hr() {
352
352
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `req-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
353
353
  }
354
354
  function tt(t) {
@@ -356,7 +356,7 @@ function tt(t) {
356
356
  const n = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(t) ? t.replace(" ", "T") : t, a = new Date(n).getTime();
357
357
  return Number.isNaN(a) ? 0 : a;
358
358
  }
359
- function hr({ children: t }) {
359
+ function gr({ children: t }) {
360
360
  const n = He(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [h, d] = w({}), [p, u] = w({}), [f, v] = w({}), [N, b] = w({}), [C, S] = w({}), [x, y] = w(null), [m, D] = w("connecting"), [T, U] = w(0), Z = oe(null), g = oe(null), R = oe(/* @__PURE__ */ new Map()), W = oe(null), $ = oe({}), de = oe({}), A = oe(null);
361
361
  function _(B) {
362
362
  for (const K of R.current.values())
@@ -413,7 +413,7 @@ function hr({ children: t }) {
413
413
  }
414
414
  function ie(B, K, Y) {
415
415
  return new Promise((xe, we) => {
416
- const Re = pr();
416
+ const Re = hr();
417
417
  R.current.set(Re, {
418
418
  expectedType: Y,
419
419
  resolve: xe,
@@ -441,24 +441,24 @@ function hr({ children: t }) {
441
441
  }, we.onmessage = (Re) => {
442
442
  var ot;
443
443
  try {
444
- const j = JSON.parse(Re.data), Ze = typeof j.request_id == "string" ? j.request_id : null, fe = typeof j.type == "string" ? j.type : null, O = typeof j.session_id == "string" ? j.session_id : null;
444
+ const j = JSON.parse(Re.data), Ze = typeof j.request_id == "string" ? j.request_id : null, ye = typeof j.type == "string" ? j.type : null, O = typeof j.session_id == "string" ? j.session_id : null;
445
445
  if (Ze) {
446
446
  const q = R.current.get(Ze);
447
- q && (fe === "error" ? (R.current.delete(Ze), q.reject(new Error(String(j.content || "Request failed.")))) : fe === q.expectedType && (R.current.delete(Ze), q.resolve(j)));
447
+ q && (ye === "error" ? (R.current.delete(Ze), q.reject(new Error(String(j.content || "Request failed.")))) : ye === q.expectedType && (R.current.delete(Ze), q.resolve(j)));
448
448
  }
449
- if (fe === "sessions_list") {
449
+ if (ye === "sessions_list") {
450
450
  const q = Array.isArray(j.sessions) ? j.sessions : [];
451
451
  Se(q), s(
452
452
  ne(
453
453
  q
454
454
  )
455
455
  );
456
- const G = new Set(q.map((ke) => ke.id)), Me = [...sn()].filter((ke) => !G.has(ke));
456
+ const G = new Set(q.map((ke) => ke.id)), Me = [...on()].filter((ke) => !G.has(ke));
457
457
  Me.length > 0 && Promise.all(
458
458
  Me.map(async (ke) => {
459
459
  try {
460
460
  const pe = await I.getChatSession(ke);
461
- return !pe || pe.detail || !pe.id ? (Nn(ke), null) : pe;
461
+ return !pe || pe.detail || !pe.id ? (wn(ke), null) : pe;
462
462
  } catch {
463
463
  return null;
464
464
  }
@@ -466,20 +466,20 @@ function hr({ children: t }) {
466
466
  ).then((ke) => {
467
467
  const pe = ke.filter((ge) => !!ge);
468
468
  pe.length && (Se(pe), H((ge) => [
469
- ...pe.filter((ft) => !ge.some((Nt) => Nt.id === ft.id)),
469
+ ...pe.filter((gt) => !ge.some((xt) => xt.id === gt.id)),
470
470
  ...ge
471
471
  ]));
472
472
  });
473
473
  return;
474
474
  }
475
- if (fe === "session_created") {
475
+ if (ye === "session_created") {
476
476
  const q = j.session;
477
477
  if (!q) return;
478
- ia(q.id), Se([q]), H((G) => [q, ...G.filter((J) => J.id !== q.id)]);
478
+ oa(q.id), Se([q]), H((G) => [q, ...G.filter((J) => J.id !== q.id)]);
479
479
  return;
480
480
  }
481
- if (fe === "session_deleted" && O) {
482
- Nn(O), H((G) => G.filter((J) => J.id !== O)), i((G) => {
481
+ if (ye === "session_deleted" && O) {
482
+ wn(O), H((G) => G.filter((J) => J.id !== O)), i((G) => {
483
483
  const J = { ...G };
484
484
  return delete J[O], J;
485
485
  }), v((G) => {
@@ -505,16 +505,16 @@ function hr({ children: t }) {
505
505
  delete q[O], $.current = q;
506
506
  return;
507
507
  }
508
- if (fe === "history_loaded" && O) {
509
- const q = Array.isArray(j.messages) ? j.messages.map(xn) : [], G = j.before_id != null, J = !!j.has_more, Me = typeof j.oldest_id == "number" ? j.oldest_id : null;
508
+ if (ye === "history_loaded" && O) {
509
+ const q = Array.isArray(j.messages) ? j.messages.map(Nn) : [], G = j.before_id != null, J = !!j.has_more, Me = typeof j.oldest_id == "number" ? j.oldest_id : null;
510
510
  i((pe) => {
511
511
  if (G) {
512
- const ge = pe[O] ?? [], ft = new Set(
512
+ const ge = pe[O] ?? [], gt = new Set(
513
513
  ge.map((Xe) => Xe.id).filter((Xe) => typeof Xe == "number")
514
- ), Nt = q.filter(
515
- (Xe) => Xe.id === void 0 || !ft.has(Xe.id)
514
+ ), xt = q.filter(
515
+ (Xe) => Xe.id === void 0 || !gt.has(Xe.id)
516
516
  );
517
- return { ...pe, [O]: [...Nt, ...ge] };
517
+ return { ...pe, [O]: [...xt, ...ge] };
518
518
  }
519
519
  return { ...pe, [O]: q };
520
520
  }), c((pe) => ({ ...pe, [O]: J })), d((pe) => ({ ...pe, [O]: Me })), u((pe) => ({ ...pe, [O]: !1 }));
@@ -527,24 +527,24 @@ function hr({ children: t }) {
527
527
  }
528
528
  return;
529
529
  }
530
- if (fe === "history_cleared" && O) {
530
+ if (ye === "history_cleared" && O) {
531
531
  i((q) => ({ ...q, [O]: [] })), c((q) => ({ ...q, [O]: !1 })), d((q) => ({ ...q, [O]: null })), u((q) => ({ ...q, [O]: !1 })), ee(O, !1), se(O, "idle"), P(O, null);
532
532
  return;
533
533
  }
534
- if (fe === "message_added" && O) {
534
+ if (ye === "message_added" && O) {
535
535
  const q = j.message;
536
536
  if (!q) return;
537
537
  ce(O, q.created_at), q.role === "user" && P(O, null), z(O, (G) => [
538
538
  ...G.filter((J) => J.type !== "thinking"),
539
- xn(q)
539
+ Nn(q)
540
540
  ]), H((G) => G);
541
541
  return;
542
542
  }
543
- if (fe === "demo_started" && O) {
543
+ if (ye === "demo_started" && O) {
544
544
  se(O, "running"), P(O, null);
545
545
  return;
546
546
  }
547
- if (fe === "demo_typing" && O) {
547
+ if (ye === "demo_typing" && O) {
548
548
  se(O, "running"), P(O, {
549
549
  content: String(j.content || ""),
550
550
  seq: Math.max(0, Number(j.seq || 0)),
@@ -552,23 +552,23 @@ function hr({ children: t }) {
552
552
  });
553
553
  return;
554
554
  }
555
- if (fe === "demo_replay_complete" && O) {
555
+ if (ye === "demo_replay_complete" && O) {
556
556
  se(O, "complete"), P(O, null);
557
557
  return;
558
558
  }
559
- if (fe === "navigation_flash") {
559
+ if (ye === "navigation_flash") {
560
560
  const q = typeof j.group == "string" ? j.group : "", G = typeof j.item == "string" ? j.item : void 0;
561
561
  q && V(q, G);
562
562
  return;
563
563
  }
564
- if (fe === "session_title_updated" && O) {
564
+ if (ye === "session_title_updated" && O) {
565
565
  const q = typeof j.title == "string" ? j.title : "";
566
566
  H(
567
567
  (G) => G.map((J) => J.id === O ? { ...J, title: q } : J)
568
568
  );
569
569
  return;
570
570
  }
571
- if (fe === "thinking" && O) {
571
+ if (ye === "thinking" && O) {
572
572
  ee(O, !0), z(O, (q) => {
573
573
  const G = q.find((J) => J.type === "thinking");
574
574
  return [
@@ -583,7 +583,7 @@ function hr({ children: t }) {
583
583
  });
584
584
  return;
585
585
  }
586
- if (fe === "llm_provider" && O) {
586
+ if (ye === "llm_provider" && O) {
587
587
  const q = typeof j.provider == "string" ? j.provider : void 0, G = typeof j.model == "string" ? j.model : void 0, Me = (typeof j.role == "string" ? j.role : void 0) === "code_specialist" ? "Delegating to code specialist..." : void 0;
588
588
  ee(O, !0), z(O, (ke) => ke.some((ge) => ge.type === "thinking") ? ke.map((ge) => ge.type === "thinking" ? {
589
589
  ...ge,
@@ -601,7 +601,7 @@ function hr({ children: t }) {
601
601
  ]);
602
602
  return;
603
603
  }
604
- if (fe === "tool_call" && O) {
604
+ if (ye === "tool_call" && O) {
605
605
  de.current = {
606
606
  ...de.current,
607
607
  [O]: {
@@ -619,14 +619,14 @@ function hr({ children: t }) {
619
619
  ]);
620
620
  return;
621
621
  }
622
- if (fe === "tool_result" && O) {
622
+ if (ye === "tool_result" && O) {
623
623
  const q = de.current[O];
624
624
  if (q && q.tool === String(j.tool || "") && j.success)
625
625
  if (q.tool === "create_custom_analytics_report" || q.tool === "update_custom_analytics_report") {
626
626
  const J = typeof j.report_id == "string" ? j.report_id : void 0, Me = typeof ((ot = q.args) == null ? void 0 : ot.report_id) == "string" ? q.args.report_id : void 0;
627
627
  V("Custom Analytics", J || Me || ""), n.invalidateQueries({ queryKey: ["runtime-drafts"] });
628
628
  } else {
629
- const J = mr(q.tool, q.args);
629
+ const J = pr(q.tool, q.args);
630
630
  J && V(J.group, J.item);
631
631
  }
632
632
  de.current = {
@@ -643,11 +643,11 @@ function hr({ children: t }) {
643
643
  ]);
644
644
  return;
645
645
  }
646
- if (fe === "complete" && O) {
646
+ if (ye === "complete" && O) {
647
647
  ee(O, !1), z(O, (q) => q.filter((G) => G.type !== "thinking"));
648
648
  return;
649
649
  }
650
- if (fe === "error") {
650
+ if (ye === "error") {
651
651
  if (Ze)
652
652
  return;
653
653
  O && (ee(O, !1), z(O, (q) => [
@@ -701,10 +701,10 @@ function hr({ children: t }) {
701
701
  async function Fe(B) {
702
702
  await ie("delete_session", { session_id: B }, "session_deleted");
703
703
  }
704
- async function xt(B) {
704
+ async function vt(B) {
705
705
  await ie("load_history", { session_id: B }, "history_loaded");
706
706
  }
707
- async function pt(B) {
707
+ async function mt(B) {
708
708
  if (p[B]) return;
709
709
  const K = h[B];
710
710
  if (K != null && l[B]) {
@@ -757,17 +757,17 @@ function hr({ children: t }) {
757
757
  function Oe(B) {
758
758
  return B ? !!l[B] : !1;
759
759
  }
760
- function ht(B) {
760
+ function pt(B) {
761
761
  return B ? !!p[B] : !1;
762
762
  }
763
763
  function it(B) {
764
764
  return B ? N[B] ?? "idle" : "idle";
765
765
  }
766
- function gt(B) {
766
+ function ht(B) {
767
767
  return B ? C[B] ?? null : null;
768
768
  }
769
769
  return /* @__PURE__ */ e(
770
- aa.Provider,
770
+ ra.Provider,
771
771
  {
772
772
  value: {
773
773
  sessions: a,
@@ -778,24 +778,24 @@ function hr({ children: t }) {
778
778
  startDemo: Te,
779
779
  completeDemoTyping: Ke,
780
780
  deleteSession: Fe,
781
- loadHistory: xt,
782
- loadMoreHistory: pt,
781
+ loadHistory: vt,
782
+ loadMoreHistory: mt,
783
783
  clearHistory: Je,
784
784
  sendMessage: De,
785
785
  transcribeAudio: Ie,
786
786
  getMessages: je,
787
787
  hasMoreHistory: Oe,
788
- isLoadingOlder: ht,
788
+ isLoadingOlder: pt,
789
789
  isThinking: Qe,
790
790
  getDemoStatus: it,
791
- getDemoTypingCue: gt
791
+ getDemoTypingCue: ht
792
792
  },
793
793
  children: t
794
794
  }
795
795
  );
796
796
  }
797
- function mt() {
798
- const t = nn(aa);
797
+ function ut() {
798
+ const t = an(ra);
799
799
  if (!t)
800
800
  throw new Error("useChat must be used within ChatProvider.");
801
801
  return t;
@@ -810,18 +810,18 @@ function qe(t, n = "USD") {
810
810
  minimumFractionDigits: 2
811
811
  }).format(t ?? 0);
812
812
  }
813
- function Jt(t, n = 2) {
813
+ function Zt(t, n = 2) {
814
814
  return new Intl.NumberFormat("en-US", {
815
815
  minimumFractionDigits: n,
816
816
  maximumFractionDigits: n
817
817
  }).format(t ?? 0);
818
818
  }
819
- let oa;
820
- function Wo(t) {
821
- oa = t;
819
+ let la;
820
+ function Qo(t) {
821
+ la = t;
822
822
  }
823
823
  function Ft(t) {
824
- return t ? new Date(t).toLocaleDateString(oa, {
824
+ return t ? new Date(t).toLocaleDateString(la, {
825
825
  year: "numeric",
826
826
  month: "2-digit",
827
827
  day: "2-digit"
@@ -831,7 +831,7 @@ function $e(t, n) {
831
831
  const a = parseFloat(String(t ?? 0)) || 0;
832
832
  return n !== void 0 ? parseFloat(a.toFixed(n)) : a;
833
833
  }
834
- const gr = {
834
+ const fr = {
835
835
  // Primary: brand-coloured fill + a 1px inset top highlight for depth
836
836
  // (button-highlight shadow). On press, the button shifts down 1px —
837
837
  // tiny detail, large perceived "this is responsive".
@@ -839,7 +839,7 @@ const gr = {
839
839
  secondary: "bg-surface text-fg ring-1 ring-line hover:bg-surface-subtle active:translate-y-px focus-visible:ring-fg/20",
840
840
  danger: "bg-red-600 text-white shadow-button-highlight hover:bg-red-700 active:translate-y-px focus-visible:ring-red-500/40",
841
841
  ghost: "bg-transparent text-fg-muted hover:bg-surface-subtle hover:text-fg focus-visible:ring-fg/20"
842
- }, fr = {
842
+ }, yr = {
843
843
  sm: "h-8 px-3 text-sm",
844
844
  md: "h-10 px-4 text-sm",
845
845
  lg: "h-11 px-5 text-sm"
@@ -867,8 +867,8 @@ function Q({
867
867
  "transition-all duration-150",
868
868
  "focus-visible:outline-none focus-visible:ring-2",
869
869
  "disabled:cursor-not-allowed disabled:opacity-50 disabled:active:translate-y-0",
870
- gr[t],
871
- fr[n],
870
+ fr[t],
871
+ yr[n],
872
872
  i
873
873
  ),
874
874
  children: o
@@ -921,8 +921,8 @@ function te({ label: t, hint: n, error: a, className: s, id: o, ...i }) {
921
921
  )
922
922
  ] });
923
923
  }
924
- const la = an(null);
925
- function yr({ children: t }) {
924
+ const ca = rn(null);
925
+ function br({ children: t }) {
926
926
  const { t: n } = X(), [a, s] = w(null), [o, i] = w(""), l = Pe(
927
927
  (f) => new Promise((v) => s({ kind: "confirm", opts: f, resolve: v })),
928
928
  []
@@ -934,7 +934,7 @@ function yr({ children: t }) {
934
934
  ), h = Ne(() => ({ confirm: l, prompt: c }), [l, c]), d = (f) => {
935
935
  a && (a.resolve(f), s(null));
936
936
  }, p = () => d((a == null ? void 0 : a.kind) === "prompt" ? o : !0), u = () => d((a == null ? void 0 : a.kind) === "prompt" ? null : !1);
937
- return /* @__PURE__ */ r(la.Provider, { value: h, children: [
937
+ return /* @__PURE__ */ r(ca.Provider, { value: h, children: [
938
938
  t,
939
939
  a && /* @__PURE__ */ r(
940
940
  "div",
@@ -974,21 +974,21 @@ function yr({ children: t }) {
974
974
  )
975
975
  ] });
976
976
  }
977
- function ca() {
978
- const t = nn(la);
977
+ function da() {
978
+ const t = an(ca);
979
979
  if (!t) throw new Error("useConfirm/usePrompt must be used within <DialogProvider>");
980
980
  return t;
981
981
  }
982
- function da() {
983
- return ca().confirm;
982
+ function ua() {
983
+ return da().confirm;
984
984
  }
985
- function br() {
986
- return ca().prompt;
985
+ function vr() {
986
+ return da().prompt;
987
987
  }
988
- const dt = [
988
+ const ct = [
989
989
  {
990
990
  label: "Introduction",
991
- icon: /* @__PURE__ */ e($a, { className: "h-4 w-4" }),
991
+ icon: /* @__PURE__ */ e(Ua, { className: "h-4 w-4" }),
992
992
  items: [
993
993
  { label: "Getting Started", path: "/tutorial" },
994
994
  { label: "Company Setup", path: "/setup" },
@@ -997,7 +997,7 @@ const dt = [
997
997
  },
998
998
  {
999
999
  label: "Selling",
1000
- icon: /* @__PURE__ */ e(Wn, { className: "h-4 w-4" }),
1000
+ icon: /* @__PURE__ */ e(Hn, { className: "h-4 w-4" }),
1001
1001
  items: [
1002
1002
  { label: "Quotation", path: "/app/quotation" },
1003
1003
  { label: "Proposal", path: "/app/proposal" },
@@ -1008,7 +1008,7 @@ const dt = [
1008
1008
  },
1009
1009
  {
1010
1010
  label: "Buying",
1011
- icon: /* @__PURE__ */ e(Ua, { className: "h-4 w-4" }),
1011
+ icon: /* @__PURE__ */ e(Va, { className: "h-4 w-4" }),
1012
1012
  items: [
1013
1013
  { label: "Purchase Order", path: "/app/purchase-order" },
1014
1014
  { label: "Purchase Invoice", path: "/app/purchase-invoice" }
@@ -1016,7 +1016,7 @@ const dt = [
1016
1016
  },
1017
1017
  {
1018
1018
  label: "Accounting",
1019
- icon: /* @__PURE__ */ e(rn, { className: "h-4 w-4" }),
1019
+ icon: /* @__PURE__ */ e(sn, { className: "h-4 w-4" }),
1020
1020
  items: [
1021
1021
  { label: "Chart of Accounts", path: "/reports/chart-of-accounts" },
1022
1022
  { label: "Payment Entry", path: "/app/payment-entry" },
@@ -1028,7 +1028,7 @@ const dt = [
1028
1028
  },
1029
1029
  {
1030
1030
  label: "Stock",
1031
- icon: /* @__PURE__ */ e(Hn, { className: "h-4 w-4" }),
1031
+ icon: /* @__PURE__ */ e(Qn, { className: "h-4 w-4" }),
1032
1032
  items: [
1033
1033
  { label: "Stock Entry", path: "/app/stock-entry" },
1034
1034
  { label: "Delivery Note", path: "/app/delivery-note" },
@@ -1037,7 +1037,7 @@ const dt = [
1037
1037
  },
1038
1038
  {
1039
1039
  label: "Reports",
1040
- icon: /* @__PURE__ */ e(Va, { className: "h-4 w-4" }),
1040
+ icon: /* @__PURE__ */ e(Ka, { className: "h-4 w-4" }),
1041
1041
  items: [
1042
1042
  { label: "Trial Balance", path: "/reports/trial-balance" },
1043
1043
  { label: "Profit & Loss", path: "/reports/profit-and-loss" },
@@ -1051,7 +1051,7 @@ const dt = [
1051
1051
  },
1052
1052
  {
1053
1053
  label: "Masters",
1054
- icon: /* @__PURE__ */ e(Ka, { className: "h-4 w-4" }),
1054
+ icon: /* @__PURE__ */ e(ja, { className: "h-4 w-4" }),
1055
1055
  items: [
1056
1056
  { label: "Company", path: "/masters/company" },
1057
1057
  { label: "Customer", path: "/masters/customer" },
@@ -1062,7 +1062,7 @@ const dt = [
1062
1062
  },
1063
1063
  {
1064
1064
  label: "Settings",
1065
- icon: /* @__PURE__ */ e(ja, { className: "h-4 w-4" }),
1065
+ icon: /* @__PURE__ */ e(Ga, { className: "h-4 w-4" }),
1066
1066
  items: [
1067
1067
  { label: "General", path: "/admin/settings" },
1068
1068
  { label: "Pricing Rule", path: "/app/pricing-rule" },
@@ -1070,60 +1070,60 @@ const dt = [
1070
1070
  ]
1071
1071
  }
1072
1072
  ];
1073
- function vr() {
1074
- return dt;
1073
+ function xr() {
1074
+ return ct;
1075
1075
  }
1076
- function Ho(t, n) {
1077
- const a = dt.findIndex((s) => s.label === t.label);
1076
+ function Yo(t, n) {
1077
+ const a = ct.findIndex((s) => s.label === t.label);
1078
1078
  if (a >= 0) {
1079
- dt[a] = t;
1079
+ ct[a] = t;
1080
1080
  return;
1081
1081
  }
1082
- (n == null ? void 0 : n.index) != null ? dt.splice(n.index, 0, t) : dt.push(t);
1082
+ (n == null ? void 0 : n.index) != null ? ct.splice(n.index, 0, t) : ct.push(t);
1083
1083
  }
1084
- function Qo(t, n) {
1085
- const a = dt.find((s) => s.label === t);
1086
- a ? a.items.push(n) : dt.push({ label: t, icon: null, items: [n] });
1084
+ function Jo(t, n) {
1085
+ const a = ct.find((s) => s.label === t);
1086
+ a ? a.items.push(n) : ct.push({ label: t, icon: null, items: [n] });
1087
1087
  }
1088
- let Zt = { appName: "Lambda ERP" };
1089
- function Yo(t) {
1090
- if (Zt = { ...Zt, ...t }, !(typeof document > "u") && (t.appName && (document.title = t.appName), t.tokens)) {
1088
+ let Xt = { appName: "Lambda ERP" };
1089
+ function Zo(t) {
1090
+ if (Xt = { ...Xt, ...t }, !(typeof document > "u") && (t.appName && (document.title = t.appName), t.tokens)) {
1091
1091
  const n = document.documentElement;
1092
1092
  for (const [a, s] of Object.entries(t.tokens))
1093
1093
  n.style.setProperty(a.startsWith("--") ? a : `--${a}`, s);
1094
1094
  }
1095
1095
  }
1096
- function xr() {
1097
- return Zt;
1096
+ function Nr() {
1097
+ return Xt;
1098
1098
  }
1099
- const ua = "sidebar-collapsed";
1100
- function jt() {
1099
+ const ma = "sidebar-collapsed";
1100
+ function Gt() {
1101
1101
  try {
1102
- const t = localStorage.getItem(ua);
1102
+ const t = localStorage.getItem(ma);
1103
1103
  return t ? new Set(JSON.parse(t)) : /* @__PURE__ */ new Set();
1104
1104
  } catch {
1105
1105
  return /* @__PURE__ */ new Set();
1106
1106
  }
1107
1107
  }
1108
- function wn(t) {
1109
- localStorage.setItem(ua, JSON.stringify([...t]));
1108
+ function kn(t) {
1109
+ localStorage.setItem(ma, JSON.stringify([...t]));
1110
1110
  }
1111
- function on(t) {
1112
- const [n, a] = w(() => !jt().has(t)), s = Pe(() => {
1111
+ function ln(t) {
1112
+ const [n, a] = w(() => !Gt().has(t)), s = Pe(() => {
1113
1113
  a((i) => {
1114
- const l = jt();
1115
- return i ? l.add(t) : l.delete(t), wn(l), !i;
1114
+ const l = Gt();
1115
+ return i ? l.add(t) : l.delete(t), kn(l), !i;
1116
1116
  });
1117
1117
  }, [t]), o = Pe(() => {
1118
1118
  a((i) => {
1119
1119
  if (i) return i;
1120
- const l = jt();
1121
- return l.delete(t), wn(l), !0;
1120
+ const l = Gt();
1121
+ return l.delete(t), kn(l), !0;
1122
1122
  });
1123
1123
  }, [t]);
1124
1124
  return [n, s, o];
1125
1125
  }
1126
- const ln = {
1126
+ const cn = {
1127
1127
  Introduction: "bg-fuchsia-300 text-fuchsia-950 ring-2 ring-inset ring-fuchsia-100",
1128
1128
  Selling: "bg-emerald-300 text-emerald-950 ring-2 ring-inset ring-emerald-100",
1129
1129
  Buying: "bg-rose-300 text-rose-950 ring-2 ring-inset ring-rose-100",
@@ -1134,8 +1134,8 @@ const ln = {
1134
1134
  Settings: "bg-purple-300 text-purple-950 ring-2 ring-inset ring-purple-100",
1135
1135
  "Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
1136
1136
  };
1137
- function Nr() {
1138
- const [t, n] = on("chats"), a = vt(), s = Ee(), { t: o } = X(), { sessions: i, createSession: l, deleteSession: c } = mt(), h = async () => {
1137
+ function wr() {
1138
+ const [t, n] = ln("chats"), a = bt(), s = Ee(), { t: o } = X(), { sessions: i, createSession: l, deleteSession: c } = ut(), h = async () => {
1139
1139
  try {
1140
1140
  const p = await l();
1141
1141
  s(`/chat/${p.id}`);
@@ -1156,7 +1156,7 @@ function Nr() {
1156
1156
  onClick: n,
1157
1157
  className: "flex w-full items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-fg-muted transition-colors hover:text-fg",
1158
1158
  children: [
1159
- /* @__PURE__ */ e(Ga, { className: "h-4 w-4" }),
1159
+ /* @__PURE__ */ e(Wa, { className: "h-4 w-4" }),
1160
1160
  /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: o("nav.chats") }),
1161
1161
  t ? /* @__PURE__ */ e(Mt, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Dt, { className: "h-3.5 w-3.5" })
1162
1162
  ]
@@ -1169,7 +1169,7 @@ function Nr() {
1169
1169
  onClick: h,
1170
1170
  className: "flex w-full items-center gap-2 px-4 py-1.5 pl-10 text-sm text-brand transition-colors hover:bg-brand/5",
1171
1171
  children: [
1172
- /* @__PURE__ */ e(Qn, { className: "h-3.5 w-3.5" }),
1172
+ /* @__PURE__ */ e(Yn, { className: "h-3.5 w-3.5" }),
1173
1173
  o("nav.newChat")
1174
1174
  ]
1175
1175
  }
@@ -1188,14 +1188,14 @@ function Nr() {
1188
1188
  children: p.title
1189
1189
  }
1190
1190
  ),
1191
- u && /* @__PURE__ */ e(cn, {}),
1191
+ u && /* @__PURE__ */ e(dn, {}),
1192
1192
  /* @__PURE__ */ e(
1193
1193
  "button",
1194
1194
  {
1195
1195
  onClick: (f) => d(f, p.id),
1196
1196
  className: "absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-fg-muted opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100",
1197
1197
  title: o("nav.deleteChat"),
1198
- children: /* @__PURE__ */ e(Yn, { className: "h-3.5 w-3.5" })
1198
+ children: /* @__PURE__ */ e(Jn, { className: "h-3.5 w-3.5" })
1199
1199
  }
1200
1200
  )
1201
1201
  ] }, p.id);
@@ -1203,7 +1203,7 @@ function Nr() {
1203
1203
  ] })
1204
1204
  ] });
1205
1205
  }
1206
- function cn() {
1206
+ function dn() {
1207
1207
  return /* @__PURE__ */ e(
1208
1208
  "span",
1209
1209
  {
@@ -1212,8 +1212,8 @@ function cn() {
1212
1212
  }
1213
1213
  );
1214
1214
  }
1215
- function wr() {
1216
- const [t, n, a] = on("custom-analytics"), s = vt(), o = Ee(), i = He(), { t: l } = X(), { navigationFlash: c, sessions: h, createSession: d } = mt(), p = (c == null ? void 0 : c.group) === "Custom Analytics", u = ln["Custom Analytics"], { data: f } = ue({
1215
+ function kr() {
1216
+ const [t, n, a] = ln("custom-analytics"), s = bt(), o = Ee(), i = He(), { t: l } = X(), { navigationFlash: c, sessions: h, createSession: d } = ut(), p = (c == null ? void 0 : c.group) === "Custom Analytics", u = cn["Custom Analytics"], { data: f } = ue({
1217
1217
  queryKey: ["runtime-drafts"],
1218
1218
  queryFn: () => I.listRuntimeDrafts(),
1219
1219
  staleTime: 3e4
@@ -1252,7 +1252,7 @@ function wr() {
1252
1252
  p && u
1253
1253
  ),
1254
1254
  children: [
1255
- /* @__PURE__ */ e(Wa, { className: "h-4 w-4" }),
1255
+ /* @__PURE__ */ e(Ha, { className: "h-4 w-4" }),
1256
1256
  /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: l("nav.customAnalytics") }),
1257
1257
  t ? /* @__PURE__ */ e(Mt, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Dt, { className: "h-3.5 w-3.5" })
1258
1258
  ]
@@ -1265,7 +1265,7 @@ function wr() {
1265
1265
  onClick: C,
1266
1266
  className: "flex w-full items-center gap-2 px-4 py-1.5 pl-10 text-sm text-brand transition-colors hover:bg-brand/5",
1267
1267
  children: [
1268
- /* @__PURE__ */ e(Qn, { className: "h-3.5 w-3.5" }),
1268
+ /* @__PURE__ */ e(Yn, { className: "h-3.5 w-3.5" }),
1269
1269
  l("nav.newAnalytics")
1270
1270
  ]
1271
1271
  }
@@ -1287,14 +1287,14 @@ function wr() {
1287
1287
  children: S.title
1288
1288
  }
1289
1289
  ),
1290
- y && /* @__PURE__ */ e(cn, {}),
1290
+ y && /* @__PURE__ */ e(dn, {}),
1291
1291
  /* @__PURE__ */ e(
1292
1292
  "button",
1293
1293
  {
1294
1294
  onClick: (D) => b(D, S.id),
1295
1295
  className: "absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-fg-muted opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100",
1296
1296
  title: l("nav.deleteReport"),
1297
- children: /* @__PURE__ */ e(Yn, { className: "h-3.5 w-3.5" })
1297
+ children: /* @__PURE__ */ e(Jn, { className: "h-3.5 w-3.5" })
1298
1298
  }
1299
1299
  )
1300
1300
  ] }, S.id);
@@ -1302,8 +1302,8 @@ function wr() {
1302
1302
  ] })
1303
1303
  ] });
1304
1304
  }
1305
- function kr({ group: t }) {
1306
- const [n, a] = on(t.label), { t: s } = X(), { navigationFlash: o } = mt(), i = (o == null ? void 0 : o.group) === t.label, l = ln[t.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
1305
+ function Cr({ group: t }) {
1306
+ const [n, a] = ln(t.label), { t: s } = X(), { navigationFlash: o } = ut(), i = (o == null ? void 0 : o.group) === t.label, l = cn[t.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
1307
1307
  return /* @__PURE__ */ r("div", { children: [
1308
1308
  /* @__PURE__ */ r(
1309
1309
  "button",
@@ -1337,7 +1337,7 @@ function kr({ group: t }) {
1337
1337
  (o == null ? void 0 : o.group) === t.label && (o == null ? void 0 : o.item) === c.label && l
1338
1338
  ),
1339
1339
  children: ({ isActive: d }) => /* @__PURE__ */ r(Ce, { children: [
1340
- d && /* @__PURE__ */ e(cn, {}),
1340
+ d && /* @__PURE__ */ e(dn, {}),
1341
1341
  s(`nav.items.${c.label}`, { defaultValue: c.label })
1342
1342
  ] })
1343
1343
  }
@@ -1345,10 +1345,10 @@ function kr({ group: t }) {
1345
1345
  }) })
1346
1346
  ] });
1347
1347
  }
1348
- const Cr = {
1348
+ const Sr = {
1349
1349
  "/setup/opening-balances": "opening_balances_enabled"
1350
1350
  };
1351
- function Sr({ isMobileOpen: t = !1, onClose: n }) {
1351
+ function Dr({ isMobileOpen: t = !1, onClose: n }) {
1352
1352
  var c;
1353
1353
  const { data: a } = ue({
1354
1354
  queryKey: ["settings"],
@@ -1358,11 +1358,11 @@ function Sr({ isMobileOpen: t = !1, onClose: n }) {
1358
1358
  queryKey: ["setup-status"],
1359
1359
  queryFn: () => I.setupStatus(),
1360
1360
  staleTime: 6e4
1361
- }), o = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], i = (o == null ? void 0 : o.company_name) || (o == null ? void 0 : o.name) || xr().appName, l = Ne(() => vr().map((d) => ({
1361
+ }), o = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], i = (o == null ? void 0 : o.company_name) || (o == null ? void 0 : o.name) || Nr().appName, l = Ne(() => xr().map((d) => ({
1362
1362
  ...d,
1363
1363
  items: d.items.filter((p) => {
1364
1364
  if (p.path === "/setup" && (s != null && s.setup_complete)) return !1;
1365
- const u = Cr[p.path];
1365
+ const u = Sr[p.path];
1366
1366
  return !u || !a ? !0 : a[u] !== "0";
1367
1367
  })
1368
1368
  })), [a, s]);
@@ -1409,52 +1409,52 @@ function Sr({ isMobileOpen: t = !1, onClose: n }) {
1409
1409
  )
1410
1410
  ] }),
1411
1411
  /* @__PURE__ */ r("nav", { className: "flex-1 overflow-y-auto py-3", children: [
1412
- /* @__PURE__ */ e(Nr, {}),
1413
1412
  /* @__PURE__ */ e(wr, {}),
1414
- l.map((h) => /* @__PURE__ */ e(kr, { group: h }, h.label))
1413
+ /* @__PURE__ */ e(kr, {}),
1414
+ l.map((h) => /* @__PURE__ */ e(Cr, { group: h }, h.label))
1415
1415
  ] })
1416
1416
  ]
1417
1417
  }
1418
1418
  );
1419
1419
  }
1420
- const kn = (t) => t.replace(/-/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
1421
- function Dr(t, n) {
1420
+ const Cn = (t) => t.replace(/-/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
1421
+ function Ar(t, n) {
1422
1422
  const a = t.split("/").filter(Boolean);
1423
1423
  if (a[0] === "setup") return n("titles.setup");
1424
1424
  if (a[0] === "tutorial") return n("titles.tutorial");
1425
1425
  if (a[0] === "chat") return n("titles.chat");
1426
1426
  if (a[0] === "reports") {
1427
1427
  const s = a[1] || "";
1428
- return n(`titles.${s}`, { defaultValue: s ? kn(s) : n("titles.reports") });
1428
+ return n(`titles.${s}`, { defaultValue: s ? Cn(s) : n("titles.reports") });
1429
1429
  }
1430
1430
  if (a[0] === "masters") {
1431
1431
  const s = a[1] || "", o = s.charAt(0).toUpperCase() + s.slice(1), i = n(`masters.${s}.one`, { defaultValue: o });
1432
1432
  return a[2] === "new" ? n("header.new", { label: i }) : a[2] ? `${i}: ${decodeURIComponent(a[2])}` : n(`masters.${s}.other`, { defaultValue: `${o}s` });
1433
1433
  }
1434
1434
  if (a[0] === "app") {
1435
- const s = a[1] || "", o = kn(s), i = n(`doctypes.${s}.one`, { defaultValue: o });
1435
+ const s = a[1] || "", o = Cn(s), i = n(`doctypes.${s}.one`, { defaultValue: o });
1436
1436
  return a[2] === "new" ? n("header.new", { label: i }) : a[2] ? `${i}: ${decodeURIComponent(a[2])}` : n(`doctypes.${s}.other`, { defaultValue: `${o}s` });
1437
1437
  }
1438
1438
  return n("titles.dashboard");
1439
1439
  }
1440
- function Ar(t) {
1440
+ function Pr(t) {
1441
1441
  const n = t.split("/").filter(Boolean);
1442
1442
  return (n[0] === "app" || n[0] === "masters") && n.length > 2 ? `/${n[0]}/${n[1]}` : n[0] === "setup" && n.length > 1 ? "/setup" : null;
1443
1443
  }
1444
- function Pr() {
1445
- return /* @__PURE__ */ e(yr, { children: /* @__PURE__ */ e(hr, { children: /* @__PURE__ */ e(_r, {}) }) });
1446
- }
1447
1444
  function _r() {
1448
- const { pathname: t } = vt(), n = Ee(), { user: a, logout: s } = st(), { navigationFlash: o } = mt(), { t: i } = X(), l = Dr(t, i), c = Ar(t), h = () => {
1445
+ return /* @__PURE__ */ e(br, { children: /* @__PURE__ */ e(gr, { children: /* @__PURE__ */ e(Tr, {}) }) });
1446
+ }
1447
+ function Tr() {
1448
+ const { pathname: t } = bt(), n = Ee(), { user: a, logout: s } = st(), { navigationFlash: o } = ut(), { t: i } = X(), l = Ar(t, i), c = Pr(t), h = () => {
1449
1449
  var f;
1450
1450
  c && (((f = window.history.state) == null ? void 0 : f.idx) > 0 ? n(-1) : n(c));
1451
1451
  }, [d, p] = w(!1);
1452
1452
  re(() => {
1453
1453
  p(!1);
1454
1454
  }, [t]);
1455
- const u = o ? ln[o.group] : null;
1455
+ const u = o ? cn[o.group] : null;
1456
1456
  return /* @__PURE__ */ r("div", { className: "flex h-dvh bg-surface-muted", children: [
1457
- /* @__PURE__ */ e(Sr, { isMobileOpen: d, onClose: () => p(!1) }),
1457
+ /* @__PURE__ */ e(Dr, { isMobileOpen: d, onClose: () => p(!1) }),
1458
1458
  d && /* @__PURE__ */ e(
1459
1459
  "div",
1460
1460
  {
@@ -1484,7 +1484,7 @@ function _r() {
1484
1484
  onClick: h,
1485
1485
  className: "-ml-1 rounded p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-900",
1486
1486
  "aria-label": i("header.back"),
1487
- children: /* @__PURE__ */ e(Ha, { className: "h-5 w-5" })
1487
+ children: /* @__PURE__ */ e(Qa, { className: "h-5 w-5" })
1488
1488
  }
1489
1489
  ),
1490
1490
  /* @__PURE__ */ e("h1", { className: "text-base font-semibold text-gray-500 md:text-lg", children: l })
@@ -1504,13 +1504,13 @@ function _r() {
1504
1504
  )
1505
1505
  ] })
1506
1506
  ] }),
1507
- /* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(Oa, {}) })
1507
+ /* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(qa, {}) })
1508
1508
  ] })
1509
1509
  ] });
1510
1510
  }
1511
- function Tr({ children: t }) {
1511
+ function Rr({ children: t }) {
1512
1512
  const { user: n, loading: a } = st();
1513
- return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(Ce, { children: t }) : /* @__PURE__ */ e(qa, { to: "/login", replace: !0 });
1513
+ return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(Ce, { children: t }) : /* @__PURE__ */ e(za, { to: "/login", replace: !0 });
1514
1514
  }
1515
1515
  function M({ title: t, children: n, className: a, interactive: s }) {
1516
1516
  return /* @__PURE__ */ r(
@@ -1533,7 +1533,7 @@ function M({ title: t, children: n, className: a, interactive: s }) {
1533
1533
  }
1534
1534
  );
1535
1535
  }
1536
- const Rr = {
1536
+ const Ir = {
1537
1537
  default: "bg-brand/10 text-brand ring-1 ring-inset ring-brand/20",
1538
1538
  success: "bg-emerald-50 text-emerald-700 ring-1 ring-inset ring-emerald-200",
1539
1539
  warning: "bg-amber-50 text-amber-700 ring-1 ring-inset ring-amber-200",
@@ -1546,7 +1546,7 @@ function Rt({ variant: t = "default", dot: n, children: a, className: s }) {
1546
1546
  {
1547
1547
  className: _e(
1548
1548
  "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
1549
- Rr[t],
1549
+ Ir[t],
1550
1550
  s
1551
1551
  ),
1552
1552
  children: [
@@ -1556,7 +1556,7 @@ function Rt({ variant: t = "default", dot: n, children: a, className: s }) {
1556
1556
  }
1557
1557
  );
1558
1558
  }
1559
- const Ir = {
1559
+ const Br = {
1560
1560
  Draft: "secondary",
1561
1561
  Open: "default",
1562
1562
  Submitted: "default",
@@ -1570,8 +1570,8 @@ const Ir = {
1570
1570
  Discarded: "secondary",
1571
1571
  Overdue: "danger"
1572
1572
  };
1573
- function dn({ status: t }) {
1574
- const { t: n } = X(), a = Ir[t] ?? "secondary";
1573
+ function un({ status: t }) {
1574
+ const { t: n } = X(), a = Br[t] ?? "secondary";
1575
1575
  return /* @__PURE__ */ e(Rt, { variant: a, children: n(`status.${t}`, { defaultValue: t }) });
1576
1576
  }
1577
1577
  function ze(t) {
@@ -1608,15 +1608,15 @@ function _t() {
1608
1608
  /* @__PURE__ */ e("div", { className: "h-9 w-9 shrink-0 animate-pulse rounded-lg bg-surface-subtle" })
1609
1609
  ] }) });
1610
1610
  }
1611
- const Br = {
1612
- "Sales Invoice": hn,
1613
- "Purchase Invoice": hn,
1614
- "Payment Entry": Za,
1615
- "Sales Order": Wn,
1616
- Quotation: rn
1611
+ const Er = {
1612
+ "Sales Invoice": gn,
1613
+ "Purchase Invoice": gn,
1614
+ "Payment Entry": Xa,
1615
+ "Sales Order": Hn,
1616
+ Quotation: sn
1617
1617
  };
1618
- function Er({ doc: t }) {
1619
- const { t: n } = X(), a = t.doctype ?? t.type ?? "Document", s = t.creation ?? t.date, o = Br[a] ?? rn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(t.name)}`;
1618
+ function Lr({ doc: t }) {
1619
+ const { t: n } = X(), a = t.doctype ?? t.type ?? "Document", s = t.creation ?? t.date, o = Er[a] ?? sn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(t.name)}`;
1620
1620
  return /* @__PURE__ */ r(
1621
1621
  ve,
1622
1622
  {
@@ -1628,7 +1628,7 @@ function Er({ doc: t }) {
1628
1628
  /* @__PURE__ */ e("div", { className: "truncate text-sm font-medium text-fg", children: t.name }),
1629
1629
  /* @__PURE__ */ e("div", { className: "truncate text-xs text-fg-muted", children: n(`nav.items.${a}`, { defaultValue: a }) })
1630
1630
  ] }),
1631
- /* @__PURE__ */ e(dn, { status: t.status }),
1631
+ /* @__PURE__ */ e(un, { status: t.status }),
1632
1632
  /* @__PURE__ */ e("div", { className: "hidden text-xs tabular-nums text-fg-muted sm:block", children: s ? Ft(s) : "—" })
1633
1633
  ]
1634
1634
  }
@@ -1645,7 +1645,7 @@ function kt() {
1645
1645
  /* @__PURE__ */ e("div", { className: "hidden h-3 w-16 animate-pulse rounded bg-surface-subtle sm:block" })
1646
1646
  ] });
1647
1647
  }
1648
- function Lr() {
1648
+ function Or() {
1649
1649
  const { t } = X(), { data: n, isLoading: a } = ue({
1650
1650
  queryKey: ["dashboard-summary"],
1651
1651
  queryFn: () => I.dashboardSummary()
@@ -1662,7 +1662,7 @@ function Lr() {
1662
1662
  {
1663
1663
  title: t("dashboard.totalRevenue"),
1664
1664
  value: n == null ? void 0 : n.total_revenue,
1665
- icon: Qa,
1665
+ icon: Ya,
1666
1666
  tone: "text-emerald-600 bg-emerald-500/10"
1667
1667
  }
1668
1668
  ),
@@ -1671,7 +1671,7 @@ function Lr() {
1671
1671
  {
1672
1672
  title: t("dashboard.outstandingReceivable"),
1673
1673
  value: n == null ? void 0 : n.outstanding_receivable,
1674
- icon: Ya,
1674
+ icon: Ja,
1675
1675
  tone: "text-sky-600 bg-sky-500/10"
1676
1676
  }
1677
1677
  ),
@@ -1680,7 +1680,7 @@ function Lr() {
1680
1680
  {
1681
1681
  title: t("dashboard.outstandingPayable"),
1682
1682
  value: n == null ? void 0 : n.outstanding_payable,
1683
- icon: Ja,
1683
+ icon: Za,
1684
1684
  tone: "text-amber-600 bg-amber-500/10"
1685
1685
  }
1686
1686
  ),
@@ -1689,7 +1689,7 @@ function Lr() {
1689
1689
  {
1690
1690
  title: t("dashboard.totalStockValue"),
1691
1691
  value: n == null ? void 0 : n.total_stock_value,
1692
- icon: Hn,
1692
+ icon: Qn,
1693
1693
  tone: "text-brand bg-brand/10"
1694
1694
  }
1695
1695
  )
@@ -1700,28 +1700,28 @@ function Lr() {
1700
1700
  /* @__PURE__ */ e(kt, {}),
1701
1701
  /* @__PURE__ */ e(kt, {}),
1702
1702
  /* @__PURE__ */ e(kt, {})
1703
- ] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ e(Er, { doc: s }, `${s.name}-${o}`)) : /* @__PURE__ */ e("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: t("dashboard.noRecentDocuments") }) }) })
1703
+ ] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ e(Lr, { doc: s }, `${s.name}-${o}`)) : /* @__PURE__ */ e("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: t("dashboard.noRecentDocuments") }) }) })
1704
1704
  ] });
1705
1705
  }
1706
- const ma = "lad.docListContext";
1707
- function pa() {
1706
+ const pa = "lad.docListContext";
1707
+ function ha() {
1708
1708
  try {
1709
- return JSON.parse(sessionStorage.getItem(ma) || "{}");
1709
+ return JSON.parse(sessionStorage.getItem(pa) || "{}");
1710
1710
  } catch {
1711
1711
  return {};
1712
1712
  }
1713
1713
  }
1714
- function ha(t, n) {
1714
+ function ga(t, n) {
1715
1715
  try {
1716
- const a = pa();
1717
- a[t] = n, sessionStorage.setItem(ma, JSON.stringify(a));
1716
+ const a = ha();
1717
+ a[t] = n, sessionStorage.setItem(pa, JSON.stringify(a));
1718
1718
  } catch {
1719
1719
  }
1720
1720
  }
1721
- function Or(t) {
1722
- return pa()[t];
1721
+ function qr(t) {
1722
+ return ha()[t];
1723
1723
  }
1724
- function qr(t, n) {
1724
+ function zr(t, n) {
1725
1725
  const { data: a, isLoading: s, error: o, refetch: i } = ue({
1726
1726
  queryKey: ["documents", t, n],
1727
1727
  queryFn: () => I.listDocuments(t, n),
@@ -1780,7 +1780,7 @@ const rt = [
1780
1780
  { name: "qty", label: "Qty", type: "number", required: !0 },
1781
1781
  { name: "rate", label: "Rate", type: "currency", required: !0 },
1782
1782
  { name: "amount", label: "Amount", type: "currency", readOnly: !0 }
1783
- ], zr = [
1783
+ ], Mr = [
1784
1784
  ...rt,
1785
1785
  {
1786
1786
  name: "frequency",
@@ -1807,7 +1807,7 @@ const rt = [
1807
1807
  { name: "description", label: "Description", type: "text" },
1808
1808
  { name: "rate", label: "Rate (%)", type: "number" },
1809
1809
  { name: "tax_amount", label: "Amount", type: "currency", readOnly: !0 }
1810
- ], un = {
1810
+ ], mn = {
1811
1811
  quotation: {
1812
1812
  slug: "quotation",
1813
1813
  label: "Quotation",
@@ -1827,7 +1827,7 @@ const rt = [
1827
1827
  { name: "remarks", label: "Notes / Terms", type: "textarea" }
1828
1828
  ],
1829
1829
  childTables: [
1830
- { key: "items", label: "Items", fields: zr },
1830
+ { key: "items", label: "Items", fields: Mr },
1831
1831
  { key: "taxes", label: "Taxes", fields: at }
1832
1832
  ],
1833
1833
  listColumns: ["name", "customer", "transaction_date", "grand_total", "status"],
@@ -2414,17 +2414,17 @@ const rt = [
2414
2414
  conversions: []
2415
2415
  }
2416
2416
  };
2417
- function ga(t) {
2418
- return un[t];
2417
+ function fa(t) {
2418
+ return mn[t];
2419
2419
  }
2420
- function Jo(t) {
2421
- un[t.slug] = t;
2420
+ function Xo(t) {
2421
+ mn[t.slug] = t;
2422
2422
  }
2423
- function Zo() {
2424
- return Object.values(un);
2423
+ function el() {
2424
+ return Object.values(mn);
2425
2425
  }
2426
- function fa({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2427
- const o = Ee(), i = s === "master", l = Or(i ? `master:${t}` : t), c = i ? `/masters/${t}` : `/app/${t}`, { data: h } = ue({
2426
+ function ya({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2427
+ const o = Ee(), i = s === "master", l = qr(i ? `master:${t}` : t), c = i ? `/masters/${t}` : `/app/${t}`, { data: h } = ue({
2428
2428
  queryKey: ["adjacent", s, t, n, (l == null ? void 0 : l.filters) ?? null],
2429
2429
  queryFn: () => i ? I.adjacentMaster(t, n) : I.adjacentDocument(t, n, l == null ? void 0 : l.filters)
2430
2430
  }), d = (h == null ? void 0 : h.prev) ?? null, p = (h == null ? void 0 : h.next) ?? null;
@@ -2449,7 +2449,7 @@ function fa({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2449
2449
  title: "Previous record (k / ←)",
2450
2450
  onClick: () => d && o(`${c}/${d}`),
2451
2451
  className: u,
2452
- children: /* @__PURE__ */ e(Xa, { className: "h-4 w-4" })
2452
+ children: /* @__PURE__ */ e(er, { className: "h-4 w-4" })
2453
2453
  }
2454
2454
  ),
2455
2455
  /* @__PURE__ */ e(
@@ -2465,7 +2465,7 @@ function fa({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2465
2465
  )
2466
2466
  ] });
2467
2467
  }
2468
- function Mr(t) {
2468
+ function Fr(t) {
2469
2469
  return typeof t == "string" ? { value: t, label: t } : t;
2470
2470
  }
2471
2471
  function Ve({ label: t, options: n, value: a, onChange: s, className: o, required: i, disabled: l }) {
@@ -2499,7 +2499,7 @@ function Ve({ label: t, options: n, value: a, onChange: s, className: o, require
2499
2499
  children: [
2500
2500
  /* @__PURE__ */ e("option", { value: "", children: "Select..." }),
2501
2501
  n.map((h) => {
2502
- const { value: d, label: p } = Mr(h);
2502
+ const { value: d, label: p } = Fr(h);
2503
2503
  return /* @__PURE__ */ e("option", { value: d, children: p }, d);
2504
2504
  })
2505
2505
  ]
@@ -2507,7 +2507,7 @@ function Ve({ label: t, options: n, value: a, onChange: s, className: o, require
2507
2507
  )
2508
2508
  ] });
2509
2509
  }
2510
- function Fr({ text: t }) {
2510
+ function $r({ text: t }) {
2511
2511
  const [n, a] = w(!1);
2512
2512
  return /* @__PURE__ */ r("span", { className: "relative ml-1 inline-flex", children: [
2513
2513
  /* @__PURE__ */ e(
@@ -2527,7 +2527,7 @@ function Fr({ text: t }) {
2527
2527
  ] })
2528
2528
  ] });
2529
2529
  }
2530
- function $r() {
2530
+ function Ur() {
2531
2531
  const { t } = X(), [n, a] = w(!1), s = [
2532
2532
  ["# Heading", t("notesMarkup.heading", { defaultValue: "bold heading" })],
2533
2533
  ["*italic* **bold**", t("notesMarkup.emphasis", { defaultValue: "italic / bold" })],
@@ -2553,7 +2553,7 @@ function $r() {
2553
2553
  className: "inline-flex h-4 w-4 items-center justify-center rounded-full text-fg-muted hover:text-fg",
2554
2554
  onClick: () => a((o) => !o),
2555
2555
  "aria-label": t("notesMarkup.title", { defaultValue: "Formatting help" }),
2556
- children: /* @__PURE__ */ e(er, { className: "h-3.5 w-3.5" })
2556
+ children: /* @__PURE__ */ e(tr, { className: "h-3.5 w-3.5" })
2557
2557
  }
2558
2558
  ),
2559
2559
  n && /* @__PURE__ */ r("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-80 rounded-md bg-gray-900 px-3 py-2.5 text-xs leading-relaxed text-white shadow-lg", children: [
@@ -2570,7 +2570,7 @@ function $r() {
2570
2570
  }
2571
2571
  );
2572
2572
  }
2573
- function Ur(t, n = !0) {
2573
+ function Vr(t, n = !0) {
2574
2574
  const { data: a } = ue({
2575
2575
  queryKey: ["currencies", ""],
2576
2576
  queryFn: () => I.currencies(t),
@@ -2579,23 +2579,23 @@ function Ur(t, n = !0) {
2579
2579
  });
2580
2580
  return (a == null ? void 0 : a.currencies) ?? [];
2581
2581
  }
2582
- const Vr = /* @__PURE__ */ new Set([
2582
+ const Kr = /* @__PURE__ */ new Set([
2583
2583
  "customer",
2584
2584
  "supplier",
2585
2585
  "item",
2586
2586
  "warehouse"
2587
2587
  ]);
2588
- function Xt(t, n) {
2589
- return !t || !n ? null : Vr.has(t) ? `/masters/${t}/${encodeURIComponent(n)}` : t === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
2588
+ function en(t, n) {
2589
+ return !t || !n ? null : Kr.has(t) ? `/masters/${t}/${encodeURIComponent(n)}` : t === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
2590
2590
  }
2591
- function Cn({ label: t, hint: n, extra: a }) {
2591
+ function Sn({ label: t, hint: n, extra: a }) {
2592
2592
  return /* @__PURE__ */ r("label", { className: "mb-1.5 block text-sm font-medium text-fg", children: [
2593
2593
  t,
2594
- n && /* @__PURE__ */ e(Fr, { text: n }),
2594
+ n && /* @__PURE__ */ e($r, { text: n }),
2595
2595
  a
2596
2596
  ] });
2597
2597
  }
2598
- function Kr({
2598
+ function jr({
2599
2599
  field: t,
2600
2600
  value: n,
2601
2601
  onChange: a,
@@ -2637,7 +2637,7 @@ function Kr({
2637
2637
  onBlur: () => setTimeout(() => h(!1), 200)
2638
2638
  }
2639
2639
  ),
2640
- c && f && f.length > 0 && p && ea(
2640
+ c && f && f.length > 0 && p && ta(
2641
2641
  /* @__PURE__ */ e(
2642
2642
  "ul",
2643
2643
  {
@@ -2670,10 +2670,10 @@ function It({
2670
2670
  currency: l = "USD"
2671
2671
  }) {
2672
2672
  var v;
2673
- const { t: c } = X(), h = s || !!t.readOnly, d = () => i ? null : /* @__PURE__ */ e(Cn, { label: c(`fields.${t.label}`, { defaultValue: t.label }), hint: t.hint }), p = t.type === "select" && t.optionsSource === "currency", u = Ur(void 0, p);
2673
+ const { t: c } = X(), h = s || !!t.readOnly, d = () => i ? null : /* @__PURE__ */ e(Sn, { label: c(`fields.${t.label}`, { defaultValue: t.label }), hint: t.hint }), p = t.type === "select" && t.optionsSource === "currency", u = Vr(void 0, p);
2674
2674
  if (h) {
2675
2675
  if (t.type === "link" && n) {
2676
- const C = t.linkDoctypeField && o ? String(o[t.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : t.linkDoctype, S = Xt(C, String(n));
2676
+ const C = t.linkDoctypeField && o ? String(o[t.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : t.linkDoctype, S = en(C, String(n));
2677
2677
  if (S)
2678
2678
  return /* @__PURE__ */ r("div", { children: [
2679
2679
  /* @__PURE__ */ e(d, {}),
@@ -2703,7 +2703,7 @@ function It({
2703
2703
  return /* @__PURE__ */ r("div", { children: [
2704
2704
  /* @__PURE__ */ e(d, {}),
2705
2705
  /* @__PURE__ */ e(
2706
- Kr,
2706
+ jr,
2707
2707
  {
2708
2708
  field: N,
2709
2709
  value: n ?? "",
@@ -2732,11 +2732,11 @@ function It({
2732
2732
  const N = t.name === "remarks";
2733
2733
  return /* @__PURE__ */ r("div", { children: [
2734
2734
  !i && /* @__PURE__ */ e(
2735
- Cn,
2735
+ Sn,
2736
2736
  {
2737
2737
  label: c(`fields.${t.label}`, { defaultValue: t.label }),
2738
2738
  hint: t.hint,
2739
- extra: N ? /* @__PURE__ */ e($r, {}) : void 0
2739
+ extra: N ? /* @__PURE__ */ e(Ur, {}) : void 0
2740
2740
  }
2741
2741
  ),
2742
2742
  /* @__PURE__ */ e(
@@ -2766,7 +2766,7 @@ function It({
2766
2766
  )
2767
2767
  ] });
2768
2768
  }
2769
- function jr({
2769
+ function Gr({
2770
2770
  tableDef: t,
2771
2771
  rows: n,
2772
2772
  onChange: a,
@@ -2828,7 +2828,7 @@ function jr({
2828
2828
  !s && /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e(Q, { variant: "secondary", size: "sm", onClick: c, children: i("common.addRow") }) })
2829
2829
  ] });
2830
2830
  }
2831
- function Gr({
2831
+ function Wr({
2832
2832
  isNew: t,
2833
2833
  doctype: n,
2834
2834
  name: a,
@@ -2885,7 +2885,7 @@ function Gr({
2885
2885
  )
2886
2886
  ] });
2887
2887
  }
2888
- function Sn(t, n) {
2888
+ function Dn(t, n) {
2889
2889
  if (!n) return t;
2890
2890
  const a = { ...t };
2891
2891
  if (n.childTables.some((i) => i.key === "items") && Array.isArray(a.items) && (a.items = a.items.map((i) => ({
@@ -2907,9 +2907,9 @@ function Sn(t, n) {
2907
2907
  }
2908
2908
  return a;
2909
2909
  }
2910
- function Dn() {
2910
+ function An() {
2911
2911
  var Se;
2912
- const { doctype: t, name: n } = ut(), a = Ee(), s = He(), { t: o } = X(), i = ga(t ?? ""), l = !n, [c, h] = w({}), [d, p] = w(!1), { data: u, isLoading: f } = ue({
2912
+ const { doctype: t, name: n } = dt(), a = Ee(), s = He(), { t: o } = X(), i = fa(t ?? ""), l = !n, [c, h] = w({}), [d, p] = w(!1), { data: u, isLoading: f } = ue({
2913
2913
  queryKey: ["document", t, n],
2914
2914
  queryFn: () => I.getDocument(t, n),
2915
2915
  enabled: !!t && !!n && !l
@@ -2984,7 +2984,7 @@ function Dn() {
2984
2984
  (E, ie) => {
2985
2985
  E === "currency" && p(!0), h((Le) => {
2986
2986
  const Te = { ...Le, [E]: ie };
2987
- return E === "currency" && (Te.conversion_rate = 0), Sn(Te, i);
2987
+ return E === "currency" && (Te.conversion_rate = 0), Dn(Te, i);
2988
2988
  });
2989
2989
  },
2990
2990
  [i]
@@ -2992,7 +2992,7 @@ function Dn() {
2992
2992
  (E, ie) => {
2993
2993
  h((Le) => {
2994
2994
  const Te = { ...Le, [E]: ie };
2995
- return Sn(Te, i);
2995
+ return Dn(Te, i);
2996
2996
  });
2997
2997
  },
2998
2998
  [i]
@@ -3018,8 +3018,8 @@ function Dn() {
3018
3018
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
3019
3019
  /* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
3020
3020
  /* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
3021
- !l && /* @__PURE__ */ e(fa, { slug: i.slug, name: n, onSave: R }),
3022
- !l && c.status && /* @__PURE__ */ e(dn, { status: c.status }),
3021
+ !l && /* @__PURE__ */ e(ya, { slug: i.slug, name: n, onSave: R }),
3022
+ !l && c.status && /* @__PURE__ */ e(un, { status: c.status }),
3023
3023
  !l && c.currency && /* @__PURE__ */ r(
3024
3024
  "span",
3025
3025
  {
@@ -3036,7 +3036,7 @@ function Dn() {
3036
3036
  )
3037
3037
  ] }),
3038
3038
  /* @__PURE__ */ e(
3039
- Gr,
3039
+ Wr,
3040
3040
  {
3041
3041
  isNew: l,
3042
3042
  doctype: t,
@@ -3081,7 +3081,7 @@ function Dn() {
3081
3081
  )) })
3082
3082
  ] }),
3083
3083
  i.childTables.map((E) => /* @__PURE__ */ e(
3084
- jr,
3084
+ Gr,
3085
3085
  {
3086
3086
  tableDef: E,
3087
3087
  rows: c[E.key] ?? [],
@@ -3108,35 +3108,35 @@ function Dn() {
3108
3108
  function be(t) {
3109
3109
  return t.toISOString().split("T")[0];
3110
3110
  }
3111
- function ya(t) {
3111
+ function ba(t) {
3112
3112
  const n = new Date(t), a = n.getDay(), s = a === 0 ? 6 : a - 1;
3113
3113
  return n.setDate(n.getDate() - s), n;
3114
3114
  }
3115
- function Wr(t) {
3116
- const n = ya(t);
3115
+ function Hr(t) {
3116
+ const n = ba(t);
3117
3117
  return n.setDate(n.getDate() + 6), n;
3118
3118
  }
3119
- function An(t) {
3119
+ function Pn(t) {
3120
3120
  return new Date(t.getFullYear(), t.getMonth(), 1);
3121
3121
  }
3122
3122
  function Et(t) {
3123
3123
  return new Date(t.getFullYear(), t.getMonth() + 1, 0);
3124
3124
  }
3125
- function en(t) {
3125
+ function tn(t) {
3126
3126
  const n = Math.floor(t.getMonth() / 3);
3127
3127
  return new Date(t.getFullYear(), n * 3, 1);
3128
3128
  }
3129
- function tn(t) {
3130
- const n = en(t);
3129
+ function nn(t) {
3130
+ const n = tn(t);
3131
3131
  return new Date(n.getFullYear(), n.getMonth() + 3, 0);
3132
3132
  }
3133
- function Pn(t) {
3133
+ function _n(t) {
3134
3134
  return new Date(t.getFullYear(), 0, 1);
3135
3135
  }
3136
3136
  function Lt(t) {
3137
3137
  return new Date(t.getFullYear(), 11, 31);
3138
3138
  }
3139
- const Hr = [
3139
+ const Qr = [
3140
3140
  {
3141
3141
  label: "Today",
3142
3142
  range: () => {
@@ -3146,44 +3146,44 @@ const Hr = [
3146
3146
  },
3147
3147
  {
3148
3148
  label: "This Week",
3149
- range: () => [be(ya(/* @__PURE__ */ new Date())), be(Wr(/* @__PURE__ */ new Date()))]
3149
+ range: () => [be(ba(/* @__PURE__ */ new Date())), be(Hr(/* @__PURE__ */ new Date()))]
3150
3150
  },
3151
3151
  {
3152
3152
  label: "This Month",
3153
- range: () => [be(An(/* @__PURE__ */ new Date())), be(Et(/* @__PURE__ */ new Date()))]
3153
+ range: () => [be(Pn(/* @__PURE__ */ new Date())), be(Et(/* @__PURE__ */ new Date()))]
3154
3154
  },
3155
3155
  {
3156
3156
  label: "This Quarter",
3157
- range: () => [be(en(/* @__PURE__ */ new Date())), be(tn(/* @__PURE__ */ new Date()))]
3157
+ range: () => [be(tn(/* @__PURE__ */ new Date())), be(nn(/* @__PURE__ */ new Date()))]
3158
3158
  },
3159
3159
  {
3160
3160
  label: "This Year",
3161
- range: () => [be(Pn(/* @__PURE__ */ new Date())), be(Lt(/* @__PURE__ */ new Date()))]
3161
+ range: () => [be(_n(/* @__PURE__ */ new Date())), be(Lt(/* @__PURE__ */ new Date()))]
3162
3162
  },
3163
3163
  {
3164
3164
  label: "Last Month",
3165
3165
  range: () => {
3166
3166
  const t = /* @__PURE__ */ new Date(), n = new Date(t.getFullYear(), t.getMonth() - 1, 1);
3167
- return [be(An(n)), be(Et(n))];
3167
+ return [be(Pn(n)), be(Et(n))];
3168
3168
  }
3169
3169
  },
3170
3170
  {
3171
3171
  label: "Last Quarter",
3172
3172
  range: () => {
3173
3173
  const t = /* @__PURE__ */ new Date(), n = new Date(t.getFullYear(), t.getMonth() - 3, 1);
3174
- return [be(en(n)), be(tn(n))];
3174
+ return [be(tn(n)), be(nn(n))];
3175
3175
  }
3176
3176
  },
3177
3177
  {
3178
3178
  label: "Last Year",
3179
3179
  range: () => {
3180
3180
  const t = new Date((/* @__PURE__ */ new Date()).getFullYear() - 1, 6, 1);
3181
- return [be(Pn(t)), be(Lt(t))];
3181
+ return [be(_n(t)), be(Lt(t))];
3182
3182
  }
3183
3183
  }
3184
3184
  ];
3185
3185
  function $t({ onSelect: t }) {
3186
- return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: Hr.map((n) => /* @__PURE__ */ e(
3186
+ return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: Qr.map((n) => /* @__PURE__ */ e(
3187
3187
  "button",
3188
3188
  {
3189
3189
  type: "button",
@@ -3197,7 +3197,7 @@ function $t({ onSelect: t }) {
3197
3197
  n.label
3198
3198
  )) });
3199
3199
  }
3200
- function mn({ onSelect: t }) {
3200
+ function pn({ onSelect: t }) {
3201
3201
  return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: [
3202
3202
  { label: "Today", value: () => be(/* @__PURE__ */ new Date()) },
3203
3203
  { label: "End of This Month", value: () => be(Et(/* @__PURE__ */ new Date())) },
@@ -3205,7 +3205,7 @@ function mn({ onSelect: t }) {
3205
3205
  const a = /* @__PURE__ */ new Date();
3206
3206
  return be(Et(new Date(a.getFullYear(), a.getMonth() - 1, 1)));
3207
3207
  } },
3208
- { label: "End of This Quarter", value: () => be(tn(/* @__PURE__ */ new Date())) },
3208
+ { label: "End of This Quarter", value: () => be(nn(/* @__PURE__ */ new Date())) },
3209
3209
  { label: "End of This Year", value: () => be(Lt(/* @__PURE__ */ new Date())) },
3210
3210
  { label: "End of Last Year", value: () => be(Lt(new Date((/* @__PURE__ */ new Date()).getFullYear() - 1, 0, 1))) }
3211
3211
  ].map((a) => /* @__PURE__ */ e(
@@ -3219,21 +3219,21 @@ function mn({ onSelect: t }) {
3219
3219
  a.label
3220
3220
  )) });
3221
3221
  }
3222
- const Qr = ["All", "Draft", "Submitted", "Cancelled"], Yr = /* @__PURE__ */ new Set([
3222
+ const Yr = ["All", "Draft", "Submitted", "Cancelled"], Jr = /* @__PURE__ */ new Set([
3223
3223
  "grand_total",
3224
3224
  "outstanding_amount",
3225
3225
  "paid_amount",
3226
3226
  "total_debit",
3227
3227
  "total_amount",
3228
3228
  "net_total"
3229
- ]), Jr = /* @__PURE__ */ new Set([
3229
+ ]), Zr = /* @__PURE__ */ new Set([
3230
3230
  "transaction_date",
3231
3231
  "posting_date",
3232
3232
  "due_date",
3233
3233
  "delivery_date",
3234
3234
  "valid_till",
3235
3235
  "date"
3236
- ]), _n = {
3236
+ ]), Tn = {
3237
3237
  customer: "customer",
3238
3238
  supplier: "supplier",
3239
3239
  item_code: "item",
@@ -3243,13 +3243,13 @@ const Qr = ["All", "Draft", "Submitted", "Cancelled"], Yr = /* @__PURE__ */ new
3243
3243
  account: "account",
3244
3244
  cost_center: "cost-center"
3245
3245
  };
3246
- function Zr(t) {
3246
+ function Xr(t) {
3247
3247
  if (typeof t != "string") return null;
3248
3248
  const n = t.toLowerCase();
3249
3249
  return n === "customer" ? "customer" : n === "supplier" ? "supplier" : null;
3250
3250
  }
3251
- const Xr = ["25", "50", "100", "200"];
3252
- function Tn({
3251
+ const es = ["25", "50", "100", "200"];
3252
+ function Rn({
3253
3253
  page: t,
3254
3254
  totalPages: n,
3255
3255
  pageSize: a,
@@ -3288,7 +3288,7 @@ function Tn({
3288
3288
  value: a,
3289
3289
  onChange: (f) => c(Number(f.target.value)),
3290
3290
  className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
3291
- children: Xr.map((f) => /* @__PURE__ */ e("option", { value: f, children: f }, f))
3291
+ children: es.map((f) => /* @__PURE__ */ e("option", { value: f, children: f }, f))
3292
3292
  }
3293
3293
  )
3294
3294
  ] }),
@@ -3333,8 +3333,8 @@ function Tn({
3333
3333
  ] })
3334
3334
  ] });
3335
3335
  }
3336
- function es() {
3337
- const { t } = X(), n = ze(), { doctype: a } = ut(), s = ga(a ?? ""), o = vt(), i = (s == null ? void 0 : s.listFilters) ?? [], l = Ne(() => {
3336
+ function ts() {
3337
+ const { t } = X(), n = ze(), { doctype: a } = dt(), s = fa(a ?? ""), o = bt(), i = (s == null ? void 0 : s.listFilters) ?? [], l = Ne(() => {
3338
3338
  const P = new URLSearchParams(o.search), V = {};
3339
3339
  for (const ne of i) V[ne] = P.get(ne) ?? "";
3340
3340
  return V;
@@ -3352,14 +3352,14 @@ function es() {
3352
3352
  for (const V of i)
3353
3353
  l[V] && (P[V] = l[V]);
3354
3354
  return f.length > 0 && v && (P.search = v, P.search_fields = f.join(",")), p && (P.include_discarded = "true"), P.limit = u, P.offset = S * u, P;
3355
- }, [c, h, d, p, u, S, s == null ? void 0 : s.dateField, i, l, f, v]), { data: R, isLoading: W } = qr(a ?? "", g), $ = (R == null ? void 0 : R.rows) ?? [], de = (R == null ? void 0 : R.total) ?? 0;
3355
+ }, [c, h, d, p, u, S, s == null ? void 0 : s.dateField, i, l, f, v]), { data: R, isLoading: W } = zr(a ?? "", g), $ = (R == null ? void 0 : R.rows) ?? [], de = (R == null ? void 0 : R.total) ?? 0;
3356
3356
  re(() => {
3357
3357
  const { limit: P, offset: V, ...ne } = g;
3358
- ha(a ?? "", { filters: ne, search: o.search });
3358
+ ga(a ?? "", { filters: ne, search: o.search });
3359
3359
  }, [a, g, o.search]);
3360
3360
  const A = Math.max(1, Math.ceil(de / u)), _ = de === 0 ? 0 : S * u + 1, z = Math.min(de, (S + 1) * u), ee = Ne(() => {
3361
3361
  if (!s) return [];
3362
- const P = Jn(), V = (ne) => {
3362
+ const P = Zn(), V = (ne) => {
3363
3363
  const H = ne.split("_").map((ce) => ce.charAt(0).toUpperCase() + ce.slice(1)).join(" ");
3364
3364
  return t(`fields.${H}`, { defaultValue: H });
3365
3365
  };
@@ -3379,9 +3379,9 @@ function es() {
3379
3379
  if (ne === "status")
3380
3380
  return P.accessor("status", {
3381
3381
  header: t("fields.Status", { defaultValue: "Status" }),
3382
- cell: (H) => /* @__PURE__ */ e(dn, { status: H.getValue() })
3382
+ cell: (H) => /* @__PURE__ */ e(un, { status: H.getValue() })
3383
3383
  });
3384
- if (Yr.has(ne))
3384
+ if (Jr.has(ne))
3385
3385
  return P.accessor(ne, {
3386
3386
  header: V(ne),
3387
3387
  cell: (H) => {
@@ -3395,7 +3395,7 @@ function es() {
3395
3395
  cell: (H) => {
3396
3396
  const ce = H.getValue();
3397
3397
  if (!ce) return "-";
3398
- const Se = Zr(H.row.original.party_type), E = Se ? Xt(Se, String(ce)) : null;
3398
+ const Se = Xr(H.row.original.party_type), E = Se ? en(Se, String(ce)) : null;
3399
3399
  return E ? /* @__PURE__ */ e(
3400
3400
  ve,
3401
3401
  {
@@ -3407,14 +3407,14 @@ function es() {
3407
3407
  ) : String(ce);
3408
3408
  }
3409
3409
  });
3410
- if (_n[ne]) {
3411
- const H = _n[ne];
3410
+ if (Tn[ne]) {
3411
+ const H = Tn[ne];
3412
3412
  return P.accessor(ne, {
3413
3413
  header: V(ne),
3414
3414
  cell: (ce) => {
3415
3415
  const Se = ce.getValue();
3416
3416
  if (!Se) return "-";
3417
- const E = Xt(H, String(Se));
3417
+ const E = en(H, String(Se));
3418
3418
  return E ? /* @__PURE__ */ e(
3419
3419
  ve,
3420
3420
  {
@@ -3427,17 +3427,17 @@ function es() {
3427
3427
  }
3428
3428
  });
3429
3429
  }
3430
- return Jr.has(ne) ? P.accessor(ne, {
3430
+ return Zr.has(ne) ? P.accessor(ne, {
3431
3431
  header: V(ne),
3432
3432
  cell: (H) => Ft(H.getValue())
3433
3433
  }) : P.accessor(ne, {
3434
3434
  header: V(ne)
3435
3435
  });
3436
3436
  });
3437
- }, [s, t, n]), se = Zn({
3437
+ }, [s, t, n]), se = Xn({
3438
3438
  data: $,
3439
3439
  columns: ee,
3440
- getCoreRowModel: Xn()
3440
+ getCoreRowModel: ea()
3441
3441
  });
3442
3442
  return s ? /* @__PURE__ */ r("div", { className: "space-y-4", children: [
3443
3443
  /* @__PURE__ */ e("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ e(ve, { to: `/app/${s.slug}/new`, children: /* @__PURE__ */ e(Q, { children: t("common.new") }) }) }),
@@ -3457,7 +3457,7 @@ function es() {
3457
3457
  Ve,
3458
3458
  {
3459
3459
  label: t("fields.Status", { defaultValue: "Status" }),
3460
- options: Qr.map((P) => ({
3460
+ options: Yr.map((P) => ({
3461
3461
  value: P,
3462
3462
  label: P === "All" ? t("common.all") : t(`status.${P}`, { defaultValue: P })
3463
3463
  })),
@@ -3513,7 +3513,7 @@ function es() {
3513
3513
  /* @__PURE__ */ e($t, { onSelect: (P, V) => x({ from: P, to: V, page: null }) }),
3514
3514
  W ? /* @__PURE__ */ e("p", { className: "text-fg-muted", children: t("common.loading") }) : $.length === 0 ? /* @__PURE__ */ e("p", { className: "py-8 text-center text-fg-muted", children: t("reports.noDocuments") }) : /* @__PURE__ */ r(Ce, { children: [
3515
3515
  /* @__PURE__ */ e(
3516
- Tn,
3516
+ Rn,
3517
3517
  {
3518
3518
  page: S,
3519
3519
  totalPages: A,
@@ -3543,7 +3543,7 @@ function es() {
3543
3543
  ) }, V.id)) }, P.id)) })
3544
3544
  ] }) }),
3545
3545
  /* @__PURE__ */ e(
3546
- Tn,
3546
+ Rn,
3547
3547
  {
3548
3548
  page: S,
3549
3549
  totalPages: A,
@@ -3643,7 +3643,7 @@ function Ae({
3643
3643
  )
3644
3644
  }
3645
3645
  ),
3646
- d && c.length > 0 && ea(
3646
+ d && c.length > 0 && ta(
3647
3647
  /* @__PURE__ */ e("div", { ref: S, style: v, className: "max-h-48 overflow-y-auto rounded-lg bg-surface ring-1 ring-line shadow-card-hover", children: c.map((g, R) => {
3648
3648
  const W = g.name ?? g.id ?? String(g);
3649
3649
  return /* @__PURE__ */ e(
@@ -3669,9 +3669,9 @@ const Tt = () => ({
3669
3669
  position_title: "",
3670
3670
  position_blurb: "",
3671
3671
  is_recommended: 0
3672
- }), ts = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
3673
- function Rn() {
3674
- const { name: t } = ut(), n = !t, a = Ee(), s = He(), { t: o } = X(), i = (A, _) => o(A, { defaultValue: _ }), l = da(), [c, h] = w({
3672
+ }), ns = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
3673
+ function In() {
3674
+ const { name: t } = dt(), n = !t, a = Ee(), s = He(), { t: o } = X(), i = (A, _) => o(A, { defaultValue: _ }), l = ua(), [c, h] = w({
3675
3675
  title: "Offerte",
3676
3676
  customer: "",
3677
3677
  company: "",
@@ -3813,7 +3813,7 @@ function Rn() {
3813
3813
  ] }),
3814
3814
  d.map((A, _) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
3815
3815
  /* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
3816
- /* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children: ts[_] ?? _ + 1 }),
3816
+ /* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children: ns[_] ?? _ + 1 }),
3817
3817
  /* @__PURE__ */ e("div", { className: "flex-1", children: /* @__PURE__ */ e(Ae, { label: "", value: A.quotation, onChange: (z) => Z(_, { quotation: z }), linkDoctype: "quotation", readOnly: !1 }) }),
3818
3818
  /* @__PURE__ */ e("button", { type: "button", onClick: () => W(_, -1), disabled: _ === 0, className: "px-1 text-fg-muted disabled:opacity-30", children: "↑" }),
3819
3819
  /* @__PURE__ */ e("button", { type: "button", onClick: () => W(_, 1), disabled: _ === d.length - 1, className: "px-1 text-fg-muted disabled:opacity-30", children: "↓" }),
@@ -3848,12 +3848,12 @@ function Rn() {
3848
3848
  ] })
3849
3849
  ] });
3850
3850
  }
3851
- const ns = ["25", "50", "100", "200"];
3852
- function as() {
3851
+ const as = ["25", "50", "100", "200"];
3852
+ function rs() {
3853
3853
  var y;
3854
- const { type: t } = ut(), n = Ee(), a = vt(), s = (y = a.state) == null ? void 0 : y.notice;
3854
+ const { type: t } = dt(), n = Ee(), a = bt(), s = (y = a.state) == null ? void 0 : y.notice;
3855
3855
  re(() => {
3856
- t && ha(`master:${t}`, { filters: {}, search: a.search });
3856
+ t && ga(`master:${t}`, { filters: {}, search: a.search });
3857
3857
  }, [t, a.search]);
3858
3858
  const [o] = le("per_page", 50), [i] = le("page", 1), l = i - 1, c = Ye(), h = (m) => c({ page: m === 0 ? null : m + 1 }), d = (m) => c({ per_page: m, page: null }), { data: p, isLoading: u } = ue({
3859
3859
  queryKey: ["masters", t, l, o],
@@ -3865,7 +3865,7 @@ function as() {
3865
3865
  enabled: !!t
3866
3866
  }), f = (p == null ? void 0 : p.rows) ?? [], v = (p == null ? void 0 : p.total) ?? 0, N = Math.max(1, Math.ceil(v / o)), b = v === 0 ? 0 : l * o + 1, C = Math.min(v, (l + 1) * o), S = Ne(() => {
3867
3867
  if (!f || f.length === 0) return [];
3868
- const m = Jn();
3868
+ const m = Zn();
3869
3869
  return Object.keys(f[0]).map(
3870
3870
  (T) => m.accessor(T, {
3871
3871
  header: T.split("_").map((U) => U.charAt(0).toUpperCase() + U.slice(1)).join(" "),
@@ -3886,10 +3886,10 @@ function as() {
3886
3886
  }
3887
3887
  })
3888
3888
  );
3889
- }, [f, t]), x = Zn({
3889
+ }, [f, t]), x = Xn({
3890
3890
  data: f,
3891
3891
  columns: S,
3892
- getCoreRowModel: Xn()
3892
+ getCoreRowModel: ea()
3893
3893
  });
3894
3894
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
3895
3895
  s && /* @__PURE__ */ e("div", { className: "rounded-md bg-amber-50 px-4 py-3 text-sm text-amber-800", children: s }),
@@ -3941,7 +3941,7 @@ function as() {
3941
3941
  value: o,
3942
3942
  onChange: (m) => d(Number(m.target.value)),
3943
3943
  className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
3944
- children: ns.map((m) => /* @__PURE__ */ e("option", { value: m, children: m }, m))
3944
+ children: as.map((m) => /* @__PURE__ */ e("option", { value: m, children: m }, m))
3945
3945
  }
3946
3946
  )
3947
3947
  ] }),
@@ -3975,7 +3975,7 @@ function as() {
3975
3975
  ] })
3976
3976
  ] });
3977
3977
  }
3978
- const rs = {
3978
+ const ss = {
3979
3979
  customer: [
3980
3980
  { name: "name", label: "ID", type: "text", required: !0 },
3981
3981
  { name: "customer_name", label: "Customer Name", type: "text", required: !0 },
@@ -4038,16 +4038,16 @@ const rs = {
4038
4038
  { name: "tax_id", label: "Tax ID", type: "text" },
4039
4039
  { name: "iban", label: "IBAN", type: "text" }
4040
4040
  ]
4041
- }, ss = {
4041
+ }, is = {
4042
4042
  customer: "Customer",
4043
4043
  supplier: "Supplier",
4044
4044
  item: "Item",
4045
4045
  warehouse: "Warehouse",
4046
4046
  company: "Company"
4047
- }, In = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
4048
- function Bn() {
4047
+ }, Bn = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
4048
+ function En() {
4049
4049
  var Z;
4050
- const { type: t, name: n } = ut(), a = Ee(), s = He(), { t: o } = X(), i = !n || n === "new", l = ss[t ?? ""] ?? t ?? "", c = o(`masters.${t}.one`, { defaultValue: l }), h = rs[t ?? ""] ?? [], d = (g) => o(`fields.${g.label}`, { defaultValue: g.label }), [p, u] = w({}), { data: f, isLoading: v } = ue({
4050
+ const { type: t, name: n } = dt(), a = Ee(), s = He(), { t: o } = X(), i = !n || n === "new", l = is[t ?? ""] ?? t ?? "", c = o(`masters.${t}.one`, { defaultValue: l }), h = ss[t ?? ""] ?? [], d = (g) => o(`fields.${g.label}`, { defaultValue: g.label }), [p, u] = w({}), { data: f, isLoading: v } = ue({
4051
4051
  queryKey: ["master", t, n],
4052
4052
  queryFn: () => I.getMaster(t, n),
4053
4053
  enabled: !!t && !!n && !i
@@ -4099,7 +4099,7 @@ function Bn() {
4099
4099
  if (U.length > 0) return;
4100
4100
  const g = t === "company" && !p.name ? { ...p, name: p.company_name } : p;
4101
4101
  i ? b.mutate(g) : C.mutate(g);
4102
- }, y = da(), m = async () => {
4102
+ }, y = ua(), m = async () => {
4103
4103
  await y({
4104
4104
  title: o("masterForm.deleteConfirm", { label: c }),
4105
4105
  confirmLabel: o("common.delete", { defaultValue: "Delete" }),
@@ -4111,13 +4111,13 @@ function Bn() {
4111
4111
  if (!i && v)
4112
4112
  return /* @__PURE__ */ e("p", { className: "text-fg-muted", children: o("common.loading") });
4113
4113
  const T = b.isPending || C.isPending, U = h.filter((g) => {
4114
- if (!g.required || g.readOnly || i && g.name === "name" && In.has(t ?? "")) return !1;
4114
+ if (!g.required || g.readOnly || i && g.name === "name" && Bn.has(t ?? "")) return !1;
4115
4115
  const R = p[g.name];
4116
4116
  return R == null || String(R).trim() === "";
4117
4117
  });
4118
4118
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
4119
4119
  /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
4120
- i ? /* @__PURE__ */ e("div", {}) : /* @__PURE__ */ e(fa, { kind: "master", slug: t, name: n, onSave: x }),
4120
+ i ? /* @__PURE__ */ e("div", {}) : /* @__PURE__ */ e(ya, { kind: "master", slug: t, name: n, onSave: x }),
4121
4121
  /* @__PURE__ */ r("div", { className: "flex gap-2", children: [
4122
4122
  /* @__PURE__ */ e(Q, { onClick: x, disabled: T || U.length > 0, children: o(T ? "common.saving" : "common.save") }),
4123
4123
  !i && /* @__PURE__ */ e(
@@ -4135,7 +4135,7 @@ function Bn() {
4135
4135
  U.length > 0 && /* @__PURE__ */ e("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-800 ring-1 ring-amber-200", children: o("masterForm.required", { fields: U.map(d).join(", ") }) }),
4136
4136
  p.disabled === 1 && /* @__PURE__ */ e("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-800 ring-1 ring-amber-200", children: o("masterForm.disabledNotice", { label: c }) }),
4137
4137
  /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: h.map((g) => {
4138
- const W = g.name === "name" && !i || g.readOnly, $ = g.required && !(i && g.name === "name" && In.has(t ?? ""));
4138
+ const W = g.name === "name" && !i || g.readOnly, $ = g.required && !(i && g.name === "name" && Bn.has(t ?? ""));
4139
4139
  if (g.type === "select" && g.options) {
4140
4140
  const A = p[g.name], _ = typeof A == "string" && A !== "" && !g.options.includes(A) ? [...g.options, A] : g.options;
4141
4141
  return /* @__PURE__ */ e("div", { children: /* @__PURE__ */ e(
@@ -4187,67 +4187,67 @@ function Bn() {
4187
4187
  }) }) })
4188
4188
  ] });
4189
4189
  }
4190
- function is(t) {
4190
+ function os(t) {
4191
4191
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4192
4192
  queryKey: ["report", "trial-balance", t],
4193
4193
  queryFn: () => I.trialBalance(t)
4194
4194
  });
4195
4195
  return { data: n, isLoading: a, error: s, refetch: o };
4196
4196
  }
4197
- function os(t) {
4197
+ function ls(t) {
4198
4198
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4199
4199
  queryKey: ["report", "chart-of-accounts", t],
4200
4200
  queryFn: () => I.chartOfAccounts(t)
4201
4201
  });
4202
4202
  return { data: n, isLoading: a, error: s, refetch: o };
4203
4203
  }
4204
- function ls(t) {
4204
+ function cs(t) {
4205
4205
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4206
4206
  queryKey: ["report", "general-ledger", t],
4207
4207
  queryFn: () => I.generalLedger(t)
4208
4208
  });
4209
4209
  return { data: n, isLoading: a, error: s, refetch: o };
4210
4210
  }
4211
- function cs(t) {
4211
+ function ds(t) {
4212
4212
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4213
4213
  queryKey: ["report", "stock-balance", t],
4214
4214
  queryFn: () => I.stockBalance(t)
4215
4215
  });
4216
4216
  return { data: n, isLoading: a, error: s, refetch: o };
4217
4217
  }
4218
- function ds(t) {
4218
+ function us(t) {
4219
4219
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4220
4220
  queryKey: ["report", "profit-and-loss", t],
4221
4221
  queryFn: () => I.profitAndLoss(t)
4222
4222
  });
4223
4223
  return { data: n, isLoading: a, error: s, refetch: o };
4224
4224
  }
4225
- function us(t) {
4225
+ function ms(t) {
4226
4226
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4227
4227
  queryKey: ["report", "balance-sheet", t],
4228
4228
  queryFn: () => I.balanceSheet(t)
4229
4229
  });
4230
4230
  return { data: n, isLoading: a, error: s, refetch: o };
4231
4231
  }
4232
- function ms(t) {
4232
+ function ps(t) {
4233
4233
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4234
4234
  queryKey: ["report", "ar-aging", t],
4235
4235
  queryFn: () => I.arAging(t)
4236
4236
  });
4237
4237
  return { data: n, isLoading: a, error: s, refetch: o };
4238
4238
  }
4239
- function ps(t) {
4239
+ function hs(t) {
4240
4240
  const { data: n, isLoading: a, error: s, refetch: o } = ue({
4241
4241
  queryKey: ["report", "ap-aging", t],
4242
4242
  queryFn: () => I.apAging(t)
4243
4243
  });
4244
4244
  return { data: n, isLoading: a, error: s, refetch: o };
4245
4245
  }
4246
- function hs() {
4246
+ function gs() {
4247
4247
  const { t } = X(), [n] = le("company", ""), [a] = le("from", ""), [s] = le("to", ""), o = Ye(), [i, l] = w(n), [c, h] = w(a), [d, p] = w(s), u = ze(i), f = (y) => qe(y, u), v = Ne(() => {
4248
4248
  const y = {};
4249
4249
  return n && (y.company = n), a && (y.from_date = a), s && (y.to_date = s), y;
4250
- }, [n, a, s]), { data: N, isLoading: b, refetch: C } = is(v), S = () => {
4250
+ }, [n, a, s]), { data: N, isLoading: b, refetch: C } = os(v), S = () => {
4251
4251
  o({
4252
4252
  company: i || null,
4253
4253
  from: c || null,
@@ -4320,8 +4320,8 @@ function hs() {
4320
4320
  ] })
4321
4321
  ] });
4322
4322
  }
4323
- const gs = ["Asset", "Liability", "Equity", "Income", "Expense"];
4324
- function fs() {
4323
+ const fs = ["Asset", "Liability", "Equity", "Income", "Expense"];
4324
+ function ys() {
4325
4325
  const { t } = X(), n = (/* @__PURE__ */ new Date()).getFullYear(), [a, s] = w(String(n)), [o, i] = w(/* @__PURE__ */ new Set()), l = Ne(() => {
4326
4326
  const x = [];
4327
4327
  for (let y = n; y >= n - 6; y--)
@@ -4330,7 +4330,7 @@ function fs() {
4330
4330
  }, [n, t]), c = Ne(() => {
4331
4331
  const x = {};
4332
4332
  return a !== "all" && (x.from_date = `${a}-01-01`, x.to_date = `${a}-12-31`), x;
4333
- }, [a]), { data: h, isLoading: d } = os(c), p = ze(""), u = (x) => qe(x, p), f = (h == null ? void 0 : h.accounts) ?? [], { childrenOf: v, rootsByType: N } = Ne(() => {
4333
+ }, [a]), { data: h, isLoading: d } = ls(c), p = ze(""), u = (x) => qe(x, p), f = (h == null ? void 0 : h.accounts) ?? [], { childrenOf: v, rootsByType: N } = Ne(() => {
4334
4334
  const x = new Map(f.map((D) => [D.name, D])), y = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map();
4335
4335
  for (const D of f)
4336
4336
  if (D.parent_account && x.has(D.parent_account)) {
@@ -4400,21 +4400,21 @@ function fs() {
4400
4400
  ] }),
4401
4401
  d && /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("common.loading", { defaultValue: "Loading…" }) }) }),
4402
4402
  !d && f.length === 0 && /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("coa.empty", { defaultValue: "No accounts found. Complete the company setup first." }) }) }),
4403
- !d && gs.filter((x) => (N.get(x) ?? []).length > 0).map((x) => /* @__PURE__ */ r(M, { children: [
4403
+ !d && fs.filter((x) => (N.get(x) ?? []).length > 0).map((x) => /* @__PURE__ */ r(M, { children: [
4404
4404
  /* @__PURE__ */ e("h3", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-fg-muted", children: t(`coa.rootType.${x}`, { defaultValue: x }) }),
4405
4405
  /* @__PURE__ */ e("div", { children: (N.get(x) ?? []).map((y) => S(y, 0)) })
4406
4406
  ] }, x))
4407
4407
  ] });
4408
4408
  }
4409
- function ys(t) {
4409
+ function bs(t) {
4410
4410
  return t.toLowerCase().replace(/\s+/g, "-");
4411
4411
  }
4412
- const bs = ["25", "50", "100", "200"];
4413
- function vs() {
4412
+ const vs = ["25", "50", "100", "200"];
4413
+ function xs() {
4414
4414
  const { t } = X(), [n] = le("account", ""), [a] = le("party", ""), [s] = le("from", ""), [o] = le("to", ""), [i] = le("per_page", 50), [l] = le("page", 1), c = l - 1, h = Ye(), d = (_) => h({ page: _ === 0 ? null : _ + 1 }), p = (_) => h({ per_page: _, page: null }), [u, f] = w(n), [v, N] = w(a), [b, C] = w(s), [S, x] = w(o), y = ze(), m = (_) => qe(_, y), D = Ne(() => {
4415
4415
  const _ = {};
4416
4416
  return n && (_.account = n), a && (_.party = a), s && (_.from_date = s), o && (_.to_date = o), _.limit = String(i), _.offset = String(c * i), _;
4417
- }, [n, a, s, o, i, c]), { data: T, isLoading: U, refetch: Z } = ls(D), g = (T == null ? void 0 : T.rows) ?? [], R = (T == null ? void 0 : T.total) ?? 0, W = Math.max(1, Math.ceil(R / i)), $ = R === 0 ? 0 : c * i + 1, de = Math.min(R, (c + 1) * i), A = () => {
4417
+ }, [n, a, s, o, i, c]), { data: T, isLoading: U, refetch: Z } = cs(D), g = (T == null ? void 0 : T.rows) ?? [], R = (T == null ? void 0 : T.total) ?? 0, W = Math.max(1, Math.ceil(R / i)), $ = R === 0 ? 0 : c * i + 1, de = Math.min(R, (c + 1) * i), A = () => {
4418
4418
  h({
4419
4419
  account: u || null,
4420
4420
  party: v || null,
@@ -4491,7 +4491,7 @@ function vs() {
4491
4491
  /* @__PURE__ */ e("td", { className: "px-4 py-2", children: _.voucher_type && _.voucher_no ? /* @__PURE__ */ e(
4492
4492
  ve,
4493
4493
  {
4494
- to: `/app/${ys(_.voucher_type)}/${_.voucher_no}`,
4494
+ to: `/app/${bs(_.voucher_type)}/${_.voucher_no}`,
4495
4495
  className: "font-medium text-blue-600 hover:text-blue-800",
4496
4496
  children: _.voucher_no
4497
4497
  }
@@ -4521,7 +4521,7 @@ function vs() {
4521
4521
  value: i,
4522
4522
  onChange: (_) => p(Number(_.target.value)),
4523
4523
  className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
4524
- children: bs.map((_) => /* @__PURE__ */ e("option", { value: _, children: _ }, _))
4524
+ children: vs.map((_) => /* @__PURE__ */ e("option", { value: _, children: _ }, _))
4525
4525
  }
4526
4526
  )
4527
4527
  ] }),
@@ -4557,11 +4557,11 @@ function vs() {
4557
4557
  ] })
4558
4558
  ] });
4559
4559
  }
4560
- function xs() {
4560
+ function Ns() {
4561
4561
  const { t } = X(), [n] = le("item_code", ""), [a] = le("warehouse", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), h = ze(), d = (b) => qe(b, h), p = Ne(() => {
4562
4562
  const b = {};
4563
4563
  return n && (b.item_code = n), a && (b.warehouse = a), b;
4564
- }, [n, a]), { data: u, isLoading: f, refetch: v } = cs(p), N = () => {
4564
+ }, [n, a]), { data: u, isLoading: f, refetch: v } = ds(p), N = () => {
4565
4565
  s({
4566
4566
  item_code: o || null,
4567
4567
  warehouse: l || null
@@ -4604,18 +4604,18 @@ function xs() {
4604
4604
  /* @__PURE__ */ e("td", { className: "px-4 py-2 font-medium text-gray-900", children: b.item_code }),
4605
4605
  /* @__PURE__ */ e("td", { className: "px-4 py-2 text-gray-700", children: b.item_name }),
4606
4606
  /* @__PURE__ */ e("td", { className: "px-4 py-2 text-gray-700", children: b.warehouse }),
4607
- /* @__PURE__ */ e("td", { className: "px-4 py-2 text-right", children: Jt(b.actual_qty) }),
4607
+ /* @__PURE__ */ e("td", { className: "px-4 py-2 text-right", children: Zt(b.actual_qty) }),
4608
4608
  /* @__PURE__ */ e("td", { className: "px-4 py-2 text-right", children: d(b.valuation_rate) }),
4609
4609
  /* @__PURE__ */ e("td", { className: "px-4 py-2 text-right font-medium", children: d(b.stock_value) })
4610
4610
  ] }, C)) })
4611
4611
  ] }) }) })
4612
4612
  ] });
4613
4613
  }
4614
- function Ns() {
4614
+ function ws() {
4615
4615
  const { t } = X(), [n] = le("company", ""), [a] = le("from", ""), [s] = le("to", ""), o = Ye(), [i, l] = w(n), c = ze(i), h = (y) => qe(y, c), [d, p] = w(a), [u, f] = w(s), v = Ne(() => {
4616
4616
  const y = {};
4617
4617
  return n && (y.company = n), a && (y.from_date = a), s && (y.to_date = s), y;
4618
- }, [n, a, s]), { data: N, isLoading: b, refetch: C } = ds(v), S = () => {
4618
+ }, [n, a, s]), { data: N, isLoading: b, refetch: C } = us(v), S = () => {
4619
4619
  o({
4620
4620
  company: i || null,
4621
4621
  from: d || null,
@@ -4675,7 +4675,7 @@ function Ns() {
4675
4675
  ] }) : /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noData") })
4676
4676
  ] });
4677
4677
  }
4678
- function Gt({ title: t, rows: n, total: a, totalLabel: s, currency: o }) {
4678
+ function Wt({ title: t, rows: n, total: a, totalLabel: s, currency: o }) {
4679
4679
  const { t: i } = X(), l = (c) => qe(c, o);
4680
4680
  return /* @__PURE__ */ r(M, { children: [
4681
4681
  /* @__PURE__ */ e("h3", { className: "mb-3 text-base font-semibold text-gray-800", children: t }),
@@ -4695,12 +4695,12 @@ function Gt({ title: t, rows: n, total: a, totalLabel: s, currency: o }) {
4695
4695
  ] })
4696
4696
  ] });
4697
4697
  }
4698
- function ws() {
4698
+ function ks() {
4699
4699
  var S, x, y;
4700
4700
  const { t } = X(), [n] = le("company", ""), [a] = le("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), h = ze(o), d = (m) => qe(m, h), p = Ne(() => {
4701
4701
  const m = {};
4702
4702
  return n && (m.company = n), a && (m.as_of_date = a), m;
4703
- }, [n, a]), { data: u, isLoading: f, refetch: v } = us(p), N = () => {
4703
+ }, [n, a]), { data: u, isLoading: f, refetch: v } = ms(p), N = () => {
4704
4704
  s({ company: o || null, as_of_date: l || null }), v();
4705
4705
  }, b = u && (((S = u.assets) == null ? void 0 : S.length) > 0 || ((x = u.liabilities) == null ? void 0 : x.length) > 0 || ((y = u.equity) == null ? void 0 : y.length) > 0), C = u ? Math.abs(u.total_assets - u.total_liabilities_and_equity) < 0.01 : !1;
4706
4706
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4709,13 +4709,13 @@ function ws() {
4709
4709
  /* @__PURE__ */ e(te, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (m) => c(m.target.value) }),
4710
4710
  /* @__PURE__ */ e(Q, { onClick: N, children: t("common.apply") })
4711
4711
  ] }),
4712
- /* @__PURE__ */ e(mn, { onSelect: (m) => {
4712
+ /* @__PURE__ */ e(pn, { onSelect: (m) => {
4713
4713
  c(m), s({ as_of_date: m });
4714
4714
  } }),
4715
4715
  f ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: t("common.loading") }) : b ? /* @__PURE__ */ r("div", { className: "space-y-4", children: [
4716
- /* @__PURE__ */ e(Gt, { title: t("reports.assets"), rows: u.assets || [], total: u.total_assets, totalLabel: t("reports.totalAssets"), currency: h }),
4717
- /* @__PURE__ */ e(Gt, { title: t("reports.liabilities"), rows: u.liabilities || [], total: u.total_liabilities, totalLabel: t("reports.totalLiabilities"), currency: h }),
4718
- /* @__PURE__ */ e(Gt, { title: t("reports.equity"), rows: u.equity || [], total: u.total_equity, totalLabel: t("reports.totalEquity"), currency: h }),
4716
+ /* @__PURE__ */ e(Wt, { title: t("reports.assets"), rows: u.assets || [], total: u.total_assets, totalLabel: t("reports.totalAssets"), currency: h }),
4717
+ /* @__PURE__ */ e(Wt, { title: t("reports.liabilities"), rows: u.liabilities || [], total: u.total_liabilities, totalLabel: t("reports.totalLiabilities"), currency: h }),
4718
+ /* @__PURE__ */ e(Wt, { title: t("reports.equity"), rows: u.equity || [], total: u.total_equity, totalLabel: t("reports.totalEquity"), currency: h }),
4719
4719
  /* @__PURE__ */ e(M, { children: /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
4720
4720
  /* @__PURE__ */ r("div", { className: "text-sm", children: [
4721
4721
  /* @__PURE__ */ r("div", { className: "text-gray-500", children: [
@@ -4734,11 +4734,11 @@ function ws() {
4734
4734
  ] }) : /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noData") })
4735
4735
  ] });
4736
4736
  }
4737
- function ks() {
4737
+ function Cs() {
4738
4738
  const { t } = X(), [n] = le("company", ""), [a] = le("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), h = ze(o), d = (b) => qe(b, h), p = Ne(() => {
4739
4739
  const b = {};
4740
4740
  return n && (b.company = n), a && (b.as_of_date = a), b;
4741
- }, [n, a]), { data: u, isLoading: f, refetch: v } = ms(p), N = () => {
4741
+ }, [n, a]), { data: u, isLoading: f, refetch: v } = ps(p), N = () => {
4742
4742
  s({ company: o || null, as_of_date: l || null }), v();
4743
4743
  };
4744
4744
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4747,7 +4747,7 @@ function ks() {
4747
4747
  /* @__PURE__ */ e(te, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (b) => c(b.target.value) }),
4748
4748
  /* @__PURE__ */ e(Q, { onClick: N, children: t("common.apply") })
4749
4749
  ] }),
4750
- /* @__PURE__ */ e(mn, { onSelect: (b) => {
4750
+ /* @__PURE__ */ e(pn, { onSelect: (b) => {
4751
4751
  c(b), s({ as_of_date: b });
4752
4752
  } }),
4753
4753
  f ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: t("common.loading") }) : !u || !u.rows || u.rows.length === 0 ? /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noReceivables") }) : /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
@@ -4792,11 +4792,11 @@ function ks() {
4792
4792
  ] }) }) })
4793
4793
  ] });
4794
4794
  }
4795
- function Cs() {
4795
+ function Ss() {
4796
4796
  const { t } = X(), [n] = le("company", ""), [a] = le("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), h = ze(o), d = (b) => qe(b, h), p = Ne(() => {
4797
4797
  const b = {};
4798
4798
  return n && (b.company = n), a && (b.as_of_date = a), b;
4799
- }, [n, a]), { data: u, isLoading: f, refetch: v } = ps(p), N = () => {
4799
+ }, [n, a]), { data: u, isLoading: f, refetch: v } = hs(p), N = () => {
4800
4800
  s({ company: o || null, as_of_date: l || null }), v();
4801
4801
  };
4802
4802
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4805,7 +4805,7 @@ function Cs() {
4805
4805
  /* @__PURE__ */ e(te, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (b) => c(b.target.value) }),
4806
4806
  /* @__PURE__ */ e(Q, { onClick: N, children: t("common.apply") })
4807
4807
  ] }),
4808
- /* @__PURE__ */ e(mn, { onSelect: (b) => {
4808
+ /* @__PURE__ */ e(pn, { onSelect: (b) => {
4809
4809
  c(b), s({ as_of_date: b });
4810
4810
  } }),
4811
4811
  f ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: t("common.loading") }) : !u || !u.rows || u.rows.length === 0 ? /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noPayables") }) : /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
@@ -4850,11 +4850,11 @@ function Cs() {
4850
4850
  ] }) }) })
4851
4851
  ] });
4852
4852
  }
4853
- const ba = '(function(){"use strict";function u(r,t){const e=Number(r??0)||0;return t==null?e:Number(e.toFixed(t))}const p={flt:u,sum(r,t){return r.reduce((e,a)=>typeof t=="function"?e+u(t(a)):typeof t=="string"?e+u(a[t]):e+u(a),0)},count(r){return r.length},sortBy(r,t,e="asc"){const n=(e===!0?"desc":e===!1?"asc":e)==="desc"?-1:1;return[...r].sort((s,i)=>{const c=s[t],o=i[t];return c==null&&o==null?0:c==null?1:o==null?-1:c<o?-1*n:c>o?1*n:0})},topN(r,t,e=10){return typeof t=="number"?r.slice(0,t):p.sortBy(r,t,"desc").slice(0,e)},group(r,t,e){if(typeof t=="function"){const s=new Map;for(const i of r){const c=t(i),o=JSON.stringify(c);s.has(o)||s.set(o,{key:c,rows:[]}),s.get(o).rows.push(i)}return Array.from(s.values())}const a=t,n=new Map;for(const s of r){const i=a.map(f=>s[f]),c=JSON.stringify(i);if(!n.has(c)){const f={};a.forEach((l,m)=>{f[l]=i[m]});for(const[l,[m]]of Object.entries(e||{}))f[l]=0;n.set(c,f)}const o=n.get(c);for(const[f,[l,m]]of Object.entries(e||{}))l==="count"?o[f]=u(o[f])+1:o[f]=u(o[f])+u(s[m||f])}return Array.from(n.values())},leftJoin(r,t,e,a=e){const n=new Map(t.map(s=>[s[a],s]));return r.map(s=>({...s,...n.get(s[e])||{}}))},monthKey(r){return String(r??"").slice(0,7)},quarterKey(r){const t=String(r??""),e=t.slice(0,4),a=Number(t.slice(5,7));return!e||!a?"":`${e}-Q${Math.floor((a+2)/3)}`},yearKey(r){return String(r??"").slice(0,4)},pivot(r,t,e,a){const n=new Map;for(const s of r){const i=String(s[t]??"—"),c=String(s[e]??"—");n.has(i)||n.set(i,{[t]:i});const o=n.get(i);o[c]=u(o[c])+u(s[a])}return Array.from(n.values())}};function y(r){if(!r||typeof r!="object")throw new Error("Transform must return an object");if(r.tables&&!Array.isArray(r.tables))throw new Error("tables must be an array");if(r.charts&&!Array.isArray(r.charts))throw new Error("charts must be an array");if(r.kpis&&!Array.isArray(r.kpis))throw new Error("kpis must be an array");return r}self.onmessage=r=>{try{const t=Object.fromEntries(r.data.datasets.map(s=>[s.name,s.rows])),e=r.data.datasets.map(s=>s.name).filter(s=>/^[$A-Z_][0-9A-Z_$]*$/i.test(s)).map(s=>`const ${s} = datasets[${JSON.stringify(s)}];`).join(`\n`),n=new Function("datasets","params","helpers",`"use strict";\n${e}\n${r.data.transformJs}`)(t,r.data.params||{},p);self.postMessage({ok:!0,output:y(n)})}catch(t){self.postMessage({ok:!1,error:t instanceof Error?t.message:String(t)})}}})();\n//# sourceMappingURL=report-runtime.worker-DrBTCfV6.js.map\n', En = typeof self < "u" && self.Blob && new Blob([ba], { type: "text/javascript;charset=utf-8" });
4854
- function Ss(t) {
4853
+ const va = '(function(){"use strict";function u(r,t){const e=Number(r??0)||0;return t==null?e:Number(e.toFixed(t))}const p={flt:u,sum(r,t){return r.reduce((e,a)=>typeof t=="function"?e+u(t(a)):typeof t=="string"?e+u(a[t]):e+u(a),0)},count(r){return r.length},sortBy(r,t,e="asc"){const n=(e===!0?"desc":e===!1?"asc":e)==="desc"?-1:1;return[...r].sort((s,i)=>{const c=s[t],o=i[t];return c==null&&o==null?0:c==null?1:o==null?-1:c<o?-1*n:c>o?1*n:0})},topN(r,t,e=10){return typeof t=="number"?r.slice(0,t):p.sortBy(r,t,"desc").slice(0,e)},group(r,t,e){if(typeof t=="function"){const s=new Map;for(const i of r){const c=t(i),o=JSON.stringify(c);s.has(o)||s.set(o,{key:c,rows:[]}),s.get(o).rows.push(i)}return Array.from(s.values())}const a=t,n=new Map;for(const s of r){const i=a.map(f=>s[f]),c=JSON.stringify(i);if(!n.has(c)){const f={};a.forEach((l,m)=>{f[l]=i[m]});for(const[l,[m]]of Object.entries(e||{}))f[l]=0;n.set(c,f)}const o=n.get(c);for(const[f,[l,m]]of Object.entries(e||{}))l==="count"?o[f]=u(o[f])+1:o[f]=u(o[f])+u(s[m||f])}return Array.from(n.values())},leftJoin(r,t,e,a=e){const n=new Map(t.map(s=>[s[a],s]));return r.map(s=>({...s,...n.get(s[e])||{}}))},monthKey(r){return String(r??"").slice(0,7)},quarterKey(r){const t=String(r??""),e=t.slice(0,4),a=Number(t.slice(5,7));return!e||!a?"":`${e}-Q${Math.floor((a+2)/3)}`},yearKey(r){return String(r??"").slice(0,4)},pivot(r,t,e,a){const n=new Map;for(const s of r){const i=String(s[t]??"—"),c=String(s[e]??"—");n.has(i)||n.set(i,{[t]:i});const o=n.get(i);o[c]=u(o[c])+u(s[a])}return Array.from(n.values())}};function y(r){if(!r||typeof r!="object")throw new Error("Transform must return an object");if(r.tables&&!Array.isArray(r.tables))throw new Error("tables must be an array");if(r.charts&&!Array.isArray(r.charts))throw new Error("charts must be an array");if(r.kpis&&!Array.isArray(r.kpis))throw new Error("kpis must be an array");return r}self.onmessage=r=>{try{const t=Object.fromEntries(r.data.datasets.map(s=>[s.name,s.rows])),e=r.data.datasets.map(s=>s.name).filter(s=>/^[$A-Z_][0-9A-Z_$]*$/i.test(s)).map(s=>`const ${s} = datasets[${JSON.stringify(s)}];`).join(`\n`),n=new Function("datasets","params","helpers",`"use strict";\n${e}\n${r.data.transformJs}`)(t,r.data.params||{},p);self.postMessage({ok:!0,output:y(n)})}catch(t){self.postMessage({ok:!1,error:t instanceof Error?t.message:String(t)})}}})();\n//# sourceMappingURL=report-runtime.worker-DrBTCfV6.js.map\n', Ln = typeof self < "u" && self.Blob && new Blob([va], { type: "text/javascript;charset=utf-8" });
4854
+ function Ds(t) {
4855
4855
  let n;
4856
4856
  try {
4857
- if (n = En && (self.URL || self.webkitURL).createObjectURL(En), !n) throw "";
4857
+ if (n = Ln && (self.URL || self.webkitURL).createObjectURL(Ln), !n) throw "";
4858
4858
  const a = new Worker(n, {
4859
4859
  name: t == null ? void 0 : t.name
4860
4860
  });
@@ -4863,7 +4863,7 @@ function Ss(t) {
4863
4863
  }), a;
4864
4864
  } catch {
4865
4865
  return new Worker(
4866
- "data:text/javascript;charset=utf-8," + encodeURIComponent(ba),
4866
+ "data:text/javascript;charset=utf-8," + encodeURIComponent(va),
4867
4867
  {
4868
4868
  name: t == null ? void 0 : t.name
4869
4869
  }
@@ -4872,7 +4872,7 @@ function Ss(t) {
4872
4872
  n && (self.URL || self.webkitURL).revokeObjectURL(n);
4873
4873
  }
4874
4874
  }
4875
- function Ds() {
4875
+ function As() {
4876
4876
  const t = /* @__PURE__ */ new Date(), n = t.toISOString().slice(0, 10), a = new Date(t);
4877
4877
  a.setMonth(a.getMonth() - 12);
4878
4878
  const s = a.toISOString().slice(0, 10);
@@ -4943,9 +4943,9 @@ return {
4943
4943
  2
4944
4944
  );
4945
4945
  }
4946
- const va = Ds();
4947
- function As() {
4948
- const t = Ee(), { sessions: n, createSession: a } = mt(), [s] = le("report_id", ""), [o] = le("metric", ""), [i] = le("group_by", ""), [l] = le("from", ""), [c] = le("to", ""), [h] = le("company", ""), [d, p] = w(va), [u, f] = w([]), [v, N] = w(null), [b, C] = w(""), [S, x] = w(!1), [y, m] = w(!1), [D, T] = w(""), U = oe(null), Z = oe(""), g = oe(""), R = oe(0), W = Ne(() => !o || !i ? "" : JSON.stringify(Rs({
4946
+ const xa = As();
4947
+ function Ps() {
4948
+ const t = Ee(), { sessions: n, createSession: a } = ut(), [s] = le("report_id", ""), [o] = le("metric", ""), [i] = le("group_by", ""), [l] = le("from", ""), [c] = le("to", ""), [h] = le("company", ""), [d, p] = w(xa), [u, f] = w([]), [v, N] = w(null), [b, C] = w(""), [S, x] = w(!1), [y, m] = w(!1), [D, T] = w(""), U = oe(null), Z = oe(""), g = oe(""), R = oe(0), W = Ne(() => !o || !i ? "" : JSON.stringify(Is({
4949
4949
  metric: o,
4950
4950
  groupBy: i,
4951
4951
  fromDate: l || void 0,
@@ -4959,7 +4959,7 @@ function As() {
4959
4959
  const ne = JSON.parse(z ?? d), H = await I.runtimeData({ requests: ne.data_requests || [] });
4960
4960
  if (!se()) return;
4961
4961
  f(H.datasets), (P = U.current) == null || P.terminate();
4962
- const ce = new Ss();
4962
+ const ce = new Ds();
4963
4963
  U.current = ce;
4964
4964
  const Se = await new Promise((E, ie) => {
4965
4965
  const Le = window.setTimeout(() => {
@@ -4999,7 +4999,7 @@ function As() {
4999
4999
  z = !0;
5000
5000
  });
5001
5001
  }, [s, W]);
5002
- const de = !!(!s && W), A = Ne(() => Ts(v), [v]), _ = async () => {
5002
+ const de = !!(!s && W), A = Ne(() => Rs(v), [v]), _ = async () => {
5003
5003
  var H;
5004
5004
  const z = d.trim() !== g.current.trim(), ee = s || "unsaved-runtime-report", se = u.map((ce) => ({
5005
5005
  name: ce.name,
@@ -5051,7 +5051,7 @@ function As() {
5051
5051
  /* @__PURE__ */ e(Q, { onClick: () => void $(), disabled: S, children: S ? "Running..." : "Run Report" })
5052
5052
  ] })
5053
5053
  ] }) }),
5054
- y ? /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : b ? /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: b }) }) : v ? /* @__PURE__ */ e(Ps, { output: v }) : /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
5054
+ y ? /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : b ? /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: b }) }) : v ? /* @__PURE__ */ e(_s, { output: v }) : /* @__PURE__ */ e(M, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
5055
5055
  u.length > 0 && /* @__PURE__ */ e(M, { title: "Fetched Datasets", children: /* @__PURE__ */ e("div", { className: "space-y-4", children: u.map((z) => /* @__PURE__ */ r("div", { className: "rounded-md border border-gray-200 p-4", children: [
5056
5056
  /* @__PURE__ */ r("div", { className: "flex items-baseline justify-between gap-4", children: [
5057
5057
  /* @__PURE__ */ r("div", { children: [
@@ -5080,12 +5080,12 @@ function As() {
5080
5080
  ] })
5081
5081
  ] });
5082
5082
  }
5083
- function Ps({ output: t }) {
5083
+ function _s({ output: t }) {
5084
5084
  var o, i;
5085
5085
  const n = ze(), a = (t.tables ?? []).map((l, c) => ({
5086
5086
  ...l,
5087
5087
  id: l.id || `table_${c + 1}`
5088
- })), s = xa(a);
5088
+ })), s = Na(a);
5089
5089
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
5090
5090
  /* @__PURE__ */ r(M, { children: [
5091
5091
  /* @__PURE__ */ e("div", { className: "flex items-baseline justify-between gap-4", children: /* @__PURE__ */ r("div", { children: [
@@ -5101,13 +5101,13 @@ function Ps({ output: t }) {
5101
5101
  const h = l.dataTable ? s.get(l.dataTable) : void 0, d = l.data ?? (h == null ? void 0 : h.rows) ?? [];
5102
5102
  if (!d.length)
5103
5103
  return /* @__PURE__ */ e(M, { title: l.title, children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: "Chart has no usable data." }) }, l.id || `chart_${c + 1}`);
5104
- const p = l.type === "pie" ? [] : d.map((v) => String(v[l.x] ?? "")), u = Ls(p), f = Math.max(320, 200 + u.axisHeight);
5104
+ const p = l.type === "pie" ? [] : d.map((v) => String(v[l.x] ?? "")), u = Os(p), f = Math.max(320, 200 + u.axisHeight);
5105
5105
  return /* @__PURE__ */ r(M, { children: [
5106
5106
  /* @__PURE__ */ e("div", { className: "pb-3 text-sm font-semibold text-gray-700", children: l.title }),
5107
- /* @__PURE__ */ e("div", { style: { height: f }, className: "w-full", children: /* @__PURE__ */ e(tr, { width: "100%", height: "100%", children: l.type === "line" ? /* @__PURE__ */ r(nr, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
5108
- /* @__PURE__ */ e(gn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
5107
+ /* @__PURE__ */ e("div", { style: { height: f }, className: "w-full", children: /* @__PURE__ */ e(nr, { width: "100%", height: "100%", children: l.type === "line" ? /* @__PURE__ */ r(ar, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
5108
+ /* @__PURE__ */ e(fn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
5109
5109
  /* @__PURE__ */ e(
5110
- fn,
5110
+ yn,
5111
5111
  {
5112
5112
  dataKey: l.x,
5113
5113
  tick: { fill: "#6b7280", fontSize: 12 },
@@ -5117,16 +5117,16 @@ function Ps({ output: t }) {
5117
5117
  height: u.axisHeight
5118
5118
  }
5119
5119
  ),
5120
- /* @__PURE__ */ e(yn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: Ln }),
5121
- /* @__PURE__ */ e(Vt, { formatter: (v) => Ct(v, Wt(h, l.y), n) }),
5122
- /* @__PURE__ */ e(ar, { type: "monotone", dataKey: l.y, stroke: "#3b82f6", strokeWidth: 2, dot: { r: 3 } })
5123
- ] }) : l.type === "pie" ? /* @__PURE__ */ r(rr, { children: [
5124
- /* @__PURE__ */ e(Vt, { formatter: (v) => Ct(v, Wt(h, l.y), n) }),
5125
- /* @__PURE__ */ e(sr, { data: d, dataKey: l.y, nameKey: l.x, outerRadius: 110, children: d.map((v, N) => /* @__PURE__ */ e(ir, { fill: On[N % On.length] }, N)) })
5126
- ] }) : /* @__PURE__ */ r(or, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
5127
- /* @__PURE__ */ e(gn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
5120
+ /* @__PURE__ */ e(bn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: On }),
5121
+ /* @__PURE__ */ e(Kt, { formatter: (v) => Ct(v, Ht(h, l.y), n) }),
5122
+ /* @__PURE__ */ e(rr, { type: "monotone", dataKey: l.y, stroke: "#3b82f6", strokeWidth: 2, dot: { r: 3 } })
5123
+ ] }) : l.type === "pie" ? /* @__PURE__ */ r(sr, { children: [
5124
+ /* @__PURE__ */ e(Kt, { formatter: (v) => Ct(v, Ht(h, l.y), n) }),
5125
+ /* @__PURE__ */ e(ir, { data: d, dataKey: l.y, nameKey: l.x, outerRadius: 110, children: d.map((v, N) => /* @__PURE__ */ e(or, { fill: qn[N % qn.length] }, N)) })
5126
+ ] }) : /* @__PURE__ */ r(lr, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
5127
+ /* @__PURE__ */ e(fn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
5128
5128
  /* @__PURE__ */ e(
5129
- fn,
5129
+ yn,
5130
5130
  {
5131
5131
  dataKey: l.x,
5132
5132
  tick: { fill: "#6b7280", fontSize: 12 },
@@ -5136,9 +5136,9 @@ function Ps({ output: t }) {
5136
5136
  height: u.axisHeight
5137
5137
  }
5138
5138
  ),
5139
- /* @__PURE__ */ e(yn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: Ln }),
5140
- /* @__PURE__ */ e(Vt, { formatter: (v) => Ct(v, Wt(h, l.y), n) }),
5141
- /* @__PURE__ */ e(lr, { dataKey: l.y, fill: "#3b82f6", radius: [4, 4, 0, 0] })
5139
+ /* @__PURE__ */ e(bn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: On }),
5140
+ /* @__PURE__ */ e(Kt, { formatter: (v) => Ct(v, Ht(h, l.y), n) }),
5141
+ /* @__PURE__ */ e(cr, { dataKey: l.y, fill: "#3b82f6", radius: [4, 4, 0, 0] })
5142
5142
  ] }) }) })
5143
5143
  ] }, l.id || `chart_${c + 1}`);
5144
5144
  }),
@@ -5148,21 +5148,21 @@ function Ps({ output: t }) {
5148
5148
  ] }) }) }, l.id))
5149
5149
  ] });
5150
5150
  }
5151
- function _s(t) {
5151
+ function Ts(t) {
5152
5152
  return t.replace(/_/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
5153
5153
  }
5154
- function xa(t) {
5154
+ function Na(t) {
5155
5155
  const n = /* @__PURE__ */ new Map();
5156
5156
  for (const a of t)
5157
5157
  n.set(a.id, a), a.title && n.set(a.title, a);
5158
5158
  return n;
5159
5159
  }
5160
- function Ts(t) {
5160
+ function Rs(t) {
5161
5161
  if (!t) return [];
5162
5162
  const n = (t.tables ?? []).map((o, i) => ({
5163
5163
  ...o,
5164
5164
  id: o.id || `table_${i + 1}`
5165
- })), a = xa(n), s = [];
5165
+ })), a = Na(n), s = [];
5166
5166
  for (const o of t.charts ?? []) {
5167
5167
  const i = o.dataTable ? a.get(o.dataTable) : void 0, l = o.data ?? (i == null ? void 0 : i.rows) ?? [];
5168
5168
  if (!l.length) {
@@ -5173,10 +5173,10 @@ function Ts(t) {
5173
5173
  }
5174
5174
  return s;
5175
5175
  }
5176
- function Rs(t) {
5177
- const n = `${Is(t.metric)} by ${_s(t.groupBy)}`, a = t.groupBy === "month" ? "helpers.monthKey" : t.groupBy === "quarter" ? "helpers.quarterKey" : "helpers.yearKey";
5176
+ function Is(t) {
5177
+ const n = `${Bs(t.metric)} by ${Ts(t.groupBy)}`, a = t.groupBy === "month" ? "helpers.monthKey" : t.groupBy === "quarter" ? "helpers.quarterKey" : "helpers.yearKey";
5178
5178
  if (t.metric === "sales_revenue")
5179
- return bt({
5179
+ return yt({
5180
5180
  title: n,
5181
5181
  dataset: t.groupBy === "item" ? "sales_invoice_lines" : "sales_invoices",
5182
5182
  requestName: "rows",
@@ -5193,7 +5193,7 @@ function Rs(t) {
5193
5193
  chartType: t.groupBy === "customer" || t.groupBy === "item" ? "bar" : "line"
5194
5194
  });
5195
5195
  if (t.metric === "sales_returns")
5196
- return bt({
5196
+ return yt({
5197
5197
  title: n,
5198
5198
  dataset: "sales_invoices",
5199
5199
  requestName: "rows",
@@ -5210,7 +5210,7 @@ function Rs(t) {
5210
5210
  chartType: t.groupBy === "customer" ? "bar" : "line"
5211
5211
  });
5212
5212
  if (t.metric === "purchases")
5213
- return bt({
5213
+ return yt({
5214
5214
  title: n,
5215
5215
  dataset: t.groupBy === "item" ? "purchase_invoice_lines" : "purchase_invoices",
5216
5216
  requestName: "rows",
@@ -5228,7 +5228,7 @@ function Rs(t) {
5228
5228
  });
5229
5229
  if (t.metric === "payments_received" || t.metric === "payments_made") {
5230
5230
  const s = t.metric === "payments_received";
5231
- return bt({
5231
+ return yt({
5232
5232
  title: n,
5233
5233
  dataset: "payments",
5234
5234
  requestName: "rows",
@@ -5248,7 +5248,7 @@ function Rs(t) {
5248
5248
  }
5249
5249
  if (t.metric === "outstanding_ar" || t.metric === "outstanding_ap") {
5250
5250
  const s = t.metric === "outstanding_ar", o = s ? "ar_open_items" : "ap_open_items", i = s ? "customer" : "supplier", l = "outstanding_amount";
5251
- return bt({
5251
+ return yt({
5252
5252
  title: n,
5253
5253
  dataset: o,
5254
5254
  requestName: "rows",
@@ -5264,7 +5264,7 @@ function Rs(t) {
5264
5264
  chartType: "bar"
5265
5265
  });
5266
5266
  }
5267
- return t.metric === "stock_value" ? bt({
5267
+ return t.metric === "stock_value" ? yt({
5268
5268
  title: n,
5269
5269
  dataset: "stock_balances",
5270
5270
  requestName: "rows",
@@ -5277,9 +5277,9 @@ function Rs(t) {
5277
5277
  },
5278
5278
  fields: [t.groupBy === "warehouse" ? "warehouse" : "item_code", "stock_value"],
5279
5279
  chartType: "bar"
5280
- }) : JSON.parse(va);
5280
+ }) : JSON.parse(xa);
5281
5281
  }
5282
- function bt(t) {
5282
+ function yt(t) {
5283
5283
  const n = Object.fromEntries(Object.entries(t.filters).filter(([, s]) => s !== void 0)), a = ["month", "quarter", "year"].includes(t.groupBy) ? `${t.timeBucket}(row.${t.keyField})` : `row.${t.keyField} || "—"`;
5284
5284
  return {
5285
5285
  title: t.title,
@@ -5333,7 +5333,7 @@ return {
5333
5333
  };`
5334
5334
  };
5335
5335
  }
5336
- function Is(t) {
5336
+ function Bs(t) {
5337
5337
  return {
5338
5338
  sales_revenue: "Sales Revenue",
5339
5339
  sales_returns: "Sales Returns",
@@ -5345,35 +5345,35 @@ function Is(t) {
5345
5345
  stock_value: "Stock Value"
5346
5346
  }[t] || "Analytics";
5347
5347
  }
5348
- function Wt(t, n) {
5348
+ function Ht(t, n) {
5349
5349
  var a, s;
5350
5350
  return ((a = t == null ? void 0 : t.columns.find((o) => o.key === n)) == null ? void 0 : a.type) || ((s = t == null ? void 0 : t.columns.find((o) => o.key === n)) == null ? void 0 : s.format);
5351
5351
  }
5352
5352
  function Ct(t, n, a) {
5353
- return n === "currency" ? qe($e(t), a) : n === "percent" ? `${($e(t) * 100).toFixed(1)}%` : n === "number" ? Jt($e(t)) : n === "date" ? Ft(String(t ?? "")) : typeof t == "number" ? Jt(t) : String(t ?? "");
5353
+ return n === "currency" ? qe($e(t), a) : n === "percent" ? `${($e(t) * 100).toFixed(1)}%` : n === "number" ? Zt($e(t)) : n === "date" ? Ft(String(t ?? "")) : typeof t == "number" ? Zt(t) : String(t ?? "");
5354
5354
  }
5355
- function Ln(t) {
5355
+ function On(t) {
5356
5356
  const n = Math.abs(t);
5357
5357
  return n >= 1e6 ? `${(t / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(t / 1e3).toFixed(0)}k` : String(t);
5358
5358
  }
5359
- const On = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], Bs = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
5360
- let Ht = null;
5361
- function Es(t, n = Bs) {
5359
+ const qn = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], Es = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
5360
+ let Qt = null;
5361
+ function Ls(t, n = Es) {
5362
5362
  if (typeof document > "u") return t.length * 7;
5363
- Ht || (Ht = document.createElement("canvas"));
5364
- const a = Ht.getContext("2d");
5363
+ Qt || (Qt = document.createElement("canvas"));
5364
+ const a = Qt.getContext("2d");
5365
5365
  return a ? (a.font = n, a.measureText(t).width) : t.length * 7;
5366
5366
  }
5367
- function Ls(t) {
5367
+ function Os(t) {
5368
5368
  if (!t.length) return { angle: 0, axisHeight: 30, maxWidth: 0 };
5369
- const n = t.map((c) => Es(c)), a = Math.max(1, ...n);
5369
+ const n = t.map((c) => Ls(c)), a = Math.max(1, ...n);
5370
5370
  let s = 0;
5371
5371
  a > 55 && (s = -30), a > 110 && (s = -45), a > 200 && (s = -60), a > 300 && (s = -90);
5372
5372
  const o = Math.abs(s) * Math.PI / 180, i = s === 0 ? 20 : Math.abs(s) === 90 ? a : Math.ceil(a * Math.sin(o)), l = Math.min(280, Math.max(30, i + 18));
5373
5373
  return { angle: s, axisHeight: l, maxWidth: a };
5374
5374
  }
5375
- const Os = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
5376
- function qs() {
5375
+ const qs = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
5376
+ function zs() {
5377
5377
  const t = He(), { data: n, isLoading: a } = ue({
5378
5378
  queryKey: ["setup-status"],
5379
5379
  queryFn: () => I.setupStatus()
@@ -5406,7 +5406,7 @@ function qs() {
5406
5406
  return /* @__PURE__ */ e("p", { className: "text-gray-500", children: "Loading..." });
5407
5407
  if (n != null && n.setup_complete && !f)
5408
5408
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
5409
- /* @__PURE__ */ e(M, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((T, U) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(zs, { company: T }) }, U)) }) : /* @__PURE__ */ e("p", { className: "text-gray-400", children: "No companies found" }) }),
5409
+ /* @__PURE__ */ e(M, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((T, U) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(Ms, { company: T }) }, U)) }) : /* @__PURE__ */ e("p", { className: "text-gray-400", children: "No companies found" }) }),
5410
5410
  /* @__PURE__ */ e(ve, { to: "/", className: "text-blue-600 hover:text-blue-800 text-sm font-medium", children: "Go to Dashboard" })
5411
5411
  ] });
5412
5412
  if (f)
@@ -5441,7 +5441,7 @@ function qs() {
5441
5441
  Ve,
5442
5442
  {
5443
5443
  label: "Currency",
5444
- options: Os,
5444
+ options: qs,
5445
5445
  value: i,
5446
5446
  onChange: (T) => l(T.target.value)
5447
5447
  }
@@ -5536,7 +5536,7 @@ function qs() {
5536
5536
  ] }) })
5537
5537
  ] });
5538
5538
  }
5539
- function zs({ company: t }) {
5539
+ function Ms({ company: t }) {
5540
5540
  const n = [
5541
5541
  [t.city, t.zip_code].filter(Boolean).join(" "),
5542
5542
  t.country
@@ -5577,7 +5577,7 @@ function zs({ company: t }) {
5577
5577
  t.default_currency && /* @__PURE__ */ e("span", { className: "shrink-0 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: t.default_currency })
5578
5578
  ] });
5579
5579
  }
5580
- const Ms = [
5580
+ const Fs = [
5581
5581
  {
5582
5582
  number: 1,
5583
5583
  title: "Set Up Your Company",
@@ -5714,8 +5714,8 @@ const Ms = [
5714
5714
  ]
5715
5715
  }
5716
5716
  ];
5717
- function Na() {
5718
- const t = Ee(), { sessions: n, createSession: a } = mt();
5717
+ function wa() {
5718
+ const t = Ee(), { sessions: n, createSession: a } = ut();
5719
5719
  return async (s) => {
5720
5720
  var i;
5721
5721
  let o = ((i = n[0]) == null ? void 0 : i.id) || "";
@@ -5729,8 +5729,8 @@ function Na() {
5729
5729
  t(`/chat/${o}`, { state: { prefillMessage: s } });
5730
5730
  };
5731
5731
  }
5732
- function Fs() {
5733
- const { t } = X(), n = Na();
5732
+ function $s() {
5733
+ const { t } = X(), n = wa();
5734
5734
  return /* @__PURE__ */ e(M, { className: "border-emerald-200 bg-gradient-to-br from-emerald-50 to-white", children: /* @__PURE__ */ r("div", { className: "flex flex-col gap-4 md:flex-row md:items-start", children: [
5735
5735
  /* @__PURE__ */ e("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-lg font-bold text-emerald-700", children: "▶" }),
5736
5736
  /* @__PURE__ */ r("div", { className: "flex-1 space-y-3", children: [
@@ -5765,8 +5765,8 @@ function Fs() {
5765
5765
  ] })
5766
5766
  ] }) });
5767
5767
  }
5768
- function $s() {
5769
- const { t } = X(), n = Na(), a = [
5768
+ function Us() {
5769
+ const { t } = X(), n = wa(), a = [
5770
5770
  t("tutorial.caPrompt1"),
5771
5771
  t("tutorial.caPrompt2"),
5772
5772
  t("tutorial.caPrompt3"),
@@ -5824,7 +5824,7 @@ function $s() {
5824
5824
  ] })
5825
5825
  ] }) });
5826
5826
  }
5827
- function Us() {
5827
+ function Vs() {
5828
5828
  const { t } = X(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
5829
5829
  return /* @__PURE__ */ r(M, { children: [
5830
5830
  /* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.flowTitle") }),
@@ -5895,7 +5895,7 @@ function Us() {
5895
5895
  ] })
5896
5896
  ] });
5897
5897
  }
5898
- function Vs() {
5898
+ function Ks() {
5899
5899
  const { t } = X(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
5900
5900
  return /* @__PURE__ */ r(M, { children: [
5901
5901
  /* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.lifecycleTitle") }),
@@ -5931,7 +5931,7 @@ function Vs() {
5931
5931
  ] })
5932
5932
  ] });
5933
5933
  }
5934
- function Ks() {
5934
+ function js() {
5935
5935
  const { t } = X();
5936
5936
  return /* @__PURE__ */ r("div", { className: "mx-auto max-w-3xl space-y-6", children: [
5937
5937
  /* @__PURE__ */ r("div", { children: [
@@ -5955,11 +5955,11 @@ function Ks() {
5955
5955
  ] }),
5956
5956
  /* @__PURE__ */ e("p", { className: "mt-4 text-sm text-gray-500", children: t("tutorial.manualIntro") })
5957
5957
  ] }),
5958
- /* @__PURE__ */ e(Fs, {}),
5959
5958
  /* @__PURE__ */ e($s, {}),
5960
5959
  /* @__PURE__ */ e(Us, {}),
5961
5960
  /* @__PURE__ */ e(Vs, {}),
5962
- Ms.map((n) => {
5961
+ /* @__PURE__ */ e(Ks, {}),
5962
+ Fs.map((n) => {
5963
5963
  var a;
5964
5964
  return /* @__PURE__ */ e(M, { children: /* @__PURE__ */ r("div", { className: "flex gap-4", children: [
5965
5965
  /* @__PURE__ */ e("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-sm font-bold text-blue-700", children: n.number }),
@@ -6020,17 +6020,59 @@ function Ks() {
6020
6020
  ] }) })
6021
6021
  ] });
6022
6022
  }
6023
- const Qt = 5, js = 10 * 1024 * 1024, Gs = /* @__PURE__ */ new Set([
6023
+ const Yt = 5, Gs = 10 * 1024 * 1024, Ws = /* @__PURE__ */ new Set([
6024
6024
  "image/png",
6025
6025
  "image/jpeg",
6026
6026
  "image/gif",
6027
6027
  "image/webp",
6028
- "application/pdf"
6028
+ "application/pdf",
6029
+ // Spreadsheets
6030
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
6031
+ // xlsx
6032
+ "application/vnd.ms-excel",
6033
+ // xls
6034
+ "application/vnd.oasis.opendocument.spreadsheet",
6035
+ // ods
6036
+ // Documents
6037
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
6038
+ // docx
6039
+ "application/msword",
6040
+ // doc
6041
+ "application/vnd.oasis.opendocument.text",
6042
+ // odt
6043
+ // Presentations
6044
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
6045
+ // pptx
6046
+ "application/vnd.ms-powerpoint",
6047
+ // ppt
6048
+ "application/vnd.oasis.opendocument.presentation",
6049
+ // odp
6050
+ // Delimited / text
6051
+ "text/csv",
6052
+ "text/plain"
6053
+ ]), Hs = /* @__PURE__ */ new Set([
6054
+ "png",
6055
+ "jpg",
6056
+ "jpeg",
6057
+ "gif",
6058
+ "webp",
6059
+ "pdf",
6060
+ "xlsx",
6061
+ "xls",
6062
+ "ods",
6063
+ "docx",
6064
+ "doc",
6065
+ "odt",
6066
+ "pptx",
6067
+ "ppt",
6068
+ "odp",
6069
+ "csv",
6070
+ "txt"
6029
6071
  ]);
6030
- function Ws(t) {
6072
+ function Qs(t) {
6031
6073
  return new Promise((n) => window.setTimeout(n, t));
6032
6074
  }
6033
- function Hs(t) {
6075
+ function Ys(t) {
6034
6076
  return new Promise((n, a) => {
6035
6077
  const s = new FileReader();
6036
6078
  s.onloadend = () => {
@@ -6039,14 +6081,14 @@ function Hs(t) {
6039
6081
  }, s.onerror = () => a(s.error ?? new Error("Could not read audio.")), s.readAsDataURL(t);
6040
6082
  });
6041
6083
  }
6042
- function qn(t) {
6084
+ function zn(t) {
6043
6085
  if (!t) return "";
6044
6086
  const n = new Date(t);
6045
6087
  if (isNaN(n.getTime())) return "";
6046
6088
  const a = /* @__PURE__ */ new Date();
6047
6089
  return n.getFullYear() === a.getFullYear() && n.getMonth() === a.getMonth() && n.getDate() === a.getDate() ? n.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : n.getFullYear() === a.getFullYear() ? n.toLocaleDateString([], { day: "numeric", month: "short" }) : n.toLocaleDateString([], { day: "numeric", month: "short", year: "numeric" });
6048
6090
  }
6049
- function zn(t) {
6091
+ function Mn(t) {
6050
6092
  if (!t) return "";
6051
6093
  const n = new Date(t);
6052
6094
  return isNaN(n.getTime()) ? "" : n.toLocaleString([], {
@@ -6059,8 +6101,8 @@ function zn(t) {
6059
6101
  timeZoneName: "short"
6060
6102
  });
6061
6103
  }
6062
- function Mn() {
6063
- const { t } = X(), { sessionId: n } = ut(), a = Ee(), s = vt(), [o] = zt(), i = o.get("demo") === "1", [l, c] = w(""), [h, d] = w(""), [p, u] = w([]), [f, v] = w(""), [N, b] = w(!1), [C, S] = w("idle"), x = oe(null), y = oe(null), m = oe([]), {
6104
+ function Fn() {
6105
+ const { t } = X(), { sessionId: n } = dt(), a = Ee(), s = bt(), [o] = zt(), i = o.get("demo") === "1", [l, c] = w(""), [h, d] = w(""), [p, u] = w([]), [f, v] = w(""), [N, b] = w(!1), [C, S] = w("idle"), x = oe(null), y = oe(null), m = oe([]), {
6064
6106
  connectionStatus: D,
6065
6107
  connectionVersion: T,
6066
6108
  createSession: U,
@@ -6076,9 +6118,9 @@ function Mn() {
6076
6118
  isThinking: ee,
6077
6119
  getDemoStatus: se,
6078
6120
  getDemoTypingCue: P
6079
- } = mt(), V = oe(null), ne = oe(null), H = oe(null), ce = oe(null), [Se, E] = w(0), ie = oe(!1), Le = oe(null), Te = oe(0), Ke = oe(!0), Fe = oe(null), xt = oe(!1), pt = oe(null), Je = A(n), De = D === "connected", Ie = ee(n), je = se(n), Qe = P(n), Oe = i || je === "running", ht = _(n), it = z(n), gt = Je[Je.length - 1], B = gt ? `${gt.type}:${gt.timestamp || ""}:${gt.content}` : "empty", K = Pe(() => {
6080
- xt.current = !0, pt.current !== null && window.clearTimeout(pt.current), pt.current = window.setTimeout(() => {
6081
- xt.current = !1, pt.current = null;
6121
+ } = ut(), V = oe(null), ne = oe(null), H = oe(null), ce = oe(null), [Se, E] = w(0), ie = oe(!1), Le = oe(null), Te = oe(0), Ke = oe(!0), Fe = oe(null), vt = oe(!1), mt = oe(null), Je = A(n), De = D === "connected", Ie = ee(n), je = se(n), Qe = P(n), Oe = i || je === "running", pt = _(n), it = z(n), ht = Je[Je.length - 1], B = ht ? `${ht.type}:${ht.timestamp || ""}:${ht.content}` : "empty", K = Pe(() => {
6122
+ vt.current = !0, mt.current !== null && window.clearTimeout(mt.current), mt.current = window.setTimeout(() => {
6123
+ vt.current = !1, mt.current = null;
6082
6124
  }, 600);
6083
6125
  }, []), Y = Pe((k = "smooth") => {
6084
6126
  const F = V.current;
@@ -6090,7 +6132,7 @@ function Mn() {
6090
6132
  };
6091
6133
  requestAnimationFrame(ae), window.setTimeout(ae, 120);
6092
6134
  }, [Oe, Ie, K]);
6093
- pn(() => {
6135
+ hn(() => {
6094
6136
  const k = V.current, F = Fe.current;
6095
6137
  if (!k || F === null) return;
6096
6138
  const ae = k.scrollHeight - F;
@@ -6103,29 +6145,29 @@ function Mn() {
6103
6145
  let F = 0;
6104
6146
  const ae = new ResizeObserver(() => {
6105
6147
  Fe.current === null && (!Ke.current && !Oe && !Ie || (cancelAnimationFrame(F), F = requestAnimationFrame(() => {
6106
- const ye = V.current;
6107
- if (!ye) return;
6108
- ye.scrollHeight - ye.scrollTop - ye.clientHeight <= 120 && (K(), ye.scrollTo({ top: ye.scrollHeight, behavior: "auto" }));
6148
+ const fe = V.current;
6149
+ if (!fe) return;
6150
+ fe.scrollHeight - fe.scrollTop - fe.clientHeight <= 120 && (K(), fe.scrollTo({ top: fe.scrollHeight, behavior: "auto" }));
6109
6151
  })));
6110
6152
  }), he = k.firstElementChild;
6111
6153
  return he && ae.observe(he), ae.observe(k), () => {
6112
6154
  ae.disconnect(), cancelAnimationFrame(F);
6113
6155
  };
6114
- }, [Oe, Ie, K]), pn(() => {
6156
+ }, [Oe, Ie, K]), hn(() => {
6115
6157
  const k = ce.current;
6116
6158
  if (!k || (E(k.offsetHeight), typeof ResizeObserver > "u")) return;
6117
6159
  const F = new ResizeObserver(() => E(k.offsetHeight));
6118
6160
  return F.observe(k), () => F.disconnect();
6119
6161
  }, []);
6120
6162
  const xe = Pe(() => {
6121
- if (!n || it || !ht) return;
6163
+ if (!n || it || !pt) return;
6122
6164
  const k = V.current;
6123
6165
  Fe.current = k ? k.scrollHeight : null, Ke.current = !1, W(n).catch(() => {
6124
6166
  Fe.current = null;
6125
6167
  });
6126
- }, [n, it, ht, W]), we = oe(null);
6168
+ }, [n, it, pt, W]), we = oe(null);
6127
6169
  re(() => {
6128
- d(""), Le.current = null, Te.current += 1, n && ia(n);
6170
+ d(""), Le.current = null, Te.current += 1, n && oa(n);
6129
6171
  const k = s.state;
6130
6172
  k != null && k.prefillMessage && we.current !== k ? (we.current = k, c(k.prefillMessage), window.setTimeout(() => {
6131
6173
  var F;
@@ -6154,7 +6196,7 @@ function Mn() {
6154
6196
  }, 50), ie.current = Ie;
6155
6197
  }, [Ie, De]);
6156
6198
  function ot(k) {
6157
- if (xt.current) return;
6199
+ if (vt.current) return;
6158
6200
  const F = k.currentTarget, ae = F.scrollHeight - F.scrollTop - F.clientHeight;
6159
6201
  Ke.current = ae < 80;
6160
6202
  }
@@ -6173,50 +6215,51 @@ function Mn() {
6173
6215
  re(() => {
6174
6216
  if (!Qe || !n || Ze.current === Qe.seq) return;
6175
6217
  Ze.current = Qe.seq;
6176
- const k = n, F = Qe.content, ae = F.length > 0 ? Math.max(8, Qe.typingMs / F.length) : 0, he = Qe.seq, ye = ++Te.current;
6177
- async function et() {
6218
+ const k = n, F = Qe.content, ae = F.length > 0 ? Math.max(8, Qe.typingMs / F.length) : 0, he = Qe.seq, fe = ++Te.current;
6219
+ async function ft() {
6178
6220
  c("");
6179
- for (const yt of F) {
6180
- if (ye !== Te.current) return;
6181
- c((Ge) => Ge + yt), await Ws(ae);
6221
+ for (const et of F) {
6222
+ if (fe !== Te.current) return;
6223
+ c((Ge) => Ge + et), await Qs(ae);
6182
6224
  }
6183
- ye === Te.current && j.current(k, he);
6225
+ fe === Te.current && j.current(k, he);
6184
6226
  }
6185
- et();
6227
+ ft();
6186
6228
  }, [Qe, n]), re(() => {
6187
6229
  je === "complete" && (Te.current += 1, c(""));
6188
6230
  }, [je]);
6189
- const fe = Pe((k) => {
6231
+ const ye = Pe((k) => {
6190
6232
  if (!n) return;
6191
6233
  v("");
6192
6234
  const F = Array.from(k);
6193
6235
  u((ae) => {
6194
6236
  const he = [...ae];
6195
- for (const ye of F) {
6196
- if (he.length >= Qt) {
6197
- v(`Maximum ${Qt} attachments per message.`);
6237
+ for (const fe of F) {
6238
+ if (he.length >= Yt) {
6239
+ v(`Maximum ${Yt} attachments per message.`);
6198
6240
  break;
6199
6241
  }
6200
- if (!Gs.has(ye.type)) {
6201
- v(`Unsupported file type: ${ye.type || ye.name}`);
6242
+ const ft = fe.name.includes(".") ? fe.name.split(".").pop().toLowerCase() : "";
6243
+ if (!Ws.has(fe.type) && !Hs.has(ft)) {
6244
+ v(`Unsupported file type: ${fe.type || fe.name}`);
6202
6245
  continue;
6203
6246
  }
6204
- if (ye.size > js) {
6205
- v(`"${ye.name}" is too large (max 10 MB).`);
6247
+ if (fe.size > Gs) {
6248
+ v(`"${fe.name}" is too large (max 10 MB).`);
6206
6249
  continue;
6207
6250
  }
6208
- const et = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, yt = ye.type.startsWith("image/") ? URL.createObjectURL(ye) : void 0, Ge = { localId: et, file: ye, previewUrl: yt, uploading: !0 };
6209
- he.push(Ge), I.uploadChatAttachment(n, ye).then((lt) => {
6251
+ const et = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, Ge = fe.type.startsWith("image/") ? URL.createObjectURL(fe) : void 0, Ut = { localId: et, file: fe, previewUrl: Ge, uploading: !0 };
6252
+ he.push(Ut), I.uploadChatAttachment(n, fe).then((Nt) => {
6210
6253
  u(
6211
6254
  (At) => At.map(
6212
- (wt) => wt.localId === et ? { ...wt, uploading: !1, uploadedId: lt.id } : wt
6255
+ (wt) => wt.localId === et ? { ...wt, uploading: !1, uploadedId: Nt.id } : wt
6213
6256
  )
6214
6257
  );
6215
- }).catch((lt) => {
6216
- const At = (lt == null ? void 0 : lt.message) || "Upload failed";
6217
- v(`"${ye.name}": ${At}`), u(
6258
+ }).catch((Nt) => {
6259
+ const At = (Nt == null ? void 0 : Nt.message) || "Upload failed";
6260
+ v(`"${fe.name}": ${At}`), u(
6218
6261
  (wt) => wt.map(
6219
- (Ut) => Ut.localId === et ? { ...Ut, uploading: !1, error: At } : Ut
6262
+ (Vt) => Vt.localId === et ? { ...Vt, uploading: !1, error: At } : Vt
6220
6263
  )
6221
6264
  );
6222
6265
  });
@@ -6234,7 +6277,7 @@ function Mn() {
6234
6277
  const F = k.relatedTarget;
6235
6278
  (!F || !k.currentTarget.contains(F)) && b(!1);
6236
6279
  }, J = (k) => {
6237
- k.preventDefault(), b(!1), k.dataTransfer.files && k.dataTransfer.files.length > 0 && fe(k.dataTransfer.files);
6280
+ k.preventDefault(), b(!1), k.dataTransfer.files && k.dataTransfer.files.length > 0 && ye(k.dataTransfer.files);
6238
6281
  }, Me = (k) => {
6239
6282
  const F = [];
6240
6283
  for (const ae of k.clipboardData.items)
@@ -6242,9 +6285,9 @@ function Mn() {
6242
6285
  const he = ae.getAsFile();
6243
6286
  he && F.push(he);
6244
6287
  }
6245
- F.length > 0 && (k.preventDefault(), fe(F));
6288
+ F.length > 0 && (k.preventDefault(), ye(F));
6246
6289
  }, ke = p.some((k) => k.uploading), pe = p.some((k) => k.error), ge = p.filter((k) => k.uploadedId && !k.error).map((k) => k.uploadedId);
6247
- function ft() {
6290
+ function gt() {
6248
6291
  const k = l.trim();
6249
6292
  if (n && !(!k && ge.length === 0) && !ke && $(n, k, ge.length > 0 ? ge : void 0)) {
6250
6293
  for (const F of p)
@@ -6252,8 +6295,8 @@ function Mn() {
6252
6295
  u([]), v(""), c("");
6253
6296
  }
6254
6297
  }
6255
- function Nt(k) {
6256
- k.key === "Enter" && !k.shiftKey && (k.preventDefault(), ft());
6298
+ function xt(k) {
6299
+ k.key === "Enter" && !k.shiftKey && (k.preventDefault(), gt());
6257
6300
  }
6258
6301
  function Xe(k) {
6259
6302
  const F = k.trim();
@@ -6262,7 +6305,7 @@ function Mn() {
6262
6305
  ae && (ae.focus(), ae.style.height = "auto", ae.style.height = Math.min(Math.max(ae.scrollHeight, 48), 120) + "px");
6263
6306
  }, 0));
6264
6307
  }
6265
- async function _a() {
6308
+ async function Ta() {
6266
6309
  if (C !== "idle") return;
6267
6310
  let k;
6268
6311
  try {
@@ -6276,18 +6319,18 @@ function Mn() {
6276
6319
  y.current = F, m.current = [], F.ondataavailable = (ae) => {
6277
6320
  ae.data.size > 0 && m.current.push(ae.data);
6278
6321
  }, F.onstop = async () => {
6279
- var yt;
6322
+ var et;
6280
6323
  k.getTracks().forEach((Ge) => Ge.stop());
6281
6324
  const ae = m.current;
6282
6325
  if (m.current = [], y.current = null, ae.length === 0) {
6283
6326
  S("idle");
6284
6327
  return;
6285
6328
  }
6286
- const he = F.mimeType || ((yt = ae[0]) == null ? void 0 : yt.type) || "audio/webm", ye = new Blob(ae, { type: he }), et = (he.split(";")[0].split("/")[1] || "webm").toLowerCase();
6329
+ const he = F.mimeType || ((et = ae[0]) == null ? void 0 : et.type) || "audio/webm", fe = new Blob(ae, { type: he }), ft = (he.split(";")[0].split("/")[1] || "webm").toLowerCase();
6287
6330
  S("transcribing");
6288
6331
  try {
6289
- const Ge = await Hs(ye), lt = await de(Ge, et, n);
6290
- Xe(lt);
6332
+ const Ge = await Ys(fe), Ut = await de(Ge, ft, n);
6333
+ Xe(Ut);
6291
6334
  } catch (Ge) {
6292
6335
  v(Ge instanceof Error ? Ge.message : t("chat.transcribeFailed"));
6293
6336
  } finally {
@@ -6295,12 +6338,12 @@ function Mn() {
6295
6338
  }
6296
6339
  }, F.start(), S("recording");
6297
6340
  }
6298
- function Ta() {
6341
+ function Ra() {
6299
6342
  const k = y.current;
6300
6343
  k && k.state !== "inactive" && k.stop();
6301
6344
  }
6302
- function Ra() {
6303
- C === "recording" ? Ta() : C === "idle" && _a();
6345
+ function Ia() {
6346
+ C === "recording" ? Ra() : C === "idle" && Ta();
6304
6347
  }
6305
6348
  return n ? /* @__PURE__ */ r(
6306
6349
  "div",
@@ -6323,11 +6366,11 @@ function Mn() {
6323
6366
  className: "mx-auto max-w-3xl space-y-4",
6324
6367
  style: { paddingBottom: (Se || 96) + 16 },
6325
6368
  children: [
6326
- (ht || it) && Je.length > 0 && /* @__PURE__ */ e("div", { className: "flex justify-center", children: /* @__PURE__ */ e(
6369
+ (pt || it) && Je.length > 0 && /* @__PURE__ */ e("div", { className: "flex justify-center", children: /* @__PURE__ */ e(
6327
6370
  "button",
6328
6371
  {
6329
6372
  onClick: xe,
6330
- disabled: it || !ht,
6373
+ disabled: it || !pt,
6331
6374
  className: "rounded-full bg-surface px-3 py-1 text-xs text-fg-muted ring-1 ring-line transition-colors hover:bg-surface-subtle hover:text-fg disabled:cursor-not-allowed disabled:opacity-60",
6332
6375
  children: t(it ? "common.loading" : "chat.loadOlder")
6333
6376
  }
@@ -6354,7 +6397,7 @@ function Mn() {
6354
6397
  k
6355
6398
  )) })
6356
6399
  ] }),
6357
- Je.map((k, F) => /* @__PURE__ */ e(Ys, { message: k }, F)),
6400
+ Je.map((k, F) => /* @__PURE__ */ e(Zs, { message: k }, F)),
6358
6401
  /* @__PURE__ */ e("div", { ref: ne })
6359
6402
  ]
6360
6403
  }
@@ -6396,11 +6439,11 @@ function Mn() {
6396
6439
  {
6397
6440
  ref: x,
6398
6441
  type: "file",
6399
- accept: "image/png,image/jpeg,image/gif,image/webp,application/pdf",
6442
+ accept: "image/png,image/jpeg,image/gif,image/webp,application/pdf,.xlsx,.xls,.ods,.docx,.doc,.odt,.pptx,.ppt,.odp,.csv,.txt,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/vnd.oasis.opendocument.spreadsheet,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/msword,application/vnd.oasis.opendocument.text,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.ms-powerpoint,application/vnd.oasis.opendocument.presentation,text/csv,text/plain",
6400
6443
  multiple: !0,
6401
6444
  className: "hidden",
6402
6445
  onChange: (k) => {
6403
- k.target.files && k.target.files.length > 0 && (fe(k.target.files), k.target.value = "");
6446
+ k.target.files && k.target.files.length > 0 && (ye(k.target.files), k.target.value = "");
6404
6447
  }
6405
6448
  }
6406
6449
  ),
@@ -6411,7 +6454,7 @@ function Mn() {
6411
6454
  ref: H,
6412
6455
  value: l,
6413
6456
  onChange: (k) => c(k.target.value),
6414
- onKeyDown: Nt,
6457
+ onKeyDown: xt,
6415
6458
  onPaste: Me,
6416
6459
  placeholder: t(Oe ? "chat.placeholderDemo" : De ? "chat.placeholderType" : "chat.placeholderConnecting"),
6417
6460
  disabled: !De || !n || Ie || Oe,
@@ -6431,7 +6474,7 @@ function Mn() {
6431
6474
  var k;
6432
6475
  return (k = x.current) == null ? void 0 : k.click();
6433
6476
  },
6434
- disabled: !De || !n || Ie || Oe || p.length >= Qt,
6477
+ disabled: !De || !n || Ie || Oe || p.length >= Yt,
6435
6478
  className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-fg-muted transition-all hover:bg-surface-subtle hover:text-fg disabled:cursor-not-allowed disabled:opacity-40 md:h-10 md:w-10",
6436
6479
  title: t("chat.attachTitle"),
6437
6480
  children: /* @__PURE__ */ e("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ e("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48" }) })
@@ -6440,7 +6483,7 @@ function Mn() {
6440
6483
  /* @__PURE__ */ e(
6441
6484
  "button",
6442
6485
  {
6443
- onClick: Ra,
6486
+ onClick: Ia,
6444
6487
  disabled: !De || !n || Ie || Oe || C === "transcribing",
6445
6488
  className: `flex h-11 w-11 shrink-0 items-center justify-center rounded-lg transition-all disabled:cursor-not-allowed disabled:opacity-40 md:h-10 md:w-10 ${C === "recording" ? "bg-rose-500/10 text-rose-600 hover:bg-rose-500/20" : "text-fg-muted hover:bg-surface-subtle hover:text-fg"}`,
6446
6489
  title: t(C === "recording" ? "chat.voiceStop" : C === "transcribing" ? "chat.voiceTranscribing" : "chat.voiceStart"),
@@ -6455,7 +6498,7 @@ function Mn() {
6455
6498
  /* @__PURE__ */ e(
6456
6499
  "button",
6457
6500
  {
6458
- onClick: ft,
6501
+ onClick: gt,
6459
6502
  disabled: !l.trim() && ge.length === 0 || !De || !n || Ie || Oe || ke || pe,
6460
6503
  className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-brand transition-all hover:bg-brand/10 active:translate-y-px disabled:cursor-not-allowed disabled:text-fg-muted disabled:active:translate-y-0 md:h-10 md:w-10",
6461
6504
  children: /* @__PURE__ */ e(
@@ -6487,7 +6530,7 @@ function Mn() {
6487
6530
  }
6488
6531
  ) : /* @__PURE__ */ e("div", { className: "flex h-full items-center justify-center text-fg-muted", children: t("chat.creating") });
6489
6532
  }
6490
- function Qs({ attachments: t }) {
6533
+ function Js({ attachments: t }) {
6491
6534
  return !t || t.length === 0 ? null : /* @__PURE__ */ e("div", { className: "mt-1 flex flex-wrap gap-1.5", children: t.map((n) => {
6492
6535
  const a = I.getChatAttachmentUrl(n.id), s = n.mime_type.startsWith("image/");
6493
6536
  return /* @__PURE__ */ r(
@@ -6507,14 +6550,14 @@ function Qs({ attachments: t }) {
6507
6550
  );
6508
6551
  }) });
6509
6552
  }
6510
- function Ys({ message: t }) {
6553
+ function Zs({ message: t }) {
6511
6554
  return t.type === "user" ? /* @__PURE__ */ e("div", { className: "flex justify-end", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-br-md bg-gradient-to-b from-brand to-brand/90 px-4 py-2.5 text-sm text-brand-fg ring-1 ring-black/10 shadow-bubble-user", children: [
6512
6555
  /* @__PURE__ */ e("div", { className: "whitespace-pre-wrap", children: t.content }),
6513
- /* @__PURE__ */ e(Qs, { attachments: t.attachments }),
6514
- t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: zn(t.timestamp), children: qn(t.timestamp) })
6556
+ /* @__PURE__ */ e(Js, { attachments: t.attachments }),
6557
+ t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: Mn(t.timestamp), children: zn(t.timestamp) })
6515
6558
  ] }) }) : t.type === "assistant" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-bl-md bg-surface px-4 py-2.5 text-sm text-fg ring-1 ring-line shadow-card", children: [
6516
- /* @__PURE__ */ e(Js, { content: t.content }),
6517
- t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: zn(t.timestamp), children: qn(t.timestamp) })
6559
+ /* @__PURE__ */ e(Xs, { content: t.content }),
6560
+ t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: Mn(t.timestamp), children: zn(t.timestamp) })
6518
6561
  ] }) }) : t.type === "thinking" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line shadow-card", children: [
6519
6562
  /* @__PURE__ */ e("span", { className: "inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-brand" }),
6520
6563
  t.content,
@@ -6553,7 +6596,7 @@ function Ys({ message: t }) {
6553
6596
  }
6554
6597
  ) }) : t.type === "error" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ e("div", { className: "max-w-[80%] rounded-2xl rounded-bl-md bg-rose-50 px-4 py-2.5 text-sm text-rose-700 ring-1 ring-rose-200 shadow-card", children: t.content }) }) : null;
6555
6598
  }
6556
- function Js({ content: t }) {
6599
+ function Xs({ content: t }) {
6557
6600
  const n = t.split(`
6558
6601
  `), a = [];
6559
6602
  let s = !1, o = [];
@@ -6597,7 +6640,7 @@ function Js({ content: t }) {
6597
6640
  );
6598
6641
  }), /* @__PURE__ */ e("div", { children: a });
6599
6642
  }
6600
- function wa(t, n, a) {
6643
+ function ka(t, n, a) {
6601
6644
  const s = t.startsWith("/") && !t.startsWith("/api/"), o = "font-medium text-brand underline decoration-brand/40 underline-offset-2 transition-colors hover:decoration-brand";
6602
6645
  return s ? /* @__PURE__ */ e(ve, { to: t, className: o, children: n }, a) : /* @__PURE__ */ e(
6603
6646
  "a",
@@ -6611,13 +6654,13 @@ function wa(t, n, a) {
6611
6654
  a
6612
6655
  );
6613
6656
  }
6614
- const Zs = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
6657
+ const ei = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
6615
6658
  function Ot(t) {
6616
6659
  return t.split(/(\[[^\]]+\]\([^)]+\)|\*\*[^*]+?\*\*|`[^`]+`)/g).flatMap((a, s) => {
6617
6660
  const o = a.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
6618
6661
  if (o) {
6619
6662
  const [, i, l] = o;
6620
- return wa(l, Ot(i), s);
6663
+ return ka(l, Ot(i), s);
6621
6664
  }
6622
6665
  return a.startsWith("**") && a.endsWith("**") && a.length > 4 ? /* @__PURE__ */ e("strong", { className: "font-semibold", children: Ot(a.slice(2, -2)) }, s) : a.startsWith("`") && a.endsWith("`") ? /* @__PURE__ */ e(
6623
6666
  "code",
@@ -6626,24 +6669,24 @@ function Ot(t) {
6626
6669
  children: a.slice(1, -1)
6627
6670
  },
6628
6671
  s
6629
- ) : Xs(a, `${s}`);
6672
+ ) : ti(a, `${s}`);
6630
6673
  });
6631
6674
  }
6632
- function Xs(t, n) {
6675
+ function ti(t, n) {
6633
6676
  const a = [];
6634
6677
  let s = 0, o;
6635
- const i = new RegExp(Zs.source, "g");
6678
+ const i = new RegExp(ei.source, "g");
6636
6679
  let l = 0;
6637
6680
  for (; (o = i.exec(t)) !== null; ) {
6638
6681
  const c = o.index;
6639
6682
  let h = o[0], d = "";
6640
6683
  for (; h.length > 0 && /[.,;:!?]$/.test(h); )
6641
6684
  d = h.slice(-1) + d, h = h.slice(0, -1);
6642
- c > s && a.push(t.slice(s, c)), a.push(wa(h, h, `${n}-u${l}`)), d && a.push(d), s = c + o[0].length, l += 1;
6685
+ c > s && a.push(t.slice(s, c)), a.push(ka(h, h, `${n}-u${l}`)), d && a.push(d), s = c + o[0].length, l += 1;
6643
6686
  }
6644
6687
  return s < t.length && a.push(t.slice(s)), a.length > 0 ? a : [t];
6645
6688
  }
6646
- function ei() {
6689
+ function ni() {
6647
6690
  const t = Ee(), [n] = zt(), { user: a, login: s, register: o } = st(), { t: i } = X(), l = n.get("invite") || "", [c, h] = w(l ? "register" : "login"), [d, p] = w(!1), [u, f] = w(!1), [v, N] = w([]), [b, C] = w(!0), [S, x] = w(""), [y, m] = w(""), [D, T] = w(""), [U, Z] = w(""), [g, R] = w("");
6648
6691
  re(() => {
6649
6692
  a && a.role !== "public_manager" && t("/", { replace: !0 });
@@ -6743,8 +6786,8 @@ function ei() {
6743
6786
  },
6744
6787
  className: "flex w-full items-center justify-center gap-2 rounded-lg border border-border bg-surface px-4 py-2 text-sm font-medium text-fg transition-colors hover:bg-surface-muted",
6745
6788
  children: [
6746
- /* @__PURE__ */ e(ni, { provider: $ }),
6747
- i("login.continueWithProvider", { provider: ti($) })
6789
+ /* @__PURE__ */ e(ri, { provider: $ }),
6790
+ i("login.continueWithProvider", { provider: ai($) })
6748
6791
  ]
6749
6792
  },
6750
6793
  $
@@ -6777,10 +6820,10 @@ function ei() {
6777
6820
  ] }) })
6778
6821
  ] }) });
6779
6822
  }
6780
- function ti(t) {
6823
+ function ai(t) {
6781
6824
  return t.charAt(0).toUpperCase() + t.slice(1);
6782
6825
  }
6783
- function ni({ provider: t }) {
6826
+ function ri({ provider: t }) {
6784
6827
  return t === "google" ? /* @__PURE__ */ r("svg", { className: "h-4 w-4", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
6785
6828
  /* @__PURE__ */ e("path", { fill: "#EA4335", d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" }),
6786
6829
  /* @__PURE__ */ e("path", { fill: "#4285F4", d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" }),
@@ -6788,7 +6831,7 @@ function ni({ provider: t }) {
6788
6831
  /* @__PURE__ */ e("path", { fill: "#34A853", d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" })
6789
6832
  ] }) : t === "apple" ? /* @__PURE__ */ e("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ e("path", { d: "M16.365 1.43c0 1.14-.42 2.22-1.14 3.03-.78.9-2.06 1.6-3.12 1.5-.13-1.1.42-2.28 1.08-3.03.78-.9 2.13-1.56 3.18-1.5zM20.7 17.1c-.56 1.3-.83 1.88-1.55 3.03-1 1.6-2.42 3.6-4.18 3.62-1.56.02-1.96-1.02-4.07-1-2.12.01-2.56 1.02-4.12 1.01-1.76-.02-3.1-1.82-4.1-3.42C-.3 16.9-.6 11.16 1.7 8.1c1.16-1.54 3-2.51 4.85-2.51 1.87 0 3.05 1.02 4.6 1.02 1.5 0 2.42-1.02 4.6-1.02 1.62 0 3.34.88 4.56 2.4-4.01 2.2-3.36 7.92 0 9.11z" }) }) : null;
6790
6833
  }
6791
- function ai() {
6834
+ function si() {
6792
6835
  const t = Ee(), n = oe(!1), [a, s] = w("");
6793
6836
  return re(() => {
6794
6837
  n.current || (n.current = !0, I.createChatSession().then((o) => {
@@ -6811,17 +6854,17 @@ function ai() {
6811
6854
  /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: "Starting live demo..." })
6812
6855
  ] }) }) });
6813
6856
  }
6814
- function Fn() {
6857
+ function $n() {
6815
6858
  return { account: "", debit: "", credit: "", party_type: "", party: "" };
6816
6859
  }
6817
- function $n() {
6860
+ function Un() {
6818
6861
  return { item_code: "", qty: "", rate: "" };
6819
6862
  }
6820
- function Un() {
6863
+ function Vn() {
6821
6864
  return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
6822
6865
  }
6823
- function ri() {
6824
- const t = Ee(), n = He(), [a, s] = w(""), [o, i] = w((/* @__PURE__ */ new Date()).toISOString().split("T")[0]), [l, c] = w(""), [h, d] = w([Fn()]), [p, u] = w([$n()]), [f, v] = w([Un()]), [N, b] = w({}), C = me({
6866
+ function ii() {
6867
+ const t = Ee(), n = He(), [a, s] = w(""), [o, i] = w((/* @__PURE__ */ new Date()).toISOString().split("T")[0]), [l, c] = w(""), [h, d] = w([$n()]), [p, u] = w([Un()]), [f, v] = w([Vn()]), [N, b] = w({}), C = me({
6825
6868
  mutationFn: () => I.importAccountBalances({
6826
6869
  company: a,
6827
6870
  posting_date: o,
@@ -6892,7 +6935,7 @@ function ri() {
6892
6935
  /* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: m.credit, onChange: (T) => y(h, d, D, "credit", T.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0.00" }) })
6893
6936
  ] }, D)) })
6894
6937
  ] }) }),
6895
- /* @__PURE__ */ e("div", { className: "mt-2 flex gap-2", children: /* @__PURE__ */ e("button", { onClick: () => d([...h, Fn()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
6938
+ /* @__PURE__ */ e("div", { className: "mt-2 flex gap-2", children: /* @__PURE__ */ e("button", { onClick: () => d([...h, $n()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
6896
6939
  /* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
6897
6940
  /* @__PURE__ */ e(Q, { onClick: () => C.mutate(), disabled: !a || C.isPending, children: C.isPending ? "Importing..." : "Import Account Balances" }),
6898
6941
  C.error && /* @__PURE__ */ e("span", { className: "text-xs text-red-600", children: C.error.message }),
@@ -6917,7 +6960,7 @@ function ri() {
6917
6960
  /* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: m.rate, onChange: (T) => y(p, u, D, "rate", T.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0.00" }) })
6918
6961
  ] }, D)) })
6919
6962
  ] }) }),
6920
- /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e("button", { onClick: () => u([...p, $n()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
6963
+ /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e("button", { onClick: () => u([...p, Un()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
6921
6964
  /* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
6922
6965
  /* @__PURE__ */ e(Q, { onClick: () => S.mutate(), disabled: !a || !l || S.isPending, children: S.isPending ? "Importing..." : "Import Stock Balances" }),
6923
6966
  S.error && /* @__PURE__ */ e("span", { className: "text-xs text-red-600", children: S.error.message }),
@@ -6960,7 +7003,7 @@ function ri() {
6960
7003
  /* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "text", value: m.remarks, onChange: (T) => y(f, v, D, "remarks", T.target.value), className: "w-full rounded border border-gray-300 px-2 py-1.5 text-sm", placeholder: "Old invoice ref" }) })
6961
7004
  ] }, D)) })
6962
7005
  ] }) }),
6963
- /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e("button", { onClick: () => v([...f, Un()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
7006
+ /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e("button", { onClick: () => v([...f, Vn()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
6964
7007
  /* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
6965
7008
  /* @__PURE__ */ e(Q, { onClick: () => x.mutate(), disabled: !a || x.isPending, children: x.isPending ? "Importing..." : "Import Outstanding Invoices" }),
6966
7009
  x.error && /* @__PURE__ */ e("span", { className: "text-xs text-red-600", children: x.error.message }),
@@ -6986,7 +7029,7 @@ function ri() {
6986
7029
  ] })
6987
7030
  ] });
6988
7031
  }
6989
- function si() {
7032
+ function oi() {
6990
7033
  const { user: t } = st(), n = He(), { data: a, isLoading: s } = ue({
6991
7034
  queryKey: ["auth-users"],
6992
7035
  queryFn: () => I.authListUsers()
@@ -7007,7 +7050,7 @@ function si() {
7007
7050
  }), N = me({
7008
7051
  mutationFn: (m) => I.authRevokeInvite(m),
7009
7052
  onSuccess: () => n.invalidateQueries({ queryKey: ["auth-invites"] })
7010
- }), [b, C] = w(null), S = br(), x = (m) => `${window.location.origin}/login?invite=${m}`, y = async (m) => {
7053
+ }), [b, C] = w(null), S = vr(), x = (m) => `${window.location.origin}/login?invite=${m}`, y = async (m) => {
7011
7054
  try {
7012
7055
  await navigator.clipboard.writeText(x(m)), C(m), setTimeout(() => C((D) => D === m ? null : D), 2e3);
7013
7056
  } catch {
@@ -7147,98 +7190,98 @@ function si() {
7147
7190
  ] }) })
7148
7191
  ] });
7149
7192
  }
7150
- const ii = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, oi = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, li = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, ci = { dashboard: "Dashboard", setup: "Company Setup", tutorial: "Getting Started", chat: "Chat", reports: "Reports", "trial-balance": "Trial Balance", "general-ledger": "General Ledger", "stock-balance": "Stock Balance", "profit-and-loss": "Profit & Loss", "balance-sheet": "Balance Sheet", "ar-aging": "Accounts Receivable Aging", "ap-aging": "Accounts Payable Aging", analytics: "Analytics", "chart-of-accounts": "Chart of Accounts" }, di = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, ui = { company: { one: "Company", other: "Companies" }, customer: { one: "Customer", other: "Customers" }, supplier: { one: "Supplier", other: "Suppliers" }, item: { one: "Item", other: "Items" }, warehouse: { one: "Warehouse", other: "Warehouses" } }, mi = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, pi = { taglineFirstRun: "Create your admin account to get started", taglineRegister: "Create your account", taglineSignIn: "Sign in to your account", demoBanner: "Demo mode is active. Sign in with an admin account to manage settings or disable public access.", fullName: "Full Name", email: "Email", password: "Password", confirmPassword: "Confirm Password", createAdmin: "Create Admin Account", register: "Register", signIn: "Sign In", browsingTitle: "Just browsing?", browsingBody: "Start a fresh chat session and watch the live demo.", enterDemo: "Enter Live Demo", haveInvite: "Have an invite?", noAccountPrompt: "Need an account?", registerLink: "Register", alreadyHaveAccount: "Already have an account?", signInLink: "Sign in", passwordsNoMatch: "Passwords do not match", passwordTooShort: "Password must be at least 6 characters", registrationFailed: "Registration failed", loginFailed: "Login failed", orContinueWith: "or continue with", continueWithProvider: "Continue with {{provider}}", oauthError: { generic: "Sign-in failed. Please try again.", email_exists: "An account with this email already exists. Sign in, then link this provider from your account settings.", email_unverified: "Your provider did not confirm a verified email, so we can't sign you in.", registration_closed: "This email has no account yet and registration is invite-only.", invite_invalid: "That invite is invalid, already used, or issued for a different email.", identity_taken: "That provider account is already linked to a different user.", account_disabled: "This account has been disabled.", token_exchange_failed: "Sign-in failed while contacting the provider. Please try again." } }, hi = { pdfTitle: "PDF & Print", pageSize: "Page Size", pdfHelp: "A4 is standard internationally (210 x 297 mm). Letter is standard in the US (8.5 x 11 in).", passwordTitle: "Change Password", currentPassword: "Current password", newPassword: "New password", confirmNewPassword: "Confirm new password", changePassword: "Change password", changingPassword: "Changing...", passwordChanged: "Password changed.", setPasswordTitle: "Set a Password", setPasswordBody: "Your account signs in with Google. Set a password to also sign in with email and password — a handy fallback if you ever lose access to your Google account.", setPassword: "Set password", passwordSet: "Password set.", linkedAccountsTitle: "Linked Accounts", linkedAccountsBody: "Link a Google or Apple account to sign in without a password.", linked: "Linked", linkProvider: "Link {{provider}}", openingTitle: "Opening Balances", openingBody: "The Opening Balances page allows importing account balances, stock, and outstanding invoices from a previous system.", openingEnabled: "Currently enabled — accessible under Introduction > Opening Balances.", openingDisabled: "Currently disabled — the page is hidden from the sidebar.", signupTitle: "Public Signup", signupBody: "Allow anyone to create their own account (as a viewer) without an invite. When off, new users can only join via an invite link.", signupEnabled: "Currently enabled — anyone with the URL can register as a viewer.", signupDisabled: "Currently disabled — registration is invite-only.", chatApiTitle: "Chat API", apiTitle: "Programmatic API", restApiBody: "Let connectors and scripts drive this ERP over its REST API (documents, masters, reports) with the same Bearer API keys. Off by default.", restApiEnabled: "Currently enabled — issued keys can call /api/documents, /api/masters, and the rest of the REST API.", restApiDisabled: "Currently disabled — the REST API only accepts the session cookie; keys are rejected.", restApiDeactivateTitle: "Deactivate the REST API?", restApiDeactivateBody: "Bearer-key access to the REST API will be switched off — connectors and scripts are rejected until you turn it back on. The web app (session cookie) is unaffected, and your API keys are NOT deleted: they start working again the instant you re-enable the API.", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API.", version: "Version {{version}}" }, gi = { Draft: "Draft", Open: "Open", Submitted: "Submitted", "To Deliver and Bill": "To Deliver and Bill", "To Deliver": "To Deliver", "To Bill": "To Bill", Completed: "Completed", Ordered: "Ordered", Paid: "Paid", Unpaid: "Unpaid", Cancelled: "Cancelled", Discarded: "Discarded", Overdue: "Overdue", Return: "Return", Closed: "Closed" }, fi = { balanced: "BALANCED", imbalanced: "IMBALANCED", income: "Income", expenses: "Expenses", totalIncome: "Total Income", totalExpenses: "Total Expenses", netProfit: "Net Profit", netLoss: "Net Loss", assets: "Assets", liabilities: "Liabilities", equity: "Equity", totalAssets: "Total Assets", totalLiabilities: "Total Liabilities", totalEquity: "Total Equity", totalLiabilitiesEquity: "Total Liabilities + Equity", current: "Current", noData: "No data found", noEntries: "No entries found", noStockData: "No stock data found", noReceivables: "No outstanding receivables", noPayables: "No outstanding payables", noDocuments: "No documents found" }, yi = { required: "Required: {{fields}}", deleteConfirm: "Delete this {{label}}?", disabledNotice: "This {{label}} is disabled. It remains in the system because other records still reference it.", disabledOnDelete: "{{label}} {{name}} was disabled instead of deleted because it is referenced by {{reason}}." }, bi = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, vi = { title: "Lambda ERP Chat", subtitle: "Ask me to create documents, look up data, or run reports.", s1: "What customers do we have?", s2: "Show me the trial balance", s3: "Create a quotation for 10 Bolt Pack M8", s4: "List all unpaid invoices", loadOlder: "Load older messages", uploading: "Uploading...", failed: "Failed", remove: "Remove", placeholderDemo: "Running live demo...", placeholderType: "Type a message...", placeholderConnecting: "Connecting...", attachTitle: "Attach file (PDF or image, max 10 MB)", creating: "Creating chat...", dropToAttach: "Drop file to attach (images or PDF, max 10 MB each)", demoError: "Could not start demo", voiceStart: "Record voice message", voiceStop: "Stop recording", voiceTranscribing: "Transcribing...", micDenied: "Microphone access was denied.", transcribeFailed: "Transcription failed. Please try again." }, xi = { "Create Credit Note": "Create Credit Note", "Create Debit Note": "Create Debit Note", "Create Delivery Note": "Create Delivery Note", "Create Purchase Invoice": "Create Purchase Invoice", "Create Purchase Receipt": "Create Purchase Receipt", "Create Return": "Create Return", "Create Sales Invoice": "Create Sales Invoice", "Create Sales Order": "Create Sales Order" }, Ni = { "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code" }, wi = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, ki = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), Ci = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, Si = { period: "Period", allTime: "All time", semantics: "Balance-sheet accounts: closing balance at period end. P&L accounts: movement within the period. Click an account for its ledger.", empty: "No accounts found. Complete the company setup first.", disabled: "disabled", rootType: { Asset: "Assets", Liability: "Liabilities", Equity: "Equity", Income: "Income", Expense: "Expenses" } }, Di = {
7151
- common: ii,
7152
- language: oi,
7153
- header: li,
7154
- titles: ci,
7155
- doctypes: di,
7156
- masters: ui,
7157
- nav: mi,
7158
- login: pi,
7159
- settings: hi,
7160
- status: gi,
7161
- reports: fi,
7162
- masterForm: yi,
7163
- dashboard: bi,
7164
- chat: vi,
7165
- conversions: xi,
7166
- fields: Ni,
7167
- tables: wi,
7168
- tutorial: ki,
7169
- notesMarkup: Ci,
7170
- coa: Si
7171
- }, Ai = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, Pi = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, _i = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, Ti = { dashboard: "Dashboard", setup: "Unternehmenseinrichtung", tutorial: "Erste Schritte", chat: "Chat", reports: "Berichte", "trial-balance": "Rohbilanz", "general-ledger": "Hauptbuch", "stock-balance": "Lagerbestand", "profit-and-loss": "Gewinn- und Verlustrechnung", "balance-sheet": "Bilanz", "ar-aging": "Offene Posten Debitoren", "ap-aging": "Offene Posten Kreditoren", analytics: "Analysen", "chart-of-accounts": "Kontenplan" }, Ri = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, Ii = { company: { one: "Unternehmen", other: "Unternehmen" }, customer: { one: "Kunde", other: "Kunden" }, supplier: { one: "Lieferant", other: "Lieferanten" }, item: { one: "Artikel", other: "Artikel" }, warehouse: { one: "Lager", other: "Lager" } }, Bi = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, Ei = { taglineFirstRun: "Erstellen Sie Ihr Administratorkonto, um zu beginnen", taglineRegister: "Erstellen Sie Ihr Konto", taglineSignIn: "Melden Sie sich bei Ihrem Konto an", demoBanner: "Der Demomodus ist aktiv. Melden Sie sich mit einem Administratorkonto an, um Einstellungen zu verwalten oder den öffentlichen Zugriff zu deaktivieren.", fullName: "Vollständiger Name", email: "E-Mail", password: "Passwort", confirmPassword: "Passwort bestätigen", createAdmin: "Administratorkonto erstellen", register: "Registrieren", signIn: "Anmelden", browsingTitle: "Nur am Stöbern?", browsingBody: "Starten Sie eine neue Chat-Sitzung und sehen Sie sich die Live-Demo an.", enterDemo: "Live-Demo starten", haveInvite: "Haben Sie eine Einladung?", noAccountPrompt: "Noch kein Konto?", registerLink: "Registrieren", alreadyHaveAccount: "Haben Sie bereits ein Konto?", signInLink: "Anmelden", passwordsNoMatch: "Passwörter stimmen nicht überein", passwordTooShort: "Das Passwort muss mindestens 6 Zeichen lang sein", registrationFailed: "Registrierung fehlgeschlagen", loginFailed: "Anmeldung fehlgeschlagen", orContinueWith: "oder weiter mit", continueWithProvider: "Weiter mit {{provider}}", oauthError: { generic: "Anmeldung fehlgeschlagen. Bitte erneut versuchen.", email_exists: "Ein Konto mit dieser E-Mail existiert bereits. Melden Sie sich an und verknüpfen Sie diesen Anbieter in den Kontoeinstellungen.", email_unverified: "Ihr Anbieter hat keine bestätigte E-Mail übermittelt, daher ist keine Anmeldung möglich.", registration_closed: "Für diese E-Mail besteht noch kein Konto und die Registrierung ist nur per Einladung möglich.", invite_invalid: "Diese Einladung ist ungültig, bereits verwendet oder für eine andere E-Mail ausgestellt.", identity_taken: "Dieses Anbieterkonto ist bereits mit einem anderen Benutzer verknüpft.", account_disabled: "Dieses Konto wurde deaktiviert.", token_exchange_failed: "Anmeldung beim Anbieter fehlgeschlagen. Bitte erneut versuchen." } }, Li = { pdfTitle: "PDF & Druck", pageSize: "Seitengröße", pdfHelp: "A4 ist international Standard (210 x 297 mm). Letter ist Standard in den USA (8,5 x 11 Zoll).", passwordTitle: "Passwort ändern", currentPassword: "Aktuelles Passwort", newPassword: "Neues Passwort", confirmNewPassword: "Neues Passwort bestätigen", changePassword: "Passwort ändern", changingPassword: "Wird geändert...", passwordChanged: "Passwort geändert.", setPasswordTitle: "Passwort festlegen", setPasswordBody: "Ihr Konto meldet sich mit Google an. Legen Sie ein Passwort fest, um sich auch mit E-Mail und Passwort anzumelden — ein praktischer Rückfall, falls Sie den Zugang zu Ihrem Google-Konto verlieren.", setPassword: "Passwort festlegen", passwordSet: "Passwort festgelegt.", linkedAccountsTitle: "Verknüpfte Konten", linkedAccountsBody: "Verknüpfen Sie ein Google- oder Apple-Konto, um sich ohne Passwort anzumelden.", linked: "Verknüpft", linkProvider: "{{provider}} verknüpfen", openingTitle: "Eröffnungsbilanzen", openingBody: "Auf der Seite Eröffnungsbilanzen können Kontensalden, Lagerbestände und offene Rechnungen aus einem früheren System importiert werden.", openingEnabled: "Derzeit aktiviert — erreichbar unter Einführung > Eröffnungsbilanzen.", openingDisabled: "Derzeit deaktiviert — die Seite ist in der Seitenleiste ausgeblendet.", signupTitle: "Öffentliche Registrierung", signupBody: "Erlauben Sie es jedem, ohne Einladung ein eigenes Konto (als Betrachter) zu erstellen. Wenn deaktiviert, können neue Benutzer nur über einen Einladungslink beitreten.", signupEnabled: "Derzeit aktiviert — jeder mit der URL kann sich als Betrachter registrieren.", signupDisabled: "Derzeit deaktiviert — die Registrierung erfolgt nur per Einladung.", chatApiTitle: "Chat-API", apiTitle: "Programmatische API", restApiBody: "Konnektoren und Skripten erlauben, dieses ERP über seine REST-API (Belege, Stammdaten, Berichte) mit denselben Bearer-API-Schlüsseln zu steuern. Standardmäßig deaktiviert.", restApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können /api/documents, /api/masters und die übrige REST-API aufrufen.", restApiDisabled: "Derzeit deaktiviert — die REST-API akzeptiert nur das Sitzungs-Cookie; Schlüssel werden abgewiesen.", restApiDeactivateTitle: "REST-API deaktivieren?", restApiDeactivateBody: "Der Bearer-Schlüssel-Zugriff auf die REST-API wird abgeschaltet — Konnektoren und Skripte werden abgewiesen, bis Sie ihn wieder einschalten. Die Web-App (Sitzungs-Cookie) ist nicht betroffen, und Ihre API-Schlüssel werden NICHT gelöscht: Sie funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat.", version: "Version {{version}}" }, Oi = { Draft: "Entwurf", Open: "Offen", Submitted: "Gebucht", "To Deliver and Bill": "Zu liefern und abzurechnen", "To Deliver": "Zu liefern", "To Bill": "Abzurechnen", Completed: "Abgeschlossen", Ordered: "Bestellt", Paid: "Bezahlt", Unpaid: "Unbezahlt", Cancelled: "Storniert", Discarded: "Verworfen", Overdue: "Überfällig", Return: "Retoure", Closed: "Geschlossen" }, qi = { balanced: "AUSGEGLICHEN", imbalanced: "NICHT AUSGEGLICHEN", income: "Erträge", expenses: "Aufwendungen", totalIncome: "Summe Erträge", totalExpenses: "Summe Aufwendungen", netProfit: "Gewinn", netLoss: "Verlust", assets: "Aktiva", liabilities: "Verbindlichkeiten", equity: "Eigenkapital", totalAssets: "Summe Aktiva", totalLiabilities: "Summe Verbindlichkeiten", totalEquity: "Summe Eigenkapital", totalLiabilitiesEquity: "Summe Verbindlichkeiten + Eigenkapital", current: "Laufend", noData: "Keine Daten gefunden", noEntries: "Keine Buchungen gefunden", noStockData: "Keine Lagerdaten gefunden", noReceivables: "Keine offenen Forderungen", noPayables: "Keine offenen Verbindlichkeiten", noDocuments: "Keine Dokumente gefunden" }, zi = { required: "Erforderlich: {{fields}}", deleteConfirm: "Diesen Datensatz löschen: {{label}}?", disabledNotice: "Dieser Datensatz ({{label}}) ist deaktiviert. Er verbleibt im System, weil andere Datensätze noch darauf verweisen.", disabledOnDelete: "{{label}} {{name}} wurde deaktiviert statt gelöscht, da er von {{reason}} referenziert wird." }, Mi = { Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname" }, Fi = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, $i = { "Create Sales Order": "Kundenauftrag erstellen", "Create Sales Invoice": "Ausgangsrechnung erstellen", "Create Delivery Note": "Lieferschein erstellen", "Create Purchase Invoice": "Eingangsrechnung erstellen", "Create Purchase Receipt": "Wareneingang erstellen", "Create Credit Note": "Gutschrift erstellen", "Create Debit Note": "Lastschrift erstellen", "Create Return": "Retoure erstellen" }, Ui = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Vi = { title: "Lambda ERP Chat", subtitle: "Bitten Sie mich, Dokumente zu erstellen, Daten abzurufen oder Berichte auszuführen.", s1: "Welche Kunden haben wir?", s2: "Zeig mir die Rohbilanz", s3: "Erstelle ein Angebot für 10 Bolt Pack M8", s4: "Liste alle unbezahlten Rechnungen auf", loadOlder: "Ältere Nachrichten laden", uploading: "Wird hochgeladen...", failed: "Fehlgeschlagen", remove: "Entfernen", placeholderDemo: "Live-Demo läuft...", placeholderType: "Nachricht eingeben...", placeholderConnecting: "Verbindung wird hergestellt...", attachTitle: "Datei anhängen (PDF oder Bild, max. 10 MB)", creating: "Chat wird erstellt...", dropToAttach: "Datei zum Anhängen ablegen (Bilder oder PDF, je max. 10 MB)", demoError: "Demo konnte nicht gestartet werden", voiceStart: "Sprachnachricht aufnehmen", voiceStop: "Aufnahme stoppen", voiceTranscribing: "Wird transkribiert...", micDenied: "Zugriff auf das Mikrofon wurde verweigert.", transcribeFailed: "Transkription fehlgeschlagen. Bitte erneut versuchen." }, Ki = /* @__PURE__ */ JSON.parse('{"pageTitle":"Erste Schritte mit Lambda ERP","intro":"Lambda ERP ist ein KI-natives ERP-System, bei dem die gesamte Funktionalität – etwa das Erstellen von Aufträgen, das Prüfen von Beständen und das Erfassen von Zahlungen – über eine Chat-Oberfläche zugänglich ist. Es leitet an, denkt mit und prüft alle Ihre täglichen Geschäftsaufgaben.","openChat":"KI-Chat öffnen","tipLabel":"Tipp:","topTip":"Der KI-Chat kann Ihnen auch direkte Links zu Dokumenten und herunterladbaren PDFs geben. Bitten Sie ihn einfach, ein Dokument zu erstellen oder nachzuschlagen, und er fügt anklickbare Links in seine Antwort ein.","manualIntro":"Wenn Sie genau verstehen möchten, wie die Dinge unter der Haube funktionieren, oder Dinge lieber manuell erledigen, finden Sie hier einen vollständigen Geschäftszyklus Schritt für Schritt.","caTitle":"Dynamische Analysen – Chatten Sie sich zu jedem Diagramm","caBadge":"Kernfunktion","caBody":"Brauchen Sie einen Bericht, den die Vorlagen nicht liefern? Beschreiben Sie ihn einfach im Chat. Der Assistent ruft ein Code-Spezialmodell auf, das den Bericht für Sie schreibt, ihn live über Ihre ERP-Daten ausführt und einen teilbaren Link zurückgibt. Das Diagramm oder die Tabelle wird in Sekunden gerendert und als Entwurf unter „Eigene Analysen“ in der Seitenleiste gespeichert – Sie können ihn erneut öffnen, die URL mit Kollegen teilen oder den Assistenten bitten, ihn zu verfeinern.","caTryAsking":"Versuchen Sie zu fragen (zum Vorausfüllen im Chat klicken):","caPrompt1":"Zeig mir die Top 10 Kunden nach Umsatz dieses Jahr als Balkendiagramm","caPrompt2":"Monatlicher Einkaufstrend nach Lieferant über alle Monate, x-Achse mit Lieferantennamen beschriften","caPrompt3":"Bestseller-Artikel nach Menge, mit Tabelle und Diagramm","caPrompt4":"Welche Kunden schulden mir gerade am meisten?","caTryInChat":"Im Chat ausprobieren","caOpenWorkspace":"Analyse-Arbeitsbereich öffnen","flowTitle":"Überblick Dokumentenfluss","salesCycle":"Verkaufszyklus","purchaseCycle":"Einkaufszyklus","returns":"Retouren","flowShortcut":"Abkürzung: Das Angebot kann den Kundenauftrag überspringen und direkt zur Ausgangsrechnung oder zum Lieferschein führen","legendStock":"Lagerwirkung","legendGl":"Buchungswirkung","legendCash":"Geldwirkung","legendReversal":"Stornierung","lifecycleTitle":"Dokumenten-Lebenszyklus","lcDraftLabel":"Entwurf:","lcDraftDesc":"Bearbeitbar. Keine finanzielle oder Bestandswirkung.","lcSubmittedLabel":"Gebucht:","lcSubmittedDesc":"Gesperrt. Buchungen und Lagerbuchungen werden erzeugt.","lcCancelledLabel":"Storniert:","lcCancelledDesc":"Alle Buchungen storniert. Das Dokument wird dauerhaft archiviert.","lcNoDelete":"Es gibt kein Löschen. Um einen Entwurf zu verwerfen: buchen und dann stornieren.","lcCorrect":"Um ein gebuchtes Dokument zu korrigieren: stornieren und ein neues erstellen.","readyTitle":"Sie sind startklar","readyBody1":"Sie verstehen jetzt den vollständigen Zyklus. Ein typisches Praxisszenario sieht so aus: Sie erhalten einen Kundenauftrag (Angebot → Kundenauftrag), prüfen den Bestand, kaufen, was Sie brauchen (Bestellung → Wareneingang → Eingangsrechnung → Zahlung), liefern an den Kunden (Lieferschein), stellen ihm die Rechnung (Ausgangsrechnung) und ziehen die Zahlung ein (Zahlung). Kommt etwas zurück, erstellen Sie eine Gutschrift und eine Lieferschein-Retoure, um Finanzen und Bestand umzukehren. Die Rohbilanz bestätigt, dass alles ausgeglichen ist.","readyBody2":"Sie können all dies auch über den KI-Chat per natürlicher Konversation erledigen – beschreiben Sie einfach, was Sie brauchen, und er erstellt die richtigen Dokumente für Sie.","chips":{"Quotation":"Angebot","Sales Order":"Kundenauftrag","Delivery Note":"Lieferschein","Sales Invoice":"Ausgangsrechnung","Payment Entry":"Zahlung","Purchase Order":"Bestellung","Purchase Receipt":"Wareneingang","Purchase Invoice":"Eingangsrechnung","Credit Note":"Gutschrift","DN Return":"Lieferschein-Retoure","Debit Note":"Lastschrift","Draft":"Entwurf","Submitted":"Gebucht","Cancelled":"Storniert"},"links":{"Go to Setup":"Zur Einrichtung","Customers":"Kunden","Suppliers":"Lieferanten","Items":"Artikel","Warehouses":"Lager","New Quotation":"Neues Angebot","View Quotations":"Angebote anzeigen","Stock Balance":"Lagerbestand","New Purchase Order":"Neue Bestellung","Purchase Receipts":"Wareneingänge","Purchase Invoices":"Eingangsrechnungen","Delivery Notes":"Lieferscheine","Sales Invoices":"Ausgangsrechnungen","New Payment Entry":"Neue Zahlung","New Stock Entry":"Neue Lagerbuchung","New Journal Entry":"Neuer Buchungssatz","Profit & Loss":"Gewinn- und Verlustrechnung","Balance Sheet":"Bilanz","AR Aging":"Offene Posten Debitoren","AP Aging":"Offene Posten Kreditoren","Trial Balance":"Rohbilanz","General Ledger":"Hauptbuch","Open AI Chat":"KI-Chat öffnen"},"steps":{"1":{"title":"Unternehmen einrichten","description":"Erstellen Sie ein Unternehmen mit einer Basiswährung. Dadurch wird Ihr Kontenplan generiert (30 Standardkonten in den Bereichen Aktiva, Verbindlichkeiten, Eigenkapital, Erträge und Aufwendungen) sowie eine Standard-Kostenstelle. Sie können außerdem Demodaten mit Beispielkunden, -lieferanten und -artikeln anlegen, um schnell loszulegen."},"2":{"title":"Stammdaten anlegen","description":"Bevor Sie buchen können, benötigen Sie Stammdaten. Legen Sie mindestens einen Kunden, einen Lieferanten, einen Artikel (mit Standardpreis) und ein Lager an. Wenn Sie in Schritt 1 Demodaten angelegt haben, existieren diese bereits.","tip":"Artikel haben einen Standardpreis, der beim Hinzufügen zu Dokumenten automatisch ausgefüllt wird. Sie können den Preis pro Transaktion jederzeit überschreiben."},"3":{"title":"Angebot erstellen","description":"Ein Angebot ist eine unverbindliche Offerte an einen Kunden. Wählen Sie einen Kunden, fügen Sie Positionen mit Mengen und Preisen hinzu, optional Steuerzeilen, und speichern Sie. Angebote haben keine finanzielle Auswirkung – sie erzeugen keine Buchungs- oder Lagerbewegungen. Legen Sie ein Gültigkeitsdatum fest, damit das Angebot automatisch abläuft."},"4":{"title":"Buchen und in Kundenauftrag umwandeln","description":"Öffnen Sie Ihr gespeichertes Angebot und klicken Sie auf Buchen, um es zu bestätigen. Klicken Sie dann auf „Kundenauftrag erstellen“, um es umzuwandeln. Der Kundenauftrag stellt eine bestätigte Zusage des Kunden dar. Er hat weiterhin keine finanzielle Auswirkung, reserviert aber Bestand für die Planung.","tip":"Nur gebuchte Dokumente können in den nächsten Schritt umgewandelt werden. Entwurf → Buchen → Umwandeln ist der Standardablauf. Für schnelle Geschäfte können Sie den Kundenauftrag überspringen und direkt vom Angebot zur Ausgangsrechnung oder zum Lieferschein gehen."},"5":{"title":"Bestand vor der Erfüllung prüfen","description":"Bevor Sie liefern können, prüfen Sie, ob der Artikel tatsächlich auf Lager ist. Öffnen Sie den Bericht Lagerbestand und suchen Sie den Artikel. Wenn Ihr Lager eine Menge von null aufweist, müssen Sie zunächst Bestand beschaffen – entweder über eine Bestellung (Einkauf bei einem Lieferanten) oder eine Lagerbuchung (manueller Eingang).","tip":"Dies ist ein häufiges Szenario aus der Praxis: Sie verkaufen etwas und stellen dann fest, dass Sie es erst einkaufen müssen. Das ERP unterstützt beide Abläufe."},"6":{"title":"Einkaufszyklus: Bestand bei einem Lieferanten kaufen","description":"Wenn Sie Bestand einkaufen müssen, haben Sie zwei gültige Wege. Der Standardweg ist Bestellung → Wareneingang → Eingangsrechnung: Nutzen Sie ihn, wenn die Ware vor oder getrennt von der Lieferantenrechnung eintrifft. Treffen Rechnung und Wareneingang gleichzeitig ein, können Sie die Eingangsrechnung direkt erstellen und „Lager aktualisieren“ aktivieren, sodass dasselbe Dokument sowohl den Bestand vereinnahmt als auch die Verbindlichkeit erfasst.","tip":"Verwenden Sie zuerst den Wareneingang, wenn Sie Waren getrennt erhalten. Verwenden Sie die Eingangsrechnung mit „Lager aktualisieren“, wenn ein Schritt sowohl den Bestand vereinnahmen als auch die Lieferantenrechnung buchen soll. Setzen Sie in diesem direkten Weg ein Lager in jeder Bestandszeile."},"7":{"title":"Lieferschein erstellen","description":"Nachdem Sie nun Bestand haben, kehren Sie zu Ihrem gebuchten Kundenauftrag zurück und klicken Sie auf „Lieferschein erstellen“. Setzen Sie in jeder Position das Lager (von dem die Ware versendet wird) und buchen Sie. Dadurch wird Bestand aus dem Lager ausgebucht – Ihr Lagerbestand sinkt.","tip":"Der Lieferschein ist das Versanddokument. Er reduziert den Bestand, erzeugt aber keine Rechnung. Sie können Lieferung und Rechnungsstellung getrennt vornehmen."},"8":{"title":"Ausgangsrechnung erstellen und buchen","description":"Erstellen Sie aus dem gebuchten Kundenauftrag eine Ausgangsrechnung. Beim Buchen der Rechnung werden Buchungen erzeugt: Forderungen aus Lieferungen und Leistungen werden im Soll gebucht (der Kunde schuldet Ihnen Geld) und Umsatzerlöse im Haben (erzielter Ertrag). Sind Steuern konfiguriert, wird auch die Steuerverbindlichkeit im Haben gebucht. Der offene Betrag zeigt, was der Kunde noch schuldet."},"9":{"title":"Kundenzahlungen erfassen","description":"Erstellen Sie eine Zahlung, um vom Kunden erhaltenes Geld zu erfassen. Setzen Sie die Zahlungsart auf „Receive“ (Erhalten), wählen Sie den Kunden, geben Sie den Betrag an und ordnen Sie ihn der Ausgangsrechnung zu. Sie können Teilzahlungen vornehmen – der offene Betrag der Rechnung aktualisiert sich entsprechend. Erstellen Sie weitere Zahlungen, bis die Rechnung vollständig beglichen ist.","tip":"Teilzahlungen sind üblich. Eine Rechnung über 10.000 kann jetzt mit 3.000 und später mit 7.000 bezahlt werden. Jede Zahlung reduziert den offenen Betrag."},"10":{"title":"Lagerbuchungen (manuelle Bestandsführung)","description":"Verwenden Sie Lagerbuchungen für Bestandsbewegungen, die nicht mit Ein- oder Verkäufen verbunden sind. „Material Receipt“ fügt Bestand hinzu (Eröffnungsbestände, Korrekturen). „Material Issue“ bucht Bestand aus (Abschreibungen, interner Verbrauch). „Material Transfer“ verschiebt Bestand zwischen Lägern. Jede Buchung aktualisiert das Lagerbuch mit gleitender Durchschnittsbewertung.","tip":"Verwenden Sie für eingekaufte Waren Wareneingänge statt Lagerbuchungen – sie sind mit der Bestellung verknüpft und bieten einen sauberen Prüfpfad."},"11":{"title":"Buchungssätze","description":"Buchungssätze sind manuelle buchhalterische Anpassungen – Aufwandsabgrenzungen, Korrekturen, Umgliederungen, Eröffnungsbestände. Jeder Satz muss ausgeglichene Soll- und Haben-Beträge haben (Summe Soll = Summe Haben). Verwenden Sie sie, wenn kein anderer Dokumenttyp passt."},"12":{"title":"Gehaltszahlungen","description":"Lambda ERP wickelt Gehälter über die vorhandenen Buchhaltungswerkzeuge ab. Grenzen Sie zunächst den Gehaltsaufwand ab: Erstellen Sie einen Buchungssatz, der Gehaltsaufwand im Soll und Gehaltsverbindlichkeiten im Haben für den gesamten Lohnbetrag bucht. Bezahlen Sie dann die Mitarbeiter: Erstellen Sie einen weiteren Buchungssatz (oder eine Zahlung), der Gehaltsverbindlichkeiten im Soll und Ihr Bankkonto im Haben bucht. Dieser zweistufige Prozess hält Ihre Bücher korrekt – der Aufwand wird in der richtigen Periode erfasst und der Geldabfluss separat nachverfolgt.","tip":"Sie können den KI-Assistenten bitten, dies für Sie zu erledigen: „Grenze 15.000 an Gehältern für April ab“ gefolgt von „Zahle die April-Gehälter von der Bank“. Er erstellt die richtigen Buchungssätze automatisch."},"13":{"title":"Retouren und Gutschriften","description":"Wenn ein Kunde Waren zurückgibt oder Sie eine Gutschrift ausstellen müssen, erstellen Sie eine Retoure. Retouren verwenden denselben Dokumenttyp mit negativen Mengen. Öffnen Sie eine gebuchte Ausgangsrechnung und erstellen Sie eine Gutschrift (Ausgangsrechnungs-Retoure) – dies kehrt die Buchungen um und reduziert den offenen Betrag der ursprünglichen Rechnung. Erstellen Sie für den Bestand eine Lieferschein-Retoure, um Waren zurück ins Lager zu nehmen. Auf der Einkaufsseite erstellen Sie eine Lastschrift (Eingangsrechnungs-Retoure), um eine Lieferantenrechnung umzukehren, oder eine Wareneingangs-Retoure, um Waren zurückzusenden.","tip":"Eine Gutschrift ist einfach eine Ausgangsrechnung mit is_return=1 und negativen Mengen. Dieselbe Buchungslogik läuft – negative Beträge wechseln automatisch auf die richtige Soll-/Haben-Seite. Für eine vollständige Verkaufsretoure benötigen Sie sowohl eine Gutschrift (Finanzen) als auch eine Lieferschein-Retoure (Bestand)."},"14":{"title":"Berichte ausführen","description":"Prüfen Sie Ihre Bücher. Die Gewinn- und Verlustrechnung zeigt Erträge gegenüber Aufwendungen und den Periodengewinn. Die Bilanz zeigt Ihre finanzielle Lage (Aktiva = Verbindlichkeiten + Eigenkapital). Die Offenen Posten Debitoren zeigen, wer Ihnen Geld schuldet und wie überfällig es ist. Die Offenen Posten Kreditoren zeigen, was Sie Lieferanten schulden. Die Rohbilanz überprüft die doppelte Buchführung. Das Hauptbuch zeigt jede einzelne Buchung. Der Lagerbestand zeigt den aktuellen Bestand."},"15":{"title":"Arbeiten in Fremdwährungen","description":"Ihre Bücher werden in einer einzigen Basiswährung geführt (bei der Unternehmenseinrichtung gewählt), aber Sie können in jeder Währung buchen. Setzen Sie eine Währung auf einer Rechnung oder einem Beleg – oder geben Sie einem Kunden oder Lieferanten eine Standardwährung – und der Wechselkurs für dieses Datum wird automatisch ermittelt und auf dem Dokument gespeichert. Das Dokument behält seine Beträge in seiner eigenen Währung, während das Hauptbuch stets in Ihrer Basiswährung bucht. Wenn Sie später zu einem anderen Kurs einnehmen oder zahlen, wird der realisierte Währungsgewinn oder -verlust automatisch auf ein Konto Währungsgewinn/-verlust gebucht. Sie können sogar ein Fremdwährungs-Bankguthaben halten und es später zum Kurs Ihrer Bank umrechnen – die Differenz zum Buchwert wird dann realisiert. Zum Monatsende können Sie offene Fremdwährungssalden zum Stichtagskurs neu bewerten (ein unrealisierter Gewinn/Verlust, der in der nächsten Periode storniert wird), und Sie können jeden Jahresabschluss zur Anzeige in eine andere Währung umgerechnet betrachten.","tip":"Am einfachsten geht das über den KI-Chat – probieren Sie „Erstelle eine Ausgangsrechnung für Lumiere Audio in EUR“, „Zeig mir die Bilanz in EUR“ oder „Wie hoch ist unser unrealisiertes Währungsrisiko zum Monatsende?“. Die Demodaten enthalten bereits einen EUR-Kunden (Lumiere Audio SARL), dessen Rechnung zu einem anderen Kurs eingenommen wurde, sowie eine offene EUR-Lieferantenrechnung – öffnen Sie das Hauptbuch, um die realisierten Währungsbuchungen zu sehen."}},"setupTitle":"Richten Sie Ihr Unternehmen ein — KI-geführt","setupBadge":"Hier starten","setupBody":"Sagen Sie dem Assistenten, welche Art von Unternehmen Sie führen, und er erstellt Ihren Kontenplan für Sie — zugeschnitten auf Ihre Branche, mit den passenden Konten und sinnvollen Voreinstellungen. Er erklärt jede Entscheidung und legt erst dann etwas an, wenn Sie zustimmen.","setupSectors":"Zugeschnitten auf Dienstleistungen, Einzelhandel & POS, Gastronomie, Großhandel & Distribution, Import/Export, Fertigung und Bauwesen.","setupGetStarted":"Im Chat loslegen","setupManual":"Lieber ein manuelles Formular? Nutzen Sie die klassische Einrichtung.","setupManualLink":"Klassische Einrichtung","setupPrompt":"Ich möchte mein Unternehmen einrichten. Können Sie mich durch den Prozess führen?"}'), ji = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, Gi = { period: "Periode", allTime: "Gesamter Zeitraum", semantics: "Bilanzkonten: Saldo per Periodenende. Erfolgskonten: Bewegung innerhalb der Periode. Konto anklicken für den Kontoauszug.", empty: "Keine Konten gefunden. Zuerst die Firmeneinrichtung abschliessen.", disabled: "deaktiviert", rootType: { Asset: "Aktiven", Liability: "Passiven", Equity: "Eigenkapital", Income: "Ertrag", Expense: "Aufwand" } }, Wi = {
7172
- common: Ai,
7173
- language: Pi,
7174
- header: _i,
7175
- titles: Ti,
7176
- doctypes: Ri,
7177
- masters: Ii,
7178
- nav: Bi,
7179
- login: Ei,
7180
- settings: Li,
7181
- status: Oi,
7182
- reports: qi,
7183
- masterForm: zi,
7184
- fields: Mi,
7185
- tables: Fi,
7186
- conversions: $i,
7187
- dashboard: Ui,
7188
- chat: Vi,
7189
- tutorial: Ki,
7190
- notesMarkup: ji,
7191
- coa: Gi
7192
- }, Hi = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Qi = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Yi = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Ji = { dashboard: "Tableau de bord", setup: "Configuration de l'entreprise", tutorial: "Premiers pas", chat: "Chat", reports: "Rapports", "trial-balance": "Balance comptable", "general-ledger": "Grand livre", "stock-balance": "Solde de stock", "profit-and-loss": "Compte de résultat", "balance-sheet": "Bilan", "ar-aging": "Balance âgée clients", "ap-aging": "Balance âgée fournisseurs", analytics: "Analyses", "chart-of-accounts": "Plan comptable" }, Zi = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, Xi = { company: { one: "Société", other: "Sociétés" }, customer: { one: "Client", other: "Clients" }, supplier: { one: "Fournisseur", other: "Fournisseurs" }, item: { one: "Article", other: "Articles" }, warehouse: { one: "Entrepôt", other: "Entrepôts" } }, eo = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, to = { taglineFirstRun: "Créez votre compte administrateur pour commencer", taglineRegister: "Créez votre compte", taglineSignIn: "Connectez-vous à votre compte", demoBanner: "Le mode démo est actif. Connectez-vous avec un compte administrateur pour gérer les paramètres ou désactiver l'accès public.", fullName: "Nom complet", email: "E-mail", password: "Mot de passe", confirmPassword: "Confirmer le mot de passe", createAdmin: "Créer un compte administrateur", register: "S'inscrire", signIn: "Se connecter", browsingTitle: "Simple visite ?", browsingBody: "Démarrez une nouvelle session de chat et regardez la démo en direct.", enterDemo: "Lancer la démo", haveInvite: "Vous avez une invitation ?", noAccountPrompt: "Besoin d'un compte ?", registerLink: "S'inscrire", alreadyHaveAccount: "Vous avez déjà un compte ?", signInLink: "Se connecter", passwordsNoMatch: "Les mots de passe ne correspondent pas", passwordTooShort: "Le mot de passe doit comporter au moins 6 caractères", registrationFailed: "Échec de l'inscription", loginFailed: "Échec de la connexion", orContinueWith: "ou continuer avec", continueWithProvider: "Continuer avec {{provider}}", oauthError: { generic: "Échec de la connexion. Veuillez réessayer.", email_exists: "Un compte avec cet e-mail existe déjà. Connectez-vous, puis liez ce fournisseur depuis les paramètres du compte.", email_unverified: "Votre fournisseur n'a pas confirmé d'e-mail vérifié, la connexion est donc impossible.", registration_closed: "Cet e-mail n'a pas encore de compte et l'inscription se fait uniquement sur invitation.", invite_invalid: "Cette invitation est invalide, déjà utilisée ou émise pour un autre e-mail.", identity_taken: "Ce compte fournisseur est déjà lié à un autre utilisateur.", account_disabled: "Ce compte a été désactivé.", token_exchange_failed: "Échec de la connexion auprès du fournisseur. Veuillez réessayer." } }, no = { pdfTitle: "PDF et impression", pageSize: "Format de page", pdfHelp: "A4 est la norme internationale (210 x 297 mm). Letter est la norme aux États-Unis (8,5 x 11 po).", passwordTitle: "Changer le mot de passe", currentPassword: "Mot de passe actuel", newPassword: "Nouveau mot de passe", confirmNewPassword: "Confirmer le nouveau mot de passe", changePassword: "Changer le mot de passe", changingPassword: "Modification...", passwordChanged: "Mot de passe modifié.", setPasswordTitle: "Définir un mot de passe", setPasswordBody: "Votre compte se connecte avec Google. Définissez un mot de passe pour vous connecter aussi avec e-mail et mot de passe — un recours pratique si vous perdez l'accès à votre compte Google.", setPassword: "Définir le mot de passe", passwordSet: "Mot de passe défini.", linkedAccountsTitle: "Comptes liés", linkedAccountsBody: "Liez un compte Google ou Apple pour vous connecter sans mot de passe.", linked: "Lié", linkProvider: "Lier {{provider}}", openingTitle: "Soldes d'ouverture", openingBody: "La page Soldes d'ouverture permet d'importer les soldes des comptes, le stock et les factures impayées d'un système précédent.", openingEnabled: "Actuellement activé — accessible sous Introduction > Soldes d'ouverture.", openingDisabled: "Actuellement désactivé — la page est masquée dans la barre latérale.", signupTitle: "Inscription publique", signupBody: "Permettre à quiconque de créer son propre compte (en tant que lecteur) sans invitation. Lorsque désactivé, les nouveaux utilisateurs ne peuvent rejoindre que via un lien d'invitation.", signupEnabled: "Actuellement activé — toute personne disposant de l'URL peut s'inscrire en tant que lecteur.", signupDisabled: "Actuellement désactivé — l'inscription se fait uniquement sur invitation.", chatApiTitle: "API de chat", apiTitle: "API programmatique", restApiBody: "Permettre à des connecteurs et scripts de piloter cet ERP via son API REST (documents, données de base, rapports) avec les mêmes clés API Bearer. Désactivé par défaut.", restApiEnabled: "Actuellement activé — les clés émises peuvent appeler /api/documents, /api/masters et le reste de l'API REST.", restApiDisabled: "Actuellement désactivé — l'API REST n'accepte que le cookie de session ; les clés sont rejetées.", restApiDeactivateTitle: "Désactiver l'API REST ?", restApiDeactivateBody: "L'accès par clé Bearer à l'API REST sera désactivé — les connecteurs et scripts sont rejetés jusqu'à sa réactivation. L'application web (cookie de session) n'est pas affectée, et vos clés API ne sont PAS supprimées : elles fonctionnent à nouveau dès que vous réactivez l'API.", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat.", version: "Version {{version}}" }, ao = { Draft: "Brouillon", Open: "Ouvert", Submitted: "Validé", "To Deliver and Bill": "À livrer et facturer", "To Deliver": "À livrer", "To Bill": "À facturer", Completed: "Terminé", Ordered: "Commandé", Paid: "Payé", Unpaid: "Impayé", Cancelled: "Annulé", Discarded: "Supprimé", Overdue: "En retard", Return: "Retour", Closed: "Clôturé" }, ro = { balanced: "ÉQUILIBRÉ", imbalanced: "DÉSÉQUILIBRÉ", income: "Produits", expenses: "Charges", totalIncome: "Total des produits", totalExpenses: "Total des charges", netProfit: "Bénéfice", netLoss: "Perte", assets: "Actif", liabilities: "Passif", equity: "Capitaux propres", totalAssets: "Total de l'actif", totalLiabilities: "Total du passif", totalEquity: "Total des capitaux propres", totalLiabilitiesEquity: "Total passif + capitaux propres", current: "Non échu", noData: "Aucune donnée trouvée", noEntries: "Aucune écriture trouvée", noStockData: "Aucune donnée de stock trouvée", noReceivables: "Aucune créance en cours", noPayables: "Aucune dette en cours", noDocuments: "Aucun document trouvé" }, so = { required: "Requis : {{fields}}", deleteConfirm: "Supprimer ce {{label}} ?", disabledNotice: "Ce {{label}} est désactivé. Il reste dans le système car d'autres enregistrements y font référence.", disabledOnDelete: "{{label}} {{name}} a été désactivé au lieu d'être supprimé car il est référencé par {{reason}}." }, io = { Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société" }, oo = { items: "Lignes", taxes: "Taxes", references: "Références de paiement", accounts: "Écritures de compte", payments: "Paiements", plans: "Articles du plan", monthly_distribution: "Répartition mensuelle" }, lo = { "Create Sales Order": "Créer une commande client", "Create Sales Invoice": "Créer une facture de vente", "Create Delivery Note": "Créer un bon de livraison", "Create Purchase Invoice": "Créer une facture d'achat", "Create Purchase Receipt": "Créer un bon de réception", "Create Credit Note": "Créer un avoir", "Create Debit Note": "Créer une note de débit", "Create Return": "Créer un retour" }, co = { totalRevenue: "Chiffre d'affaires total", outstandingReceivable: "Créances en cours", outstandingPayable: "Dettes en cours", totalStockValue: "Valeur totale du stock", recentDocuments: "Documents récents", noRecentDocuments: "Aucun document récent" }, uo = { title: "Chat Lambda ERP", subtitle: "Demandez-moi de créer des documents, de consulter des données ou d'exécuter des rapports.", s1: "Quels clients avons-nous ?", s2: "Affiche la balance comptable", s3: "Crée un devis pour 10 Bolt Pack M8", s4: "Liste toutes les factures impayées", loadOlder: "Charger les messages plus anciens", uploading: "Téléversement...", failed: "Échec", remove: "Supprimer", placeholderDemo: "Démo en direct en cours...", placeholderType: "Tapez un message...", placeholderConnecting: "Connexion...", attachTitle: "Joindre un fichier (PDF ou image, max 10 Mo)", creating: "Création du chat...", dropToAttach: "Déposez un fichier à joindre (images ou PDF, max 10 Mo chacun)", demoError: "Impossible de démarrer la démo", voiceStart: "Enregistrer un message vocal", voiceStop: "Arrêter l'enregistrement", voiceTranscribing: "Transcription...", micDenied: "L'accès au microphone a été refusé.", transcribeFailed: "Échec de la transcription. Veuillez réessayer." }, mo = /* @__PURE__ */ JSON.parse(`{"pageTitle":"Premiers pas avec Lambda ERP","intro":"Lambda ERP est un système ERP nativement IA, où toutes les fonctionnalités – comme créer des commandes, vérifier l'inventaire ou enregistrer des paiements – sont accessibles via une interface de chat. Il guide, raisonne et vérifie toutes vos tâches quotidiennes.","openChat":"Ouvrir le chat IA","tipLabel":"Astuce :","topTip":"Le chat IA peut aussi vous donner des liens directs vers des documents et des PDF téléchargeables. Demandez-lui simplement de créer ou de rechercher un document et il inclura des liens cliquables dans sa réponse.","manualIntro":"Si vous souhaitez comprendre pleinement le fonctionnement interne, ou préférez procéder manuellement, voici un cycle commercial complet étape par étape.","caTitle":"Analyses dynamiques – discutez pour obtenir n'importe quel graphique","caBadge":"Fonctionnalité phare","caBody":"Besoin d'un rapport que les modèles prédéfinis ne fournissent pas ? Décrivez-le simplement dans le chat. L'assistant appelle un modèle spécialiste du code qui écrit le rapport pour vous, l'exécute en direct sur vos données ERP et renvoie un lien partageable. Le graphique ou le tableau s'affiche en quelques secondes et est enregistré comme brouillon sous « Analyses personnalisées » dans la barre latérale – vous pouvez le rouvrir, partager l'URL avec vos collègues ou demander à l'assistant de l'affiner.","caTryAsking":"Essayez de demander (cliquez pour préremplir dans le chat) :","caPrompt1":"Montre-moi les 10 meilleurs clients par chiffre d'affaires cette année en diagramme à barres","caPrompt2":"Tendance mensuelle des achats par fournisseur sur tous les mois, étiquette l'axe des x avec le nom du fournisseur","caPrompt3":"Articles les plus vendus par quantité, avec un tableau et un graphique","caPrompt4":"Quels clients me doivent le plus en ce moment ?","caTryInChat":"Essayer dans le chat","caOpenWorkspace":"Ouvrir l'espace d'analyse","flowTitle":"Aperçu du flux des documents","salesCycle":"Cycle de vente","purchaseCycle":"Cycle d'achat","returns":"Retours","flowShortcut":"Raccourci : le devis peut ignorer la commande client et aller directement à la facture de vente ou au bon de livraison","legendStock":"impact stock","legendGl":"impact comptable","legendCash":"impact trésorerie","legendReversal":"annulation","lifecycleTitle":"Cycle de vie du document","lcDraftLabel":"Brouillon :","lcDraftDesc":"Modifiable. Aucun impact financier ni sur le stock.","lcSubmittedLabel":"Validé :","lcSubmittedDesc":"Verrouillé. Les écritures comptables et de stock sont générées.","lcCancelledLabel":"Annulé :","lcCancelledDesc":"Toutes les écritures sont inversées. Le document est archivé définitivement.","lcNoDelete":"Il n'y a pas de suppression. Pour annuler un brouillon : validez-le, puis annulez-le.","lcCorrect":"Pour corriger un document validé : annulez-le et créez-en un nouveau.","readyTitle":"Vous êtes prêt","readyBody1":"Vous comprenez maintenant le cycle complet. Un scénario réel typique ressemble à ceci : vous recevez une commande client (Devis → Commande client), vérifiez le stock, achetez ce dont vous avez besoin (Bon de commande → Bon de réception → Facture d'achat → Paiement), livrez au client (Bon de livraison), facturez-le (Facture de vente) et encaissez le paiement (Paiement). Si quelque chose revient, créez un avoir et un retour de bon de livraison pour inverser les finances et le stock. La Balance comptable confirme que tout est équilibré.","readyBody2":"Vous pouvez aussi tout faire via le chat IA en conversation naturelle – décrivez simplement ce dont vous avez besoin et il créera les bons documents pour vous.","chips":{"Quotation":"Devis","Sales Order":"Commande client","Delivery Note":"Bon de livraison","Sales Invoice":"Facture de vente","Payment Entry":"Paiement","Purchase Order":"Bon de commande","Purchase Receipt":"Bon de réception","Purchase Invoice":"Facture d'achat","Credit Note":"Avoir","DN Return":"Retour BL","Debit Note":"Note de débit","Draft":"Brouillon","Submitted":"Validé","Cancelled":"Annulé"},"links":{"Go to Setup":"Aller à la configuration","Customers":"Clients","Suppliers":"Fournisseurs","Items":"Articles","Warehouses":"Entrepôts","New Quotation":"Nouveau devis","View Quotations":"Voir les devis","Stock Balance":"Solde de stock","New Purchase Order":"Nouveau bon de commande","Purchase Receipts":"Bons de réception","Purchase Invoices":"Factures d'achat","Delivery Notes":"Bons de livraison","Sales Invoices":"Factures de vente","New Payment Entry":"Nouveau paiement","New Stock Entry":"Nouveau mouvement de stock","New Journal Entry":"Nouvelle écriture de journal","Profit & Loss":"Compte de résultat","Balance Sheet":"Bilan","AR Aging":"Balance âgée clients","AP Aging":"Balance âgée fournisseurs","Trial Balance":"Balance comptable","General Ledger":"Grand livre","Open AI Chat":"Ouvrir le chat IA"},"steps":{"1":{"title":"Configurer votre société","description":"Créez une société avec une devise de base. Cela génère votre plan comptable (30 comptes standard répartis entre Actif, Passif, Capitaux propres, Produits et Charges) ainsi qu'un centre de coûts par défaut. Vous pouvez aussi charger des données de démonstration avec des clients, fournisseurs et articles d'exemple pour démarrer rapidement."},"2":{"title":"Créer les données de base","description":"Avant de pouvoir effectuer des transactions, vous avez besoin de fiches de base. Créez au moins un client, un fournisseur, un article (avec un prix standard) et un entrepôt. Si vous avez chargé les données de démonstration à l'étape 1, elles existent déjà.","tip":"Les articles ont un prix standard qui se remplit automatiquement lorsque vous les ajoutez à des documents. Vous pouvez toujours modifier le prix par transaction."},"3":{"title":"Créer un devis","description":"Un devis est une offre non contraignante adressée à un client. Sélectionnez un client, ajoutez des lignes avec quantités et prix, éventuellement des lignes de taxe, puis enregistrez. Les devis n'ont aucun impact financier – ils ne créent ni écritures comptables ni mouvements de stock. Définissez une date de validité pour que l'offre expire automatiquement."},"4":{"title":"Valider et convertir en commande client","description":"Ouvrez votre devis enregistré et cliquez sur Valider pour le confirmer. Cliquez ensuite sur « Créer une commande client » pour le convertir. La commande client représente un engagement confirmé du client. Elle n'a toujours aucun impact financier, mais réserve du stock à des fins de planification.","tip":"Seuls les documents validés peuvent être convertis à l'étape suivante. Brouillon → Valider → Convertir est le flux standard. Pour les affaires rapides, vous pouvez ignorer la commande client et passer directement du devis à la facture de vente ou au bon de livraison."},"5":{"title":"Vérifier le stock avant l'exécution","description":"Avant de pouvoir livrer, vérifiez si vous avez réellement l'article en stock. Ouvrez le rapport Solde de stock et recherchez l'article. Si votre entrepôt affiche une quantité nulle, vous devrez d'abord approvisionner le stock – soit par un bon de commande (achat auprès d'un fournisseur), soit par un mouvement de stock (réception manuelle).","tip":"C'est un scénario courant dans la pratique : vous vendez quelque chose, puis réalisez que vous devez d'abord l'acheter. L'ERP gère les deux flux."},"6":{"title":"Cycle d'achat : acheter du stock à un fournisseur","description":"Si vous devez acheter du stock, vous avez deux chemins valides. Le chemin standard est Bon de commande → Bon de réception → Facture d'achat : utilisez-le lorsque les marchandises arrivent avant ou séparément de la facture du fournisseur. Si la facture et la réception arrivent ensemble, vous pouvez créer directement la facture d'achat et activer « Mettre à jour le stock » afin que le même document réceptionne le stock et enregistre la dette fournisseur.","tip":"Utilisez d'abord le bon de réception lorsque vous recevez les marchandises séparément. Utilisez la facture d'achat avec « Mettre à jour le stock » lorsqu'une seule étape doit à la fois réceptionner le stock et comptabiliser la facture fournisseur. Dans ce chemin direct, indiquez un entrepôt sur chaque ligne d'article en stock."},"7":{"title":"Créer un bon de livraison","description":"Maintenant que vous avez du stock, revenez à votre commande client validée et cliquez sur « Créer un bon de livraison ». Indiquez l'entrepôt sur chaque ligne d'article (d'où partent les marchandises), puis validez. Cela sort le stock de l'entrepôt – votre solde de stock diminue.","tip":"Le bon de livraison est le document d'expédition. Il réduit le stock mais ne crée pas de facture. Vous pouvez livrer et facturer séparément."},"8":{"title":"Créer et valider la facture de vente","description":"À partir de la commande client validée, créez une facture de vente. Lorsque vous validez la facture, des écritures comptables sont générées : les Clients (créances) sont débités (le client vous doit de l'argent) et les Produits des ventes crédités (revenu acquis). Si des taxes sont configurées, la TVA collectée est également créditée. Le montant dû indique ce que le client doit encore."},"9":{"title":"Enregistrer les paiements clients","description":"Créez un paiement pour enregistrer l'argent reçu du client. Définissez le type de paiement sur « Receive » (Recevoir), sélectionnez le client, indiquez le montant et affectez-le à la facture de vente. Vous pouvez effectuer des paiements partiels – le montant dû de la facture se met à jour en conséquence. Créez des paiements supplémentaires jusqu'à ce que la facture soit entièrement réglée.","tip":"Les paiements partiels sont courants. Une facture de 10 000 peut être payée 3 000 maintenant et 7 000 plus tard. Chaque paiement réduit le montant dû."},"10":{"title":"Mouvements de stock (inventaire manuel)","description":"Utilisez les mouvements de stock pour les mouvements d'inventaire non liés aux achats ou aux ventes. « Material Receipt » ajoute du stock (soldes d'ouverture, ajustements). « Material Issue » sort du stock (pertes, consommation interne). « Material Transfer » déplace du stock entre entrepôts. Chaque mouvement met à jour le livre de stock avec une valorisation au coût moyen pondéré.","tip":"Pour les marchandises achetées, utilisez des bons de réception plutôt que des mouvements de stock – ils sont liés au bon de commande et offrent une piste d'audit appropriée."},"11":{"title":"Écritures de journal","description":"Les écritures de journal sont des ajustements comptables manuels – charges à payer, corrections, reclassements, soldes d'ouverture. Chaque écriture doit avoir des débits et crédits équilibrés (total débit = total crédit). Utilisez-les lorsqu'aucun autre type de document ne convient."},"12":{"title":"Paiements des salaires","description":"Lambda ERP gère les salaires à l'aide des outils comptables existants. Comptabilisez d'abord la charge salariale : créez une écriture de journal qui débite la Charge salariale et crédite les Salaires à payer pour le montant total de la paie. Payez ensuite les employés : créez une autre écriture de journal (ou un paiement) qui débite les Salaires à payer et crédite votre compte bancaire. Ce processus en deux étapes garde vos comptes exacts – la charge est enregistrée dans la bonne période et la sortie de trésorerie est suivie séparément.","tip":"Vous pouvez demander à l'assistant IA de le faire pour vous : « Comptabilise 15 000 de salaires pour avril » suivi de « Paie les salaires d'avril depuis la banque ». Il créera automatiquement les bonnes écritures de journal."},"13":{"title":"Retours et avoirs","description":"Lorsqu'un client retourne des marchandises ou que vous devez émettre un avoir, créez un retour. Les retours utilisent le même type de document avec des quantités négatives. Ouvrez une facture de vente validée et créez un avoir (retour de facture de vente) – cela inverse les écritures comptables et réduit le montant dû de la facture d'origine. Pour le stock, créez un retour de bon de livraison pour réintégrer les marchandises en entrepôt. Côté achats, créez une note de débit (retour de facture d'achat) pour inverser une facture fournisseur, ou un retour de bon de réception pour renvoyer des marchandises.","tip":"Un avoir est simplement une facture de vente avec is_return=1 et des quantités négatives. La même logique comptable s'applique – les montants négatifs basculent automatiquement du bon côté débit/crédit. Pour un retour de vente complet, vous avez besoin à la fois d'un avoir (financier) et d'un retour de bon de livraison (stock)."},"14":{"title":"Exécuter les rapports","description":"Vérifiez vos comptes. Le Compte de résultat montre les produits face aux charges et le résultat net d'une période. Le Bilan montre votre situation financière (actif = passif + capitaux propres). La Balance âgée clients montre qui vous doit de l'argent et le retard. La Balance âgée fournisseurs montre ce que vous devez aux fournisseurs. La Balance comptable vérifie l'intégrité de la partie double. Le Grand livre montre chaque écriture individuelle. Le Solde de stock montre l'inventaire actuel."},"15":{"title":"Travailler en devises étrangères","description":"Vos comptes sont tenus dans une seule devise de base (choisie à la configuration de la société), mais vous pouvez effectuer des transactions dans n'importe quelle devise. Définissez une devise sur une facture ou un effet – ou attribuez une devise par défaut à un client ou un fournisseur – et le taux de change de cette date est recherché automatiquement et enregistré sur le document. Le document conserve ses montants dans sa propre devise, tandis que le Grand livre comptabilise toujours dans votre devise de base. Lorsque vous encaissez ou payez ultérieurement à un taux différent, le gain ou la perte de change réalisé est comptabilisé automatiquement sur un compte Gain/Perte de change. Vous pouvez même détenir un solde bancaire en devise étrangère et le convertir plus tard au taux de votre banque – l'écart par rapport à sa valeur comptable est alors réalisé. En fin de mois, vous pouvez réévaluer les soldes en devises ouverts au taux de clôture (un gain/perte latent qui s'inverse à la période suivante), et vous pouvez consulter n'importe quel état financier converti dans une autre devise pour l'affichage.","tip":"Le plus simple est de passer par le chat IA – essayez « Crée une facture de vente pour Lumiere Audio en EUR », « Montre-moi le bilan en EUR » ou « Quelle est notre exposition de change latente en fin de mois ? ». Les données de démonstration incluent déjà un client EUR (Lumiere Audio SARL) dont la facture a été encaissée à un taux différent, ainsi qu'une facture fournisseur EUR ouverte – ouvrez le Grand livre pour voir les écritures de change réalisées."}},"setupTitle":"Configurez votre entreprise — guidé par l'IA","setupBadge":"Commencez ici","setupBody":"Dites à l'assistant quel type d'entreprise vous dirigez, et il construit votre plan comptable pour vous — adapté à votre secteur, avec les bons comptes et des valeurs par défaut cohérentes déjà en place. Il explique chaque décision et ne crée quoi que ce soit qu'après votre approbation.","setupSectors":"Adapté aux services, au commerce de détail & POS, à l'hôtellerie-restauration, au commerce de gros & distribution, à l'import/export, à la fabrication et à la construction.","setupGetStarted":"Commencer dans le chat","setupManual":"Vous préférez un formulaire manuel ? Utilisez la configuration classique.","setupManualLink":"Configuration classique","setupPrompt":"Je souhaite configurer mon entreprise. Pouvez-vous me guider ?"}`), po = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, ho = { period: "Période", allTime: "Toute la période", semantics: "Comptes de bilan : solde à la fin de la période. Comptes de résultat : mouvement de la période. Cliquez sur un compte pour son grand livre.", empty: "Aucun compte trouvé. Terminez d'abord la configuration de l'entreprise.", disabled: "désactivé", rootType: { Asset: "Actifs", Liability: "Passifs", Equity: "Capitaux propres", Income: "Produits", Expense: "Charges" } }, go = {
7193
- common: Hi,
7194
- language: Qi,
7195
- header: Yi,
7196
- titles: Ji,
7197
- doctypes: Zi,
7198
- masters: Xi,
7199
- nav: eo,
7200
- login: to,
7201
- settings: no,
7202
- status: ao,
7203
- reports: ro,
7204
- masterForm: so,
7205
- fields: io,
7206
- tables: oo,
7207
- conversions: lo,
7208
- dashboard: co,
7209
- chat: uo,
7210
- tutorial: mo,
7211
- notesMarkup: po,
7212
- coa: ho
7213
- }, ka = [
7193
+ const li = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, ci = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, di = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, ui = { dashboard: "Dashboard", setup: "Company Setup", tutorial: "Getting Started", chat: "Chat", reports: "Reports", "trial-balance": "Trial Balance", "general-ledger": "General Ledger", "stock-balance": "Stock Balance", "profit-and-loss": "Profit & Loss", "balance-sheet": "Balance Sheet", "ar-aging": "Accounts Receivable Aging", "ap-aging": "Accounts Payable Aging", analytics: "Analytics", "chart-of-accounts": "Chart of Accounts" }, mi = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, pi = { company: { one: "Company", other: "Companies" }, customer: { one: "Customer", other: "Customers" }, supplier: { one: "Supplier", other: "Suppliers" }, item: { one: "Item", other: "Items" }, warehouse: { one: "Warehouse", other: "Warehouses" } }, hi = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, gi = { taglineFirstRun: "Create your admin account to get started", taglineRegister: "Create your account", taglineSignIn: "Sign in to your account", demoBanner: "Demo mode is active. Sign in with an admin account to manage settings or disable public access.", fullName: "Full Name", email: "Email", password: "Password", confirmPassword: "Confirm Password", createAdmin: "Create Admin Account", register: "Register", signIn: "Sign In", browsingTitle: "Just browsing?", browsingBody: "Start a fresh chat session and watch the live demo.", enterDemo: "Enter Live Demo", haveInvite: "Have an invite?", noAccountPrompt: "Need an account?", registerLink: "Register", alreadyHaveAccount: "Already have an account?", signInLink: "Sign in", passwordsNoMatch: "Passwords do not match", passwordTooShort: "Password must be at least 6 characters", registrationFailed: "Registration failed", loginFailed: "Login failed", orContinueWith: "or continue with", continueWithProvider: "Continue with {{provider}}", oauthError: { generic: "Sign-in failed. Please try again.", email_exists: "An account with this email already exists. Sign in, then link this provider from your account settings.", email_unverified: "Your provider did not confirm a verified email, so we can't sign you in.", registration_closed: "This email has no account yet and registration is invite-only.", invite_invalid: "That invite is invalid, already used, or issued for a different email.", identity_taken: "That provider account is already linked to a different user.", account_disabled: "This account has been disabled.", token_exchange_failed: "Sign-in failed while contacting the provider. Please try again." } }, fi = { pdfTitle: "PDF & Print", pageSize: "Page Size", pdfHelp: "A4 is standard internationally (210 x 297 mm). Letter is standard in the US (8.5 x 11 in).", passwordTitle: "Change Password", currentPassword: "Current password", newPassword: "New password", confirmNewPassword: "Confirm new password", changePassword: "Change password", changingPassword: "Changing...", passwordChanged: "Password changed.", setPasswordTitle: "Set a Password", setPasswordBody: "Your account signs in with Google. Set a password to also sign in with email and password — a handy fallback if you ever lose access to your Google account.", setPassword: "Set password", passwordSet: "Password set.", linkedAccountsTitle: "Linked Accounts", linkedAccountsBody: "Link a Google or Apple account to sign in without a password.", linked: "Linked", linkProvider: "Link {{provider}}", openingTitle: "Opening Balances", openingBody: "The Opening Balances page allows importing account balances, stock, and outstanding invoices from a previous system.", openingEnabled: "Currently enabled — accessible under Introduction > Opening Balances.", openingDisabled: "Currently disabled — the page is hidden from the sidebar.", signupTitle: "Public Signup", signupBody: "Allow anyone to create their own account (as a viewer) without an invite. When off, new users can only join via an invite link.", signupEnabled: "Currently enabled — anyone with the URL can register as a viewer.", signupDisabled: "Currently disabled — registration is invite-only.", chatApiTitle: "Chat API", apiTitle: "Programmatic API", restApiBody: "Let connectors and scripts drive this ERP over its REST API (documents, masters, reports) with the same Bearer API keys. Off by default.", restApiEnabled: "Currently enabled — issued keys can call /api/documents, /api/masters, and the rest of the REST API.", restApiDisabled: "Currently disabled — the REST API only accepts the session cookie; keys are rejected.", restApiDeactivateTitle: "Deactivate the REST API?", restApiDeactivateBody: "Bearer-key access to the REST API will be switched off — connectors and scripts are rejected until you turn it back on. The web app (session cookie) is unaffected, and your API keys are NOT deleted: they start working again the instant you re-enable the API.", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API.", version: "Version {{version}}" }, yi = { Draft: "Draft", Open: "Open", Submitted: "Submitted", "To Deliver and Bill": "To Deliver and Bill", "To Deliver": "To Deliver", "To Bill": "To Bill", Completed: "Completed", Ordered: "Ordered", Paid: "Paid", Unpaid: "Unpaid", Cancelled: "Cancelled", Discarded: "Discarded", Overdue: "Overdue", Return: "Return", Closed: "Closed" }, bi = { balanced: "BALANCED", imbalanced: "IMBALANCED", income: "Income", expenses: "Expenses", totalIncome: "Total Income", totalExpenses: "Total Expenses", netProfit: "Net Profit", netLoss: "Net Loss", assets: "Assets", liabilities: "Liabilities", equity: "Equity", totalAssets: "Total Assets", totalLiabilities: "Total Liabilities", totalEquity: "Total Equity", totalLiabilitiesEquity: "Total Liabilities + Equity", current: "Current", noData: "No data found", noEntries: "No entries found", noStockData: "No stock data found", noReceivables: "No outstanding receivables", noPayables: "No outstanding payables", noDocuments: "No documents found" }, vi = { required: "Required: {{fields}}", deleteConfirm: "Delete this {{label}}?", disabledNotice: "This {{label}} is disabled. It remains in the system because other records still reference it.", disabledOnDelete: "{{label}} {{name}} was disabled instead of deleted because it is referenced by {{reason}}." }, xi = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, Ni = { title: "Lambda ERP Chat", subtitle: "Ask me to create documents, look up data, or run reports.", s1: "What customers do we have?", s2: "Show me the trial balance", s3: "Create a quotation for 10 Bolt Pack M8", s4: "List all unpaid invoices", loadOlder: "Load older messages", uploading: "Uploading...", failed: "Failed", remove: "Remove", placeholderDemo: "Running live demo...", placeholderType: "Type a message...", placeholderConnecting: "Connecting...", attachTitle: "Attach file (PDF or image, max 10 MB)", creating: "Creating chat...", dropToAttach: "Drop file to attach (images or PDF, max 10 MB each)", demoError: "Could not start demo", voiceStart: "Record voice message", voiceStop: "Stop recording", voiceTranscribing: "Transcribing...", micDenied: "Microphone access was denied.", transcribeFailed: "Transcription failed. Please try again." }, wi = { "Create Credit Note": "Create Credit Note", "Create Debit Note": "Create Debit Note", "Create Delivery Note": "Create Delivery Note", "Create Purchase Invoice": "Create Purchase Invoice", "Create Purchase Receipt": "Create Purchase Receipt", "Create Return": "Create Return", "Create Sales Invoice": "Create Sales Invoice", "Create Sales Order": "Create Sales Order" }, ki = { "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code" }, Ci = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, Si = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), Di = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, Ai = { period: "Period", allTime: "All time", semantics: "Balance-sheet accounts: closing balance at period end. P&L accounts: movement within the period. Click an account for its ledger.", empty: "No accounts found. Complete the company setup first.", disabled: "disabled", rootType: { Asset: "Assets", Liability: "Liabilities", Equity: "Equity", Income: "Income", Expense: "Expenses" } }, Pi = {
7194
+ common: li,
7195
+ language: ci,
7196
+ header: di,
7197
+ titles: ui,
7198
+ doctypes: mi,
7199
+ masters: pi,
7200
+ nav: hi,
7201
+ login: gi,
7202
+ settings: fi,
7203
+ status: yi,
7204
+ reports: bi,
7205
+ masterForm: vi,
7206
+ dashboard: xi,
7207
+ chat: Ni,
7208
+ conversions: wi,
7209
+ fields: ki,
7210
+ tables: Ci,
7211
+ tutorial: Si,
7212
+ notesMarkup: Di,
7213
+ coa: Ai
7214
+ }, _i = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, Ti = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, Ri = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, Ii = { dashboard: "Dashboard", setup: "Unternehmenseinrichtung", tutorial: "Erste Schritte", chat: "Chat", reports: "Berichte", "trial-balance": "Rohbilanz", "general-ledger": "Hauptbuch", "stock-balance": "Lagerbestand", "profit-and-loss": "Gewinn- und Verlustrechnung", "balance-sheet": "Bilanz", "ar-aging": "Offene Posten Debitoren", "ap-aging": "Offene Posten Kreditoren", analytics: "Analysen", "chart-of-accounts": "Kontenplan" }, Bi = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, Ei = { company: { one: "Unternehmen", other: "Unternehmen" }, customer: { one: "Kunde", other: "Kunden" }, supplier: { one: "Lieferant", other: "Lieferanten" }, item: { one: "Artikel", other: "Artikel" }, warehouse: { one: "Lager", other: "Lager" } }, Li = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, Oi = { taglineFirstRun: "Erstellen Sie Ihr Administratorkonto, um zu beginnen", taglineRegister: "Erstellen Sie Ihr Konto", taglineSignIn: "Melden Sie sich bei Ihrem Konto an", demoBanner: "Der Demomodus ist aktiv. Melden Sie sich mit einem Administratorkonto an, um Einstellungen zu verwalten oder den öffentlichen Zugriff zu deaktivieren.", fullName: "Vollständiger Name", email: "E-Mail", password: "Passwort", confirmPassword: "Passwort bestätigen", createAdmin: "Administratorkonto erstellen", register: "Registrieren", signIn: "Anmelden", browsingTitle: "Nur am Stöbern?", browsingBody: "Starten Sie eine neue Chat-Sitzung und sehen Sie sich die Live-Demo an.", enterDemo: "Live-Demo starten", haveInvite: "Haben Sie eine Einladung?", noAccountPrompt: "Noch kein Konto?", registerLink: "Registrieren", alreadyHaveAccount: "Haben Sie bereits ein Konto?", signInLink: "Anmelden", passwordsNoMatch: "Passwörter stimmen nicht überein", passwordTooShort: "Das Passwort muss mindestens 6 Zeichen lang sein", registrationFailed: "Registrierung fehlgeschlagen", loginFailed: "Anmeldung fehlgeschlagen", orContinueWith: "oder weiter mit", continueWithProvider: "Weiter mit {{provider}}", oauthError: { generic: "Anmeldung fehlgeschlagen. Bitte erneut versuchen.", email_exists: "Ein Konto mit dieser E-Mail existiert bereits. Melden Sie sich an und verknüpfen Sie diesen Anbieter in den Kontoeinstellungen.", email_unverified: "Ihr Anbieter hat keine bestätigte E-Mail übermittelt, daher ist keine Anmeldung möglich.", registration_closed: "Für diese E-Mail besteht noch kein Konto und die Registrierung ist nur per Einladung möglich.", invite_invalid: "Diese Einladung ist ungültig, bereits verwendet oder für eine andere E-Mail ausgestellt.", identity_taken: "Dieses Anbieterkonto ist bereits mit einem anderen Benutzer verknüpft.", account_disabled: "Dieses Konto wurde deaktiviert.", token_exchange_failed: "Anmeldung beim Anbieter fehlgeschlagen. Bitte erneut versuchen." } }, qi = { pdfTitle: "PDF & Druck", pageSize: "Seitengröße", pdfHelp: "A4 ist international Standard (210 x 297 mm). Letter ist Standard in den USA (8,5 x 11 Zoll).", passwordTitle: "Passwort ändern", currentPassword: "Aktuelles Passwort", newPassword: "Neues Passwort", confirmNewPassword: "Neues Passwort bestätigen", changePassword: "Passwort ändern", changingPassword: "Wird geändert...", passwordChanged: "Passwort geändert.", setPasswordTitle: "Passwort festlegen", setPasswordBody: "Ihr Konto meldet sich mit Google an. Legen Sie ein Passwort fest, um sich auch mit E-Mail und Passwort anzumelden — ein praktischer Rückfall, falls Sie den Zugang zu Ihrem Google-Konto verlieren.", setPassword: "Passwort festlegen", passwordSet: "Passwort festgelegt.", linkedAccountsTitle: "Verknüpfte Konten", linkedAccountsBody: "Verknüpfen Sie ein Google- oder Apple-Konto, um sich ohne Passwort anzumelden.", linked: "Verknüpft", linkProvider: "{{provider}} verknüpfen", openingTitle: "Eröffnungsbilanzen", openingBody: "Auf der Seite Eröffnungsbilanzen können Kontensalden, Lagerbestände und offene Rechnungen aus einem früheren System importiert werden.", openingEnabled: "Derzeit aktiviert — erreichbar unter Einführung > Eröffnungsbilanzen.", openingDisabled: "Derzeit deaktiviert — die Seite ist in der Seitenleiste ausgeblendet.", signupTitle: "Öffentliche Registrierung", signupBody: "Erlauben Sie es jedem, ohne Einladung ein eigenes Konto (als Betrachter) zu erstellen. Wenn deaktiviert, können neue Benutzer nur über einen Einladungslink beitreten.", signupEnabled: "Derzeit aktiviert — jeder mit der URL kann sich als Betrachter registrieren.", signupDisabled: "Derzeit deaktiviert — die Registrierung erfolgt nur per Einladung.", chatApiTitle: "Chat-API", apiTitle: "Programmatische API", restApiBody: "Konnektoren und Skripten erlauben, dieses ERP über seine REST-API (Belege, Stammdaten, Berichte) mit denselben Bearer-API-Schlüsseln zu steuern. Standardmäßig deaktiviert.", restApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können /api/documents, /api/masters und die übrige REST-API aufrufen.", restApiDisabled: "Derzeit deaktiviert — die REST-API akzeptiert nur das Sitzungs-Cookie; Schlüssel werden abgewiesen.", restApiDeactivateTitle: "REST-API deaktivieren?", restApiDeactivateBody: "Der Bearer-Schlüssel-Zugriff auf die REST-API wird abgeschaltet — Konnektoren und Skripte werden abgewiesen, bis Sie ihn wieder einschalten. Die Web-App (Sitzungs-Cookie) ist nicht betroffen, und Ihre API-Schlüssel werden NICHT gelöscht: Sie funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat.", version: "Version {{version}}" }, zi = { Draft: "Entwurf", Open: "Offen", Submitted: "Gebucht", "To Deliver and Bill": "Zu liefern und abzurechnen", "To Deliver": "Zu liefern", "To Bill": "Abzurechnen", Completed: "Abgeschlossen", Ordered: "Bestellt", Paid: "Bezahlt", Unpaid: "Unbezahlt", Cancelled: "Storniert", Discarded: "Verworfen", Overdue: "Überfällig", Return: "Retoure", Closed: "Geschlossen" }, Mi = { balanced: "AUSGEGLICHEN", imbalanced: "NICHT AUSGEGLICHEN", income: "Erträge", expenses: "Aufwendungen", totalIncome: "Summe Erträge", totalExpenses: "Summe Aufwendungen", netProfit: "Gewinn", netLoss: "Verlust", assets: "Aktiva", liabilities: "Verbindlichkeiten", equity: "Eigenkapital", totalAssets: "Summe Aktiva", totalLiabilities: "Summe Verbindlichkeiten", totalEquity: "Summe Eigenkapital", totalLiabilitiesEquity: "Summe Verbindlichkeiten + Eigenkapital", current: "Laufend", noData: "Keine Daten gefunden", noEntries: "Keine Buchungen gefunden", noStockData: "Keine Lagerdaten gefunden", noReceivables: "Keine offenen Forderungen", noPayables: "Keine offenen Verbindlichkeiten", noDocuments: "Keine Dokumente gefunden" }, Fi = { required: "Erforderlich: {{fields}}", deleteConfirm: "Diesen Datensatz löschen: {{label}}?", disabledNotice: "Dieser Datensatz ({{label}}) ist deaktiviert. Er verbleibt im System, weil andere Datensätze noch darauf verweisen.", disabledOnDelete: "{{label}} {{name}} wurde deaktiviert statt gelöscht, da er von {{reason}} referenziert wird." }, $i = { Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname" }, Ui = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Vi = { "Create Sales Order": "Kundenauftrag erstellen", "Create Sales Invoice": "Ausgangsrechnung erstellen", "Create Delivery Note": "Lieferschein erstellen", "Create Purchase Invoice": "Eingangsrechnung erstellen", "Create Purchase Receipt": "Wareneingang erstellen", "Create Credit Note": "Gutschrift erstellen", "Create Debit Note": "Lastschrift erstellen", "Create Return": "Retoure erstellen" }, Ki = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, ji = { title: "Lambda ERP Chat", subtitle: "Bitten Sie mich, Dokumente zu erstellen, Daten abzurufen oder Berichte auszuführen.", s1: "Welche Kunden haben wir?", s2: "Zeig mir die Rohbilanz", s3: "Erstelle ein Angebot für 10 Bolt Pack M8", s4: "Liste alle unbezahlten Rechnungen auf", loadOlder: "Ältere Nachrichten laden", uploading: "Wird hochgeladen...", failed: "Fehlgeschlagen", remove: "Entfernen", placeholderDemo: "Live-Demo läuft...", placeholderType: "Nachricht eingeben...", placeholderConnecting: "Verbindung wird hergestellt...", attachTitle: "Datei anhängen (PDF oder Bild, max. 10 MB)", creating: "Chat wird erstellt...", dropToAttach: "Datei zum Anhängen ablegen (Bilder oder PDF, je max. 10 MB)", demoError: "Demo konnte nicht gestartet werden", voiceStart: "Sprachnachricht aufnehmen", voiceStop: "Aufnahme stoppen", voiceTranscribing: "Wird transkribiert...", micDenied: "Zugriff auf das Mikrofon wurde verweigert.", transcribeFailed: "Transkription fehlgeschlagen. Bitte erneut versuchen." }, Gi = /* @__PURE__ */ JSON.parse('{"pageTitle":"Erste Schritte mit Lambda ERP","intro":"Lambda ERP ist ein KI-natives ERP-System, bei dem die gesamte Funktionalität – etwa das Erstellen von Aufträgen, das Prüfen von Beständen und das Erfassen von Zahlungen – über eine Chat-Oberfläche zugänglich ist. Es leitet an, denkt mit und prüft alle Ihre täglichen Geschäftsaufgaben.","openChat":"KI-Chat öffnen","tipLabel":"Tipp:","topTip":"Der KI-Chat kann Ihnen auch direkte Links zu Dokumenten und herunterladbaren PDFs geben. Bitten Sie ihn einfach, ein Dokument zu erstellen oder nachzuschlagen, und er fügt anklickbare Links in seine Antwort ein.","manualIntro":"Wenn Sie genau verstehen möchten, wie die Dinge unter der Haube funktionieren, oder Dinge lieber manuell erledigen, finden Sie hier einen vollständigen Geschäftszyklus Schritt für Schritt.","caTitle":"Dynamische Analysen – Chatten Sie sich zu jedem Diagramm","caBadge":"Kernfunktion","caBody":"Brauchen Sie einen Bericht, den die Vorlagen nicht liefern? Beschreiben Sie ihn einfach im Chat. Der Assistent ruft ein Code-Spezialmodell auf, das den Bericht für Sie schreibt, ihn live über Ihre ERP-Daten ausführt und einen teilbaren Link zurückgibt. Das Diagramm oder die Tabelle wird in Sekunden gerendert und als Entwurf unter „Eigene Analysen“ in der Seitenleiste gespeichert – Sie können ihn erneut öffnen, die URL mit Kollegen teilen oder den Assistenten bitten, ihn zu verfeinern.","caTryAsking":"Versuchen Sie zu fragen (zum Vorausfüllen im Chat klicken):","caPrompt1":"Zeig mir die Top 10 Kunden nach Umsatz dieses Jahr als Balkendiagramm","caPrompt2":"Monatlicher Einkaufstrend nach Lieferant über alle Monate, x-Achse mit Lieferantennamen beschriften","caPrompt3":"Bestseller-Artikel nach Menge, mit Tabelle und Diagramm","caPrompt4":"Welche Kunden schulden mir gerade am meisten?","caTryInChat":"Im Chat ausprobieren","caOpenWorkspace":"Analyse-Arbeitsbereich öffnen","flowTitle":"Überblick Dokumentenfluss","salesCycle":"Verkaufszyklus","purchaseCycle":"Einkaufszyklus","returns":"Retouren","flowShortcut":"Abkürzung: Das Angebot kann den Kundenauftrag überspringen und direkt zur Ausgangsrechnung oder zum Lieferschein führen","legendStock":"Lagerwirkung","legendGl":"Buchungswirkung","legendCash":"Geldwirkung","legendReversal":"Stornierung","lifecycleTitle":"Dokumenten-Lebenszyklus","lcDraftLabel":"Entwurf:","lcDraftDesc":"Bearbeitbar. Keine finanzielle oder Bestandswirkung.","lcSubmittedLabel":"Gebucht:","lcSubmittedDesc":"Gesperrt. Buchungen und Lagerbuchungen werden erzeugt.","lcCancelledLabel":"Storniert:","lcCancelledDesc":"Alle Buchungen storniert. Das Dokument wird dauerhaft archiviert.","lcNoDelete":"Es gibt kein Löschen. Um einen Entwurf zu verwerfen: buchen und dann stornieren.","lcCorrect":"Um ein gebuchtes Dokument zu korrigieren: stornieren und ein neues erstellen.","readyTitle":"Sie sind startklar","readyBody1":"Sie verstehen jetzt den vollständigen Zyklus. Ein typisches Praxisszenario sieht so aus: Sie erhalten einen Kundenauftrag (Angebot → Kundenauftrag), prüfen den Bestand, kaufen, was Sie brauchen (Bestellung → Wareneingang → Eingangsrechnung → Zahlung), liefern an den Kunden (Lieferschein), stellen ihm die Rechnung (Ausgangsrechnung) und ziehen die Zahlung ein (Zahlung). Kommt etwas zurück, erstellen Sie eine Gutschrift und eine Lieferschein-Retoure, um Finanzen und Bestand umzukehren. Die Rohbilanz bestätigt, dass alles ausgeglichen ist.","readyBody2":"Sie können all dies auch über den KI-Chat per natürlicher Konversation erledigen – beschreiben Sie einfach, was Sie brauchen, und er erstellt die richtigen Dokumente für Sie.","chips":{"Quotation":"Angebot","Sales Order":"Kundenauftrag","Delivery Note":"Lieferschein","Sales Invoice":"Ausgangsrechnung","Payment Entry":"Zahlung","Purchase Order":"Bestellung","Purchase Receipt":"Wareneingang","Purchase Invoice":"Eingangsrechnung","Credit Note":"Gutschrift","DN Return":"Lieferschein-Retoure","Debit Note":"Lastschrift","Draft":"Entwurf","Submitted":"Gebucht","Cancelled":"Storniert"},"links":{"Go to Setup":"Zur Einrichtung","Customers":"Kunden","Suppliers":"Lieferanten","Items":"Artikel","Warehouses":"Lager","New Quotation":"Neues Angebot","View Quotations":"Angebote anzeigen","Stock Balance":"Lagerbestand","New Purchase Order":"Neue Bestellung","Purchase Receipts":"Wareneingänge","Purchase Invoices":"Eingangsrechnungen","Delivery Notes":"Lieferscheine","Sales Invoices":"Ausgangsrechnungen","New Payment Entry":"Neue Zahlung","New Stock Entry":"Neue Lagerbuchung","New Journal Entry":"Neuer Buchungssatz","Profit & Loss":"Gewinn- und Verlustrechnung","Balance Sheet":"Bilanz","AR Aging":"Offene Posten Debitoren","AP Aging":"Offene Posten Kreditoren","Trial Balance":"Rohbilanz","General Ledger":"Hauptbuch","Open AI Chat":"KI-Chat öffnen"},"steps":{"1":{"title":"Unternehmen einrichten","description":"Erstellen Sie ein Unternehmen mit einer Basiswährung. Dadurch wird Ihr Kontenplan generiert (30 Standardkonten in den Bereichen Aktiva, Verbindlichkeiten, Eigenkapital, Erträge und Aufwendungen) sowie eine Standard-Kostenstelle. Sie können außerdem Demodaten mit Beispielkunden, -lieferanten und -artikeln anlegen, um schnell loszulegen."},"2":{"title":"Stammdaten anlegen","description":"Bevor Sie buchen können, benötigen Sie Stammdaten. Legen Sie mindestens einen Kunden, einen Lieferanten, einen Artikel (mit Standardpreis) und ein Lager an. Wenn Sie in Schritt 1 Demodaten angelegt haben, existieren diese bereits.","tip":"Artikel haben einen Standardpreis, der beim Hinzufügen zu Dokumenten automatisch ausgefüllt wird. Sie können den Preis pro Transaktion jederzeit überschreiben."},"3":{"title":"Angebot erstellen","description":"Ein Angebot ist eine unverbindliche Offerte an einen Kunden. Wählen Sie einen Kunden, fügen Sie Positionen mit Mengen und Preisen hinzu, optional Steuerzeilen, und speichern Sie. Angebote haben keine finanzielle Auswirkung – sie erzeugen keine Buchungs- oder Lagerbewegungen. Legen Sie ein Gültigkeitsdatum fest, damit das Angebot automatisch abläuft."},"4":{"title":"Buchen und in Kundenauftrag umwandeln","description":"Öffnen Sie Ihr gespeichertes Angebot und klicken Sie auf Buchen, um es zu bestätigen. Klicken Sie dann auf „Kundenauftrag erstellen“, um es umzuwandeln. Der Kundenauftrag stellt eine bestätigte Zusage des Kunden dar. Er hat weiterhin keine finanzielle Auswirkung, reserviert aber Bestand für die Planung.","tip":"Nur gebuchte Dokumente können in den nächsten Schritt umgewandelt werden. Entwurf → Buchen → Umwandeln ist der Standardablauf. Für schnelle Geschäfte können Sie den Kundenauftrag überspringen und direkt vom Angebot zur Ausgangsrechnung oder zum Lieferschein gehen."},"5":{"title":"Bestand vor der Erfüllung prüfen","description":"Bevor Sie liefern können, prüfen Sie, ob der Artikel tatsächlich auf Lager ist. Öffnen Sie den Bericht Lagerbestand und suchen Sie den Artikel. Wenn Ihr Lager eine Menge von null aufweist, müssen Sie zunächst Bestand beschaffen – entweder über eine Bestellung (Einkauf bei einem Lieferanten) oder eine Lagerbuchung (manueller Eingang).","tip":"Dies ist ein häufiges Szenario aus der Praxis: Sie verkaufen etwas und stellen dann fest, dass Sie es erst einkaufen müssen. Das ERP unterstützt beide Abläufe."},"6":{"title":"Einkaufszyklus: Bestand bei einem Lieferanten kaufen","description":"Wenn Sie Bestand einkaufen müssen, haben Sie zwei gültige Wege. Der Standardweg ist Bestellung → Wareneingang → Eingangsrechnung: Nutzen Sie ihn, wenn die Ware vor oder getrennt von der Lieferantenrechnung eintrifft. Treffen Rechnung und Wareneingang gleichzeitig ein, können Sie die Eingangsrechnung direkt erstellen und „Lager aktualisieren“ aktivieren, sodass dasselbe Dokument sowohl den Bestand vereinnahmt als auch die Verbindlichkeit erfasst.","tip":"Verwenden Sie zuerst den Wareneingang, wenn Sie Waren getrennt erhalten. Verwenden Sie die Eingangsrechnung mit „Lager aktualisieren“, wenn ein Schritt sowohl den Bestand vereinnahmen als auch die Lieferantenrechnung buchen soll. Setzen Sie in diesem direkten Weg ein Lager in jeder Bestandszeile."},"7":{"title":"Lieferschein erstellen","description":"Nachdem Sie nun Bestand haben, kehren Sie zu Ihrem gebuchten Kundenauftrag zurück und klicken Sie auf „Lieferschein erstellen“. Setzen Sie in jeder Position das Lager (von dem die Ware versendet wird) und buchen Sie. Dadurch wird Bestand aus dem Lager ausgebucht – Ihr Lagerbestand sinkt.","tip":"Der Lieferschein ist das Versanddokument. Er reduziert den Bestand, erzeugt aber keine Rechnung. Sie können Lieferung und Rechnungsstellung getrennt vornehmen."},"8":{"title":"Ausgangsrechnung erstellen und buchen","description":"Erstellen Sie aus dem gebuchten Kundenauftrag eine Ausgangsrechnung. Beim Buchen der Rechnung werden Buchungen erzeugt: Forderungen aus Lieferungen und Leistungen werden im Soll gebucht (der Kunde schuldet Ihnen Geld) und Umsatzerlöse im Haben (erzielter Ertrag). Sind Steuern konfiguriert, wird auch die Steuerverbindlichkeit im Haben gebucht. Der offene Betrag zeigt, was der Kunde noch schuldet."},"9":{"title":"Kundenzahlungen erfassen","description":"Erstellen Sie eine Zahlung, um vom Kunden erhaltenes Geld zu erfassen. Setzen Sie die Zahlungsart auf „Receive“ (Erhalten), wählen Sie den Kunden, geben Sie den Betrag an und ordnen Sie ihn der Ausgangsrechnung zu. Sie können Teilzahlungen vornehmen – der offene Betrag der Rechnung aktualisiert sich entsprechend. Erstellen Sie weitere Zahlungen, bis die Rechnung vollständig beglichen ist.","tip":"Teilzahlungen sind üblich. Eine Rechnung über 10.000 kann jetzt mit 3.000 und später mit 7.000 bezahlt werden. Jede Zahlung reduziert den offenen Betrag."},"10":{"title":"Lagerbuchungen (manuelle Bestandsführung)","description":"Verwenden Sie Lagerbuchungen für Bestandsbewegungen, die nicht mit Ein- oder Verkäufen verbunden sind. „Material Receipt“ fügt Bestand hinzu (Eröffnungsbestände, Korrekturen). „Material Issue“ bucht Bestand aus (Abschreibungen, interner Verbrauch). „Material Transfer“ verschiebt Bestand zwischen Lägern. Jede Buchung aktualisiert das Lagerbuch mit gleitender Durchschnittsbewertung.","tip":"Verwenden Sie für eingekaufte Waren Wareneingänge statt Lagerbuchungen – sie sind mit der Bestellung verknüpft und bieten einen sauberen Prüfpfad."},"11":{"title":"Buchungssätze","description":"Buchungssätze sind manuelle buchhalterische Anpassungen – Aufwandsabgrenzungen, Korrekturen, Umgliederungen, Eröffnungsbestände. Jeder Satz muss ausgeglichene Soll- und Haben-Beträge haben (Summe Soll = Summe Haben). Verwenden Sie sie, wenn kein anderer Dokumenttyp passt."},"12":{"title":"Gehaltszahlungen","description":"Lambda ERP wickelt Gehälter über die vorhandenen Buchhaltungswerkzeuge ab. Grenzen Sie zunächst den Gehaltsaufwand ab: Erstellen Sie einen Buchungssatz, der Gehaltsaufwand im Soll und Gehaltsverbindlichkeiten im Haben für den gesamten Lohnbetrag bucht. Bezahlen Sie dann die Mitarbeiter: Erstellen Sie einen weiteren Buchungssatz (oder eine Zahlung), der Gehaltsverbindlichkeiten im Soll und Ihr Bankkonto im Haben bucht. Dieser zweistufige Prozess hält Ihre Bücher korrekt – der Aufwand wird in der richtigen Periode erfasst und der Geldabfluss separat nachverfolgt.","tip":"Sie können den KI-Assistenten bitten, dies für Sie zu erledigen: „Grenze 15.000 an Gehältern für April ab“ gefolgt von „Zahle die April-Gehälter von der Bank“. Er erstellt die richtigen Buchungssätze automatisch."},"13":{"title":"Retouren und Gutschriften","description":"Wenn ein Kunde Waren zurückgibt oder Sie eine Gutschrift ausstellen müssen, erstellen Sie eine Retoure. Retouren verwenden denselben Dokumenttyp mit negativen Mengen. Öffnen Sie eine gebuchte Ausgangsrechnung und erstellen Sie eine Gutschrift (Ausgangsrechnungs-Retoure) – dies kehrt die Buchungen um und reduziert den offenen Betrag der ursprünglichen Rechnung. Erstellen Sie für den Bestand eine Lieferschein-Retoure, um Waren zurück ins Lager zu nehmen. Auf der Einkaufsseite erstellen Sie eine Lastschrift (Eingangsrechnungs-Retoure), um eine Lieferantenrechnung umzukehren, oder eine Wareneingangs-Retoure, um Waren zurückzusenden.","tip":"Eine Gutschrift ist einfach eine Ausgangsrechnung mit is_return=1 und negativen Mengen. Dieselbe Buchungslogik läuft – negative Beträge wechseln automatisch auf die richtige Soll-/Haben-Seite. Für eine vollständige Verkaufsretoure benötigen Sie sowohl eine Gutschrift (Finanzen) als auch eine Lieferschein-Retoure (Bestand)."},"14":{"title":"Berichte ausführen","description":"Prüfen Sie Ihre Bücher. Die Gewinn- und Verlustrechnung zeigt Erträge gegenüber Aufwendungen und den Periodengewinn. Die Bilanz zeigt Ihre finanzielle Lage (Aktiva = Verbindlichkeiten + Eigenkapital). Die Offenen Posten Debitoren zeigen, wer Ihnen Geld schuldet und wie überfällig es ist. Die Offenen Posten Kreditoren zeigen, was Sie Lieferanten schulden. Die Rohbilanz überprüft die doppelte Buchführung. Das Hauptbuch zeigt jede einzelne Buchung. Der Lagerbestand zeigt den aktuellen Bestand."},"15":{"title":"Arbeiten in Fremdwährungen","description":"Ihre Bücher werden in einer einzigen Basiswährung geführt (bei der Unternehmenseinrichtung gewählt), aber Sie können in jeder Währung buchen. Setzen Sie eine Währung auf einer Rechnung oder einem Beleg – oder geben Sie einem Kunden oder Lieferanten eine Standardwährung – und der Wechselkurs für dieses Datum wird automatisch ermittelt und auf dem Dokument gespeichert. Das Dokument behält seine Beträge in seiner eigenen Währung, während das Hauptbuch stets in Ihrer Basiswährung bucht. Wenn Sie später zu einem anderen Kurs einnehmen oder zahlen, wird der realisierte Währungsgewinn oder -verlust automatisch auf ein Konto Währungsgewinn/-verlust gebucht. Sie können sogar ein Fremdwährungs-Bankguthaben halten und es später zum Kurs Ihrer Bank umrechnen – die Differenz zum Buchwert wird dann realisiert. Zum Monatsende können Sie offene Fremdwährungssalden zum Stichtagskurs neu bewerten (ein unrealisierter Gewinn/Verlust, der in der nächsten Periode storniert wird), und Sie können jeden Jahresabschluss zur Anzeige in eine andere Währung umgerechnet betrachten.","tip":"Am einfachsten geht das über den KI-Chat – probieren Sie „Erstelle eine Ausgangsrechnung für Lumiere Audio in EUR“, „Zeig mir die Bilanz in EUR“ oder „Wie hoch ist unser unrealisiertes Währungsrisiko zum Monatsende?“. Die Demodaten enthalten bereits einen EUR-Kunden (Lumiere Audio SARL), dessen Rechnung zu einem anderen Kurs eingenommen wurde, sowie eine offene EUR-Lieferantenrechnung – öffnen Sie das Hauptbuch, um die realisierten Währungsbuchungen zu sehen."}},"setupTitle":"Richten Sie Ihr Unternehmen ein — KI-geführt","setupBadge":"Hier starten","setupBody":"Sagen Sie dem Assistenten, welche Art von Unternehmen Sie führen, und er erstellt Ihren Kontenplan für Sie — zugeschnitten auf Ihre Branche, mit den passenden Konten und sinnvollen Voreinstellungen. Er erklärt jede Entscheidung und legt erst dann etwas an, wenn Sie zustimmen.","setupSectors":"Zugeschnitten auf Dienstleistungen, Einzelhandel & POS, Gastronomie, Großhandel & Distribution, Import/Export, Fertigung und Bauwesen.","setupGetStarted":"Im Chat loslegen","setupManual":"Lieber ein manuelles Formular? Nutzen Sie die klassische Einrichtung.","setupManualLink":"Klassische Einrichtung","setupPrompt":"Ich möchte mein Unternehmen einrichten. Können Sie mich durch den Prozess führen?"}'), Wi = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, Hi = { period: "Periode", allTime: "Gesamter Zeitraum", semantics: "Bilanzkonten: Saldo per Periodenende. Erfolgskonten: Bewegung innerhalb der Periode. Konto anklicken für den Kontoauszug.", empty: "Keine Konten gefunden. Zuerst die Firmeneinrichtung abschliessen.", disabled: "deaktiviert", rootType: { Asset: "Aktiven", Liability: "Passiven", Equity: "Eigenkapital", Income: "Ertrag", Expense: "Aufwand" } }, Qi = {
7215
+ common: _i,
7216
+ language: Ti,
7217
+ header: Ri,
7218
+ titles: Ii,
7219
+ doctypes: Bi,
7220
+ masters: Ei,
7221
+ nav: Li,
7222
+ login: Oi,
7223
+ settings: qi,
7224
+ status: zi,
7225
+ reports: Mi,
7226
+ masterForm: Fi,
7227
+ fields: $i,
7228
+ tables: Ui,
7229
+ conversions: Vi,
7230
+ dashboard: Ki,
7231
+ chat: ji,
7232
+ tutorial: Gi,
7233
+ notesMarkup: Wi,
7234
+ coa: Hi
7235
+ }, Yi = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Ji = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Zi = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Xi = { dashboard: "Tableau de bord", setup: "Configuration de l'entreprise", tutorial: "Premiers pas", chat: "Chat", reports: "Rapports", "trial-balance": "Balance comptable", "general-ledger": "Grand livre", "stock-balance": "Solde de stock", "profit-and-loss": "Compte de résultat", "balance-sheet": "Bilan", "ar-aging": "Balance âgée clients", "ap-aging": "Balance âgée fournisseurs", analytics: "Analyses", "chart-of-accounts": "Plan comptable" }, eo = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, to = { company: { one: "Société", other: "Sociétés" }, customer: { one: "Client", other: "Clients" }, supplier: { one: "Fournisseur", other: "Fournisseurs" }, item: { one: "Article", other: "Articles" }, warehouse: { one: "Entrepôt", other: "Entrepôts" } }, no = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, ao = { taglineFirstRun: "Créez votre compte administrateur pour commencer", taglineRegister: "Créez votre compte", taglineSignIn: "Connectez-vous à votre compte", demoBanner: "Le mode démo est actif. Connectez-vous avec un compte administrateur pour gérer les paramètres ou désactiver l'accès public.", fullName: "Nom complet", email: "E-mail", password: "Mot de passe", confirmPassword: "Confirmer le mot de passe", createAdmin: "Créer un compte administrateur", register: "S'inscrire", signIn: "Se connecter", browsingTitle: "Simple visite ?", browsingBody: "Démarrez une nouvelle session de chat et regardez la démo en direct.", enterDemo: "Lancer la démo", haveInvite: "Vous avez une invitation ?", noAccountPrompt: "Besoin d'un compte ?", registerLink: "S'inscrire", alreadyHaveAccount: "Vous avez déjà un compte ?", signInLink: "Se connecter", passwordsNoMatch: "Les mots de passe ne correspondent pas", passwordTooShort: "Le mot de passe doit comporter au moins 6 caractères", registrationFailed: "Échec de l'inscription", loginFailed: "Échec de la connexion", orContinueWith: "ou continuer avec", continueWithProvider: "Continuer avec {{provider}}", oauthError: { generic: "Échec de la connexion. Veuillez réessayer.", email_exists: "Un compte avec cet e-mail existe déjà. Connectez-vous, puis liez ce fournisseur depuis les paramètres du compte.", email_unverified: "Votre fournisseur n'a pas confirmé d'e-mail vérifié, la connexion est donc impossible.", registration_closed: "Cet e-mail n'a pas encore de compte et l'inscription se fait uniquement sur invitation.", invite_invalid: "Cette invitation est invalide, déjà utilisée ou émise pour un autre e-mail.", identity_taken: "Ce compte fournisseur est déjà lié à un autre utilisateur.", account_disabled: "Ce compte a été désactivé.", token_exchange_failed: "Échec de la connexion auprès du fournisseur. Veuillez réessayer." } }, ro = { pdfTitle: "PDF et impression", pageSize: "Format de page", pdfHelp: "A4 est la norme internationale (210 x 297 mm). Letter est la norme aux États-Unis (8,5 x 11 po).", passwordTitle: "Changer le mot de passe", currentPassword: "Mot de passe actuel", newPassword: "Nouveau mot de passe", confirmNewPassword: "Confirmer le nouveau mot de passe", changePassword: "Changer le mot de passe", changingPassword: "Modification...", passwordChanged: "Mot de passe modifié.", setPasswordTitle: "Définir un mot de passe", setPasswordBody: "Votre compte se connecte avec Google. Définissez un mot de passe pour vous connecter aussi avec e-mail et mot de passe — un recours pratique si vous perdez l'accès à votre compte Google.", setPassword: "Définir le mot de passe", passwordSet: "Mot de passe défini.", linkedAccountsTitle: "Comptes liés", linkedAccountsBody: "Liez un compte Google ou Apple pour vous connecter sans mot de passe.", linked: "Lié", linkProvider: "Lier {{provider}}", openingTitle: "Soldes d'ouverture", openingBody: "La page Soldes d'ouverture permet d'importer les soldes des comptes, le stock et les factures impayées d'un système précédent.", openingEnabled: "Actuellement activé — accessible sous Introduction > Soldes d'ouverture.", openingDisabled: "Actuellement désactivé — la page est masquée dans la barre latérale.", signupTitle: "Inscription publique", signupBody: "Permettre à quiconque de créer son propre compte (en tant que lecteur) sans invitation. Lorsque désactivé, les nouveaux utilisateurs ne peuvent rejoindre que via un lien d'invitation.", signupEnabled: "Actuellement activé — toute personne disposant de l'URL peut s'inscrire en tant que lecteur.", signupDisabled: "Actuellement désactivé — l'inscription se fait uniquement sur invitation.", chatApiTitle: "API de chat", apiTitle: "API programmatique", restApiBody: "Permettre à des connecteurs et scripts de piloter cet ERP via son API REST (documents, données de base, rapports) avec les mêmes clés API Bearer. Désactivé par défaut.", restApiEnabled: "Actuellement activé — les clés émises peuvent appeler /api/documents, /api/masters et le reste de l'API REST.", restApiDisabled: "Actuellement désactivé — l'API REST n'accepte que le cookie de session ; les clés sont rejetées.", restApiDeactivateTitle: "Désactiver l'API REST ?", restApiDeactivateBody: "L'accès par clé Bearer à l'API REST sera désactivé — les connecteurs et scripts sont rejetés jusqu'à sa réactivation. L'application web (cookie de session) n'est pas affectée, et vos clés API ne sont PAS supprimées : elles fonctionnent à nouveau dès que vous réactivez l'API.", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat.", version: "Version {{version}}" }, so = { Draft: "Brouillon", Open: "Ouvert", Submitted: "Validé", "To Deliver and Bill": "À livrer et facturer", "To Deliver": "À livrer", "To Bill": "À facturer", Completed: "Terminé", Ordered: "Commandé", Paid: "Payé", Unpaid: "Impayé", Cancelled: "Annulé", Discarded: "Supprimé", Overdue: "En retard", Return: "Retour", Closed: "Clôturé" }, io = { balanced: "ÉQUILIBRÉ", imbalanced: "DÉSÉQUILIBRÉ", income: "Produits", expenses: "Charges", totalIncome: "Total des produits", totalExpenses: "Total des charges", netProfit: "Bénéfice", netLoss: "Perte", assets: "Actif", liabilities: "Passif", equity: "Capitaux propres", totalAssets: "Total de l'actif", totalLiabilities: "Total du passif", totalEquity: "Total des capitaux propres", totalLiabilitiesEquity: "Total passif + capitaux propres", current: "Non échu", noData: "Aucune donnée trouvée", noEntries: "Aucune écriture trouvée", noStockData: "Aucune donnée de stock trouvée", noReceivables: "Aucune créance en cours", noPayables: "Aucune dette en cours", noDocuments: "Aucun document trouvé" }, oo = { required: "Requis : {{fields}}", deleteConfirm: "Supprimer ce {{label}} ?", disabledNotice: "Ce {{label}} est désactivé. Il reste dans le système car d'autres enregistrements y font référence.", disabledOnDelete: "{{label}} {{name}} a été désactivé au lieu d'être supprimé car il est référencé par {{reason}}." }, lo = { Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société" }, co = { items: "Lignes", taxes: "Taxes", references: "Références de paiement", accounts: "Écritures de compte", payments: "Paiements", plans: "Articles du plan", monthly_distribution: "Répartition mensuelle" }, uo = { "Create Sales Order": "Créer une commande client", "Create Sales Invoice": "Créer une facture de vente", "Create Delivery Note": "Créer un bon de livraison", "Create Purchase Invoice": "Créer une facture d'achat", "Create Purchase Receipt": "Créer un bon de réception", "Create Credit Note": "Créer un avoir", "Create Debit Note": "Créer une note de débit", "Create Return": "Créer un retour" }, mo = { totalRevenue: "Chiffre d'affaires total", outstandingReceivable: "Créances en cours", outstandingPayable: "Dettes en cours", totalStockValue: "Valeur totale du stock", recentDocuments: "Documents récents", noRecentDocuments: "Aucun document récent" }, po = { title: "Chat Lambda ERP", subtitle: "Demandez-moi de créer des documents, de consulter des données ou d'exécuter des rapports.", s1: "Quels clients avons-nous ?", s2: "Affiche la balance comptable", s3: "Crée un devis pour 10 Bolt Pack M8", s4: "Liste toutes les factures impayées", loadOlder: "Charger les messages plus anciens", uploading: "Téléversement...", failed: "Échec", remove: "Supprimer", placeholderDemo: "Démo en direct en cours...", placeholderType: "Tapez un message...", placeholderConnecting: "Connexion...", attachTitle: "Joindre un fichier (PDF ou image, max 10 Mo)", creating: "Création du chat...", dropToAttach: "Déposez un fichier à joindre (images ou PDF, max 10 Mo chacun)", demoError: "Impossible de démarrer la démo", voiceStart: "Enregistrer un message vocal", voiceStop: "Arrêter l'enregistrement", voiceTranscribing: "Transcription...", micDenied: "L'accès au microphone a été refusé.", transcribeFailed: "Échec de la transcription. Veuillez réessayer." }, ho = /* @__PURE__ */ JSON.parse(`{"pageTitle":"Premiers pas avec Lambda ERP","intro":"Lambda ERP est un système ERP nativement IA, où toutes les fonctionnalités – comme créer des commandes, vérifier l'inventaire ou enregistrer des paiements – sont accessibles via une interface de chat. Il guide, raisonne et vérifie toutes vos tâches quotidiennes.","openChat":"Ouvrir le chat IA","tipLabel":"Astuce :","topTip":"Le chat IA peut aussi vous donner des liens directs vers des documents et des PDF téléchargeables. Demandez-lui simplement de créer ou de rechercher un document et il inclura des liens cliquables dans sa réponse.","manualIntro":"Si vous souhaitez comprendre pleinement le fonctionnement interne, ou préférez procéder manuellement, voici un cycle commercial complet étape par étape.","caTitle":"Analyses dynamiques – discutez pour obtenir n'importe quel graphique","caBadge":"Fonctionnalité phare","caBody":"Besoin d'un rapport que les modèles prédéfinis ne fournissent pas ? Décrivez-le simplement dans le chat. L'assistant appelle un modèle spécialiste du code qui écrit le rapport pour vous, l'exécute en direct sur vos données ERP et renvoie un lien partageable. Le graphique ou le tableau s'affiche en quelques secondes et est enregistré comme brouillon sous « Analyses personnalisées » dans la barre latérale – vous pouvez le rouvrir, partager l'URL avec vos collègues ou demander à l'assistant de l'affiner.","caTryAsking":"Essayez de demander (cliquez pour préremplir dans le chat) :","caPrompt1":"Montre-moi les 10 meilleurs clients par chiffre d'affaires cette année en diagramme à barres","caPrompt2":"Tendance mensuelle des achats par fournisseur sur tous les mois, étiquette l'axe des x avec le nom du fournisseur","caPrompt3":"Articles les plus vendus par quantité, avec un tableau et un graphique","caPrompt4":"Quels clients me doivent le plus en ce moment ?","caTryInChat":"Essayer dans le chat","caOpenWorkspace":"Ouvrir l'espace d'analyse","flowTitle":"Aperçu du flux des documents","salesCycle":"Cycle de vente","purchaseCycle":"Cycle d'achat","returns":"Retours","flowShortcut":"Raccourci : le devis peut ignorer la commande client et aller directement à la facture de vente ou au bon de livraison","legendStock":"impact stock","legendGl":"impact comptable","legendCash":"impact trésorerie","legendReversal":"annulation","lifecycleTitle":"Cycle de vie du document","lcDraftLabel":"Brouillon :","lcDraftDesc":"Modifiable. Aucun impact financier ni sur le stock.","lcSubmittedLabel":"Validé :","lcSubmittedDesc":"Verrouillé. Les écritures comptables et de stock sont générées.","lcCancelledLabel":"Annulé :","lcCancelledDesc":"Toutes les écritures sont inversées. Le document est archivé définitivement.","lcNoDelete":"Il n'y a pas de suppression. Pour annuler un brouillon : validez-le, puis annulez-le.","lcCorrect":"Pour corriger un document validé : annulez-le et créez-en un nouveau.","readyTitle":"Vous êtes prêt","readyBody1":"Vous comprenez maintenant le cycle complet. Un scénario réel typique ressemble à ceci : vous recevez une commande client (Devis → Commande client), vérifiez le stock, achetez ce dont vous avez besoin (Bon de commande → Bon de réception → Facture d'achat → Paiement), livrez au client (Bon de livraison), facturez-le (Facture de vente) et encaissez le paiement (Paiement). Si quelque chose revient, créez un avoir et un retour de bon de livraison pour inverser les finances et le stock. La Balance comptable confirme que tout est équilibré.","readyBody2":"Vous pouvez aussi tout faire via le chat IA en conversation naturelle – décrivez simplement ce dont vous avez besoin et il créera les bons documents pour vous.","chips":{"Quotation":"Devis","Sales Order":"Commande client","Delivery Note":"Bon de livraison","Sales Invoice":"Facture de vente","Payment Entry":"Paiement","Purchase Order":"Bon de commande","Purchase Receipt":"Bon de réception","Purchase Invoice":"Facture d'achat","Credit Note":"Avoir","DN Return":"Retour BL","Debit Note":"Note de débit","Draft":"Brouillon","Submitted":"Validé","Cancelled":"Annulé"},"links":{"Go to Setup":"Aller à la configuration","Customers":"Clients","Suppliers":"Fournisseurs","Items":"Articles","Warehouses":"Entrepôts","New Quotation":"Nouveau devis","View Quotations":"Voir les devis","Stock Balance":"Solde de stock","New Purchase Order":"Nouveau bon de commande","Purchase Receipts":"Bons de réception","Purchase Invoices":"Factures d'achat","Delivery Notes":"Bons de livraison","Sales Invoices":"Factures de vente","New Payment Entry":"Nouveau paiement","New Stock Entry":"Nouveau mouvement de stock","New Journal Entry":"Nouvelle écriture de journal","Profit & Loss":"Compte de résultat","Balance Sheet":"Bilan","AR Aging":"Balance âgée clients","AP Aging":"Balance âgée fournisseurs","Trial Balance":"Balance comptable","General Ledger":"Grand livre","Open AI Chat":"Ouvrir le chat IA"},"steps":{"1":{"title":"Configurer votre société","description":"Créez une société avec une devise de base. Cela génère votre plan comptable (30 comptes standard répartis entre Actif, Passif, Capitaux propres, Produits et Charges) ainsi qu'un centre de coûts par défaut. Vous pouvez aussi charger des données de démonstration avec des clients, fournisseurs et articles d'exemple pour démarrer rapidement."},"2":{"title":"Créer les données de base","description":"Avant de pouvoir effectuer des transactions, vous avez besoin de fiches de base. Créez au moins un client, un fournisseur, un article (avec un prix standard) et un entrepôt. Si vous avez chargé les données de démonstration à l'étape 1, elles existent déjà.","tip":"Les articles ont un prix standard qui se remplit automatiquement lorsque vous les ajoutez à des documents. Vous pouvez toujours modifier le prix par transaction."},"3":{"title":"Créer un devis","description":"Un devis est une offre non contraignante adressée à un client. Sélectionnez un client, ajoutez des lignes avec quantités et prix, éventuellement des lignes de taxe, puis enregistrez. Les devis n'ont aucun impact financier – ils ne créent ni écritures comptables ni mouvements de stock. Définissez une date de validité pour que l'offre expire automatiquement."},"4":{"title":"Valider et convertir en commande client","description":"Ouvrez votre devis enregistré et cliquez sur Valider pour le confirmer. Cliquez ensuite sur « Créer une commande client » pour le convertir. La commande client représente un engagement confirmé du client. Elle n'a toujours aucun impact financier, mais réserve du stock à des fins de planification.","tip":"Seuls les documents validés peuvent être convertis à l'étape suivante. Brouillon → Valider → Convertir est le flux standard. Pour les affaires rapides, vous pouvez ignorer la commande client et passer directement du devis à la facture de vente ou au bon de livraison."},"5":{"title":"Vérifier le stock avant l'exécution","description":"Avant de pouvoir livrer, vérifiez si vous avez réellement l'article en stock. Ouvrez le rapport Solde de stock et recherchez l'article. Si votre entrepôt affiche une quantité nulle, vous devrez d'abord approvisionner le stock – soit par un bon de commande (achat auprès d'un fournisseur), soit par un mouvement de stock (réception manuelle).","tip":"C'est un scénario courant dans la pratique : vous vendez quelque chose, puis réalisez que vous devez d'abord l'acheter. L'ERP gère les deux flux."},"6":{"title":"Cycle d'achat : acheter du stock à un fournisseur","description":"Si vous devez acheter du stock, vous avez deux chemins valides. Le chemin standard est Bon de commande → Bon de réception → Facture d'achat : utilisez-le lorsque les marchandises arrivent avant ou séparément de la facture du fournisseur. Si la facture et la réception arrivent ensemble, vous pouvez créer directement la facture d'achat et activer « Mettre à jour le stock » afin que le même document réceptionne le stock et enregistre la dette fournisseur.","tip":"Utilisez d'abord le bon de réception lorsque vous recevez les marchandises séparément. Utilisez la facture d'achat avec « Mettre à jour le stock » lorsqu'une seule étape doit à la fois réceptionner le stock et comptabiliser la facture fournisseur. Dans ce chemin direct, indiquez un entrepôt sur chaque ligne d'article en stock."},"7":{"title":"Créer un bon de livraison","description":"Maintenant que vous avez du stock, revenez à votre commande client validée et cliquez sur « Créer un bon de livraison ». Indiquez l'entrepôt sur chaque ligne d'article (d'où partent les marchandises), puis validez. Cela sort le stock de l'entrepôt – votre solde de stock diminue.","tip":"Le bon de livraison est le document d'expédition. Il réduit le stock mais ne crée pas de facture. Vous pouvez livrer et facturer séparément."},"8":{"title":"Créer et valider la facture de vente","description":"À partir de la commande client validée, créez une facture de vente. Lorsque vous validez la facture, des écritures comptables sont générées : les Clients (créances) sont débités (le client vous doit de l'argent) et les Produits des ventes crédités (revenu acquis). Si des taxes sont configurées, la TVA collectée est également créditée. Le montant dû indique ce que le client doit encore."},"9":{"title":"Enregistrer les paiements clients","description":"Créez un paiement pour enregistrer l'argent reçu du client. Définissez le type de paiement sur « Receive » (Recevoir), sélectionnez le client, indiquez le montant et affectez-le à la facture de vente. Vous pouvez effectuer des paiements partiels – le montant dû de la facture se met à jour en conséquence. Créez des paiements supplémentaires jusqu'à ce que la facture soit entièrement réglée.","tip":"Les paiements partiels sont courants. Une facture de 10 000 peut être payée 3 000 maintenant et 7 000 plus tard. Chaque paiement réduit le montant dû."},"10":{"title":"Mouvements de stock (inventaire manuel)","description":"Utilisez les mouvements de stock pour les mouvements d'inventaire non liés aux achats ou aux ventes. « Material Receipt » ajoute du stock (soldes d'ouverture, ajustements). « Material Issue » sort du stock (pertes, consommation interne). « Material Transfer » déplace du stock entre entrepôts. Chaque mouvement met à jour le livre de stock avec une valorisation au coût moyen pondéré.","tip":"Pour les marchandises achetées, utilisez des bons de réception plutôt que des mouvements de stock – ils sont liés au bon de commande et offrent une piste d'audit appropriée."},"11":{"title":"Écritures de journal","description":"Les écritures de journal sont des ajustements comptables manuels – charges à payer, corrections, reclassements, soldes d'ouverture. Chaque écriture doit avoir des débits et crédits équilibrés (total débit = total crédit). Utilisez-les lorsqu'aucun autre type de document ne convient."},"12":{"title":"Paiements des salaires","description":"Lambda ERP gère les salaires à l'aide des outils comptables existants. Comptabilisez d'abord la charge salariale : créez une écriture de journal qui débite la Charge salariale et crédite les Salaires à payer pour le montant total de la paie. Payez ensuite les employés : créez une autre écriture de journal (ou un paiement) qui débite les Salaires à payer et crédite votre compte bancaire. Ce processus en deux étapes garde vos comptes exacts – la charge est enregistrée dans la bonne période et la sortie de trésorerie est suivie séparément.","tip":"Vous pouvez demander à l'assistant IA de le faire pour vous : « Comptabilise 15 000 de salaires pour avril » suivi de « Paie les salaires d'avril depuis la banque ». Il créera automatiquement les bonnes écritures de journal."},"13":{"title":"Retours et avoirs","description":"Lorsqu'un client retourne des marchandises ou que vous devez émettre un avoir, créez un retour. Les retours utilisent le même type de document avec des quantités négatives. Ouvrez une facture de vente validée et créez un avoir (retour de facture de vente) – cela inverse les écritures comptables et réduit le montant dû de la facture d'origine. Pour le stock, créez un retour de bon de livraison pour réintégrer les marchandises en entrepôt. Côté achats, créez une note de débit (retour de facture d'achat) pour inverser une facture fournisseur, ou un retour de bon de réception pour renvoyer des marchandises.","tip":"Un avoir est simplement une facture de vente avec is_return=1 et des quantités négatives. La même logique comptable s'applique – les montants négatifs basculent automatiquement du bon côté débit/crédit. Pour un retour de vente complet, vous avez besoin à la fois d'un avoir (financier) et d'un retour de bon de livraison (stock)."},"14":{"title":"Exécuter les rapports","description":"Vérifiez vos comptes. Le Compte de résultat montre les produits face aux charges et le résultat net d'une période. Le Bilan montre votre situation financière (actif = passif + capitaux propres). La Balance âgée clients montre qui vous doit de l'argent et le retard. La Balance âgée fournisseurs montre ce que vous devez aux fournisseurs. La Balance comptable vérifie l'intégrité de la partie double. Le Grand livre montre chaque écriture individuelle. Le Solde de stock montre l'inventaire actuel."},"15":{"title":"Travailler en devises étrangères","description":"Vos comptes sont tenus dans une seule devise de base (choisie à la configuration de la société), mais vous pouvez effectuer des transactions dans n'importe quelle devise. Définissez une devise sur une facture ou un effet – ou attribuez une devise par défaut à un client ou un fournisseur – et le taux de change de cette date est recherché automatiquement et enregistré sur le document. Le document conserve ses montants dans sa propre devise, tandis que le Grand livre comptabilise toujours dans votre devise de base. Lorsque vous encaissez ou payez ultérieurement à un taux différent, le gain ou la perte de change réalisé est comptabilisé automatiquement sur un compte Gain/Perte de change. Vous pouvez même détenir un solde bancaire en devise étrangère et le convertir plus tard au taux de votre banque – l'écart par rapport à sa valeur comptable est alors réalisé. En fin de mois, vous pouvez réévaluer les soldes en devises ouverts au taux de clôture (un gain/perte latent qui s'inverse à la période suivante), et vous pouvez consulter n'importe quel état financier converti dans une autre devise pour l'affichage.","tip":"Le plus simple est de passer par le chat IA – essayez « Crée une facture de vente pour Lumiere Audio en EUR », « Montre-moi le bilan en EUR » ou « Quelle est notre exposition de change latente en fin de mois ? ». Les données de démonstration incluent déjà un client EUR (Lumiere Audio SARL) dont la facture a été encaissée à un taux différent, ainsi qu'une facture fournisseur EUR ouverte – ouvrez le Grand livre pour voir les écritures de change réalisées."}},"setupTitle":"Configurez votre entreprise — guidé par l'IA","setupBadge":"Commencez ici","setupBody":"Dites à l'assistant quel type d'entreprise vous dirigez, et il construit votre plan comptable pour vous — adapté à votre secteur, avec les bons comptes et des valeurs par défaut cohérentes déjà en place. Il explique chaque décision et ne crée quoi que ce soit qu'après votre approbation.","setupSectors":"Adapté aux services, au commerce de détail & POS, à l'hôtellerie-restauration, au commerce de gros & distribution, à l'import/export, à la fabrication et à la construction.","setupGetStarted":"Commencer dans le chat","setupManual":"Vous préférez un formulaire manuel ? Utilisez la configuration classique.","setupManualLink":"Configuration classique","setupPrompt":"Je souhaite configurer mon entreprise. Pouvez-vous me guider ?"}`), go = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, fo = { period: "Période", allTime: "Toute la période", semantics: "Comptes de bilan : solde à la fin de la période. Comptes de résultat : mouvement de la période. Cliquez sur un compte pour son grand livre.", empty: "Aucun compte trouvé. Terminez d'abord la configuration de l'entreprise.", disabled: "désactivé", rootType: { Asset: "Actifs", Liability: "Passifs", Equity: "Capitaux propres", Income: "Produits", Expense: "Charges" } }, yo = {
7236
+ common: Yi,
7237
+ language: Ji,
7238
+ header: Zi,
7239
+ titles: Xi,
7240
+ doctypes: eo,
7241
+ masters: to,
7242
+ nav: no,
7243
+ login: ao,
7244
+ settings: ro,
7245
+ status: so,
7246
+ reports: io,
7247
+ masterForm: oo,
7248
+ fields: lo,
7249
+ tables: co,
7250
+ conversions: uo,
7251
+ dashboard: mo,
7252
+ chat: po,
7253
+ tutorial: ho,
7254
+ notesMarkup: go,
7255
+ coa: fo
7256
+ }, Ca = [
7214
7257
  { code: "en", label: "English" },
7215
7258
  { code: "de", label: "Deutsch" },
7216
7259
  { code: "fr", label: "Français" }
7217
- ], Ca = "lambda-erp:language";
7218
- function fo(t) {
7219
- return !!t && ka.some((n) => n.code === t);
7260
+ ], Sa = "lambda-erp:language";
7261
+ function bo(t) {
7262
+ return !!t && Ca.some((n) => n.code === t);
7220
7263
  }
7221
- function yo() {
7264
+ function vo() {
7222
7265
  try {
7223
- const t = localStorage.getItem(Ca);
7224
- if (fo(t)) return t;
7266
+ const t = localStorage.getItem(Sa);
7267
+ if (bo(t)) return t;
7225
7268
  } catch {
7226
7269
  }
7227
7270
  return "en";
7228
7271
  }
7229
- function bo(t) {
7272
+ function xo(t) {
7230
7273
  try {
7231
- localStorage.setItem(Ca, t);
7274
+ localStorage.setItem(Sa, t);
7232
7275
  } catch {
7233
7276
  }
7234
7277
  }
7235
- ta.use(Fa).init({
7278
+ na.use($a).init({
7236
7279
  resources: {
7237
- en: { translation: Di },
7238
- de: { translation: Wi },
7239
- fr: { translation: go }
7280
+ en: { translation: Pi },
7281
+ de: { translation: Qi },
7282
+ fr: { translation: yo }
7240
7283
  },
7241
- lng: yo(),
7284
+ lng: vo(),
7242
7285
  fallbackLng: "en",
7243
7286
  // any key missing in de/fr falls back to the English value
7244
7287
  interpolation: { escapeValue: !1 },
@@ -7246,21 +7289,21 @@ ta.use(Fa).init({
7246
7289
  react: { useSuspense: !1 }
7247
7290
  // resources are bundled synchronously — no Suspense needed
7248
7291
  });
7249
- ta.on("languageChanged", bo);
7250
- function vo({ label: t }) {
7292
+ na.on("languageChanged", xo);
7293
+ function No({ label: t }) {
7251
7294
  var o;
7252
7295
  const { t: n, i18n: a } = X(), s = ((o = a.language) == null ? void 0 : o.split("-")[0]) ?? "en";
7253
7296
  return /* @__PURE__ */ e(
7254
7297
  Ve,
7255
7298
  {
7256
7299
  label: t === null ? void 0 : t ?? n("language.label"),
7257
- options: ka.map((i) => ({ value: i.code, label: i.label })),
7300
+ options: Ca.map((i) => ({ value: i.code, label: i.label })),
7258
7301
  value: s,
7259
7302
  onChange: (i) => a.changeLanguage(i.target.value)
7260
7303
  }
7261
7304
  );
7262
7305
  }
7263
- const Vn = [
7306
+ const Kn = [
7264
7307
  { value: "1h", label: "Last 1 hour", hours: 1 },
7265
7308
  { value: "2h", label: "Last 2 hours", hours: 2 },
7266
7309
  { value: "4h", label: "Last 4 hours", hours: 4 },
@@ -7271,14 +7314,14 @@ const Vn = [
7271
7314
  function We(t) {
7272
7315
  return t === 0 ? "$0.00" : t < 0.01 ? `$${t.toFixed(4)}` : `$${t.toFixed(2)}`;
7273
7316
  }
7274
- function xo({ demoActive: t }) {
7317
+ function wo({ demoActive: t }) {
7275
7318
  var S, x;
7276
7319
  const { t: n } = X(), [a, s] = w("1h"), { data: o, isLoading: i, isFetching: l, error: c, refetch: h, dataUpdatedAt: d } = ue({
7277
7320
  queryKey: ["demo-spend"],
7278
7321
  queryFn: () => I.getDemoSpend(),
7279
7322
  // Refresh once a minute — demo spend changes slowly; no need to poll harder.
7280
7323
  refetchInterval: 6e4
7281
- }), p = Vn.find((y) => y.value === a), u = (S = o == null ? void 0 : o.windows) == null ? void 0 : S[a], f = ((x = o == null ? void 0 : o.caps) == null ? void 0 : x.global_hourly_usd) ?? 0, v = u ? u.demo_usd / p.hours : 0, N = u ? u.total_usd / p.hours : 0, b = f > 0 ? Math.min(100, v / f * 100) : 0, C = b >= 90 ? "bg-red-500" : b >= 60 ? "bg-amber-500" : "bg-emerald-500";
7324
+ }), p = Kn.find((y) => y.value === a), u = (S = o == null ? void 0 : o.windows) == null ? void 0 : S[a], f = ((x = o == null ? void 0 : o.caps) == null ? void 0 : x.global_hourly_usd) ?? 0, v = u ? u.demo_usd / p.hours : 0, N = u ? u.total_usd / p.hours : 0, b = f > 0 ? Math.min(100, v / f * 100) : 0, C = b >= 90 ? "bg-red-500" : b >= 60 ? "bg-amber-500" : "bg-emerald-500";
7282
7325
  return /* @__PURE__ */ r(M, { title: n("settings.tokenSpendTitle"), children: [
7283
7326
  /* @__PURE__ */ r("div", { className: "flex flex-wrap items-end justify-between gap-4", children: [
7284
7327
  /* @__PURE__ */ r("div", { className: "max-w-lg text-sm text-gray-600", children: [
@@ -7297,7 +7340,7 @@ function xo({ demoActive: t }) {
7297
7340
  Ve,
7298
7341
  {
7299
7342
  label: "Time range",
7300
- options: Vn.map((y) => ({ value: y.value, label: y.label })),
7343
+ options: Kn.map((y) => ({ value: y.value, label: y.label })),
7301
7344
  value: a,
7302
7345
  onChange: (y) => s(y.target.value)
7303
7346
  }
@@ -7455,7 +7498,7 @@ function St({ label: t, value: n }) {
7455
7498
  /* @__PURE__ */ e("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-gray-900", children: n })
7456
7499
  ] });
7457
7500
  }
7458
- function No() {
7501
+ function ko() {
7459
7502
  const { t } = X(), { user: n } = st(), [a, s] = w(""), [o, i] = w(""), [l, c] = w(""), [h, d] = w(""), [p, u] = w(!1), f = me({
7460
7503
  mutationFn: () => I.authChangePassword(a, o),
7461
7504
  onSuccess: () => {
@@ -7532,7 +7575,7 @@ function No() {
7532
7575
  /* @__PURE__ */ e(Q, { type: "submit", disabled: f.isPending || !a || !o || !l, children: f.isPending ? t("settings.changingPassword") : t("settings.changePassword") })
7533
7576
  ] }) });
7534
7577
  }
7535
- function wo() {
7578
+ function Co() {
7536
7579
  const { t } = X(), { user: n, refreshUser: a } = st(), [s, o] = w(""), [i, l] = w(""), [c, h] = w(""), [d, p] = w(!1), u = me({
7537
7580
  mutationFn: () => I.authSetPassword(s),
7538
7581
  onSuccess: async () => {
@@ -7598,7 +7641,7 @@ function wo() {
7598
7641
  ] })
7599
7642
  ] });
7600
7643
  }
7601
- function ko() {
7644
+ function So() {
7602
7645
  const { t } = X(), { data: n } = ue({
7603
7646
  queryKey: ["auth-setup-status"],
7604
7647
  queryFn: () => I.authSetupStatus()
@@ -7632,10 +7675,10 @@ function ko() {
7632
7675
  }) })
7633
7676
  ] });
7634
7677
  }
7635
- const Yt = { viewer: 1, manager: 2, admin: 3 };
7636
- function Sa({ ownRole: t }) {
7637
- const { t: n } = X(), { user: a } = st(), s = He(), [o, i] = w(""), [l, c] = w(t in Yt ? t : "viewer"), [h, d] = w(null), [p, u] = w(null), f = ["viewer", "manager", "admin"].filter(
7638
- (g) => Yt[g] <= (Yt[t] ?? 1)
7678
+ const Jt = { viewer: 1, manager: 2, admin: 3 };
7679
+ function Da({ ownRole: t }) {
7680
+ const { t: n } = X(), { user: a } = st(), s = He(), [o, i] = w(""), [l, c] = w(t in Jt ? t : "viewer"), [h, d] = w(null), [p, u] = w(null), f = ["viewer", "manager", "admin"].filter(
7681
+ (g) => Jt[g] <= (Jt[t] ?? 1)
7639
7682
  ), v = `${window.location.origin}/api/mcp`, N = h ? `claude mcp add --transport http --scope user lambda-erp ${v} \\
7640
7683
  --header "Authorization: Bearer ${h}"` : "", b = h ? `# ~/.codex/config.toml
7641
7684
  [mcp_servers.lambda-erp]
@@ -7808,7 +7851,7 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: C } = ue({
7808
7851
  )
7809
7852
  ] });
7810
7853
  }
7811
- function Kn({
7854
+ function jn({
7812
7855
  enabled: t,
7813
7856
  onToggle: n,
7814
7857
  body: a,
@@ -7831,7 +7874,7 @@ function Kn({
7831
7874
  )
7832
7875
  ] });
7833
7876
  }
7834
- function Co({
7877
+ function Do({
7835
7878
  chatEnabled: t,
7836
7879
  restEnabled: n,
7837
7880
  onToggleChat: a,
@@ -7842,7 +7885,7 @@ function Co({
7842
7885
  return /* @__PURE__ */ r(M, { title: i("settings.apiTitle"), children: [
7843
7886
  /* @__PURE__ */ r("div", { className: "space-y-4", children: [
7844
7887
  /* @__PURE__ */ e(
7845
- Kn,
7888
+ jn,
7846
7889
  {
7847
7890
  enabled: t,
7848
7891
  onToggle: () => t ? c("chat") : a(),
@@ -7853,7 +7896,7 @@ function Co({
7853
7896
  ),
7854
7897
  /* @__PURE__ */ e("div", { className: "border-t border-gray-100" }),
7855
7898
  /* @__PURE__ */ e(
7856
- Kn,
7899
+ jn,
7857
7900
  {
7858
7901
  enabled: n,
7859
7902
  onToggle: () => n ? c("rest") : s(),
@@ -7865,7 +7908,7 @@ function Co({
7865
7908
  ] }),
7866
7909
  (t || n) && /* @__PURE__ */ r("div", { className: "mt-4 border-t border-gray-100 pt-4", children: [
7867
7910
  /* @__PURE__ */ e("div", { className: "mb-2 text-xs font-medium text-gray-500", children: i("settings.chatApiKeysTitle") }),
7868
- /* @__PURE__ */ e(Sa, { ownRole: o })
7911
+ /* @__PURE__ */ e(Da, { ownRole: o })
7869
7912
  ] }),
7870
7913
  l && /* @__PURE__ */ e(
7871
7914
  "div",
@@ -7903,7 +7946,7 @@ function Co({
7903
7946
  )
7904
7947
  ] });
7905
7948
  }
7906
- function So() {
7949
+ function Ao() {
7907
7950
  const { user: t } = st(), { t: n } = X(), a = He(), s = (t == null ? void 0 : t.role) === "admin", { data: o, isLoading: i } = ue({
7908
7951
  queryKey: ["settings"],
7909
7952
  queryFn: () => I.getSettings()
@@ -7929,11 +7972,11 @@ function So() {
7929
7972
  });
7930
7973
  return i ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: n("common.loading") }) : /* @__PURE__ */ r("div", { className: "space-y-6", children: [
7931
7974
  /* @__PURE__ */ r(M, { title: n("language.title"), children: [
7932
- /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(vo, {}) }) }),
7975
+ /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(No, {}) }) }),
7933
7976
  /* @__PURE__ */ e("p", { className: "mt-2 text-xs text-gray-400", children: n("language.help") })
7934
7977
  ] }),
7935
- (t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(wo, {}) : /* @__PURE__ */ e(No, {})),
7936
- (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(ko, {}),
7978
+ (t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(Co, {}) : /* @__PURE__ */ e(ko, {})),
7979
+ (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(So, {}),
7937
7980
  /* @__PURE__ */ r(M, { title: n("settings.pdfTitle"), children: [
7938
7981
  /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: s ? /* @__PURE__ */ e(
7939
7982
  Ve,
@@ -7982,7 +8025,7 @@ function So() {
7982
8025
  )
7983
8026
  ] }) }),
7984
8027
  s && /* @__PURE__ */ e(
7985
- Co,
8028
+ Do,
7986
8029
  {
7987
8030
  chatEnabled: (o == null ? void 0 : o.chat_api_enabled) === "1",
7988
8031
  restEnabled: (o == null ? void 0 : o.rest_api_enabled) === "1",
@@ -7997,9 +8040,9 @@ function So() {
7997
8040
  ),
7998
8041
  !s && (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ r(M, { title: n("settings.chatApiKeysTitle"), children: [
7999
8042
  /* @__PURE__ */ e("p", { className: "mb-3 text-sm text-gray-700", children: n("settings.chatApiPersonal") }),
8000
- /* @__PURE__ */ e(Sa, { ownRole: (t == null ? void 0 : t.role) ?? "viewer" })
8043
+ /* @__PURE__ */ e(Da, { ownRole: (t == null ? void 0 : t.role) ?? "viewer" })
8001
8044
  ] }),
8002
- s && /* @__PURE__ */ e(xo, { demoActive: !!(c != null && c.active) }),
8045
+ s && /* @__PURE__ */ e(wo, { demoActive: !!(c != null && c.active) }),
8003
8046
  s && /* @__PURE__ */ e(M, { title: n("settings.publicTitle"), children: c != null && c.active ? /* @__PURE__ */ r("div", { children: [
8004
8047
  /* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
8005
8048
  /* @__PURE__ */ e("span", { className: "inline-block h-2 w-2 rounded-full bg-green-500" }),
@@ -8051,78 +8094,78 @@ function So() {
8051
8094
  (h == null ? void 0 : h.version) && /* @__PURE__ */ e("p", { className: "pt-2 text-center text-xs text-gray-400", children: n("settings.version", { version: h.version }) })
8052
8095
  ] });
8053
8096
  }
8054
- const Da = {};
8055
- function Xo(t, n) {
8056
- Da[t] = n;
8097
+ const Aa = {};
8098
+ function tl(t, n) {
8099
+ Aa[t] = n;
8057
8100
  }
8058
- function Do(t, n) {
8059
- return Da[t] ?? n;
8101
+ function Po(t, n) {
8102
+ return Aa[t] ?? n;
8060
8103
  }
8061
- function Ao() {
8062
- const t = Do("Dashboard", Lr);
8104
+ function _o() {
8105
+ const t = Po("Dashboard", Or);
8063
8106
  return /* @__PURE__ */ e(t, {});
8064
8107
  }
8065
- const Po = [
8066
- { path: "/login", element: /* @__PURE__ */ e(ei, {}) },
8067
- { path: "/demo", element: /* @__PURE__ */ e(ai, {}) }
8068
- ], _o = [
8069
- { index: !0, element: /* @__PURE__ */ e(Ao, {}) },
8070
- { path: "setup", element: /* @__PURE__ */ e(qs, {}) },
8071
- { path: "setup/opening-balances", element: /* @__PURE__ */ e(ri, {}) },
8072
- { path: "tutorial", element: /* @__PURE__ */ e(Ks, {}) },
8073
- { path: "chat", element: /* @__PURE__ */ e(Mn, {}) },
8074
- { path: "chat/:sessionId", element: /* @__PURE__ */ e(Mn, {}) },
8108
+ const To = [
8109
+ { path: "/login", element: /* @__PURE__ */ e(ni, {}) },
8110
+ { path: "/demo", element: /* @__PURE__ */ e(si, {}) }
8111
+ ], Ro = [
8112
+ { index: !0, element: /* @__PURE__ */ e(_o, {}) },
8113
+ { path: "setup", element: /* @__PURE__ */ e(zs, {}) },
8114
+ { path: "setup/opening-balances", element: /* @__PURE__ */ e(ii, {}) },
8115
+ { path: "tutorial", element: /* @__PURE__ */ e(js, {}) },
8116
+ { path: "chat", element: /* @__PURE__ */ e(Fn, {}) },
8117
+ { path: "chat/:sessionId", element: /* @__PURE__ */ e(Fn, {}) },
8075
8118
  // Proposal (Sammelofferte) — a custom builder; the list reuses the generic
8076
8119
  // DocumentList via the `proposal` doctype config. The static "proposal"
8077
8120
  // segment outranks the ":doctype" wildcard below in react-router's matcher.
8078
- { path: "app/proposal/new", element: /* @__PURE__ */ e(Rn, {}) },
8079
- { path: "app/proposal/:name", element: /* @__PURE__ */ e(Rn, {}) },
8121
+ { path: "app/proposal/new", element: /* @__PURE__ */ e(In, {}) },
8122
+ { path: "app/proposal/:name", element: /* @__PURE__ */ e(In, {}) },
8080
8123
  // Documents
8081
- { path: "app/:doctype", element: /* @__PURE__ */ e(es, {}) },
8082
- { path: "app/:doctype/new", element: /* @__PURE__ */ e(Dn, {}) },
8083
- { path: "app/:doctype/:name", element: /* @__PURE__ */ e(Dn, {}) },
8124
+ { path: "app/:doctype", element: /* @__PURE__ */ e(ts, {}) },
8125
+ { path: "app/:doctype/new", element: /* @__PURE__ */ e(An, {}) },
8126
+ { path: "app/:doctype/:name", element: /* @__PURE__ */ e(An, {}) },
8084
8127
  // Masters (reuse same routes - the components detect whether it's a doctype or master)
8085
- { path: "masters/:type", element: /* @__PURE__ */ e(as, {}) },
8086
- { path: "masters/:type/new", element: /* @__PURE__ */ e(Bn, {}) },
8087
- { path: "masters/:type/:name", element: /* @__PURE__ */ e(Bn, {}) },
8128
+ { path: "masters/:type", element: /* @__PURE__ */ e(rs, {}) },
8129
+ { path: "masters/:type/new", element: /* @__PURE__ */ e(En, {}) },
8130
+ { path: "masters/:type/:name", element: /* @__PURE__ */ e(En, {}) },
8088
8131
  // Reports
8089
- { path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(fs, {}) },
8090
- { path: "reports/trial-balance", element: /* @__PURE__ */ e(hs, {}) },
8091
- { path: "reports/general-ledger", element: /* @__PURE__ */ e(vs, {}) },
8092
- { path: "reports/stock-balance", element: /* @__PURE__ */ e(xs, {}) },
8093
- { path: "reports/profit-and-loss", element: /* @__PURE__ */ e(Ns, {}) },
8094
- { path: "reports/balance-sheet", element: /* @__PURE__ */ e(ws, {}) },
8095
- { path: "reports/ar-aging", element: /* @__PURE__ */ e(ks, {}) },
8096
- { path: "reports/ap-aging", element: /* @__PURE__ */ e(Cs, {}) },
8097
- { path: "reports/analytics", element: /* @__PURE__ */ e(As, {}) },
8132
+ { path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(ys, {}) },
8133
+ { path: "reports/trial-balance", element: /* @__PURE__ */ e(gs, {}) },
8134
+ { path: "reports/general-ledger", element: /* @__PURE__ */ e(xs, {}) },
8135
+ { path: "reports/stock-balance", element: /* @__PURE__ */ e(Ns, {}) },
8136
+ { path: "reports/profit-and-loss", element: /* @__PURE__ */ e(ws, {}) },
8137
+ { path: "reports/balance-sheet", element: /* @__PURE__ */ e(ks, {}) },
8138
+ { path: "reports/ar-aging", element: /* @__PURE__ */ e(Cs, {}) },
8139
+ { path: "reports/ap-aging", element: /* @__PURE__ */ e(Ss, {}) },
8140
+ { path: "reports/analytics", element: /* @__PURE__ */ e(Ps, {}) },
8098
8141
  // Admin
8099
- { path: "admin/users", element: /* @__PURE__ */ e(si, {}) },
8100
- { path: "admin/settings", element: /* @__PURE__ */ e(So, {}) }
8101
- ], Aa = [], Pa = [];
8102
- function To(t, n) {
8103
- (n == null ? void 0 : n.area) === "top" ? Aa.push(t) : Pa.push(t);
8104
- }
8105
- const jn = (t) => t.index ? "__index__" : t.path ?? "";
8106
- function Gn(t, n) {
8142
+ { path: "admin/users", element: /* @__PURE__ */ e(oi, {}) },
8143
+ { path: "admin/settings", element: /* @__PURE__ */ e(Ao, {}) }
8144
+ ], Pa = [], _a = [];
8145
+ function Io(t, n) {
8146
+ (n == null ? void 0 : n.area) === "top" ? Pa.push(t) : _a.push(t);
8147
+ }
8148
+ const Gn = (t) => t.index ? "__index__" : t.path ?? "";
8149
+ function Wn(t, n) {
8107
8150
  const a = [...t];
8108
8151
  for (const s of n) {
8109
- const o = jn(s), i = a.findIndex((l) => jn(l) === o);
8152
+ const o = Gn(s), i = a.findIndex((l) => Gn(l) === o);
8110
8153
  i >= 0 ? a[i] = s : a.push(s);
8111
8154
  }
8112
8155
  return a;
8113
8156
  }
8114
- function Ro() {
8157
+ function Bo() {
8115
8158
  return [
8116
- ...Gn(Po, Aa),
8159
+ ...Wn(To, Pa),
8117
8160
  {
8118
8161
  path: "/",
8119
- element: /* @__PURE__ */ e(Tr, { children: /* @__PURE__ */ e(Pr, {}) }),
8120
- children: Gn(_o, Pa)
8162
+ element: /* @__PURE__ */ e(Rr, { children: /* @__PURE__ */ e(_r, {}) }),
8163
+ children: Wn(Ro, _a)
8121
8164
  }
8122
8165
  ];
8123
8166
  }
8124
- function Io({ slug: t, parentSlug: n, linkField: a }) {
8125
- const { name: s = "" } = ut(), o = Ee();
8167
+ function Eo({ slug: t, parentSlug: n, linkField: a }) {
8168
+ const { name: s = "" } = dt(), o = Ee();
8126
8169
  return re(() => {
8127
8170
  let i = !0;
8128
8171
  return I.getDocument(t, s).then((l) => {
@@ -8136,7 +8179,7 @@ function Io({ slug: t, parentSlug: n, linkField: a }) {
8136
8179
  };
8137
8180
  }, [t, s, n, a, o]), /* @__PURE__ */ e("div", { className: "p-6 text-sm text-fg-muted", children: "…" });
8138
8181
  }
8139
- async function Bo() {
8182
+ async function Lo() {
8140
8183
  try {
8141
8184
  const t = await L(
8142
8185
  "/chat-doctypes",
@@ -8144,33 +8187,33 @@ async function Bo() {
8144
8187
  );
8145
8188
  for (const n of t.doctypes || []) {
8146
8189
  const a = n.page;
8147
- a && a.kind === "via" && To({
8190
+ a && a.kind === "via" && Io({
8148
8191
  path: `app/${n.slug}/:name`,
8149
- element: /* @__PURE__ */ e(Io, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
8192
+ element: /* @__PURE__ */ e(Eo, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
8150
8193
  });
8151
8194
  }
8152
8195
  } catch {
8153
8196
  }
8154
8197
  }
8155
- function Eo() {
8156
- return new La({
8198
+ function Oo() {
8199
+ return new Oa({
8157
8200
  defaultOptions: {
8158
8201
  queries: { retry: 1, refetchOnWindowFocus: !1 }
8159
8202
  }
8160
8203
  });
8161
8204
  }
8162
- async function el(t = {}) {
8205
+ async function nl(t = {}) {
8163
8206
  const n = t.rootElement ?? document.getElementById("root");
8164
8207
  if (!n)
8165
8208
  throw new Error('bootstrap: no mount element (pass rootElement or add <div id="root">)');
8166
- const a = t.queryClient ?? Eo();
8167
- await Bo();
8168
- const s = za(Ro());
8169
- Ba(n).render(
8170
- /* @__PURE__ */ e(Ia, { children: /* @__PURE__ */ e(Ea, { client: a, children: /* @__PURE__ */ e(ur, { children: /* @__PURE__ */ e(Ma, { router: s }) }) }) })
8209
+ const a = t.queryClient ?? Oo();
8210
+ await Lo();
8211
+ const s = Ma(Bo());
8212
+ Ea(n).render(
8213
+ /* @__PURE__ */ e(Ba, { children: /* @__PURE__ */ e(La, { client: a, children: /* @__PURE__ */ e(mr, { children: /* @__PURE__ */ e(Fa, { router: s }) }) }) })
8171
8214
  );
8172
8215
  }
8173
- function tl({
8216
+ function al({
8174
8217
  onConfirm: t,
8175
8218
  children: n,
8176
8219
  confirmLabel: a,
@@ -8238,37 +8281,37 @@ function tl({
8238
8281
  }
8239
8282
  export {
8240
8283
  Ue as ApiError,
8241
- Pr as AppShell,
8242
- ur as AuthProvider,
8243
- tl as ConfirmButton,
8244
- yr as DialogProvider,
8245
- fa as DocPager,
8246
- ka as SUPPORTED_LANGUAGES,
8284
+ _r as AppShell,
8285
+ mr as AuthProvider,
8286
+ al as ConfirmButton,
8287
+ br as DialogProvider,
8288
+ ya as DocPager,
8289
+ Ca as SUPPORTED_LANGUAGES,
8247
8290
  I as api,
8248
- el as bootstrap,
8249
- Ro as buildRoutes,
8250
- Go as configureApiBase,
8251
- Yo as configureBranding,
8252
- Eo as createAppQueryClient,
8291
+ nl as bootstrap,
8292
+ Bo as buildRoutes,
8293
+ Ho as configureApiBase,
8294
+ Zo as configureBranding,
8295
+ Oo as createAppQueryClient,
8253
8296
  Ft as formatDate,
8254
- Zo as getAllDoctypeConfigs,
8255
- xr as getBranding,
8256
- Do as getComponent,
8257
- ga as getDoctypeConfig,
8258
- Or as getListContext,
8259
- vr as getNavGroups,
8260
- yo as getStoredLanguage,
8261
- rl as i18n,
8262
- Xo as registerComponent,
8263
- Jo as registerDoctype,
8264
- Ho as registerNavGroup,
8265
- Qo as registerNavItem,
8266
- To as registerRoute,
8297
+ el as getAllDoctypeConfigs,
8298
+ Nr as getBranding,
8299
+ Po as getComponent,
8300
+ fa as getDoctypeConfig,
8301
+ qr as getListContext,
8302
+ xr as getNavGroups,
8303
+ vo as getStoredLanguage,
8304
+ il as i18n,
8305
+ tl as registerComponent,
8306
+ Xo as registerDoctype,
8307
+ Yo as registerNavGroup,
8308
+ Jo as registerNavItem,
8309
+ Io as registerRoute,
8267
8310
  L as request,
8268
- Wo as setDateLocale,
8269
- ha as setListContext,
8311
+ Qo as setDateLocale,
8312
+ ga as setListContext,
8270
8313
  st as useAuth,
8271
- da as useConfirm,
8272
- br as usePrompt
8314
+ ua as useConfirm,
8315
+ vr as usePrompt
8273
8316
  };
8274
8317
  //# sourceMappingURL=index.js.map