@lambda-development/erp-core 1.0.0 → 1.0.2

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
@@ -3,15 +3,15 @@ import { useState as w, useEffect as ce, useCallback as Ue, useContext as Sn, cr
3
3
  import { createRoot as Pr } from "react-dom/client";
4
4
  import { useQueryClient as et, useQuery as ve, useMutation as ke, QueryClientProvider as Tr, QueryClient as Rr } from "@tanstack/react-query";
5
5
  import { NavLink as Yt, useLocation as Ct, useNavigate as Ke, Outlet as Br, Navigate as Bt, Link as Ce, useSearchParams as Jt, useParams as bt, createBrowserRouter as Ir, RouterProvider as Er } from "react-router-dom";
6
- import { useTranslation as se, initReactI18next as Lr } from "react-i18next";
6
+ import { useTranslation as re, initReactI18next as Lr } from "react-i18next";
7
7
  import { BookOpen as Or, ShoppingCart as _a, CreditCard as Fr, FileText as _n, Package as Da, BarChart3 as Mr, CalendarRange as qr, Database as zr, Settings as $r, MessageCircle as Vr, ChevronDown as St, ChevronRight as It, Plus as Pa, Trash2 as Ta, LineChart as Ur, ArrowLeft as Kr, TrendingUp as jr, ArrowDownRight as Wr, ArrowUpRight as Gr, Wallet as Hr, Receipt as zn, ChevronLeft as Qr, Info as Yr, Search as $n, Filter as Jr, X as Zr, SlidersHorizontal as Ra, ChevronUp as Ba, ChevronsUpDown as Ia, FileUp as Xr, Loader2 as yn, CheckCircle2 as bn, AlertTriangle as es, RefreshCw as ts, Undo2 as ns } from "lucide-react";
8
8
  import { createColumnHelper as Ea, useReactTable as La, getCoreRowModel as Oa, flexRender as Wt } from "@tanstack/react-table";
9
9
  import { createPortal as Fa } from "react-dom";
10
10
  import { ResponsiveContainer as as, LineChart as rs, CartesianGrid as Vn, XAxis as Un, YAxis as Kn, Tooltip as an, Legend as jn, Line as ss, PieChart as is, Pie as os, Cell as ls, BarChart as cs, Bar as ds } from "recharts";
11
11
  import Ma from "i18next";
12
- import { default as jc } from "i18next";
12
+ import { default as Qc } from "i18next";
13
13
  let ot = "/api";
14
- function Rc(e) {
14
+ function Lc(e) {
15
15
  ot = e.replace(/\/+$/, "");
16
16
  }
17
17
  function qa(e) {
@@ -415,7 +415,7 @@ function ut(e) {
415
415
  return Number.isNaN(a) ? 0 : a;
416
416
  }
417
417
  function hs({ children: e }) {
418
- const n = et(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [h, d] = w({}), [g, m] = w({}), [b, v] = w({}), [k, y] = w({}), [A, S] = w({}), [x, p] = w(null), [f, B] = w("connecting"), [E, J] = w(0), Z = pe(null), O = pe(null), q = pe(/* @__PURE__ */ new Map()), Q = pe(null), N = pe({}), D = pe({}), $ = pe(null);
418
+ const n = et(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [h, d] = w({}), [g, m] = w({}), [b, v] = w({}), [k, y] = w({}), [A, S] = w({}), [x, p] = w(null), [f, B] = w("connecting"), [E, J] = w(0), Z = pe(null), L = pe(null), q = pe(/* @__PURE__ */ new Map()), Q = pe(null), N = pe({}), D = pe({}), $ = pe(null);
419
419
  function u(C) {
420
420
  for (const j of q.current.values())
421
421
  j.reject(new Error(C));
@@ -450,7 +450,7 @@ function hs({ children: e }) {
450
450
  function Ne(C) {
451
451
  s((j) => ue(C(j)));
452
452
  }
453
- function xe(C, j) {
453
+ function be(C, j) {
454
454
  const G = j || (/* @__PURE__ */ new Date()).toISOString(), ye = N.current[C];
455
455
  ut(G) >= ut(ye) && (N.current = {
456
456
  ...N.current,
@@ -499,13 +499,13 @@ function hs({ children: e }) {
499
499
  }, we.onmessage = ($e) => {
500
500
  var Te;
501
501
  try {
502
- const re = JSON.parse($e.data), gt = typeof re.request_id == "string" ? re.request_id : null, Le = typeof re.type == "string" ? re.type : null, X = typeof re.session_id == "string" ? re.session_id : null;
502
+ const se = JSON.parse($e.data), gt = typeof se.request_id == "string" ? se.request_id : null, Le = typeof se.type == "string" ? se.type : null, X = typeof se.session_id == "string" ? se.session_id : null;
503
503
  if (gt) {
504
504
  const ee = q.current.get(gt);
505
- ee && (Le === "error" ? (q.current.delete(gt), ee.reject(new Error(String(re.content || "Request failed.")))) : Le === ee.expectedType && (q.current.delete(gt), ee.resolve(re)));
505
+ ee && (Le === "error" ? (q.current.delete(gt), ee.reject(new Error(String(se.content || "Request failed.")))) : Le === ee.expectedType && (q.current.delete(gt), ee.resolve(se)));
506
506
  }
507
507
  if (Le === "sessions_list") {
508
- const ee = Array.isArray(re.sessions) ? re.sessions : [];
508
+ const ee = Array.isArray(se.sessions) ? se.sessions : [];
509
509
  qe(ee), s(
510
510
  ue(
511
511
  ee
@@ -531,7 +531,7 @@ function hs({ children: e }) {
531
531
  return;
532
532
  }
533
533
  if (Le === "session_created") {
534
- const ee = re.session;
534
+ const ee = se.session;
535
535
  if (!ee) return;
536
536
  ja(ee.id), qe([ee]), Ne((ie) => [ee, ...ie.filter((de) => de.id !== ee.id)]);
537
537
  return;
@@ -564,7 +564,7 @@ function hs({ children: e }) {
564
564
  return;
565
565
  }
566
566
  if (Le === "history_loaded" && X) {
567
- const ee = Array.isArray(re.messages) ? re.messages.map(Qn) : [], ie = re.before_id != null, de = !!re.has_more, Je = typeof re.oldest_id == "number" ? re.oldest_id : null;
567
+ const ee = Array.isArray(se.messages) ? se.messages.map(Qn) : [], ie = se.before_id != null, de = !!se.has_more, Je = typeof se.oldest_id == "number" ? se.oldest_id : null;
568
568
  i((Se) => {
569
569
  if (ie) {
570
570
  const Oe = Se[X] ?? [], At = new Set(
@@ -576,12 +576,12 @@ function hs({ children: e }) {
576
576
  }
577
577
  return { ...Se, [X]: ee };
578
578
  }), c((Se) => ({ ...Se, [X]: de })), d((Se) => ({ ...Se, [X]: Je })), m((Se) => ({ ...Se, [X]: !1 }));
579
- const Ve = typeof re.title == "string" ? re.title : null;
579
+ const Ve = typeof se.title == "string" ? se.title : null;
580
580
  if (Ve && Ne(
581
581
  (Se) => Se.map((Oe) => Oe.id === X ? { ...Oe, title: Ve } : Oe)
582
582
  ), !ie) {
583
583
  const Se = ee[ee.length - 1];
584
- Se != null && Se.timestamp && (xe(X, Se.timestamp), Ne((Oe) => Oe));
584
+ Se != null && Se.timestamp && (be(X, Se.timestamp), Ne((Oe) => Oe));
585
585
  }
586
586
  return;
587
587
  }
@@ -590,9 +590,9 @@ function hs({ children: e }) {
590
590
  return;
591
591
  }
592
592
  if (Le === "message_added" && X) {
593
- const ee = re.message;
593
+ const ee = se.message;
594
594
  if (!ee) return;
595
- xe(X, ee.created_at), ee.role === "user" && W(X, null), P(X, (ie) => [
595
+ be(X, ee.created_at), ee.role === "user" && W(X, null), P(X, (ie) => [
596
596
  ...ie.filter((de) => de.type !== "thinking"),
597
597
  Qn(ee)
598
598
  ]), Ne((ie) => ie);
@@ -604,9 +604,9 @@ function hs({ children: e }) {
604
604
  }
605
605
  if (Le === "demo_typing" && X) {
606
606
  T(X, "running"), W(X, {
607
- content: String(re.content || ""),
608
- seq: Math.max(0, Number(re.seq || 0)),
609
- typingMs: Math.max(0, Number(re.typing_ms || 0))
607
+ content: String(se.content || ""),
608
+ seq: Math.max(0, Number(se.seq || 0)),
609
+ typingMs: Math.max(0, Number(se.typing_ms || 0))
610
610
  });
611
611
  return;
612
612
  }
@@ -615,12 +615,12 @@ function hs({ children: e }) {
615
615
  return;
616
616
  }
617
617
  if (Le === "navigation_flash") {
618
- const ee = typeof re.group == "string" ? re.group : "", ie = typeof re.item == "string" ? re.item : void 0;
618
+ const ee = typeof se.group == "string" ? se.group : "", ie = typeof se.item == "string" ? se.item : void 0;
619
619
  ee && le(ee, ie);
620
620
  return;
621
621
  }
622
622
  if (Le === "session_title_updated" && X) {
623
- const ee = typeof re.title == "string" ? re.title : "";
623
+ const ee = typeof se.title == "string" ? se.title : "";
624
624
  Ne(
625
625
  (ie) => ie.map((de) => de.id === X ? { ...de, title: ee } : de)
626
626
  );
@@ -633,7 +633,7 @@ function hs({ children: e }) {
633
633
  ...ee.filter((de) => de.type !== "thinking"),
634
634
  {
635
635
  type: "thinking",
636
- content: `Thinking (step ${re.iteration})...`,
636
+ content: `Thinking (step ${se.iteration})...`,
637
637
  provider: ie == null ? void 0 : ie.provider,
638
638
  model: ie == null ? void 0 : ie.model
639
639
  }
@@ -642,7 +642,7 @@ function hs({ children: e }) {
642
642
  return;
643
643
  }
644
644
  if (Le === "llm_provider" && X) {
645
- const ee = typeof re.provider == "string" ? re.provider : void 0, ie = typeof re.model == "string" ? re.model : void 0, de = typeof re.role == "string" ? re.role : void 0, Je = de === "report_specialist" || de === "code_specialist" ? "Delegating to report specialist..." : void 0;
645
+ const ee = typeof se.provider == "string" ? se.provider : void 0, ie = typeof se.model == "string" ? se.model : void 0, de = typeof se.role == "string" ? se.role : void 0, Je = de === "report_specialist" || de === "code_specialist" ? "Delegating to report specialist..." : void 0;
646
646
  V(X, !0), P(X, (Ve) => Ve.some((Oe) => Oe.type === "thinking") ? Ve.map((Oe) => Oe.type === "thinking" ? {
647
647
  ...Oe,
648
648
  provider: ee,
@@ -663,25 +663,25 @@ function hs({ children: e }) {
663
663
  D.current = {
664
664
  ...D.current,
665
665
  [X]: {
666
- tool: String(re.tool || ""),
667
- args: re.args
666
+ tool: String(se.tool || ""),
667
+ args: se.args
668
668
  }
669
669
  }, P(X, (ee) => [
670
670
  ...ee.filter((ie) => ie.type !== "thinking"),
671
671
  {
672
672
  type: "tool_call",
673
- content: `Calling ${re.tool}...`,
674
- tool: re.tool,
675
- args: re.args
673
+ content: `Calling ${se.tool}...`,
674
+ tool: se.tool,
675
+ args: se.args
676
676
  }
677
677
  ]);
678
678
  return;
679
679
  }
680
680
  if (Le === "tool_result" && X) {
681
681
  const ee = D.current[X];
682
- if (ee && ee.tool === String(re.tool || "") && re.success)
682
+ if (ee && ee.tool === String(se.tool || "") && se.success)
683
683
  if (ee.tool === "create_custom_analytics_report" || ee.tool === "update_custom_analytics_report") {
684
- const de = typeof re.report_id == "string" ? re.report_id : void 0, Je = typeof ((Te = ee.args) == null ? void 0 : Te.report_id) == "string" ? ee.args.report_id : void 0;
684
+ const de = typeof se.report_id == "string" ? se.report_id : void 0, Je = typeof ((Te = ee.args) == null ? void 0 : Te.report_id) == "string" ? ee.args.report_id : void 0;
685
685
  le("Custom Analytics", de || Je || ""), n.invalidateQueries({ queryKey: ["runtime-drafts"] });
686
686
  } else {
687
687
  const de = ms(ee.tool, ee.args);
@@ -694,9 +694,9 @@ function hs({ children: e }) {
694
694
  ...ie,
695
695
  {
696
696
  type: "tool_result",
697
- content: String(re.summary || ""),
698
- tool: re.tool,
699
- success: !!re.success
697
+ content: String(se.summary || ""),
698
+ tool: se.tool,
699
+ success: !!se.success
700
700
  }
701
701
  ]);
702
702
  return;
@@ -710,7 +710,7 @@ function hs({ children: e }) {
710
710
  return;
711
711
  X && (V(X, !1), P(X, (ee) => [
712
712
  ...ee.filter((ie) => ie.type !== "thinking"),
713
- { type: "error", content: String(re.content || "Chat error.") }
713
+ { type: "error", content: String(se.content || "Chat error.") }
714
714
  ]));
715
715
  }
716
716
  } catch {
@@ -723,18 +723,18 @@ function hs({ children: e }) {
723
723
  window.location.href = "/login";
724
724
  return;
725
725
  }
726
- O.current = window.setTimeout(j, 3e3);
726
+ L.current = window.setTimeout(j, 3e3);
727
727
  }
728
728
  };
729
729
  }
730
730
  return j(), () => {
731
- if (C = !0, O.current !== null && window.clearTimeout(O.current), $.current !== null && window.clearTimeout($.current), u("Chat disconnected."), Z.current) {
731
+ if (C = !0, L.current !== null && window.clearTimeout(L.current), $.current !== null && window.clearTimeout($.current), u("Chat disconnected."), Z.current) {
732
732
  const G = Z.current;
733
733
  Z.current = null, G.close();
734
734
  }
735
735
  };
736
736
  }, []);
737
- async function be() {
737
+ async function xe() {
738
738
  if (Q.current)
739
739
  return Q.current;
740
740
  const C = ae("create_session", {}, "session_created").then((j) => j.session).finally(() => {
@@ -742,7 +742,7 @@ function hs({ children: e }) {
742
742
  });
743
743
  return Q.current = C, C;
744
744
  }
745
- async function L(C) {
745
+ async function O(C) {
746
746
  T(C, "running"), W(C, null);
747
747
  try {
748
748
  await ae("start_demo", { session_id: C }, "demo_started");
@@ -832,8 +832,8 @@ function hs({ children: e }) {
832
832
  connectionStatus: f,
833
833
  connectionVersion: E,
834
834
  navigationFlash: x,
835
- createSession: be,
836
- startDemo: L,
835
+ createSession: xe,
836
+ startDemo: O,
837
837
  completeDemoTyping: oe,
838
838
  deleteSession: Ie,
839
839
  loadHistory: Ae,
@@ -875,7 +875,7 @@ function vn(e, n = 2) {
875
875
  }).format(e ?? 0);
876
876
  }
877
877
  let Pn;
878
- function Bc(e) {
878
+ function Oc(e) {
879
879
  Pn = e;
880
880
  }
881
881
  function De(e = /* @__PURE__ */ new Date()) {
@@ -998,7 +998,7 @@ function me({ label: e, hint: n, error: a, className: s, id: o, ...i }) {
998
998
  }
999
999
  const Ga = An(null);
1000
1000
  function ys({ children: e }) {
1001
- const { t: n } = se(), [a, s] = w(null), [o, i] = w(""), l = Ue(
1001
+ const { t: n } = re(), [a, s] = w(null), [o, i] = w(""), l = Ue(
1002
1002
  (b) => new Promise((v) => s({ kind: "confirm", opts: b, resolve: v })),
1003
1003
  []
1004
1004
  ), c = Ue(
@@ -1160,7 +1160,7 @@ const yt = [
1160
1160
  function vs() {
1161
1161
  return yt;
1162
1162
  }
1163
- function Ic(e, n) {
1163
+ function Fc(e, n) {
1164
1164
  const a = yt.findIndex((s) => s.label === e.label);
1165
1165
  if (a >= 0) {
1166
1166
  yt[a] = e;
@@ -1168,12 +1168,12 @@ function Ic(e, n) {
1168
1168
  }
1169
1169
  (n == null ? void 0 : n.index) != null ? yt.splice(n.index, 0, e) : yt.push(e);
1170
1170
  }
1171
- function Ec(e, n) {
1171
+ function Mc(e, n) {
1172
1172
  const a = yt.find((s) => s.label === e);
1173
1173
  a ? a.items.push(n) : yt.push({ label: e, icon: null, items: [n] });
1174
1174
  }
1175
1175
  let xn = { appName: "Lambda ERP" };
1176
- function Lc(e) {
1176
+ function qc(e) {
1177
1177
  if (xn = { ...xn, ...e }, !(typeof document > "u") && (e.appName && (document.title = e.appName), e.tokens)) {
1178
1178
  const n = document.documentElement;
1179
1179
  for (const [a, s] of Object.entries(e.tokens))
@@ -1222,7 +1222,7 @@ const Bn = {
1222
1222
  "Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
1223
1223
  };
1224
1224
  function xs() {
1225
- const [e, n] = Rn("chats"), a = Ct(), s = Ke(), { t: o } = se(), { sessions: i, createSession: l, deleteSession: c } = vt(), h = async () => {
1225
+ const [e, n] = Rn("chats"), a = Ct(), s = Ke(), { t: o } = re(), { sessions: i, createSession: l, deleteSession: c } = vt(), h = async () => {
1226
1226
  try {
1227
1227
  const g = await l();
1228
1228
  s(`/chat/${g.id}`);
@@ -1300,7 +1300,7 @@ function In() {
1300
1300
  );
1301
1301
  }
1302
1302
  function ks() {
1303
- const [e, n, a] = Rn("custom-analytics"), s = Ct(), o = Ke(), i = et(), { t: l } = se(), { navigationFlash: c, sessions: h, createSession: d } = vt(), g = (c == null ? void 0 : c.group) === "Custom Analytics", m = Bn["Custom Analytics"], { data: b } = ve({
1303
+ const [e, n, a] = Rn("custom-analytics"), s = Ct(), o = Ke(), i = et(), { t: l } = re(), { navigationFlash: c, sessions: h, createSession: d } = vt(), g = (c == null ? void 0 : c.group) === "Custom Analytics", m = Bn["Custom Analytics"], { data: b } = ve({
1304
1304
  queryKey: ["runtime-drafts"],
1305
1305
  queryFn: () => F.listRuntimeDrafts(),
1306
1306
  staleTime: 3e4
@@ -1390,7 +1390,7 @@ function ks() {
1390
1390
  ] });
1391
1391
  }
1392
1392
  function Ns({ group: e }) {
1393
- const [n, a] = Rn(e.label), { t: s } = se(), { navigationFlash: o } = vt(), i = (o == null ? void 0 : o.group) === e.label, l = Bn[e.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
1393
+ const [n, a] = Rn(e.label), { t: s } = re(), { navigationFlash: o } = vt(), i = (o == null ? void 0 : o.group) === e.label, l = Bn[e.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
1394
1394
  return /* @__PURE__ */ r("div", { children: [
1395
1395
  /* @__PURE__ */ r(
1396
1396
  "button",
@@ -1568,7 +1568,7 @@ function _s() {
1568
1568
  return /* @__PURE__ */ t(ys, { children: /* @__PURE__ */ t(hs, { children: /* @__PURE__ */ t(Ds, {}) }) });
1569
1569
  }
1570
1570
  function Ds() {
1571
- const { pathname: e } = Ct(), n = Ke(), { user: a, logout: s } = Ze(), { navigationFlash: o } = vt(), { t: i, i18n: l } = se(), { settings: c } = Zt();
1571
+ const { pathname: e } = Ct(), n = Ke(), { user: a, logout: s } = Ze(), { navigationFlash: o } = vt(), { t: i, i18n: l } = re(), { settings: c } = Zt();
1572
1572
  ce(() => {
1573
1573
  const k = c.language;
1574
1574
  k && k !== (l.language || "").split("-")[0] && l.changeLanguage(k);
@@ -1718,7 +1718,7 @@ const Bs = {
1718
1718
  Overdue: "danger"
1719
1719
  };
1720
1720
  function En({ status: e }) {
1721
- const { t: n } = se(), a = Bs[e] ?? "secondary";
1721
+ const { t: n } = re(), a = Bs[e] ?? "secondary";
1722
1722
  return /* @__PURE__ */ t(Ut, { variant: a, children: n(`status.${e}`, { defaultValue: e }) });
1723
1723
  }
1724
1724
  function Qe(e) {
@@ -1763,7 +1763,7 @@ const Is = {
1763
1763
  Quotation: _n
1764
1764
  };
1765
1765
  function Es({ doc: e }) {
1766
- const { t: n } = se(), a = e.doctype ?? e.type ?? "Document", s = e.creation ?? e.date, o = Is[a] ?? _n, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(e.name)}`;
1766
+ const { t: n } = re(), a = e.doctype ?? e.type ?? "Document", s = e.creation ?? e.date, o = Is[a] ?? _n, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(e.name)}`;
1767
1767
  return /* @__PURE__ */ r(
1768
1768
  Ce,
1769
1769
  {
@@ -1793,7 +1793,7 @@ function Dt() {
1793
1793
  ] });
1794
1794
  }
1795
1795
  function Ls() {
1796
- const { t: e } = se();
1796
+ const { t: e } = re();
1797
1797
  Me(e("titles.dashboard"));
1798
1798
  const { data: n, isLoading: a } = ve({
1799
1799
  queryKey: ["dashboard-summary"],
@@ -2716,15 +2716,15 @@ const ht = [
2716
2716
  function er(e) {
2717
2717
  return Ln[e];
2718
2718
  }
2719
- function Oc(e) {
2719
+ function zc(e) {
2720
2720
  Ln[e.slug] = e;
2721
2721
  }
2722
- function Fc() {
2722
+ function $c() {
2723
2723
  return Object.values(Ln);
2724
2724
  }
2725
2725
  function tr({ doctype: e, name: n }) {
2726
2726
  var d;
2727
- const { t: a } = se(), [s, o] = w(null), [i, l] = w(!1), { data: c } = ve({
2727
+ const { t: a } = re(), [s, o] = w(null), [i, l] = w(!1), { data: c } = ve({
2728
2728
  queryKey: ["document-fields", e],
2729
2729
  queryFn: () => F.documentFields(e)
2730
2730
  });
@@ -2852,7 +2852,7 @@ function qs({ text: e }) {
2852
2852
  ] });
2853
2853
  }
2854
2854
  function zs() {
2855
- const { t: e } = se(), [n, a] = w(!1), s = [
2855
+ const { t: e } = re(), [n, a] = w(!1), s = [
2856
2856
  ["# Heading", e("notesMarkup.heading", { defaultValue: "bold heading" })],
2857
2857
  ["*italic* **bold**", e("notesMarkup.emphasis", { defaultValue: "italic / bold" })],
2858
2858
  ["---", e("notesMarkup.rule", { defaultValue: "horizontal divider line" })],
@@ -2995,7 +2995,7 @@ function Kt({
2995
2995
  doctype: c
2996
2996
  }) {
2997
2997
  var y;
2998
- const { t: h } = se(), d = s || !!e.readOnly, g = () => i ? null : /* @__PURE__ */ t(
2998
+ const { t: h } = re(), d = s || !!e.readOnly, g = () => i ? null : /* @__PURE__ */ t(
2999
2999
  ea,
3000
3000
  {
3001
3001
  label: h(`fields.${e.label}`, { defaultValue: e.label }),
@@ -3114,7 +3114,7 @@ function Ks({
3114
3114
  readOnly: s,
3115
3115
  currency: o = "USD"
3116
3116
  }) {
3117
- const { t: i } = se(), l = (d, g, m) => {
3117
+ const { t: i } = re(), l = (d, g, m) => {
3118
3118
  const b = n.map(
3119
3119
  (v, k) => k === d ? { ...v, [g]: m } : v
3120
3120
  );
@@ -3186,7 +3186,7 @@ function js({
3186
3186
  softCancelDone: v,
3187
3187
  draftReadOnly: k
3188
3188
  }) {
3189
- const { t: y } = se(), [A, S] = w(!1), [x, p] = w(!1), [f, B] = w(!1);
3189
+ const { t: y } = re(), [A, S] = w(!1), [x, p] = w(!1), [f, B] = w(!1);
3190
3190
  if (!l) return null;
3191
3191
  const E = !e && l.canCancel && s === 1;
3192
3192
  return /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-2", children: [
@@ -3266,15 +3266,15 @@ function ta(e, n) {
3266
3266
  return a;
3267
3267
  }
3268
3268
  function na() {
3269
- var ae, be;
3270
- const { doctype: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = se(), i = er(e ?? ""), l = !n;
3269
+ var ae, xe;
3270
+ const { doctype: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = re(), i = er(e ?? ""), l = !n;
3271
3271
  Me(l ? (i == null ? void 0 : i.label) ?? null : n ?? (i == null ? void 0 : i.label) ?? null);
3272
3272
  const [c, h] = w({}), [d, g] = w(!1), { data: m, isLoading: b } = ve({
3273
3273
  queryKey: ["document", e, n],
3274
3274
  queryFn: () => F.getDocument(e, n),
3275
3275
  enabled: !!e && !!n && !l
3276
3276
  }), v = fe(
3277
- () => !!(i != null && i.fields.some((L) => L.name === "currency")),
3277
+ () => !!(i != null && i.fields.some((O) => O.name === "currency")),
3278
3278
  [i]
3279
3279
  ), k = i == null ? void 0 : i.partyField, y = k ? c[k] : void 0, A = Qe(c.company), { data: S } = ve({
3280
3280
  queryKey: ["master", k, y],
@@ -3284,13 +3284,13 @@ function na() {
3284
3284
  });
3285
3285
  ce(() => {
3286
3286
  if (!l || !v || d) return;
3287
- let L;
3287
+ let O;
3288
3288
  if (y) {
3289
3289
  if (!S) return;
3290
- L = S.default_currency || A;
3290
+ O = S.default_currency || A;
3291
3291
  } else
3292
- L = A;
3293
- L && L !== c.currency && h((oe) => ({ ...oe, currency: L }));
3292
+ O = A;
3293
+ O && O !== c.currency && h((oe) => ({ ...oe, currency: O }));
3294
3294
  }, [
3295
3295
  l,
3296
3296
  v,
@@ -3301,33 +3301,33 @@ function na() {
3301
3301
  c.currency
3302
3302
  ]), ce(() => {
3303
3303
  if (l && i) {
3304
- const L = {};
3304
+ const O = {};
3305
3305
  i.fields.forEach((oe) => {
3306
- oe.type === "date" ? L[oe.name] = De() : L[oe.name] = oe.default ?? "";
3306
+ oe.type === "date" ? O[oe.name] = De() : O[oe.name] = oe.default ?? "";
3307
3307
  }), i.childTables.forEach((oe) => {
3308
- L[oe.key] = [];
3309
- }), L.docstatus = 0, h(L);
3308
+ O[oe.key] = [];
3309
+ }), O.docstatus = 0, h(O);
3310
3310
  } else m && h(m);
3311
3311
  }, [l, m, i]);
3312
3312
  const x = ke({
3313
- mutationFn: (L) => F.createDocument(e, L),
3314
- onSuccess: (L) => {
3315
- s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}/${L.name}`, { replace: !0 });
3313
+ mutationFn: (O) => F.createDocument(e, O),
3314
+ onSuccess: (O) => {
3315
+ s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}/${O.name}`, { replace: !0 });
3316
3316
  }
3317
3317
  }), p = ke({
3318
- mutationFn: (L) => F.updateDocument(e, n, L),
3319
- onSuccess: (L) => {
3320
- s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), h(L);
3318
+ mutationFn: (O) => F.updateDocument(e, n, O),
3319
+ onSuccess: (O) => {
3320
+ s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), h(O);
3321
3321
  }
3322
3322
  }), f = ke({
3323
3323
  mutationFn: () => F.submitDocument(e, n),
3324
- onSuccess: (L) => {
3325
- h(L), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
3324
+ onSuccess: (O) => {
3325
+ h(O), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
3326
3326
  }
3327
3327
  }), B = ke({
3328
3328
  mutationFn: () => F.cancelDocument(e, n),
3329
- onSuccess: (L) => {
3330
- h(L), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
3329
+ onSuccess: (O) => {
3330
+ h(O), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
3331
3331
  }
3332
3332
  }), E = ke({
3333
3333
  mutationFn: () => F.discardDocument(e, n),
@@ -3335,23 +3335,23 @@ function na() {
3335
3335
  s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}`, { replace: !0 });
3336
3336
  }
3337
3337
  }), J = ke({
3338
- mutationFn: (L) => F.convertDocument(e, n, L),
3339
- onSuccess: (L, oe) => {
3338
+ mutationFn: (O) => F.convertDocument(e, n, O),
3339
+ onSuccess: (O, oe) => {
3340
3340
  const Ie = oe.toLowerCase().replace(/\s+/g, "-");
3341
- a(`/app/${Ie}/${L.name}`);
3341
+ a(`/app/${Ie}/${O.name}`);
3342
3342
  }
3343
3343
  }), Z = Ue(
3344
- (L, oe) => {
3345
- L === "currency" && g(!0), h((Ie) => {
3346
- const Ae = { ...Ie, [L]: oe };
3347
- return L === "currency" && (Ae.conversion_rate = 0), e === "reservation" && L === "asset" && oe && (Ae.allocation_mode = "Unit"), ta(Ae, i);
3344
+ (O, oe) => {
3345
+ O === "currency" && g(!0), h((Ie) => {
3346
+ const Ae = { ...Ie, [O]: oe };
3347
+ return O === "currency" && (Ae.conversion_rate = 0), e === "reservation" && O === "asset" && oe && (Ae.allocation_mode = "Unit"), ta(Ae, i);
3348
3348
  });
3349
3349
  },
3350
3350
  [i, e]
3351
- ), O = Ue(
3352
- (L, oe) => {
3351
+ ), L = Ue(
3352
+ (O, oe) => {
3353
3353
  h((Ie) => {
3354
- const Ae = { ...Ie, [L]: oe };
3354
+ const Ae = { ...Ie, [O]: oe };
3355
3355
  return ta(Ae, i);
3356
3356
  });
3357
3357
  },
@@ -3362,8 +3362,8 @@ function na() {
3362
3362
  f.mutate();
3363
3363
  }, N = () => {
3364
3364
  B.mutate();
3365
- }, D = (L) => {
3366
- J.mutate(L);
3365
+ }, D = (O) => {
3366
+ J.mutate(O);
3367
3367
  }, $ = () => {
3368
3368
  E.mutate();
3369
3369
  }, u = () => {
@@ -3376,7 +3376,7 @@ function na() {
3376
3376
  ] });
3377
3377
  if (!l && b)
3378
3378
  return /* @__PURE__ */ t("p", { className: "text-fg-muted", children: o("common.loading") });
3379
- const P = c.docstatus ?? 0, V = !!c.discarded, T = e === "bank-transaction" && !!c.bank_statement_import, W = P >= 1 || V || T, le = c.currency || A, ue = Xe(c.conversion_rate ?? 1), Ne = i.fields.filter((L) => !L.readOnly), xe = Ne.filter((L) => L.type !== "textarea"), qe = Ne.filter((L) => L.type === "textarea"), R = i.fields.filter((L) => L.readOnly);
3379
+ const P = c.docstatus ?? 0, V = !!c.discarded, T = e === "bank-transaction" && !!c.bank_statement_import, W = P >= 1 || V || T, le = c.currency || A, ue = Xe(c.conversion_rate ?? 1), Ne = i.fields.filter((O) => !O.readOnly), be = Ne.filter((O) => O.type !== "textarea"), qe = Ne.filter((O) => O.type === "textarea"), R = i.fields.filter((O) => O.readOnly);
3380
3380
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
3381
3381
  /* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
3382
3382
  /* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
@@ -3419,57 +3419,57 @@ function na() {
3419
3419
  )
3420
3420
  ] }),
3421
3421
  (x.error || p.error || f.error || B.error) && /* @__PURE__ */ t("div", { className: "rounded-lg bg-rose-50 p-4 text-sm text-rose-700 ring-1 ring-rose-200", children: ((ae = x.error ?? p.error ?? f.error ?? B.error) == null ? void 0 : ae.message) ?? o("common.errorOccurred") }),
3422
- (((be = c._validation) == null ? void 0 : be.warnings) ?? []).map((L) => /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-900", role: "status", children: L.code === "asset_unassigned" ? o("rentals.poolWarning") : L.message }, L.code)),
3422
+ (((xe = c._validation) == null ? void 0 : xe.warnings) ?? []).map((O) => /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-900", role: "status", children: O.code === "asset_unassigned" ? o("rentals.poolWarning") : O.message }, O.code)),
3423
3423
  /* @__PURE__ */ r(H, { children: [
3424
- /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: xe.map((L) => /* @__PURE__ */ t(
3424
+ /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: be.map((O) => /* @__PURE__ */ t(
3425
3425
  Kt,
3426
3426
  {
3427
- field: L,
3428
- value: c[L.name],
3429
- onChange: (oe) => Z(L.name, oe),
3427
+ field: O,
3428
+ value: c[O.name],
3429
+ onChange: (oe) => Z(O.name, oe),
3430
3430
  readOnly: W,
3431
3431
  rowData: c,
3432
3432
  currency: le,
3433
3433
  doctype: e
3434
3434
  },
3435
- L.name
3435
+ O.name
3436
3436
  )) }),
3437
- qe.length > 0 && /* @__PURE__ */ t("div", { className: "mt-4 space-y-4", children: qe.map((L) => /* @__PURE__ */ t(
3437
+ qe.length > 0 && /* @__PURE__ */ t("div", { className: "mt-4 space-y-4", children: qe.map((O) => /* @__PURE__ */ t(
3438
3438
  Kt,
3439
3439
  {
3440
- field: L,
3441
- value: c[L.name],
3442
- onChange: (oe) => Z(L.name, oe),
3440
+ field: O,
3441
+ value: c[O.name],
3442
+ onChange: (oe) => Z(O.name, oe),
3443
3443
  readOnly: W,
3444
3444
  rowData: c,
3445
3445
  currency: le,
3446
3446
  doctype: e
3447
3447
  },
3448
- L.name
3448
+ O.name
3449
3449
  )) })
3450
3450
  ] }),
3451
- i.childTables.map((L) => /* @__PURE__ */ t(
3451
+ i.childTables.map((O) => /* @__PURE__ */ t(
3452
3452
  Ks,
3453
3453
  {
3454
- tableDef: L,
3455
- rows: c[L.key] ?? [],
3456
- onChange: (oe) => O(L.key, oe),
3454
+ tableDef: O,
3455
+ rows: c[O.key] ?? [],
3456
+ onChange: (oe) => L(O.key, oe),
3457
3457
  readOnly: W,
3458
3458
  currency: le
3459
3459
  },
3460
- L.key
3460
+ O.key
3461
3461
  )),
3462
- R.length > 0 && /* @__PURE__ */ t(H, { title: o("common.totals"), children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: R.map((L) => /* @__PURE__ */ t(
3462
+ R.length > 0 && /* @__PURE__ */ t(H, { title: o("common.totals"), children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: R.map((O) => /* @__PURE__ */ t(
3463
3463
  Kt,
3464
3464
  {
3465
- field: L,
3466
- value: c[L.name],
3465
+ field: O,
3466
+ value: c[O.name],
3467
3467
  onChange: () => {
3468
3468
  },
3469
3469
  readOnly: !0,
3470
3470
  currency: le
3471
3471
  },
3472
- L.name
3472
+ O.name
3473
3473
  )) }) })
3474
3474
  ] });
3475
3475
  }
@@ -3484,7 +3484,7 @@ function Gt({
3484
3484
  setPage: l,
3485
3485
  setPageSize: c
3486
3486
  }) {
3487
- const { t: h } = se(), [d, g] = w(String(e + 1));
3487
+ const { t: h } = re(), [d, g] = w(String(e + 1));
3488
3488
  ce(() => g(String(e + 1)), [e]);
3489
3489
  const m = () => {
3490
3490
  const b = Number.parseInt(d, 10);
@@ -3617,13 +3617,13 @@ function sr({
3617
3617
  hiddenChipFields: h = [],
3618
3618
  className: d
3619
3619
  }) {
3620
- const { t: g } = se(), m = pe(null), b = pe(null), [v, k] = w(!1), [y, A] = w(!1), [S, x] = w({ field: "", value: "" }), p = fe(() => Gs(n, s), [n, s]), f = n.trimEnd().split(/\s+/).pop() ?? "", B = y || p || f.includes(":") ? "" : f.toLowerCase(), E = fe(() => s.filter(
3620
+ const { t: g } = re(), m = pe(null), b = pe(null), [v, k] = w(!1), [y, A] = w(!1), [S, x] = w({ field: "", value: "" }), p = fe(() => Gs(n, s), [n, s]), f = n.trimEnd().split(/\s+/).pop() ?? "", B = y || p || f.includes(":") ? "" : f.toLowerCase(), E = fe(() => s.filter(
3621
3621
  (W) => !B || W.name.toLowerCase().includes(B) || W.label.toLowerCase().includes(B)
3622
3622
  ).sort((W, le) => {
3623
3623
  const ue = o[W.name] || o[`${W.name}${Nt}`] ? 1 : 0, Ne = o[le.name] || o[`${le.name}${Nt}`] ? 1 : 0;
3624
3624
  if (ue !== Ne) return Ne - ue;
3625
- const xe = W.suggestOnEmpty ? 1 : 0, qe = le.suggestOnEmpty ? 1 : 0;
3626
- return xe !== qe ? qe - xe : W.label.localeCompare(le.label);
3625
+ const be = W.suggestOnEmpty ? 1 : 0, qe = le.suggestOnEmpty ? 1 : 0;
3626
+ return be !== qe ? qe - be : W.label.localeCompare(le.label);
3627
3627
  }), [s, B, o]), J = (p == null ? void 0 : p.field.options) ?? [];
3628
3628
  ce(() => {
3629
3629
  const T = setTimeout(() => x({
@@ -3632,10 +3632,10 @@ function sr({
3632
3632
  }), 200);
3633
3633
  return () => clearTimeout(T);
3634
3634
  }, [p == null ? void 0 : p.field.name, p == null ? void 0 : p.value]);
3635
- const O = !!p && S.field === p.field.name && J.length === 0 && (!!S.value || !!p.field.suggestOnEmpty), { data: q = [], isFetching: Q } = ve({
3635
+ const L = !!p && S.field === p.field.name && J.length === 0 && (!!S.value || !!p.field.suggestOnEmpty), { data: q = [], isFetching: Q } = ve({
3636
3636
  queryKey: ["smart-list-values", e, p == null ? void 0 : p.field.name, S.value],
3637
3637
  queryFn: () => c(p.field.name, S.value),
3638
- enabled: O,
3638
+ enabled: L,
3639
3639
  staleTime: 6e4
3640
3640
  }), N = J.length ? J.filter(
3641
3641
  (T) => !(p != null && p.value) || T.label.toLowerCase().includes(p.value.toLowerCase()) || T.value.toLowerCase().startsWith(p.value.toLowerCase())
@@ -3775,7 +3775,7 @@ function sr({
3775
3775
  },
3776
3776
  Mt(T)
3777
3777
  )),
3778
- !Q && O && N.length === 0 && /* @__PURE__ */ t("div", { className: "px-3 py-4 text-sm text-fg-muted", children: g("smartSearch.noValues") }),
3778
+ !Q && L && N.length === 0 && /* @__PURE__ */ t("div", { className: "px-3 py-4 text-sm text-fg-muted", children: g("smartSearch.noValues") }),
3779
3779
  !!p.value && /* @__PURE__ */ t(
3780
3780
  "button",
3781
3781
  {
@@ -3902,7 +3902,7 @@ const Js = [
3902
3902
  }
3903
3903
  ];
3904
3904
  function Xt({ onSelect: e }) {
3905
- const { t: n } = se();
3905
+ const { t: n } = re();
3906
3906
  return /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1.5", children: Js.map((a) => /* @__PURE__ */ t(
3907
3907
  "button",
3908
3908
  {
@@ -3918,7 +3918,7 @@ function Xt({ onSelect: e }) {
3918
3918
  )) });
3919
3919
  }
3920
3920
  function On({ onSelect: e }) {
3921
- const { t: n } = se();
3921
+ const { t: n } = re();
3922
3922
  return /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1.5", children: [
3923
3923
  { id: "today", labelKey: "datePresets.today", value: (s) => De(s) },
3924
3924
  { id: "endOfThisMonth", labelKey: "datePresets.endOfThisMonth", value: (s) => De(Ht(s)) },
@@ -3970,7 +3970,7 @@ function ei(e) {
3970
3970
  return n === "customer" ? "customer" : n === "supplier" ? "supplier" : null;
3971
3971
  }
3972
3972
  function ti() {
3973
- const { t: e } = se(), n = Qe(), { doctype: a } = bt(), s = er(a ?? ""), o = Ct();
3973
+ const { t: e } = re(), n = Qe(), { doctype: a } = bt(), s = er(a ?? ""), o = Ct();
3974
3974
  Me((s == null ? void 0 : s.label) ?? a ?? null);
3975
3975
  const i = (s == null ? void 0 : s.listFilters) ?? [], l = fe(() => {
3976
3976
  const _ = new URLSearchParams(o.search), M = {}, K = /* @__PURE__ */ new Set(["q", "page", "per_page", "from", "to", "discarded", "order_by", "order"]);
@@ -3981,7 +3981,7 @@ function ti() {
3981
3981
  const _ = {};
3982
3982
  for (const M of i) _[M] = l[M] ?? "";
3983
3983
  return _;
3984
- }, [i, l]), [h] = he("status", "All"), [d] = he("from", ""), [g] = he("to", ""), [m] = he("discarded", ""), [b] = he("per_page", 50), v = (s == null ? void 0 : s.searchFields) ?? [], [k] = he("q", ""), [y, A] = w(k), [S] = he("page", 1), x = S - 1, p = lt(), { settings: f, setSetting: B } = Zt(), [E] = he("order_by", ""), [J] = he("order", ""), [Z, O] = (f[`sort.${a}`] || "").split(":"), q = E || Z || "", Q = (E ? J : O) || "desc", N = (_) => {
3984
+ }, [i, l]), [h] = he("status", "All"), [d] = he("from", ""), [g] = he("to", ""), [m] = he("discarded", ""), [b] = he("per_page", 50), v = (s == null ? void 0 : s.searchFields) ?? [], [k] = he("q", ""), [y, A] = w(k), [S] = he("page", 1), x = S - 1, p = lt(), { settings: f, setSetting: B } = Zt(), [E] = he("order_by", ""), [J] = he("order", ""), [Z, L] = (f[`sort.${a}`] || "").split(":"), q = E || Z || "", Q = (E ? J : L) || "desc", N = (_) => {
3985
3985
  const M = q === _ ? Q === "desc" ? "asc" : "desc" : oa(_) ? "desc" : "asc";
3986
3986
  p({ order_by: _, order: M, page: null }), B(`sort.${a}`, `${_}:${M}`);
3987
3987
  }, [D, $] = w(!1), u = pe(null), P = fe(
@@ -4007,11 +4007,11 @@ function ti() {
4007
4007
  };
4008
4008
  return document.addEventListener("mousedown", _), () => document.removeEventListener("mousedown", _);
4009
4009
  }, [D]);
4010
- const ue = (_) => p({ page: _ === 0 ? null : _ + 1 }), Ne = (_) => p({ status: _ === "All" ? null : _, page: null }), xe = (_) => p({ from: _ || null, page: null }), qe = (_) => p({ to: _ || null, page: null }), R = (_) => p({ discarded: _ ? "1" : null, page: null }), ae = (_) => p({ per_page: _, page: null });
4010
+ const ue = (_) => p({ page: _ === 0 ? null : _ + 1 }), Ne = (_) => p({ status: _ === "All" ? null : _, page: null }), be = (_) => p({ from: _ || null, page: null }), qe = (_) => p({ to: _ || null, page: null }), R = (_) => p({ discarded: _ ? "1" : null, page: null }), ae = (_) => p({ per_page: _, page: null });
4011
4011
  ce(() => {
4012
4012
  A(k);
4013
4013
  }, [k]);
4014
- const be = fe(() => {
4014
+ const xe = fe(() => {
4015
4015
  const _ = {};
4016
4016
  i.length === 0 && h !== "All" && (_.status = h), d && (_.from_date = d), g && (_.to_date = g), s != null && s.dateField && (_.date_field = s.dateField);
4017
4017
  for (const M of i)
@@ -4019,7 +4019,7 @@ function ti() {
4019
4019
  for (const [M, K] of Object.entries(l))
4020
4020
  _[M] = K;
4021
4021
  return v.length > 0 && k && (_.search = k, _.search_fields = v.join(",")), m && (_.include_discarded = "true"), q && (_.order_by = q, _.order = Q), T && (_.fields = T), _.limit = b, _.offset = x * b, _;
4022
- }, [h, d, g, m, b, x, s == null ? void 0 : s.dateField, i, c, l, v, k, q, Q, T]), { data: L, isLoading: oe } = Os(a ?? "", be), Ie = (L == null ? void 0 : L.rows) ?? [], Ae = (L == null ? void 0 : L.total) ?? 0, Ye = fe(() => new Set((L == null ? void 0 : L.text_fields) ?? []), [L == null ? void 0 : L.text_fields]), tt = fe(() => {
4022
+ }, [h, d, g, m, b, x, s == null ? void 0 : s.dateField, i, c, l, v, k, q, Q, T]), { data: O, isLoading: oe } = Os(a ?? "", xe), Ie = (O == null ? void 0 : O.rows) ?? [], Ae = (O == null ? void 0 : O.total) ?? 0, Ye = fe(() => new Set((O == null ? void 0 : O.text_fields) ?? []), [O == null ? void 0 : O.text_fields]), tt = fe(() => {
4023
4023
  if (!s) return [];
4024
4024
  const _ = new Map(s.fields.map((K) => [K.name, K]));
4025
4025
  return [.../* @__PURE__ */ new Set([
@@ -4044,9 +4044,9 @@ function ti() {
4044
4044
  });
4045
4045
  }, [W, s, i, v, e, Ye]);
4046
4046
  ce(() => {
4047
- const { limit: _, offset: M, ...K } = be;
4047
+ const { limit: _, offset: M, ...K } = xe;
4048
4048
  Xa(a ?? "", { filters: K, search: o.search });
4049
- }, [a, be, o.search]);
4049
+ }, [a, xe, o.search]);
4050
4050
  const je = Math.max(1, Math.ceil(Ae / b)), st = Ae === 0 ? 0 : x * b + 1, U = Math.min(Ae, (x + 1) * b), te = fe(() => {
4051
4051
  if (!s) return [];
4052
4052
  const _ = Ea(), M = (K) => {
@@ -4224,7 +4224,7 @@ function ti() {
4224
4224
  label: e("fields.From Date", { defaultValue: "From Date" }),
4225
4225
  type: "date",
4226
4226
  value: d,
4227
- onChange: (_) => xe(_.target.value)
4227
+ onChange: (_) => be(_.target.value)
4228
4228
  }
4229
4229
  ),
4230
4230
  /* @__PURE__ */ t(
@@ -4322,21 +4322,21 @@ function ze({
4322
4322
  }, [n]);
4323
4323
  const f = Ue(() => {
4324
4324
  if (x.current) {
4325
- const O = x.current.getBoundingClientRect();
4325
+ const L = x.current.getBoundingClientRect();
4326
4326
  k({
4327
4327
  position: "fixed",
4328
- top: O.bottom + 4,
4329
- left: O.left,
4330
- width: O.width,
4328
+ top: L.bottom + 4,
4329
+ left: L.left,
4330
+ width: L.width,
4331
4331
  zIndex: 9999
4332
4332
  });
4333
4333
  }
4334
4334
  }, []), B = Ue(
4335
- (O) => {
4335
+ (L) => {
4336
4336
  y.current && clearTimeout(y.current), y.current = setTimeout(async () => {
4337
4337
  b(!0);
4338
4338
  try {
4339
- const q = await F.searchLink(s, O);
4339
+ const q = await F.searchLink(s, L);
4340
4340
  h(q), g(!0);
4341
4341
  } catch {
4342
4342
  h([]);
@@ -4346,11 +4346,11 @@ function ze({
4346
4346
  }, 300);
4347
4347
  },
4348
4348
  [s]
4349
- ), E = (O) => {
4350
- const q = O.target.value;
4349
+ ), E = (L) => {
4350
+ const q = L.target.value;
4351
4351
  l(q), B(q);
4352
- }, J = (O) => {
4353
- const q = O.name ?? O.id ?? String(O);
4352
+ }, J = (L) => {
4353
+ const q = L.name ?? L.id ?? String(L);
4354
4354
  l(q), a(q), g(!1), h([]);
4355
4355
  }, Z = () => {
4356
4356
  setTimeout(() => {
@@ -4362,12 +4362,12 @@ function ze({
4362
4362
  }, 150);
4363
4363
  };
4364
4364
  return ce(() => {
4365
- const O = (q) => {
4365
+ const L = (q) => {
4366
4366
  var N, D;
4367
4367
  const Q = q.target;
4368
4368
  (N = A.current) != null && N.contains(Q) || (D = S.current) != null && D.contains(Q) || g(!1);
4369
4369
  };
4370
- return document.addEventListener("mousedown", O), () => document.removeEventListener("mousedown", O);
4370
+ return document.addEventListener("mousedown", L), () => document.removeEventListener("mousedown", L);
4371
4371
  }, []), o ? /* @__PURE__ */ r("div", { children: [
4372
4372
  e && /* @__PURE__ */ t("span", { className: "mb-1.5 block text-sm font-medium text-fg", children: e }),
4373
4373
  /* @__PURE__ */ t("span", { className: "text-sm text-fg", children: n || "—" })
@@ -4392,8 +4392,8 @@ function ze({
4392
4392
  }
4393
4393
  ),
4394
4394
  d && c.length > 0 && Fa(
4395
- /* @__PURE__ */ t("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((O, q) => {
4396
- const Q = O.name ?? O.id ?? String(O);
4395
+ /* @__PURE__ */ t("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((L, q) => {
4396
+ const Q = L.name ?? L.id ?? String(L);
4397
4397
  return /* @__PURE__ */ t(
4398
4398
  "button",
4399
4399
  {
@@ -4401,7 +4401,7 @@ function ze({
4401
4401
  onMouseDown: () => {
4402
4402
  p.current = !0;
4403
4403
  },
4404
- onClick: () => J(O),
4404
+ onClick: () => J(L),
4405
4405
  className: "block w-full px-3 py-1.5 text-left text-sm text-fg transition-colors hover:bg-surface-subtle",
4406
4406
  children: Q
4407
4407
  },
@@ -4420,7 +4420,7 @@ const qt = () => ({
4420
4420
  }), ni = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
4421
4421
  function ca() {
4422
4422
  var $;
4423
- const { name: e } = bt(), n = !e, a = Ke(), s = et(), { t: o } = se();
4423
+ const { name: e } = bt(), n = !e, a = Ke(), s = et(), { t: o } = re();
4424
4424
  Me(o("titles.proposal"));
4425
4425
  const i = (u, P) => o(u, { defaultValue: P }), l = Tn(), [c, h] = w({
4426
4426
  title: "Offerte",
@@ -4474,7 +4474,7 @@ function ca() {
4474
4474
  s.invalidateQueries({ queryKey: ["documents", "proposal"] }), a("/app/proposal");
4475
4475
  },
4476
4476
  onError: (u) => A((u == null ? void 0 : u.message) ?? "Discard failed")
4477
- }), Z = (u, P) => g((V) => V.map((T, W) => W === u ? { ...T, ...P } : T)), O = () => g((u) => [...u, qt()]), q = (u) => g((P) => P.length > 1 ? P.filter((V, T) => T !== u) : P), Q = (u, P) => g((V) => {
4477
+ }), Z = (u, P) => g((V) => V.map((T, W) => W === u ? { ...T, ...P } : T)), L = () => g((u) => [...u, qt()]), q = (u) => g((P) => P.length > 1 ? P.filter((V, T) => T !== u) : P), Q = (u, P) => g((V) => {
4478
4478
  const T = u + P;
4479
4479
  if (T < 0 || T >= V.length) return V;
4480
4480
  const W = [...V];
@@ -4561,7 +4561,7 @@ function ca() {
4561
4561
  /* @__PURE__ */ r(H, { className: "space-y-4 p-5", children: [
4562
4562
  /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
4563
4563
  /* @__PURE__ */ t("h2", { className: "font-semibold text-fg", children: i("proposal.offers", "Offers") }),
4564
- /* @__PURE__ */ t(Y, { size: "sm", variant: "secondary", onClick: O, children: i("proposal.addOffer", "Add offer") })
4564
+ /* @__PURE__ */ t(Y, { size: "sm", variant: "secondary", onClick: L, children: i("proposal.addOffer", "Add offer") })
4565
4565
  ] }),
4566
4566
  d.map((u, P) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
4567
4567
  /* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
@@ -4601,13 +4601,13 @@ function ca() {
4601
4601
  ] });
4602
4602
  }
4603
4603
  const Fn = {};
4604
- function Mc(e) {
4604
+ function Vc(e) {
4605
4605
  Fn[e.slug] = e;
4606
4606
  }
4607
4607
  function lr(e) {
4608
4608
  return Fn[e];
4609
4609
  }
4610
- function qc() {
4610
+ function Uc() {
4611
4611
  return Object.values(Fn);
4612
4612
  }
4613
4613
  const cr = {
@@ -4670,6 +4670,7 @@ const cr = {
4670
4670
  { name: "zip_code", label: "Zip Code", type: "text" },
4671
4671
  { name: "country", label: "Country", type: "text" },
4672
4672
  { name: "tax_id", label: "Tax ID", type: "text" },
4673
+ { name: "default_sales_tax_template", label: "Default sales tax", type: "text" },
4673
4674
  { name: "iban", label: "IBAN", type: "text" }
4674
4675
  ]
4675
4676
  }, ai = {
@@ -4689,10 +4690,10 @@ function si() {
4689
4690
  var st;
4690
4691
  const { type: e } = bt(), n = Ke(), a = Ct(), s = lr(e ?? ""), o = (s == null ? void 0 : s.label) ?? ai[e ?? ""] ?? e ?? "";
4691
4692
  Me(o || null);
4692
- const { t: i } = se(), l = (st = a.state) == null ? void 0 : st.notice, [c] = he("per_page", 50), [h] = he("page", 1), [d] = he("include_disabled", ""), g = h - 1, m = lt(), b = (U) => m({ page: U === 0 ? null : U + 1 }), v = (U) => m({ per_page: U, page: null }), k = (U) => m({ include_disabled: U ? "1" : null, page: null }), { settings: y, setSetting: A } = Zt(), [S] = he("order_by", ""), [x] = he("order", ""), [p, f] = (y[`sort.master:${e}`] || "").split(":"), B = S || p || "", E = (S ? x : f) || "asc", J = (U) => {
4693
+ const { t: i } = re(), l = (st = a.state) == null ? void 0 : st.notice, [c] = he("per_page", 50), [h] = he("page", 1), [d] = he("include_disabled", ""), g = h - 1, m = lt(), b = (U) => m({ page: U === 0 ? null : U + 1 }), v = (U) => m({ per_page: U, page: null }), k = (U) => m({ include_disabled: U ? "1" : null, page: null }), { settings: y, setSetting: A } = Zt(), [S] = he("order_by", ""), [x] = he("order", ""), [p, f] = (y[`sort.master:${e}`] || "").split(":"), B = S || p || "", E = (S ? x : f) || "asc", J = (U) => {
4693
4694
  const te = B === U ? E === "desc" ? "asc" : "desc" : da(U) ? "desc" : "asc";
4694
4695
  m({ order_by: U, order: te, page: null }), A(`sort.master:${e}`, `${U}:${te}`);
4695
- }, [Z] = he("q", ""), [O, q] = w(Z);
4696
+ }, [Z] = he("q", ""), [L, q] = w(Z);
4696
4697
  ce(() => {
4697
4698
  q(Z);
4698
4699
  }, [Z]);
@@ -4723,10 +4724,10 @@ function si() {
4723
4724
  const { limit: U, offset: te, fields: _e, ..._ } = D;
4724
4725
  Xa(`master:${e}`, { filters: _, search: a.search });
4725
4726
  }, [e, D, a.search]);
4726
- const P = ($ == null ? void 0 : $.rows) ?? [], V = ($ == null ? void 0 : $.total) ?? 0, T = fe(() => new Set(($ == null ? void 0 : $.text_fields) ?? []), [$ == null ? void 0 : $.text_fields]), W = Math.max(1, Math.ceil(V / c)), le = V === 0 ? 0 : g * c + 1, ue = Math.min(V, (g + 1) * c), Ne = pe({}), xe = fe(() => s != null && s.columnOptions ? s.columnOptions : (e && P.length && (Ne.current[e] = Object.keys(P[0])), e ? Ne.current[e] ?? [] : []), [s, P, e]), qe = fe(() => {
4727
+ const P = ($ == null ? void 0 : $.rows) ?? [], V = ($ == null ? void 0 : $.total) ?? 0, T = fe(() => new Set(($ == null ? void 0 : $.text_fields) ?? []), [$ == null ? void 0 : $.text_fields]), W = Math.max(1, Math.ceil(V / c)), le = V === 0 ? 0 : g * c + 1, ue = Math.min(V, (g + 1) * c), Ne = pe({}), be = fe(() => s != null && s.columnOptions ? s.columnOptions : (e && P.length && (Ne.current[e] = Object.keys(P[0])), e ? Ne.current[e] ?? [] : []), [s, P, e]), qe = fe(() => {
4727
4728
  const U = (s == null ? void 0 : s.fields) ?? cr[e ?? ""] ?? [], te = new Map(U.map((_) => [_.name, _]));
4728
4729
  return [.../* @__PURE__ */ new Set([
4729
- ...xe,
4730
+ ...be,
4730
4731
  ...U.map((_) => _.name),
4731
4732
  ...Q.map((_) => _.field)
4732
4733
  ])].map((_) => {
@@ -4743,11 +4744,11 @@ function si() {
4743
4744
  suggestOnEmpty: !!(C != null && C.length) || Q.some((G) => G.field === _)
4744
4745
  };
4745
4746
  });
4746
- }, [xe, s, Q, i, T, e]), ae = fe(
4747
+ }, [be, s, Q, i, T, e]), ae = fe(
4747
4748
  () => (y[`columns.master:${e}`] || "").split(",").map((U) => U.trim()).filter(Boolean),
4748
4749
  [y, e]
4749
- ).filter((U) => xe.includes(U)), be = ((s == null ? void 0 : s.listColumns) ?? []).filter((U) => xe.includes(U)), L = ae.length ? ae : be.length ? be : xe, oe = (U) => {
4750
- const te = L.includes(U) ? L.filter((_e) => _e !== U) : [...L, U];
4750
+ ).filter((U) => be.includes(U)), xe = ((s == null ? void 0 : s.listColumns) ?? []).filter((U) => be.includes(U)), O = ae.length ? ae : xe.length ? xe : be, oe = (U) => {
4751
+ const te = O.includes(U) ? O.filter((_e) => _e !== U) : [...O, U];
4751
4752
  te.length !== 0 && A(`columns.master:${e}`, te.join(","));
4752
4753
  }, [Ie, Ae] = w(!1), Ye = pe(null);
4753
4754
  ce(() => {
@@ -4760,7 +4761,7 @@ function si() {
4760
4761
  const tt = fe(() => {
4761
4762
  if (!P || P.length === 0) return [];
4762
4763
  const U = Ea();
4763
- return L.map(
4764
+ return O.map(
4764
4765
  (te) => {
4765
4766
  var _e, _;
4766
4767
  return U.accessor(te, {
@@ -4799,7 +4800,7 @@ function si() {
4799
4800
  });
4800
4801
  }
4801
4802
  );
4802
- }, [P, e, L.join(","), i, s]), je = La({
4803
+ }, [P, e, O.join(","), i, s]), je = La({
4803
4804
  data: P,
4804
4805
  columns: tt,
4805
4806
  getCoreRowModel: Oa()
@@ -4811,7 +4812,7 @@ function si() {
4811
4812
  sr,
4812
4813
  {
4813
4814
  scope: `master:${e}`,
4814
- value: O,
4815
+ value: L,
4815
4816
  onChange: q,
4816
4817
  fields: qe,
4817
4818
  filters: N,
@@ -4837,16 +4838,16 @@ function si() {
4837
4838
  i("common.showDisabled")
4838
4839
  ] }),
4839
4840
  /* @__PURE__ */ r("div", { className: "ml-auto flex items-center gap-2", children: [
4840
- xe.length > 0 && /* @__PURE__ */ r("div", { className: "relative", ref: Ye, children: [
4841
+ be.length > 0 && /* @__PURE__ */ r("div", { className: "relative", ref: Ye, children: [
4841
4842
  /* @__PURE__ */ t(Y, { variant: "secondary", onClick: () => Ae((U) => !U), children: /* @__PURE__ */ r("span", { className: "inline-flex items-center gap-1.5", children: [
4842
4843
  /* @__PURE__ */ t(Ra, { className: "h-4 w-4" }),
4843
4844
  i("common.columns", { defaultValue: "Columns" })
4844
4845
  ] }) }),
4845
4846
  Ie && /* @__PURE__ */ r("div", { className: "absolute right-0 z-20 mt-2 max-h-80 w-60 overflow-y-auto rounded-lg border border-line bg-surface p-2 shadow-card", children: [
4846
4847
  /* @__PURE__ */ t("div", { className: "px-2 py-1 text-xs font-medium uppercase tracking-wide text-fg-muted", children: i("common.columns", { defaultValue: "Columns" }) }),
4847
- xe.map((U) => {
4848
+ be.map((U) => {
4848
4849
  var _, M;
4849
- const te = L.includes(U), _e = te && L.length === 1;
4850
+ const te = O.includes(U), _e = te && O.length === 1;
4850
4851
  return /* @__PURE__ */ r(
4851
4852
  "label",
4852
4853
  {
@@ -4939,7 +4940,44 @@ function si() {
4939
4940
  ] })
4940
4941
  ] });
4941
4942
  }
4942
- const ii = {
4943
+ function ii({ company: e, value: n, onChange: a }) {
4944
+ const { t: s } = re(), o = ve({
4945
+ queryKey: ["company-sales-tax-templates", e],
4946
+ queryFn: () => z(
4947
+ `/masters/company/${encodeURIComponent(e)}/sales-tax-templates`
4948
+ ),
4949
+ enabled: !!e
4950
+ }), i = o.data ?? [], l = !!n && !i.some((c) => c.name === n);
4951
+ return /* @__PURE__ */ r("div", { className: "sm:col-span-2", children: [
4952
+ /* @__PURE__ */ t("label", { htmlFor: "company-sales-tax", className: "mb-1.5 block text-sm font-medium text-fg", children: s("companyTax.label") }),
4953
+ /* @__PURE__ */ r(
4954
+ "select",
4955
+ {
4956
+ id: "company-sales-tax",
4957
+ "aria-describedby": "company-sales-tax-hint",
4958
+ className: "block h-10 w-full rounded-lg bg-surface px-3 text-sm text-fg ring-1 ring-line focus:outline-none focus:ring-2 focus:ring-brand/30 disabled:cursor-not-allowed disabled:text-fg-muted",
4959
+ value: n,
4960
+ disabled: !e || o.isPending || o.isError,
4961
+ onChange: (c) => a(c.target.value),
4962
+ children: [
4963
+ /* @__PURE__ */ t("option", { value: "", children: s("companyTax.none") }),
4964
+ l && /* @__PURE__ */ t("option", { value: n, children: n }),
4965
+ i.map((c) => /* @__PURE__ */ t("option", { value: c.name, children: c.title || c.name }, c.name))
4966
+ ]
4967
+ }
4968
+ ),
4969
+ /* @__PURE__ */ t("p", { id: "company-sales-tax-hint", className: "mt-2 text-xs text-fg-muted", children: s(e ? "companyTax.hint" : "companyTax.saveFirst") }),
4970
+ e && o.isPending && /* @__PURE__ */ t("p", { className: "mt-1 text-xs text-fg-muted", role: "status", children: s("common.loading") }),
4971
+ o.isError && /* @__PURE__ */ r("p", { className: "mt-2 text-sm text-rose-700", role: "alert", children: [
4972
+ s("companyTax.loadError"),
4973
+ " ",
4974
+ /* @__PURE__ */ t("button", { type: "button", className: "underline", onClick: () => o.refetch(), children: s("companyTax.retry") })
4975
+ ] }),
4976
+ e && o.isSuccess && l && /* @__PURE__ */ t("p", { className: "mt-2 text-sm text-amber-700", role: "alert", children: s("companyTax.unavailable") }),
4977
+ e && o.isSuccess && i.length === 0 && /* @__PURE__ */ t("p", { className: "mt-2 text-xs text-fg-muted", children: s("companyTax.empty") })
4978
+ ] });
4979
+ }
4980
+ const oi = {
4943
4981
  customer: "Customer",
4944
4982
  supplier: "Supplier",
4945
4983
  item: "Item",
@@ -4948,7 +4986,7 @@ const ii = {
4948
4986
  }, ua = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
4949
4987
  function ma() {
4950
4988
  var N, D, $;
4951
- const { type: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = se(), i = !n || n === "new", l = lr(e ?? ""), c = (l == null ? void 0 : l.label) ?? ii[e ?? ""] ?? e ?? "", h = o(`masters.${e}.one`, { defaultValue: c }), d = (l == null ? void 0 : l.fields) ?? cr[e ?? ""] ?? [], g = (u) => o(`fields.${u.label}`, { defaultValue: u.label }), [m, b] = w({}), { data: v, isLoading: k } = ve({
4989
+ const { type: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = re(), i = !n || n === "new", l = lr(e ?? ""), c = (l == null ? void 0 : l.label) ?? oi[e ?? ""] ?? e ?? "", h = o(`masters.${e}.one`, { defaultValue: c }), d = (l == null ? void 0 : l.fields) ?? cr[e ?? ""] ?? [], g = (u) => o(`fields.${u.label}`, { defaultValue: u.label }), [m, b] = w({}), { data: v, isLoading: k } = ve({
4952
4990
  queryKey: ["master", e, n],
4953
4991
  queryFn: () => F.getMaster(e, n),
4954
4992
  enabled: !!e && !!n && !i
@@ -5020,7 +5058,7 @@ function ma() {
5020
5058
  confirmLabel: o("common.delete", { defaultValue: "Delete" }),
5021
5059
  danger: !0
5022
5060
  }) && f.mutate();
5023
- }, O = (u, P) => {
5061
+ }, L = (u, P) => {
5024
5062
  b((V) => ({ ...V, [u]: P }));
5025
5063
  };
5026
5064
  if (!i && k)
@@ -5067,6 +5105,16 @@ function ma() {
5067
5105
  m.disabled === 1 && /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-800 ring-1 ring-amber-200", children: o("masterForm.disabledNotice", { label: h }) }),
5068
5106
  /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: d.map((u) => {
5069
5107
  var ue, Ne;
5108
+ if (e === "company" && u.name === "default_sales_tax_template")
5109
+ return /* @__PURE__ */ t(
5110
+ ii,
5111
+ {
5112
+ company: i ? void 0 : n,
5113
+ value: m[u.name] ?? "",
5114
+ onChange: (be) => L(u.name, be)
5115
+ },
5116
+ u.name
5117
+ );
5070
5118
  const V = u.name === "name" && !i || u.readOnly, T = u.required && !(i && u.name === "name" && (l != null && l.autoName || ua.has(e ?? ""))), W = V && m[u.name] ? (Ne = (ue = l == null ? void 0 : l.columnLinks) == null ? void 0 : ue[u.name]) == null ? void 0 : Ne.call(ue, m[u.name], m) : null;
5071
5119
  if (W)
5072
5120
  return /* @__PURE__ */ r("div", { children: [
@@ -5074,7 +5122,7 @@ function ma() {
5074
5122
  /* @__PURE__ */ t(Ce, { className: "py-2 text-sm text-sky-600 hover:underline", to: W, children: String(m[u.name]) })
5075
5123
  ] }, u.name);
5076
5124
  if (u.type === "select" && u.options) {
5077
- const xe = m[u.name], qe = typeof xe == "string" && xe !== "" && !u.options.includes(xe) ? [...u.options, xe] : u.options;
5125
+ const be = m[u.name], qe = typeof be == "string" && be !== "" && !u.options.includes(be) ? [...u.options, be] : u.options;
5078
5126
  return /* @__PURE__ */ t("div", { children: /* @__PURE__ */ t(
5079
5127
  Ge,
5080
5128
  {
@@ -5083,7 +5131,7 @@ function ma() {
5083
5131
  value: m[u.name] ?? "",
5084
5132
  required: T,
5085
5133
  disabled: V,
5086
- onChange: (R) => O(u.name, R.target.value)
5134
+ onChange: (R) => L(u.name, R.target.value)
5087
5135
  }
5088
5136
  ) }, u.name);
5089
5137
  }
@@ -5099,7 +5147,7 @@ function ma() {
5099
5147
  required: T,
5100
5148
  readOnly: V,
5101
5149
  disabled: V,
5102
- onChange: (xe) => O(u.name, xe.target.value)
5150
+ onChange: (be) => L(u.name, be.target.value)
5103
5151
  }
5104
5152
  )
5105
5153
  ] }, u.name);
@@ -5114,9 +5162,9 @@ function ma() {
5114
5162
  readOnly: V,
5115
5163
  disabled: V,
5116
5164
  value: m[u.name] ?? "",
5117
- onChange: (xe) => O(
5165
+ onChange: (be) => L(
5118
5166
  u.name,
5119
- le === "number" ? parseFloat(xe.target.value) || 0 : xe.target.value
5167
+ le === "number" ? parseFloat(be.target.value) || 0 : be.target.value
5120
5168
  )
5121
5169
  },
5122
5170
  u.name
@@ -5124,56 +5172,56 @@ function ma() {
5124
5172
  }) }) })
5125
5173
  ] });
5126
5174
  }
5127
- function oi(e) {
5175
+ function li(e) {
5128
5176
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5129
5177
  queryKey: ["report", "trial-balance", e],
5130
5178
  queryFn: () => F.trialBalance(e)
5131
5179
  });
5132
5180
  return { data: n, isLoading: a, error: s, refetch: o };
5133
5181
  }
5134
- function li(e) {
5182
+ function ci(e) {
5135
5183
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5136
5184
  queryKey: ["report", "chart-of-accounts", e],
5137
5185
  queryFn: () => F.chartOfAccounts(e)
5138
5186
  });
5139
5187
  return { data: n, isLoading: a, error: s, refetch: o };
5140
5188
  }
5141
- function ci(e) {
5189
+ function di(e) {
5142
5190
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5143
5191
  queryKey: ["report", "general-ledger", e],
5144
5192
  queryFn: () => F.generalLedger(e)
5145
5193
  });
5146
5194
  return { data: n, isLoading: a, error: s, refetch: o };
5147
5195
  }
5148
- function di(e) {
5196
+ function ui(e) {
5149
5197
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5150
5198
  queryKey: ["report", "stock-balance", e],
5151
5199
  queryFn: () => F.stockBalance(e)
5152
5200
  });
5153
5201
  return { data: n, isLoading: a, error: s, refetch: o };
5154
5202
  }
5155
- function ui(e) {
5203
+ function mi(e) {
5156
5204
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5157
5205
  queryKey: ["report", "profit-and-loss", e],
5158
5206
  queryFn: () => F.profitAndLoss(e)
5159
5207
  });
5160
5208
  return { data: n, isLoading: a, error: s, refetch: o };
5161
5209
  }
5162
- function mi(e) {
5210
+ function pi(e) {
5163
5211
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5164
5212
  queryKey: ["report", "balance-sheet", e],
5165
5213
  queryFn: () => F.balanceSheet(e)
5166
5214
  });
5167
5215
  return { data: n, isLoading: a, error: s, refetch: o };
5168
5216
  }
5169
- function pi(e) {
5217
+ function hi(e) {
5170
5218
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5171
5219
  queryKey: ["report", "ar-aging", e],
5172
5220
  queryFn: () => F.arAging(e)
5173
5221
  });
5174
5222
  return { data: n, isLoading: a, error: s, refetch: o };
5175
5223
  }
5176
- function hi(e) {
5224
+ function gi(e) {
5177
5225
  const { data: n, isLoading: a, error: s, refetch: o } = ve({
5178
5226
  queryKey: ["report", "ap-aging", e],
5179
5227
  queryFn: () => F.apAging(e)
@@ -5181,17 +5229,17 @@ function hi(e) {
5181
5229
  return { data: n, isLoading: a, error: s, refetch: o };
5182
5230
  }
5183
5231
  function en({ from: e, to: n, asOf: a }) {
5184
- const { t: s } = se();
5232
+ const { t: s } = re();
5185
5233
  let o = "";
5186
5234
  return a ? o = s("reports.asOfDate", { date: rt(a) }) : e && n ? o = s("reports.periodRange", { from: rt(e), to: rt(n) }) : e ? o = s("reports.periodFrom", { from: rt(e) }) : n && (o = s("reports.periodThrough", { to: rt(n) })), o ? /* @__PURE__ */ t("div", { className: "rounded-lg border border-line bg-surface-subtle px-4 py-2 text-sm font-medium text-fg", children: o }) : null;
5187
5235
  }
5188
- function gi() {
5189
- const { t: e } = se();
5236
+ function fi() {
5237
+ const { t: e } = re();
5190
5238
  Me(e("titles.trial-balance"));
5191
5239
  const [n] = he("company", ""), [a] = he("from", ""), [s] = he("to", ""), o = lt(), [i, l] = w(n), [c, h] = w(a), [d, g] = w(s), m = Qe(i), b = (p) => He(p, m), v = fe(() => {
5192
5240
  const p = {};
5193
5241
  return n && (p.company = n), a && (p.from_date = a), s && (p.to_date = s), p;
5194
- }, [n, a, s]), { data: k, isLoading: y, refetch: A } = oi(v), S = () => {
5242
+ }, [n, a, s]), { data: k, isLoading: y, refetch: A } = li(v), S = () => {
5195
5243
  o({
5196
5244
  company: i || null,
5197
5245
  from: c || null,
@@ -5265,9 +5313,9 @@ function gi() {
5265
5313
  ] })
5266
5314
  ] });
5267
5315
  }
5268
- const fi = ["Asset", "Liability", "Equity", "Income", "Expense"];
5269
- function yi() {
5270
- const { t: e } = se();
5316
+ const yi = ["Asset", "Liability", "Equity", "Income", "Expense"];
5317
+ function bi() {
5318
+ const { t: e } = re();
5271
5319
  Me(e("titles.chart-of-accounts", { defaultValue: "Chart of Accounts" }));
5272
5320
  const n = (/* @__PURE__ */ new Date()).getFullYear(), [a, s] = w(String(n)), [o, i] = w(/* @__PURE__ */ new Set()), l = fe(() => {
5273
5321
  const x = [];
@@ -5277,7 +5325,7 @@ function yi() {
5277
5325
  }, [n, e]), c = fe(() => {
5278
5326
  const x = {};
5279
5327
  return a !== "all" && (x.from_date = `${a}-01-01`, x.to_date = `${a}-12-31`), x;
5280
- }, [a]), { data: h, isLoading: d } = li(c), g = Qe(""), m = (x) => He(x, g), b = (h == null ? void 0 : h.accounts) ?? [], { childrenOf: v, rootsByType: k } = fe(() => {
5328
+ }, [a]), { data: h, isLoading: d } = ci(c), g = Qe(""), m = (x) => He(x, g), b = (h == null ? void 0 : h.accounts) ?? [], { childrenOf: v, rootsByType: k } = fe(() => {
5281
5329
  const x = new Map(b.map((B) => [B.name, B])), p = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
5282
5330
  for (const B of b)
5283
5331
  if (B.parent_account && x.has(B.parent_account)) {
@@ -5347,23 +5395,23 @@ function yi() {
5347
5395
  ] }),
5348
5396
  d && /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("common.loading", { defaultValue: "Loading…" }) }) }),
5349
5397
  !d && b.length === 0 && /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("coa.empty", { defaultValue: "No accounts found. Complete the company setup first." }) }) }),
5350
- !d && fi.filter((x) => (k.get(x) ?? []).length > 0).map((x) => /* @__PURE__ */ r(H, { children: [
5398
+ !d && yi.filter((x) => (k.get(x) ?? []).length > 0).map((x) => /* @__PURE__ */ r(H, { children: [
5351
5399
  /* @__PURE__ */ t("h3", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-fg-muted", children: e(`coa.rootType.${x}`, { defaultValue: x }) }),
5352
5400
  /* @__PURE__ */ t("div", { children: (k.get(x) ?? []).map((p) => S(p, 0)) })
5353
5401
  ] }, x))
5354
5402
  ] });
5355
5403
  }
5356
- function bi(e) {
5404
+ function vi(e) {
5357
5405
  return e.toLowerCase().replace(/\s+/g, "-");
5358
5406
  }
5359
- const vi = ["25", "50", "100", "200"];
5360
- function xi() {
5361
- const { t: e } = se();
5407
+ const xi = ["25", "50", "100", "200"];
5408
+ function ki() {
5409
+ const { t: e } = re();
5362
5410
  Me(e("titles.general-ledger"));
5363
5411
  const [n] = he("account", ""), [a] = he("party", ""), [s] = he("from", ""), [o] = he("to", ""), [i] = he("per_page", 50), [l] = he("page", 1), c = l - 1, h = lt(), d = (u) => h({ page: u === 0 ? null : u + 1 }), g = (u) => h({ per_page: u, page: null }), [m, b] = w(n), [v, k] = w(a), [y, A] = w(s), [S, x] = w(o), p = Qe(), f = (u) => He(u, p), B = fe(() => {
5364
5412
  const u = {};
5365
5413
  return n && (u.account = n), a && (u.party = a), s && (u.from_date = s), o && (u.to_date = o), u.limit = String(i), u.offset = String(c * i), u;
5366
- }, [n, a, s, o, i, c]), { data: E, isLoading: J, refetch: Z } = ci(B), O = (E == null ? void 0 : E.rows) ?? [], q = (E == null ? void 0 : E.total) ?? 0, Q = Math.max(1, Math.ceil(q / i)), N = q === 0 ? 0 : c * i + 1, D = Math.min(q, (c + 1) * i), $ = () => {
5414
+ }, [n, a, s, o, i, c]), { data: E, isLoading: J, refetch: Z } = di(B), L = (E == null ? void 0 : E.rows) ?? [], q = (E == null ? void 0 : E.total) ?? 0, Q = Math.max(1, Math.ceil(q / i)), N = q === 0 ? 0 : c * i + 1, D = Math.min(q, (c + 1) * i), $ = () => {
5367
5415
  h({
5368
5416
  account: m || null,
5369
5417
  party: v || null,
@@ -5418,7 +5466,7 @@ function xi() {
5418
5466
  A(u), x(P), h({ from: u, to: P, page: null });
5419
5467
  } }),
5420
5468
  /* @__PURE__ */ t(en, { from: s, to: o }),
5421
- J ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : O.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noEntries") }) : /* @__PURE__ */ r(Pe, { children: [
5469
+ J ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : L.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noEntries") }) : /* @__PURE__ */ r(Pe, { children: [
5422
5470
  /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
5423
5471
  /* @__PURE__ */ t("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
5424
5472
  /* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Date", { defaultValue: "Date" }) }),
@@ -5430,7 +5478,7 @@ function xi() {
5430
5478
  /* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Voucher Type", { defaultValue: "Voucher Type" }) }),
5431
5479
  /* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Voucher No", { defaultValue: "Voucher No" }) })
5432
5480
  ] }) }),
5433
- /* @__PURE__ */ t("tbody", { className: "divide-y divide-gray-100", children: O.map((u, P) => /* @__PURE__ */ r("tr", { className: "hover:bg-gray-50", children: [
5481
+ /* @__PURE__ */ t("tbody", { className: "divide-y divide-gray-100", children: L.map((u, P) => /* @__PURE__ */ r("tr", { className: "hover:bg-gray-50", children: [
5434
5482
  /* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-500", children: rt(u.posting_date ?? u.date) }),
5435
5483
  /* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-900", children: u.account }),
5436
5484
  /* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-700", children: u.party ?? "-" }),
@@ -5441,7 +5489,7 @@ function xi() {
5441
5489
  /* @__PURE__ */ t("td", { className: "px-4 py-2", children: u.voucher_type && u.voucher_no ? /* @__PURE__ */ t(
5442
5490
  Ce,
5443
5491
  {
5444
- to: `/app/${bi(u.voucher_type)}/${u.voucher_no}`,
5492
+ to: `/app/${vi(u.voucher_type)}/${u.voucher_no}`,
5445
5493
  className: "font-medium text-blue-600 hover:text-blue-800",
5446
5494
  children: u.voucher_no
5447
5495
  }
@@ -5471,7 +5519,7 @@ function xi() {
5471
5519
  value: i,
5472
5520
  onChange: (u) => g(Number(u.target.value)),
5473
5521
  className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
5474
- children: vi.map((u) => /* @__PURE__ */ t("option", { value: u, children: u }, u))
5522
+ children: xi.map((u) => /* @__PURE__ */ t("option", { value: u, children: u }, u))
5475
5523
  }
5476
5524
  )
5477
5525
  ] }),
@@ -5507,13 +5555,13 @@ function xi() {
5507
5555
  ] })
5508
5556
  ] });
5509
5557
  }
5510
- function ki() {
5511
- const { t: e } = se();
5558
+ function Ni() {
5559
+ const { t: e } = re();
5512
5560
  Me(e("titles.stock-balance"));
5513
5561
  const [n] = he("item_code", ""), [a] = he("warehouse", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(), d = (y) => He(y, h), g = fe(() => {
5514
5562
  const y = {};
5515
5563
  return n && (y.item_code = n), a && (y.warehouse = a), y;
5516
- }, [n, a]), { data: m, isLoading: b, refetch: v } = di(g), k = () => {
5564
+ }, [n, a]), { data: m, isLoading: b, refetch: v } = ui(g), k = () => {
5517
5565
  s({
5518
5566
  item_code: o || null,
5519
5567
  warehouse: l || null
@@ -5563,13 +5611,13 @@ function ki() {
5563
5611
  ] }) }) })
5564
5612
  ] });
5565
5613
  }
5566
- function Ni() {
5567
- const { t: e } = se();
5614
+ function wi() {
5615
+ const { t: e } = re();
5568
5616
  Me(e("titles.profit-and-loss"));
5569
5617
  const [n] = he("company", ""), [a] = he("from", ""), [s] = he("to", ""), o = lt(), [i, l] = w(n), c = Qe(i), h = (p) => He(p, c), [d, g] = w(a), [m, b] = w(s), v = fe(() => {
5570
5618
  const p = {};
5571
5619
  return n && (p.company = n), a && (p.from_date = a), s && (p.to_date = s), p;
5572
- }, [n, a, s]), { data: k, isLoading: y, refetch: A } = ui(v), S = () => {
5620
+ }, [n, a, s]), { data: k, isLoading: y, refetch: A } = mi(v), S = () => {
5573
5621
  o({
5574
5622
  company: i || null,
5575
5623
  from: d || null,
@@ -5631,7 +5679,7 @@ function Ni() {
5631
5679
  ] });
5632
5680
  }
5633
5681
  function on({ title: e, rows: n, total: a, totalLabel: s, currency: o }) {
5634
- const { t: i } = se(), l = (c) => He(c, o);
5682
+ const { t: i } = re(), l = (c) => He(c, o);
5635
5683
  return /* @__PURE__ */ r(H, { children: [
5636
5684
  /* @__PURE__ */ t("h3", { className: "mb-3 text-base font-semibold text-gray-800", children: e }),
5637
5685
  /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
@@ -5650,14 +5698,14 @@ function on({ title: e, rows: n, total: a, totalLabel: s, currency: o }) {
5650
5698
  ] })
5651
5699
  ] });
5652
5700
  }
5653
- function wi() {
5701
+ function Ci() {
5654
5702
  var S, x, p;
5655
- const { t: e } = se();
5703
+ const { t: e } = re();
5656
5704
  Me(e("titles.balance-sheet"));
5657
5705
  const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (f) => He(f, h), g = fe(() => {
5658
5706
  const f = {};
5659
5707
  return n && (f.company = n), a && (f.as_of_date = a), f;
5660
- }, [n, a]), { data: m, isLoading: b, refetch: v } = mi(g), k = () => {
5708
+ }, [n, a]), { data: m, isLoading: b, refetch: v } = pi(g), k = () => {
5661
5709
  s({ company: o || null, as_of_date: l || null }), v();
5662
5710
  }, y = m && (((S = m.assets) == null ? void 0 : S.length) > 0 || ((x = m.liabilities) == null ? void 0 : x.length) > 0 || ((p = m.equity) == null ? void 0 : p.length) > 0), A = m ? Math.abs(m.total_assets - m.total_liabilities_and_equity) < 0.01 : !1;
5663
5711
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -5692,13 +5740,13 @@ function wi() {
5692
5740
  ] }) : /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noData") })
5693
5741
  ] });
5694
5742
  }
5695
- function Ci() {
5696
- const { t: e } = se();
5743
+ function Si() {
5744
+ const { t: e } = re();
5697
5745
  Me(e("titles.ar-aging"));
5698
5746
  const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (y) => He(y, h), g = fe(() => {
5699
5747
  const y = {};
5700
5748
  return n && (y.company = n), a && (y.as_of_date = a), y;
5701
- }, [n, a]), { data: m, isLoading: b, refetch: v } = pi(g), k = () => {
5749
+ }, [n, a]), { data: m, isLoading: b, refetch: v } = hi(g), k = () => {
5702
5750
  s({ company: o || null, as_of_date: l || null }), v();
5703
5751
  };
5704
5752
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -5752,13 +5800,13 @@ function Ci() {
5752
5800
  ] }) }) })
5753
5801
  ] });
5754
5802
  }
5755
- function Si() {
5756
- const { t: e } = se();
5803
+ function Ai() {
5804
+ const { t: e } = re();
5757
5805
  Me(e("titles.ap-aging"));
5758
5806
  const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (y) => He(y, h), g = fe(() => {
5759
5807
  const y = {};
5760
5808
  return n && (y.company = n), a && (y.as_of_date = a), y;
5761
- }, [n, a]), { data: m, isLoading: b, refetch: v } = hi(g), k = () => {
5809
+ }, [n, a]), { data: m, isLoading: b, refetch: v } = gi(g), k = () => {
5762
5810
  s({ company: o || null, as_of_date: l || null }), v();
5763
5811
  };
5764
5812
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -5812,11 +5860,11 @@ function Si() {
5812
5860
  ] }) }) })
5813
5861
  ] });
5814
5862
  }
5815
- function Ai(e) {
5863
+ function _i(e) {
5816
5864
  const n = Number(e ?? 0);
5817
5865
  return Number.isFinite(n) ? n : 0;
5818
5866
  }
5819
- function _i(e, n) {
5867
+ function Di(e, n) {
5820
5868
  if (!n) return e;
5821
5869
  const a = String(e ?? "");
5822
5870
  if (n === "month") return a.slice(0, 7);
@@ -5826,13 +5874,13 @@ function _i(e, n) {
5826
5874
  }
5827
5875
  function dr(e, n, a) {
5828
5876
  if (n === "count") return a ? e.filter((o) => o[a] != null).length : e.length;
5829
- const s = a ? e.filter((o) => o[a] != null).map((o) => Ai(o[a])) : [];
5877
+ const s = a ? e.filter((o) => o[a] != null).map((o) => _i(o[a])) : [];
5830
5878
  return s.length ? n === "sum" ? s.reduce((o, i) => o + i, 0) : n === "avg" ? s.reduce((o, i) => o + i, 0) / s.length : n === "min" ? Math.min(...s) : Math.max(...s) : 0;
5831
5879
  }
5832
- function Di(e, n) {
5880
+ function Pi(e, n) {
5833
5881
  return e == null && n == null ? 0 : e == null ? 1 : n == null ? -1 : typeof e == "number" && typeof n == "number" ? e - n : String(e).localeCompare(String(n), void 0, { numeric: !0 });
5834
5882
  }
5835
- function Pi(e, n) {
5883
+ function Ti(e, n) {
5836
5884
  const a = n.get(e.source);
5837
5885
  if (!a) throw new Error(`Unknown report source: ${e.source}`);
5838
5886
  const s = e.dimensions ?? [], o = e.measures ?? [];
@@ -5844,7 +5892,7 @@ function Pi(e, n) {
5844
5892
  for (const c of a) {
5845
5893
  const h = {};
5846
5894
  for (const m of s) {
5847
- const b = m.key || m.field, v = _i(c[m.field], m.bucket);
5895
+ const b = m.key || m.field, v = Di(c[m.field], m.bucket);
5848
5896
  h[b] = v == null || v === "" ? m.fallback ?? v : v;
5849
5897
  }
5850
5898
  const d = JSON.stringify(s.map((m) => h[m.key || m.field])), g = l.get(d) ?? { values: h, rows: [] };
@@ -5859,7 +5907,7 @@ function Pi(e, n) {
5859
5907
  }
5860
5908
  for (const l of [...e.sort ?? []].reverse()) {
5861
5909
  const c = l.direction === "desc" ? -1 : 1;
5862
- i.sort((h, d) => Di(h[l.field], d[l.field]) * c);
5910
+ i.sort((h, d) => Pi(h[l.field], d[l.field]) * c);
5863
5911
  }
5864
5912
  return e.limit && (i = i.slice(0, e.limit)), {
5865
5913
  id: e.id,
@@ -5868,12 +5916,12 @@ function Pi(e, n) {
5868
5916
  rows: i
5869
5917
  };
5870
5918
  }
5871
- function Ti(e, n) {
5919
+ function Ri(e, n) {
5872
5920
  if (!e.report || e.report.version !== 1 || !Array.isArray(e.report.tables))
5873
5921
  throw new Error("Unsupported custom report definition. Create a new version 1 report.");
5874
5922
  const a = new Map(n.map((l) => [l.name, l.rows])), s = e.report.tables.map((l) => {
5875
5923
  if (a.has(l.id)) throw new Error(`Duplicate report source/table id: ${l.id}`);
5876
- const c = Pi(l, a);
5924
+ const c = Ti(l, a);
5877
5925
  return a.set(l.id, c.rows), c;
5878
5926
  }), o = new Set(s.map((l) => l.id)), i = (e.report.charts ?? []).map((l) => {
5879
5927
  if (!o.has(l.data_table))
@@ -5896,7 +5944,7 @@ function Ti(e, n) {
5896
5944
  charts: i
5897
5945
  };
5898
5946
  }
5899
- function Ri() {
5947
+ function Bi() {
5900
5948
  const e = /* @__PURE__ */ new Date(), n = De(e), a = new Date(e);
5901
5949
  a.setMonth(a.getMonth() - 12);
5902
5950
  const s = De(a);
@@ -5965,23 +6013,23 @@ function Ri() {
5965
6013
  2
5966
6014
  );
5967
6015
  }
5968
- const ur = Ri();
5969
- function Bi() {
6016
+ const ur = Bi();
6017
+ function Ii() {
5970
6018
  Me("Analytics");
5971
- const e = Ke(), { sessions: n, createSession: a } = vt(), [s] = he("report_id", ""), [o] = he("metric", ""), [i] = he("group_by", ""), [l] = he("from", ""), [c] = he("to", ""), [h] = he("company", ""), [d, g] = w(ur), [m, b] = w([]), [v, k] = w(null), [y, A] = w(""), [S, x] = w(!1), [p, f] = w(!1), [B, E] = w(""), J = pe(""), Z = pe(""), O = pe(0), q = fe(() => !o || !i ? "" : JSON.stringify(Oi({
6019
+ const e = Ke(), { sessions: n, createSession: a } = vt(), [s] = he("report_id", ""), [o] = he("metric", ""), [i] = he("group_by", ""), [l] = he("from", ""), [c] = he("to", ""), [h] = he("company", ""), [d, g] = w(ur), [m, b] = w([]), [v, k] = w(null), [y, A] = w(""), [S, x] = w(!1), [p, f] = w(!1), [B, E] = w(""), J = pe(""), Z = pe(""), L = pe(0), q = fe(() => !o || !i ? "" : JSON.stringify(Fi({
5972
6020
  metric: o,
5973
6021
  groupBy: i,
5974
6022
  fromDate: l || void 0,
5975
6023
  toDate: c || void 0,
5976
6024
  company: h || void 0
5977
6025
  }), null, 2), [o, i, l, c, h]), Q = async (u) => {
5978
- const P = ++O.current, V = () => O.current === P;
6026
+ const P = ++L.current, V = () => L.current === P;
5979
6027
  A(""), x(!0);
5980
6028
  try {
5981
6029
  const W = JSON.parse(u ?? d), le = await F.runtimeData({ requests: W.data_requests || [] });
5982
6030
  if (!V()) return;
5983
6031
  b(le.datasets);
5984
- const ue = Ti(W, le.datasets);
6032
+ const ue = Ri(W, le.datasets);
5985
6033
  if (!V()) return;
5986
6034
  k(ue);
5987
6035
  } catch (T) {
@@ -6007,7 +6055,7 @@ function Bi() {
6007
6055
  u = !0;
6008
6056
  });
6009
6057
  }, [s, q]);
6010
- const N = !!(!s && q), D = fe(() => Li(v), [v]), $ = async () => {
6058
+ const N = !!(!s && q), D = fe(() => Oi(v), [v]), $ = async () => {
6011
6059
  var ue;
6012
6060
  const u = d.trim() !== Z.current.trim(), P = s || "unsaved-runtime-report", V = m.map((Ne) => ({
6013
6061
  name: Ne.name,
@@ -6059,7 +6107,7 @@ function Bi() {
6059
6107
  /* @__PURE__ */ t(Y, { onClick: () => void Q(), disabled: S, children: S ? "Running..." : "Run Report" })
6060
6108
  ] })
6061
6109
  ] }) }),
6062
- p ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : y ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: y }) }) : v ? /* @__PURE__ */ t(Ii, { output: v }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
6110
+ p ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : y ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: y }) }) : v ? /* @__PURE__ */ t(Ei, { output: v }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
6063
6111
  m.length > 0 && /* @__PURE__ */ t(H, { title: "Fetched Datasets", children: /* @__PURE__ */ t("div", { className: "space-y-4", children: m.map((u) => /* @__PURE__ */ r("div", { className: "rounded-md border border-gray-200 p-4", children: [
6064
6112
  /* @__PURE__ */ r("div", { className: "flex items-baseline justify-between gap-4", children: [
6065
6113
  /* @__PURE__ */ r("div", { children: [
@@ -6088,7 +6136,7 @@ function Bi() {
6088
6136
  ] })
6089
6137
  ] });
6090
6138
  }
6091
- function Ii({ output: e }) {
6139
+ function Ei({ output: e }) {
6092
6140
  var o, i;
6093
6141
  const n = Qe(), a = (e.tables ?? []).map((l, c) => ({
6094
6142
  ...l,
@@ -6110,11 +6158,11 @@ function Ii({ output: e }) {
6110
6158
  const h = l.dataTable ? s.get(l.dataTable) : void 0, d = l.data ?? (h == null ? void 0 : h.rows) ?? [];
6111
6159
  if (!d.length)
6112
6160
  return /* @__PURE__ */ t(H, { title: l.title, children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: "Chart has no usable data." }) }, l.id || `chart_${c + 1}`);
6113
- const g = l.type === "pie" ? [] : d.map((S) => String(S[l.x] ?? "")), m = $i(g), b = Math.max(320, 200 + m.axisHeight), v = (y = l.series) != null && y.length ? l.series : l.y ? [{ key: l.y, label: void 0 }] : [], k = (S, x, p) => {
6161
+ const g = l.type === "pie" ? [] : d.map((S) => String(S[l.x] ?? "")), m = Vi(g), b = Math.max(320, 200 + m.axisHeight), v = (y = l.series) != null && y.length ? l.series : l.y ? [{ key: l.y, label: void 0 }] : [], k = (S, x, p) => {
6114
6162
  var f;
6115
6163
  return ln(
6116
6164
  S,
6117
- Mi(h, String((p == null ? void 0 : p.dataKey) ?? ((f = v[0]) == null ? void 0 : f.key) ?? "")),
6165
+ qi(h, String((p == null ? void 0 : p.dataKey) ?? ((f = v[0]) == null ? void 0 : f.key) ?? "")),
6118
6166
  n
6119
6167
  );
6120
6168
  };
@@ -6186,7 +6234,7 @@ function Ii({ output: e }) {
6186
6234
  ] }) }) }, l.id))
6187
6235
  ] });
6188
6236
  }
6189
- function Ei(e) {
6237
+ function Li(e) {
6190
6238
  return e.replace(/_/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
6191
6239
  }
6192
6240
  function mr(e) {
@@ -6195,7 +6243,7 @@ function mr(e) {
6195
6243
  n.set(a.id, a), a.title && n.set(a.title, a);
6196
6244
  return n;
6197
6245
  }
6198
- function Li(e) {
6246
+ function Oi(e) {
6199
6247
  var o;
6200
6248
  if (!e) return [];
6201
6249
  const n = (e.tables ?? []).map((i, l) => ({
@@ -6218,8 +6266,8 @@ function Li(e) {
6218
6266
  }
6219
6267
  return s;
6220
6268
  }
6221
- function Oi(e) {
6222
- const n = `${Fi(e.metric)} by ${Ei(e.groupBy)}`;
6269
+ function Fi(e) {
6270
+ const n = `${Mi(e.metric)} by ${Li(e.groupBy)}`;
6223
6271
  if (e.metric === "sales_revenue")
6224
6272
  return kt({
6225
6273
  title: n,
@@ -6367,7 +6415,7 @@ function kt(e) {
6367
6415
  }
6368
6416
  };
6369
6417
  }
6370
- function Fi(e) {
6418
+ function Mi(e) {
6371
6419
  return {
6372
6420
  sales_revenue: "Sales Revenue",
6373
6421
  sales_returns: "Sales Returns",
@@ -6379,7 +6427,7 @@ function Fi(e) {
6379
6427
  stock_value: "Stock Value"
6380
6428
  }[e] || "Analytics";
6381
6429
  }
6382
- function Mi(e, n) {
6430
+ function qi(e, n) {
6383
6431
  var a, s;
6384
6432
  return ((a = e == null ? void 0 : e.columns.find((o) => o.key === n)) == null ? void 0 : a.type) || ((s = e == null ? void 0 : e.columns.find((o) => o.key === n)) == null ? void 0 : s.format);
6385
6433
  }
@@ -6390,23 +6438,23 @@ function pa(e) {
6390
6438
  const n = Math.abs(e);
6391
6439
  return n >= 1e6 ? `${(e / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(e / 1e3).toFixed(0)}k` : String(e);
6392
6440
  }
6393
- const Rt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], ha = Rt, qi = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
6441
+ const Rt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], ha = Rt, zi = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
6394
6442
  let cn = null;
6395
- function zi(e, n = qi) {
6443
+ function $i(e, n = zi) {
6396
6444
  if (typeof document > "u") return e.length * 7;
6397
6445
  cn || (cn = document.createElement("canvas"));
6398
6446
  const a = cn.getContext("2d");
6399
6447
  return a ? (a.font = n, a.measureText(e).width) : e.length * 7;
6400
6448
  }
6401
- function $i(e) {
6449
+ function Vi(e) {
6402
6450
  if (!e.length) return { angle: 0, axisHeight: 30, maxWidth: 0 };
6403
- const n = e.map((c) => zi(c)), a = Math.max(1, ...n);
6451
+ const n = e.map((c) => $i(c)), a = Math.max(1, ...n);
6404
6452
  let s = 0;
6405
6453
  a > 55 && (s = -30), a > 110 && (s = -45), a > 200 && (s = -60), a > 300 && (s = -90);
6406
6454
  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));
6407
6455
  return { angle: s, axisHeight: l, maxWidth: a };
6408
6456
  }
6409
- function Vi(e) {
6457
+ function Ui(e) {
6410
6458
  return ve({
6411
6459
  queryKey: ["fleet-calendar", e],
6412
6460
  queryFn: () => F.fleetCalendar(e)
@@ -6427,24 +6475,24 @@ function mn(e, n) {
6427
6475
  function fa(e) {
6428
6476
  return new Date(e.replace(" ", "T")).getTime();
6429
6477
  }
6430
- const Ui = {
6478
+ const Ki = {
6431
6479
  Reserved: "bg-amber-400 text-amber-950",
6432
6480
  "On Hire": "bg-blue-500 text-white",
6433
6481
  Returned: "bg-gray-300 text-gray-700",
6434
6482
  Cancelled: "bg-gray-200 text-gray-500 line-through"
6435
- }, Ki = {
6483
+ }, ji = {
6436
6484
  Available: "bg-green-500",
6437
6485
  "On Hire": "bg-blue-500",
6438
6486
  Maintenance: "bg-amber-500",
6439
6487
  Retired: "bg-gray-400"
6440
6488
  };
6441
- function ji() {
6442
- const { t: e } = se();
6489
+ function Wi() {
6490
+ const { t: e } = re();
6443
6491
  Me(e("rentals.fleetCalendar", { defaultValue: "Fleet Calendar" }));
6444
6492
  const n = Ke(), [a, s] = w(28), [o, i] = w(ga()), [l, c] = w(""), [h, d] = w(""), [g, m] = w(""), [b, v] = w(""), k = fe(() => mn(o, a), [o, a]), y = o.getTime(), A = a * pr, S = fe(
6445
6493
  () => Array.from({ length: a }, ($, u) => mn(o, u)),
6446
6494
  [o, a]
6447
- ), { data: x, isLoading: p, error: f } = Vi({
6495
+ ), { data: x, isLoading: p, error: f } = Ui({
6448
6496
  from: zt(o),
6449
6497
  to: zt(k),
6450
6498
  warehouse: g || void 0,
@@ -6456,7 +6504,7 @@ function ji() {
6456
6504
  V.push(u), $.set(P, V);
6457
6505
  }
6458
6506
  return $;
6459
- }, [x]), J = ((x == null ? void 0 : x.reservations) ?? []).filter(($) => !$.asset), Z = J.length, O = [...B, ...J.map(($) => ({
6507
+ }, [x]), J = ((x == null ? void 0 : x.reservations) ?? []).filter(($) => !$.asset), Z = J.length, L = [...B, ...J.map(($) => ({
6460
6508
  name: `pool:${$.name}`,
6461
6509
  asset_tag: e("rentals.unassigned"),
6462
6510
  item_code: $.item_code,
@@ -6530,7 +6578,7 @@ function ji() {
6530
6578
  e("rentals.pooledNote", { count: Z, defaultValue: "{{count}} pool booking(s) awaiting assignment" })
6531
6579
  ] })
6532
6580
  ] }),
6533
- f ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-red-500", children: e("rentals.loadError", { defaultValue: "Could not load the fleet calendar." }) }) : p ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("common.loading", { defaultValue: "Loading…" }) }) : O.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("rentals.noAssets", { defaultValue: "No assets to show. Add machines under Rentals → Fleet." }) }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("div", { style: { minWidth: un + D }, children: [
6581
+ f ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-red-500", children: e("rentals.loadError", { defaultValue: "Could not load the fleet calendar." }) }) : p ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("common.loading", { defaultValue: "Loading…" }) }) : L.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("rentals.noAssets", { defaultValue: "No assets to show. Add machines under Rentals → Fleet." }) }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("div", { style: { minWidth: un + D }, children: [
6534
6582
  /* @__PURE__ */ r("div", { className: "flex border-b bg-gray-50 text-xs text-gray-500", children: [
6535
6583
  /* @__PURE__ */ t("div", { className: "shrink-0 px-3 py-2 font-medium", style: { width: un }, children: e("rentals.machine", { defaultValue: "Machine" }) }),
6536
6584
  /* @__PURE__ */ t("div", { className: "flex", style: { width: D }, children: S.map(($) => /* @__PURE__ */ r("div", { className: "shrink-0 border-l py-2 text-center", style: { width: dn }, children: [
@@ -6538,12 +6586,12 @@ function ji() {
6538
6586
  /* @__PURE__ */ t("div", { className: "text-[10px] uppercase", children: $.toLocaleDateString(void 0, { weekday: "short" }) })
6539
6587
  ] }, $.getTime())) })
6540
6588
  ] }),
6541
- O.map(($) => {
6589
+ L.map(($) => {
6542
6590
  const u = E.get($.name) ?? [];
6543
6591
  return /* @__PURE__ */ r("div", { className: "flex border-b hover:bg-gray-50", children: [
6544
6592
  /* @__PURE__ */ r("div", { className: "shrink-0 px-3 py-2", style: { width: un }, children: [
6545
6593
  /* @__PURE__ */ r("div", { className: "flex items-center gap-2 text-sm font-medium", children: [
6546
- /* @__PURE__ */ t("span", { className: `inline-block h-2.5 w-2.5 rounded-full ${Ki[$.status ?? ""] ?? "bg-gray-300"}` }),
6594
+ /* @__PURE__ */ t("span", { className: `inline-block h-2.5 w-2.5 rounded-full ${ji[$.status ?? ""] ?? "bg-gray-300"}` }),
6547
6595
  $.asset_tag ?? $.name
6548
6596
  ] }),
6549
6597
  /* @__PURE__ */ r("div", { className: "text-xs text-gray-500", children: [
@@ -6555,7 +6603,7 @@ function ji() {
6555
6603
  /* @__PURE__ */ r("div", { className: "relative", style: { width: D, height: 44 }, children: [
6556
6604
  /* @__PURE__ */ t("div", { className: "absolute inset-0 flex", children: S.map((P) => /* @__PURE__ */ t("div", { className: "shrink-0 border-l", style: { width: dn } }, P.getTime())) }),
6557
6605
  u.map((P) => {
6558
- const { left: V, width: T } = q(P), W = Ui[P.status ?? ""] ?? "bg-slate-400 text-white";
6606
+ const { left: V, width: T } = q(P), W = Ki[P.status ?? ""] ?? "bg-slate-400 text-white";
6559
6607
  return /* @__PURE__ */ t(
6560
6608
  "button",
6561
6609
  {
@@ -6574,8 +6622,8 @@ function ji() {
6574
6622
  ] }) }) })
6575
6623
  ] });
6576
6624
  }
6577
- const Wi = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
6578
- function Gi() {
6625
+ const Gi = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
6626
+ function Hi() {
6579
6627
  Me("Company Setup");
6580
6628
  const e = et(), { data: n, isLoading: a } = ve({
6581
6629
  queryKey: ["setup-status"],
@@ -6609,7 +6657,7 @@ function Gi() {
6609
6657
  return /* @__PURE__ */ t("p", { className: "text-gray-500", children: "Loading..." });
6610
6658
  if (n != null && n.setup_complete && !b)
6611
6659
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
6612
- /* @__PURE__ */ t(H, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ t("ul", { className: "divide-y divide-gray-100", children: n.companies.map((E, J) => /* @__PURE__ */ t("li", { className: "py-3", children: /* @__PURE__ */ t(Hi, { company: E }) }, J)) }) : /* @__PURE__ */ t("p", { className: "text-gray-400", children: "No companies found" }) }),
6660
+ /* @__PURE__ */ t(H, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ t("ul", { className: "divide-y divide-gray-100", children: n.companies.map((E, J) => /* @__PURE__ */ t("li", { className: "py-3", children: /* @__PURE__ */ t(Qi, { company: E }) }, J)) }) : /* @__PURE__ */ t("p", { className: "text-gray-400", children: "No companies found" }) }),
6613
6661
  /* @__PURE__ */ t(Ce, { to: "/", className: "text-blue-600 hover:text-blue-800 text-sm font-medium", children: "Go to Dashboard" })
6614
6662
  ] });
6615
6663
  if (b)
@@ -6644,7 +6692,7 @@ function Gi() {
6644
6692
  Ge,
6645
6693
  {
6646
6694
  label: "Currency",
6647
- options: Wi,
6695
+ options: Gi,
6648
6696
  value: i,
6649
6697
  onChange: (E) => l(E.target.value)
6650
6698
  }
@@ -6739,7 +6787,7 @@ function Gi() {
6739
6787
  ] }) })
6740
6788
  ] });
6741
6789
  }
6742
- function Hi({ company: e }) {
6790
+ function Qi({ company: e }) {
6743
6791
  const n = [
6744
6792
  [e.city, e.zip_code].filter(Boolean).join(" "),
6745
6793
  e.country
@@ -6780,7 +6828,7 @@ function Hi({ company: e }) {
6780
6828
  e.default_currency && /* @__PURE__ */ t("span", { className: "shrink-0 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: e.default_currency })
6781
6829
  ] });
6782
6830
  }
6783
- const Qi = [
6831
+ const Yi = [
6784
6832
  {
6785
6833
  number: 1,
6786
6834
  title: "Set Up Your Company",
@@ -6932,8 +6980,8 @@ function hr() {
6932
6980
  e(`/chat/${o}`, { state: { prefillMessage: s } });
6933
6981
  };
6934
6982
  }
6935
- function Yi() {
6936
- const { t: e } = se(), n = hr();
6983
+ function Ji() {
6984
+ const { t: e } = re(), n = hr();
6937
6985
  return /* @__PURE__ */ t(H, { 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: [
6938
6986
  /* @__PURE__ */ t("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: "▶" }),
6939
6987
  /* @__PURE__ */ r("div", { className: "flex-1 space-y-3", children: [
@@ -6968,8 +7016,8 @@ function Yi() {
6968
7016
  ] })
6969
7017
  ] }) });
6970
7018
  }
6971
- function Ji() {
6972
- const { t: e } = se(), n = hr(), a = [
7019
+ function Zi() {
7020
+ const { t: e } = re(), n = hr(), a = [
6973
7021
  e("tutorial.caPrompt1"),
6974
7022
  e("tutorial.caPrompt2"),
6975
7023
  e("tutorial.caPrompt3"),
@@ -7027,8 +7075,8 @@ function Ji() {
7027
7075
  ] })
7028
7076
  ] }) });
7029
7077
  }
7030
- function Zi() {
7031
- const { t: e } = se(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
7078
+ function Xi() {
7079
+ const { t: e } = re(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
7032
7080
  return /* @__PURE__ */ r(H, { children: [
7033
7081
  /* @__PURE__ */ t("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: e("tutorial.flowTitle") }),
7034
7082
  /* @__PURE__ */ r("div", { className: "space-y-4 text-sm text-gray-600", children: [
@@ -7098,8 +7146,8 @@ function Zi() {
7098
7146
  ] })
7099
7147
  ] });
7100
7148
  }
7101
- function Xi() {
7102
- const { t: e } = se(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
7149
+ function eo() {
7150
+ const { t: e } = re(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
7103
7151
  return /* @__PURE__ */ r(H, { children: [
7104
7152
  /* @__PURE__ */ t("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: e("tutorial.lifecycleTitle") }),
7105
7153
  /* @__PURE__ */ r("div", { className: "space-y-2 text-sm text-gray-600", children: [
@@ -7134,8 +7182,8 @@ function Xi() {
7134
7182
  ] })
7135
7183
  ] });
7136
7184
  }
7137
- function eo() {
7138
- const { t: e } = se();
7185
+ function to() {
7186
+ const { t: e } = re();
7139
7187
  return Me(e("titles.tutorial")), /* @__PURE__ */ r("div", { className: "mx-auto max-w-3xl space-y-6", children: [
7140
7188
  /* @__PURE__ */ r("div", { children: [
7141
7189
  /* @__PURE__ */ t("h2", { className: "text-xl font-semibold text-gray-900", children: e("tutorial.pageTitle") }),
@@ -7158,11 +7206,11 @@ function eo() {
7158
7206
  ] }),
7159
7207
  /* @__PURE__ */ t("p", { className: "mt-4 text-sm text-gray-500", children: e("tutorial.manualIntro") })
7160
7208
  ] }),
7161
- /* @__PURE__ */ t(Yi, {}),
7162
7209
  /* @__PURE__ */ t(Ji, {}),
7163
7210
  /* @__PURE__ */ t(Zi, {}),
7164
7211
  /* @__PURE__ */ t(Xi, {}),
7165
- Qi.map((n) => {
7212
+ /* @__PURE__ */ t(eo, {}),
7213
+ Yi.map((n) => {
7166
7214
  var a;
7167
7215
  return /* @__PURE__ */ t(H, { children: /* @__PURE__ */ r("div", { className: "flex gap-4", children: [
7168
7216
  /* @__PURE__ */ t("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 }),
@@ -7223,7 +7271,7 @@ function eo() {
7223
7271
  ] }) })
7224
7272
  ] });
7225
7273
  }
7226
- const pn = 5, to = 10 * 1024 * 1024, no = /* @__PURE__ */ new Set([
7274
+ const pn = 5, no = 10 * 1024 * 1024, ao = /* @__PURE__ */ new Set([
7227
7275
  "image/png",
7228
7276
  "image/jpeg",
7229
7277
  "image/gif",
@@ -7258,7 +7306,7 @@ const pn = 5, to = 10 * 1024 * 1024, no = /* @__PURE__ */ new Set([
7258
7306
  "text/xml",
7259
7307
  "application/zip",
7260
7308
  "application/x-zip-compressed"
7261
- ]), ao = /* @__PURE__ */ new Set([
7309
+ ]), ro = /* @__PURE__ */ new Set([
7262
7310
  "png",
7263
7311
  "jpg",
7264
7312
  "jpeg",
@@ -7279,10 +7327,10 @@ const pn = 5, to = 10 * 1024 * 1024, no = /* @__PURE__ */ new Set([
7279
7327
  "xml",
7280
7328
  "zip"
7281
7329
  ]);
7282
- function ro(e) {
7330
+ function so(e) {
7283
7331
  return new Promise((n) => window.setTimeout(n, e));
7284
7332
  }
7285
- function so(e) {
7333
+ function io(e) {
7286
7334
  return new Promise((n, a) => {
7287
7335
  const s = new FileReader();
7288
7336
  s.onloadend = () => {
@@ -7313,12 +7361,12 @@ function ba(e) {
7313
7361
  }
7314
7362
  function va() {
7315
7363
  var Mn;
7316
- const { t: e } = se(), { sessionId: n } = bt(), a = Ke(), s = Ct(), [o] = Jt(), i = o.get("demo") === "1", [l, c] = w(""), [h, d] = w(""), [g, m] = w([]), [b, v] = w(""), [k, y] = w(!1), [A, S] = w("idle"), x = pe(null), p = pe(null), f = pe([]), {
7364
+ const { t: e } = re(), { sessionId: n } = bt(), a = Ke(), s = Ct(), [o] = Jt(), i = o.get("demo") === "1", [l, c] = w(""), [h, d] = w(""), [g, m] = w([]), [b, v] = w(""), [k, y] = w(!1), [A, S] = w("idle"), x = pe(null), p = pe(null), f = pe([]), {
7317
7365
  sessions: B,
7318
7366
  connectionStatus: E,
7319
7367
  connectionVersion: J,
7320
7368
  createSession: Z,
7321
- startDemo: O,
7369
+ startDemo: L,
7322
7370
  completeDemoTyping: q,
7323
7371
  loadHistory: Q,
7324
7372
  loadMoreHistory: N,
@@ -7330,7 +7378,7 @@ function va() {
7330
7378
  isThinking: T,
7331
7379
  getDemoStatus: W,
7332
7380
  getDemoTypingCue: le
7333
- } = vt(), ue = pe(null), Ne = pe(null), xe = pe(null), qe = pe(null), [R, ae] = w(0), be = pe(!1), L = pe(null), oe = pe(0), Ie = pe(!0), Ae = pe(null), Ye = pe(!1), tt = pe(null), je = u(n), st = (Mn = B.find((I) => I.id === n)) == null ? void 0 : Mn.title;
7381
+ } = vt(), ue = pe(null), Ne = pe(null), be = pe(null), qe = pe(null), [R, ae] = w(0), xe = pe(!1), O = pe(null), oe = pe(0), Ie = pe(!0), Ae = pe(null), Ye = pe(!1), tt = pe(null), je = u(n), st = (Mn = B.find((I) => I.id === n)) == null ? void 0 : Mn.title;
7334
7382
  Me(st || null);
7335
7383
  const U = E === "connected", te = T(n), _e = W(n), _ = le(n), M = i || _e === "running", K = P(n), C = V(n), j = je[je.length - 1], G = j ? `${j.type}:${j.timestamp || ""}:${j.content}` : "empty", ye = Ue(() => {
7336
7384
  Ye.current = !0, tt.current !== null && window.clearTimeout(tt.current), tt.current = window.setTimeout(() => {
@@ -7381,11 +7429,11 @@ function va() {
7381
7429
  });
7382
7430
  }, [n, C, K, N]), Te = pe(null);
7383
7431
  ce(() => {
7384
- d(""), L.current = null, oe.current += 1, n && ja(n);
7432
+ d(""), O.current = null, oe.current += 1, n && ja(n);
7385
7433
  const I = s.state;
7386
7434
  I != null && I.prefillMessage && Te.current !== I ? (Te.current = I, c(I.prefillMessage), window.setTimeout(() => {
7387
7435
  var ne;
7388
- return (ne = xe.current) == null ? void 0 : ne.focus();
7436
+ return (ne = be.current) == null ? void 0 : ne.focus();
7389
7437
  }, 50)) : I != null && I.prefillMessage || (Te.current = null, c(""));
7390
7438
  }, [n, i, s.state]), ce(() => {
7391
7439
  if (n || !U) return;
@@ -7397,17 +7445,17 @@ function va() {
7397
7445
  I = !0;
7398
7446
  };
7399
7447
  }, [n, U, a]);
7400
- const re = pe(Q);
7448
+ const se = pe(Q);
7401
7449
  ce(() => {
7402
- re.current = Q;
7450
+ se.current = Q;
7403
7451
  }, [Q]), ce(() => {
7404
- !n || !U || i || _e === "running" || re.current(n).catch(() => {
7452
+ !n || !U || i || _e === "running" || se.current(n).catch(() => {
7405
7453
  });
7406
7454
  }, [n, U, J, i, _e]), ce(() => {
7407
- be.current && !te && U && setTimeout(() => {
7455
+ xe.current && !te && U && setTimeout(() => {
7408
7456
  var I;
7409
- return (I = xe.current) == null ? void 0 : I.focus();
7410
- }, 50), be.current = te;
7457
+ return (I = be.current) == null ? void 0 : I.focus();
7458
+ }, 50), xe.current = te;
7411
7459
  }, [te, U]);
7412
7460
  function gt(I) {
7413
7461
  if (Ye.current) return;
@@ -7415,10 +7463,10 @@ function va() {
7415
7463
  Ie.current = ge < 80;
7416
7464
  }
7417
7465
  ce(() => {
7418
- !n || !U || !i || L.current !== n && (L.current = n, d(""), O(n).catch((I) => {
7419
- L.current = null, d(I instanceof Error ? I.message : e("chat.demoError"));
7466
+ !n || !U || !i || O.current !== n && (O.current = n, d(""), L(n).catch((I) => {
7467
+ O.current = null, d(I instanceof Error ? I.message : e("chat.demoError"));
7420
7468
  }));
7421
- }, [n, U, i, O]), ce(() => {
7469
+ }, [n, U, i, L]), ce(() => {
7422
7470
  !n || !i || _e !== "complete" || (c(""), a(`/chat/${n}`, { replace: !0 }));
7423
7471
  }, [n, i, _e, a]);
7424
7472
  const Le = pe(q);
@@ -7434,7 +7482,7 @@ function va() {
7434
7482
  c("");
7435
7483
  for (const dt of ne) {
7436
7484
  if (Be !== oe.current) return;
7437
- c((nt) => nt + dt), await ro(ge);
7485
+ c((nt) => nt + dt), await so(ge);
7438
7486
  }
7439
7487
  Be === oe.current && Le.current(I, Re);
7440
7488
  }
@@ -7454,11 +7502,11 @@ function va() {
7454
7502
  break;
7455
7503
  }
7456
7504
  const xt = Be.name.includes(".") ? Be.name.split(".").pop().toLowerCase() : "";
7457
- if (!no.has(Be.type) && !ao.has(xt)) {
7505
+ if (!ao.has(Be.type) && !ro.has(xt)) {
7458
7506
  v(`Unsupported file type: ${Be.type || Be.name}`);
7459
7507
  continue;
7460
7508
  }
7461
- if (Be.size > to) {
7509
+ if (Be.size > no) {
7462
7510
  v(`"${Be.name}" is too large (max 10 MB).`);
7463
7511
  continue;
7464
7512
  }
@@ -7515,7 +7563,7 @@ function va() {
7515
7563
  function Cr(I) {
7516
7564
  const ne = I.trim();
7517
7565
  ne && (c((ge) => ge.trim() ? `${ge.trim()} ${ne}` : ne), window.setTimeout(() => {
7518
- const ge = xe.current;
7566
+ const ge = be.current;
7519
7567
  ge && (ge.focus(), ge.style.height = "auto", ge.style.height = Math.min(Math.max(ge.scrollHeight, 48), 120) + "px");
7520
7568
  }, 0));
7521
7569
  }
@@ -7543,7 +7591,7 @@ function va() {
7543
7591
  const Re = ne.mimeType || ((dt = ge[0]) == null ? void 0 : dt.type) || "audio/webm", Be = new Blob(ge, { type: Re }), xt = (Re.split(";")[0].split("/")[1] || "webm").toLowerCase();
7544
7592
  S("transcribing");
7545
7593
  try {
7546
- const nt = await so(Be), tn = await $(nt, xt, n);
7594
+ const nt = await io(Be), tn = await $(nt, xt, n);
7547
7595
  Cr(tn);
7548
7596
  } catch (nt) {
7549
7597
  v(nt instanceof Error ? nt.message : e("chat.transcribeFailed"));
@@ -7603,7 +7651,7 @@ function va() {
7603
7651
  {
7604
7652
  onClick: () => {
7605
7653
  var ne;
7606
- c(I), (ne = xe.current) == null || ne.focus();
7654
+ c(I), (ne = be.current) == null || ne.focus();
7607
7655
  },
7608
7656
  className: "rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line transition-all hover:bg-surface-subtle hover:text-fg hover:ring-brand/30",
7609
7657
  children: I
@@ -7611,7 +7659,7 @@ function va() {
7611
7659
  I
7612
7660
  )) })
7613
7661
  ] }),
7614
- je.map((I, ne) => /* @__PURE__ */ t(oo, { message: I }, ne)),
7662
+ je.map((I, ne) => /* @__PURE__ */ t(lo, { message: I }, ne)),
7615
7663
  /* @__PURE__ */ t("div", { ref: Ne })
7616
7664
  ]
7617
7665
  }
@@ -7665,7 +7713,7 @@ function va() {
7665
7713
  /* @__PURE__ */ t(
7666
7714
  "textarea",
7667
7715
  {
7668
- ref: xe,
7716
+ ref: be,
7669
7717
  value: l,
7670
7718
  onChange: (I) => c(I.target.value),
7671
7719
  onKeyDown: wr,
@@ -7748,7 +7796,7 @@ function gr(e) {
7748
7796
  const n = e.includes(".") ? e.split(".").pop().toUpperCase() : "";
7749
7797
  return n ? n.slice(0, 4) : "FILE";
7750
7798
  }
7751
- function io({ attachments: e }) {
7799
+ function oo({ attachments: e }) {
7752
7800
  return !e || e.length === 0 ? null : /* @__PURE__ */ t("div", { className: "mt-1 flex flex-wrap gap-1.5", children: e.map((n) => {
7753
7801
  const a = F.getChatAttachmentUrl(n.id), s = n.mime_type.startsWith("image/");
7754
7802
  return /* @__PURE__ */ r(
@@ -7768,13 +7816,13 @@ function io({ attachments: e }) {
7768
7816
  );
7769
7817
  }) });
7770
7818
  }
7771
- function oo({ message: e }) {
7819
+ function lo({ message: e }) {
7772
7820
  return e.type === "user" ? /* @__PURE__ */ t("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: [
7773
7821
  /* @__PURE__ */ t("div", { className: "whitespace-pre-wrap", children: e.content }),
7774
- /* @__PURE__ */ t(io, { attachments: e.attachments }),
7822
+ /* @__PURE__ */ t(oo, { attachments: e.attachments }),
7775
7823
  e.timestamp && /* @__PURE__ */ t("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: ba(e.timestamp), children: ya(e.timestamp) })
7776
7824
  ] }) }) : e.type === "assistant" ? /* @__PURE__ */ t("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: [
7777
- /* @__PURE__ */ t(co, { content: e.content }),
7825
+ /* @__PURE__ */ t(uo, { content: e.content }),
7778
7826
  e.timestamp && /* @__PURE__ */ t("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: ba(e.timestamp), children: ya(e.timestamp) })
7779
7827
  ] }) }) : e.type === "thinking" ? /* @__PURE__ */ t("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: [
7780
7828
  /* @__PURE__ */ t("span", { className: "inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-brand" }),
@@ -7832,7 +7880,7 @@ function hn(e) {
7832
7880
  return a.startsWith(":") && a.endsWith(":") ? "center" : a.endsWith(":") ? "right" : "left";
7833
7881
  });
7834
7882
  }
7835
- function lo({
7883
+ function co({
7836
7884
  header: e,
7837
7885
  rows: n,
7838
7886
  alignments: a
@@ -7859,7 +7907,7 @@ function lo({
7859
7907
  )) }, o)) })
7860
7908
  ] }) });
7861
7909
  }
7862
- function co({ content: e }) {
7910
+ function uo({ content: e }) {
7863
7911
  const n = e.split(`
7864
7912
  `), a = [];
7865
7913
  let s = !1, o = [];
@@ -7910,7 +7958,7 @@ function co({ content: e }) {
7910
7958
  }
7911
7959
  a.push(
7912
7960
  /* @__PURE__ */ t(
7913
- lo,
7961
+ co,
7914
7962
  {
7915
7963
  header: c,
7916
7964
  rows: g,
@@ -7957,7 +8005,7 @@ function fr(e, n, a) {
7957
8005
  a
7958
8006
  );
7959
8007
  }
7960
- const uo = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
8008
+ const mo = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
7961
8009
  function wt(e) {
7962
8010
  return e.split(/(\[[^\]]+\]\([^)]+\)|\*\*[^*]+?\*\*|`[^`]+`)/g).flatMap((a, s) => {
7963
8011
  const o = a.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
@@ -7972,13 +8020,13 @@ function wt(e) {
7972
8020
  children: a.slice(1, -1)
7973
8021
  },
7974
8022
  s
7975
- ) : mo(a, `${s}`);
8023
+ ) : po(a, `${s}`);
7976
8024
  });
7977
8025
  }
7978
- function mo(e, n) {
8026
+ function po(e, n) {
7979
8027
  const a = [];
7980
8028
  let s = 0, o;
7981
- const i = new RegExp(uo.source, "g");
8029
+ const i = new RegExp(mo.source, "g");
7982
8030
  let l = 0;
7983
8031
  for (; (o = i.exec(e)) !== null; ) {
7984
8032
  const c = o.index;
@@ -7989,8 +8037,8 @@ function mo(e, n) {
7989
8037
  }
7990
8038
  return s < e.length && a.push(e.slice(s)), a.length > 0 ? a : [e];
7991
8039
  }
7992
- function po() {
7993
- const e = Ke(), [n] = Jt(), { user: a, login: s, register: o } = Ze(), { t: i } = se(), l = n.get("invite") || "", [c, h] = w(l ? "register" : "login"), [d, g] = w(!1), [m, b] = w(!1), [v, k] = w([]), [y, A] = w(!0), [S, x] = w(""), [p, f] = w(""), [B, E] = w(""), [J, Z] = w(""), [O, q] = w("");
8040
+ function ho() {
8041
+ const e = Ke(), [n] = Jt(), { user: a, login: s, register: o } = Ze(), { t: i } = re(), l = n.get("invite") || "", [c, h] = w(l ? "register" : "login"), [d, g] = w(!1), [m, b] = w(!1), [v, k] = w([]), [y, A] = w(!0), [S, x] = w(""), [p, f] = w(""), [B, E] = w(""), [J, Z] = w(""), [L, q] = w("");
7994
8042
  ce(() => {
7995
8043
  a && a.role !== "public_manager" && e("/", { replace: !0 });
7996
8044
  }, [a, e]), ce(() => {
@@ -8004,7 +8052,7 @@ function po() {
8004
8052
  }, [n, i]);
8005
8053
  const Q = async (N) => {
8006
8054
  if (N.preventDefault(), x(""), c === "register") {
8007
- if (J !== O) {
8055
+ if (J !== L) {
8008
8056
  x(i("login.passwordsNoMatch"));
8009
8057
  return;
8010
8058
  }
@@ -8067,7 +8115,7 @@ function po() {
8067
8115
  {
8068
8116
  label: i("login.confirmPassword"),
8069
8117
  type: "password",
8070
- value: O,
8118
+ value: L,
8071
8119
  onChange: (N) => q(N.target.value),
8072
8120
  required: !0
8073
8121
  }
@@ -8089,8 +8137,8 @@ function po() {
8089
8137
  },
8090
8138
  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",
8091
8139
  children: [
8092
- /* @__PURE__ */ t(go, { provider: N }),
8093
- i("login.continueWithProvider", { provider: ho(N) })
8140
+ /* @__PURE__ */ t(fo, { provider: N }),
8141
+ i("login.continueWithProvider", { provider: go(N) })
8094
8142
  ]
8095
8143
  },
8096
8144
  N
@@ -8123,10 +8171,10 @@ function po() {
8123
8171
  ] }) })
8124
8172
  ] }) });
8125
8173
  }
8126
- function ho(e) {
8174
+ function go(e) {
8127
8175
  return e.charAt(0).toUpperCase() + e.slice(1);
8128
8176
  }
8129
- function go({ provider: e }) {
8177
+ function fo({ provider: e }) {
8130
8178
  return e === "google" ? /* @__PURE__ */ r("svg", { className: "h-4 w-4", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
8131
8179
  /* @__PURE__ */ t("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" }),
8132
8180
  /* @__PURE__ */ t("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" }),
@@ -8134,7 +8182,7 @@ function go({ provider: e }) {
8134
8182
  /* @__PURE__ */ t("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" })
8135
8183
  ] }) : e === "apple" ? /* @__PURE__ */ t("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ t("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;
8136
8184
  }
8137
- function fo() {
8185
+ function yo() {
8138
8186
  const e = Ke(), n = pe(!1), [a, s] = w("");
8139
8187
  return ce(() => {
8140
8188
  n.current || (n.current = !0, F.createChatSession().then((o) => {
@@ -8166,7 +8214,7 @@ function ka() {
8166
8214
  function Na() {
8167
8215
  return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
8168
8216
  }
8169
- function yo() {
8217
+ function bo() {
8170
8218
  const e = Ke(), n = et(), [a, s] = w(""), [o, i] = w(De()), [l, c] = w(""), [h, d] = w([xa()]), [g, m] = w([ka()]), [b, v] = w([Na()]), [k, y] = w({}), A = ke({
8171
8219
  mutationFn: () => F.importAccountBalances({
8172
8220
  company: a,
@@ -8207,8 +8255,8 @@ function yo() {
8207
8255
  onSuccess: (f) => y((B) => ({ ...B, invoices: f }))
8208
8256
  });
8209
8257
  function p(f, B, E, J, Z) {
8210
- const O = [...f];
8211
- O[E][J] = Z, B(O);
8258
+ const L = [...f];
8259
+ L[E][J] = Z, B(L);
8212
8260
  }
8213
8261
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
8214
8262
  /* @__PURE__ */ t("p", { className: "text-sm text-gray-500", children: "Import balances from your previous system. Each section creates the appropriate documents (Journal Entry, Stock Entry, or Invoices) and submits them automatically." }),
@@ -8332,12 +8380,12 @@ function yo() {
8332
8380
  ] })
8333
8381
  ] });
8334
8382
  }
8335
- function bo(e) {
8383
+ function vo(e) {
8336
8384
  const n = (e || "").replace(/\s/g, "");
8337
8385
  return n.length > 8 ? `${n.slice(0, 4)} … ${n.slice(-4)}` : n;
8338
8386
  }
8339
- function vo() {
8340
- const { t: e, i18n: n } = se();
8387
+ function xo() {
8388
+ const { t: e, i18n: n } = re();
8341
8389
  Me(e("bankStatements.title"));
8342
8390
  const [a, s] = w([]), [o, i] = w([]), [l, c] = w([]), [h, d] = w({}), [g, m] = w([]), [b, v] = w(!1), [k, y] = w(null), [A, S] = w(""), [x, p] = w(null), f = async () => {
8343
8391
  const [N, D] = await Promise.all([
@@ -8359,7 +8407,7 @@ function vo() {
8359
8407
  }, E = o.filter((N) => !N.already_imported), J = E.length > 0 && E.every((N) => !!h[N.statement_key]), Z = fe(
8360
8408
  () => a.map((N) => N.name).join(", "),
8361
8409
  [a]
8362
- ), O = (N) => {
8410
+ ), L = (N) => {
8363
8411
  const D = Array.from(N), $ = D.filter((u) => {
8364
8412
  const P = u.name.includes(".") ? u.name.split(".").pop().toLowerCase() : "";
8365
8413
  return P !== "xml" && P !== "zip";
@@ -8420,7 +8468,7 @@ function vo() {
8420
8468
  (!D || !N.currentTarget.contains(D)) && v(!1);
8421
8469
  },
8422
8470
  onDrop: (N) => {
8423
- N.preventDefault(), v(!1), N.dataTransfer.files.length && O(N.dataTransfer.files);
8471
+ N.preventDefault(), v(!1), N.dataTransfer.files.length && L(N.dataTransfer.files);
8424
8472
  },
8425
8473
  children: [
8426
8474
  /* @__PURE__ */ t(Xr, { className: "mb-2 h-7 w-7 text-brand" }),
@@ -8433,7 +8481,7 @@ function vo() {
8433
8481
  type: "file",
8434
8482
  multiple: !0,
8435
8483
  accept: ".xml,.zip,application/xml,text/xml,application/zip,application/x-zip-compressed",
8436
- onChange: (N) => O(N.target.files || [])
8484
+ onChange: (N) => L(N.target.files || [])
8437
8485
  }
8438
8486
  )
8439
8487
  ]
@@ -8524,7 +8572,7 @@ function vo() {
8524
8572
  l.map((D) => /* @__PURE__ */ r("option", { value: D.name, children: [
8525
8573
  D.account_name,
8526
8574
  " · ",
8527
- bo(D.iban),
8575
+ vo(D.iban),
8528
8576
  " · ",
8529
8577
  D.currency,
8530
8578
  " · ",
@@ -8596,22 +8644,22 @@ const Vt = (e) => `${e.reference_doctype}:${e.reference_name}`;
8596
8644
  function gn(e, n) {
8597
8645
  return `/app/${e.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(n)}`;
8598
8646
  }
8599
- function xo() {
8647
+ function ko() {
8600
8648
  var qe;
8601
- const { t: e, i18n: n } = se(), a = Tn();
8649
+ const { t: e, i18n: n } = re(), a = Tn();
8602
8650
  Me(e("bankReconciliation.title"));
8603
- const [s, o] = w("Unreconciled"), [i, l] = w([]), [c, h] = w(null), [d, g] = w(null), [m, b] = w([]), [v, k] = w({}), [y, A] = w(""), [S, x] = w(""), [p, f] = w(""), [B, E] = w(!1), [J, Z] = w(""), [O, q] = w(""), Q = (R, ae) => {
8651
+ const [s, o] = w("Unreconciled"), [i, l] = w([]), [c, h] = w(null), [d, g] = w(null), [m, b] = w([]), [v, k] = w({}), [y, A] = w(""), [S, x] = w(""), [p, f] = w(""), [B, E] = w(!1), [J, Z] = w(""), [L, q] = w(""), Q = (R, ae) => {
8604
8652
  try {
8605
8653
  return new Intl.NumberFormat(n.language, { style: "currency", currency: ae }).format(R);
8606
8654
  } catch {
8607
8655
  return `${ae} ${R.toFixed(2)}`;
8608
8656
  }
8609
8657
  }, N = async (R) => {
8610
- var L;
8658
+ var O;
8611
8659
  const ae = await F.listBankReconciliationTransactions(s, 200);
8612
8660
  l(ae.rows);
8613
- const be = R && ae.rows.some((oe) => oe.name === R) ? R : ((L = ae.rows[0]) == null ? void 0 : L.name) || null;
8614
- h(be), be || g(null);
8661
+ const xe = R && ae.rows.some((oe) => oe.name === R) ? R : ((O = ae.rows[0]) == null ? void 0 : O.name) || null;
8662
+ h(xe), xe || g(null);
8615
8663
  };
8616
8664
  ce(() => {
8617
8665
  Z(""), N().catch((R) => Z(R instanceof Error ? R.message : String(R)));
@@ -8636,10 +8684,10 @@ function xo() {
8636
8684
  q(R), await N(c);
8637
8685
  }, le = async (R) => {
8638
8686
  if (!D) return;
8639
- const ae = R.bank_transactions || [], be = R.kind === "existing_voucher_group" && ae.length > 1;
8687
+ const ae = R.bank_transactions || [], xe = R.kind === "existing_voucher_group" && ae.length > 1;
8640
8688
  if (await a({
8641
8689
  title: e("bankReconciliation.confirmExistingTitle"),
8642
- body: be ? /* @__PURE__ */ r("div", { className: "space-y-2", children: [
8690
+ body: xe ? /* @__PURE__ */ r("div", { className: "space-y-2", children: [
8643
8691
  /* @__PURE__ */ t("p", { children: e("bankReconciliation.confirmGroupBody", {
8644
8692
  count: ae.length,
8645
8693
  amount: Q(R.amount, R.currency),
@@ -8661,11 +8709,11 @@ function xo() {
8661
8709
  try {
8662
8710
  await F.reconcileBankExistingVoucher({
8663
8711
  bank_transaction: D.name,
8664
- bank_transactions: be ? ae.map((oe) => oe.name) : void 0,
8712
+ bank_transactions: xe ? ae.map((oe) => oe.name) : void 0,
8665
8713
  voucher_type: R.voucher_type,
8666
8714
  voucher_no: R.voucher_no,
8667
8715
  confirmed: !0
8668
- }), await W(be ? e("bankReconciliation.groupReconciledNotice", { count: ae.length }) : e("bankReconciliation.reconciledNotice"));
8716
+ }), await W(xe ? e("bankReconciliation.groupReconciledNotice", { count: ae.length }) : e("bankReconciliation.reconciledNotice"));
8669
8717
  } catch (oe) {
8670
8718
  Z(oe instanceof Error ? oe.message : String(oe));
8671
8719
  } finally {
@@ -8691,16 +8739,16 @@ function xo() {
8691
8739
  try {
8692
8740
  await F.reconcileBankPayment({
8693
8741
  bank_transaction: D.name,
8694
- allocations: $.map((be) => ({
8695
- reference_doctype: be.reference_doctype,
8696
- reference_name: be.reference_name,
8697
- allocated_amount: Number(v[Vt(be)])
8742
+ allocations: $.map((xe) => ({
8743
+ reference_doctype: xe.reference_doctype,
8744
+ reference_name: xe.reference_name,
8745
+ allocated_amount: Number(v[Vt(xe)])
8698
8746
  })),
8699
8747
  conversion_rate: p ? Number(p) : void 0,
8700
8748
  confirmed: !0
8701
8749
  }), await W(e("bankReconciliation.reconciledNotice"));
8702
- } catch (be) {
8703
- Z(be instanceof Error ? be.message : String(be));
8750
+ } catch (xe) {
8751
+ Z(xe instanceof Error ? xe.message : String(xe));
8704
8752
  } finally {
8705
8753
  E(!1);
8706
8754
  }
@@ -8730,7 +8778,7 @@ function xo() {
8730
8778
  E(!1);
8731
8779
  }
8732
8780
  }
8733
- }, xe = async () => {
8781
+ }, be = async () => {
8734
8782
  if (!D || !(d != null && d.active_reconciliation)) return;
8735
8783
  const R = d.active_reconciliation.mode !== "Existing Voucher", ae = d.active_reconciliation.bank_transactions || [D.name];
8736
8784
  if (await a({
@@ -8745,8 +8793,8 @@ function xo() {
8745
8793
  E(!0), Z(""), q("");
8746
8794
  try {
8747
8795
  await F.undoBankReconciliation(D.name), await W(e("bankReconciliation.undoneNotice"));
8748
- } catch (L) {
8749
- Z(L instanceof Error ? L.message : String(L));
8796
+ } catch (O) {
8797
+ Z(O instanceof Error ? O.message : String(O));
8750
8798
  } finally {
8751
8799
  E(!1);
8752
8800
  }
@@ -8776,9 +8824,9 @@ function xo() {
8776
8824
  ] })
8777
8825
  ] }),
8778
8826
  J && /* @__PURE__ */ t("div", { className: "rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700", children: J }),
8779
- O && /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800", children: [
8827
+ L && /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800", children: [
8780
8828
  /* @__PURE__ */ t(bn, { className: "h-4 w-4" }),
8781
- O
8829
+ L
8782
8830
  ] }),
8783
8831
  /* @__PURE__ */ r("div", { className: "grid gap-6 lg:grid-cols-[minmax(280px,0.8fr)_minmax(0,1.7fr)]", children: [
8784
8832
  /* @__PURE__ */ r(H, { className: "self-start", children: [
@@ -8862,7 +8910,7 @@ function xo() {
8862
8910
  " ",
8863
8911
  d.active_reconciliation.voucher_no
8864
8912
  ] }),
8865
- /* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(Y, { variant: "danger", disabled: B, onClick: xe, children: [
8913
+ /* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(Y, { variant: "danger", disabled: B, onClick: be, children: [
8866
8914
  /* @__PURE__ */ t(ns, { className: "h-4 w-4" }),
8867
8915
  e("bankReconciliation.undo")
8868
8916
  ] }) })
@@ -8893,14 +8941,14 @@ function xo() {
8893
8941
  /* @__PURE__ */ t("p", { className: "mt-1 text-sm text-fg-muted", children: e("bankReconciliation.openInvoicesHint") }),
8894
8942
  /* @__PURE__ */ r("div", { className: "mt-3 divide-y divide-line", children: [
8895
8943
  d.invoices.map((R) => {
8896
- const ae = Vt(R), be = v[ae] != null, L = V(R);
8897
- return /* @__PURE__ */ r("div", { className: Fe("grid gap-3 py-3 sm:grid-cols-[auto_1fr_150px] sm:items-center", !L && !be && "opacity-45"), children: [
8944
+ const ae = Vt(R), xe = v[ae] != null, O = V(R);
8945
+ return /* @__PURE__ */ r("div", { className: Fe("grid gap-3 py-3 sm:grid-cols-[auto_1fr_150px] sm:items-center", !O && !xe && "opacity-45"), children: [
8898
8946
  /* @__PURE__ */ t(
8899
8947
  "input",
8900
8948
  {
8901
8949
  type: "checkbox",
8902
- checked: be,
8903
- disabled: !L && !be,
8950
+ checked: xe,
8951
+ disabled: !O && !xe,
8904
8952
  onChange: (oe) => k((Ie) => {
8905
8953
  const Ae = { ...Ie };
8906
8954
  return oe.target.checked ? Ae[ae] = R.suggested_allocation : delete Ae[ae], Ae;
@@ -8929,8 +8977,8 @@ function xo() {
8929
8977
  type: "number",
8930
8978
  min: "0.01",
8931
8979
  step: "0.01",
8932
- disabled: !be,
8933
- value: be ? v[ae] : "",
8980
+ disabled: !xe,
8981
+ value: xe ? v[ae] : "",
8934
8982
  onChange: (oe) => k((Ie) => ({ ...Ie, [ae]: Number(oe.target.value) })),
8935
8983
  "aria-label": e("bankReconciliation.allocation")
8936
8984
  }
@@ -8966,7 +9014,7 @@ function xo() {
8966
9014
  ] })
8967
9015
  ] });
8968
9016
  }
8969
- function ko() {
9017
+ function No() {
8970
9018
  Me("Users");
8971
9019
  const { user: e } = Ze(), n = et(), { data: a, isLoading: s } = ve({
8972
9020
  queryKey: ["auth-users"],
@@ -9128,110 +9176,113 @@ function ko() {
9128
9176
  ] }) })
9129
9177
  ] });
9130
9178
  }
9131
- const No = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, wo = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", cancelBooking: "Cancel booking", cancelBookingConfirm: "Yes, cancel booking", keepBooking: "Keep booking", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", showDisabled: "Show disabled", columns: "Columns", searchPlaceholder: "Search…", noRecords: "No records found", active: "Active", disabled: "Disabled", sortByColumn: "Sort by this column", 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" }, Co = { today: "Today", thisWeek: "This Week", thisMonth: "This Month", thisQuarter: "This Quarter", thisYear: "This Year", lastMonth: "Last Month", lastQuarter: "Last Quarter", lastYear: "Last Year", endOfThisMonth: "End of This Month", endOfLastMonth: "End of Last Month", endOfThisQuarter: "End of This Quarter", endOfThisYear: "End of This Year", endOfLastYear: "End of Last Year" }, So = { title: "Bank statement import", subtitle: "Preview and import ISO 20022 CAMT statements without posting to the ledger.", selectFiles: "CAMT files", chooseFiles: "Choose XML or ZIP files", dropFiles: "Drop XML or ZIP files here", unsupportedFiles: "Only CAMT XML or ZIP files are supported: {{files}}", fileHint: "camt.053.001.04 and camt.053.001.08 · multiple files supported", preview: "Show preview", noPosting: "Previewing and importing do not post accounting entries.", alreadyImported: "Already imported", period: "Period", openingBalance: "Opening balance", closingBalance: "Closing balance", entries: "Entries", credits: "Credits", debits: "Debits", details: "Transaction details", batches: "batches", qrReferences: "QR references", mapping: "Bank account mapping", selectBankAccount: "Select a Bank Account…", noBankAccounts: "No Bank Account has been configured yet.", createBankAccount: "Create Bank Account", mappingRequired: "Map every new statement to a Bank Account before importing.", import: "Import bank statements", importComplete: "Import completed", importCounts: "{{imported}} entries imported, {{duplicates}} duplicates skipped", history: "Recent imports", importId: "Import", bankAccount: "Bank account", source: "Source file", openReconciliation: "Open bank reconciliation" }, Ao = { title: "Bank reconciliation", subtitle: "Match imported bank transactions to posted vouchers, open invoices, or ledger accounts.", status: "Status", unreconciled: "Unreconciled", reconciled: "Reconciled", transactions: "Bank transactions", empty: "No bank transactions in this view.", remittance: "Remittance information", reference: "Reference", openTransaction: "Open bank transaction", conversionRate: "Exchange rate (1 {{currency}} in {{base}})", conversionRateHint: "Required when no exchange rate exists for the transaction date.", existingVouchers: "Existing accounting entries", existingVouchersHint: "These submitted vouchers contain an exact movement on this bank account. Matching does not post them again.", match: "Match", openInvoices: "Open invoices", openInvoicesHint: "Select one or more invoices belonging to the same party. Confirmation creates and submits a Payment Entry.", outstanding: "Outstanding", allocation: "Allocation", noInvoiceSuggestions: "No plausible open invoice was found.", allocated: "Allocated {{amount}} of {{total}}", createPayment: "Create payment and reconcile", directPosting: "Post to a ledger account", directPostingHint: "For fees, interest and other non-invoice movements. Receivable, payable, bank and cash control accounts are intentionally excluded.", counterpartyAccount: "Counter account", remarks: "Remarks", createJournal: "Create journal entry and reconcile", activeMatch: "Active reconciliation", undo: "Undo reconciliation", confirmExistingTitle: "Match existing entry?", confirmExistingBody: "Match {{transaction}} to {{voucher}}? No new ledger entry will be posted.", confirmGroupBody: "Match all {{count}} transactions totalling {{amount}} to {{voucher}}? No new ledger entry will be posted.", groupedTransactions: "{{count}} grouped transactions", confirmPaymentTitle: "Post payment and reconcile?", confirmPaymentBody: "This submits a payment of {{amount}} for {{transaction}} and allocates it across {{count}} invoice(s).", onAccountWarning: "{{amount}} will remain as an on-account payment for this party.", confirmJournalTitle: "Post journal entry and reconcile?", confirmJournalBody: "This posts {{amount}} for {{transaction}} against {{account}}.", postAndReconcile: "Post and reconcile", undoTitle: "Undo reconciliation?", undoCreatedBody: "The voucher created by this reconciliation will be cancelled, its ledger entries reversed, and invoice allocations restored.", undoExistingBody: "The existing voucher will only be unlinked. It remains submitted and its ledger entries are not changed.", undoExistingGroupBody: "All {{count}} grouped transactions ({{transactions}}) will be unlinked together. The existing voucher remains submitted and its ledger entries are not changed.", reconciledNotice: "Bank transaction reconciled.", groupReconciledNotice: "{{count}} bank transactions reconciled as one group.", undoneNotice: "Reconciliation reversed." }, _o = { placeholder: "Search or enter field:value…", search: "Search", addFilter: "+ Filter", availableFields: "Available fields", fieldHelp: "Choose a field or type its technical name followed by a colon.", field: "Field", valueFor: "Value for {{label}}", allFields: "All fields", typeForValues: "Start typing to find values in this field.", noValues: "No matching values found.", noFields: "No matching fields found.", useValue: "Use “{{value}}”", removeFilter: "Remove {{label}} filter", types: { text: "Text", textarea: "Long text", select: "Selection", link: "Linked record", date: "Date", datetime: "Date and time", number: "Number", currency: "Amount" } }, Do = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Po = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, To = { 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" }, Ro = { 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" }, "bank-account": { one: "Bank Account", other: "Bank Accounts" }, 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" } }, Bo = { 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" } }, Io = { 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", Rentals: "Rentals" }, 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", "Bank Account": "Bank Accounts", "Bank Statement Import": "Bank Statement Import", "Bank Reconciliation": "Bank Reconciliation", 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", "Fleet Calendar": "Fleet Calendar", "Fleet (Assets)": "Fleet (Assets)", Reservations: "Reservations" } }, Eo = { 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." } }, Lo = { 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}}" }, Oo = { 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" }, Fo = { periodRange: "Reporting period: {{from}} – {{to}}", periodFrom: "Reporting period from {{from}}", periodThrough: "Reporting period through {{to}}", asOfDate: "As of: {{date}}", 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" }, Mo = { 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}}." }, qo = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, zo = { 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." }, $o = { "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" }, Vo = { "Last modified": "Last modified", Created: "Created", "% 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", "Item (type)": "Item (type)", "Asset Tag / Plate": "Asset Tag / Plate", "Home Yard": "Home Yard", "Purchase Value": "Purchase Value", "Meter Reading": "Meter Reading", "Meter Unit": "Meter Unit", Yard: "Yard", "Asset (specific unit)": "Asset (specific unit)", Allocation: "Allocation", From: "From", To: "To", Purpose: "Purpose", "Purchase Date": "Purchase Date", Notes: "Notes" }, Uo = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, Ko = /* @__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 report-specialist model that creates a validated declarative report 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?"}`), jo = { 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." }, Wo = { 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" } }, Go = { fleetCalendar: "Fleet Calendar", yard: "Yard", machineType: "Machine type", prev: "Prev", today: "Today", next: "Next", weeks: "weeks", newBooking: "New booking", reserved: "Reserved", onHire: "On Hire", machine: "Machine", loadError: "Could not load the fleet calendar.", noAssets: "No assets to show. Add machines under Rentals → Fleet.", pooledNote: "{{count}} pool booking(s) awaiting assignment", unassigned: "Pool — unassigned", poolWarning: "Pool capacity is reserved. No specific machine has been assigned yet; assign a machine before dispatch." }, Ho = { Unit: "Specific machine", Pool: "Pool – assign machine later", Available: "Available", "On Hire": "On Hire", Out: "Out", Maintenance: "Maintenance", Retired: "Retired", Reserved: "Reserved", Returned: "Returned", Cancelled: "Cancelled", Customer: "Customer", Supplier: "Supplier" }, Qo = { asset: { item_code: "The Item is the machine TYPE and carries the rate; an Asset is one physical unit of it. The Item must have is_asset_tracked = 1.", asset_tag: "Plate or serial — must be unique across assets.", status: "The unit's state today (not a date range). Retired units leave the pool.", meter_reading: "Operating hours / km." }, reservation: { item_code: "Pooled booking ('a 1.7t excavator'): set Item + Yard + Qty. For a specific machine, set Asset instead.", asset: "Book one specific machine. A unit booking also consumes a slot of its Item+Yard pool.", from_datetime: "Exact start — date and time (e.g. 14:27). A bare date means 00:00.", to_datetime: "Exact end. Windows are half-open [from, to): a hire ending 09:00 and the next starting 09:00 do NOT clash." } }, Yo = {
9132
- proposal: No,
9133
- common: wo,
9134
- datePresets: Co,
9135
- bankStatements: So,
9136
- bankReconciliation: Ao,
9137
- smartSearch: _o,
9138
- language: Do,
9139
- header: Po,
9140
- titles: To,
9141
- doctypes: Ro,
9142
- masters: Bo,
9143
- nav: Io,
9144
- login: Eo,
9145
- settings: Lo,
9146
- status: Oo,
9147
- reports: Fo,
9148
- masterForm: Mo,
9149
- dashboard: qo,
9150
- chat: zo,
9151
- conversions: $o,
9152
- fields: Vo,
9153
- tables: Uo,
9154
- tutorial: Ko,
9155
- notesMarkup: jo,
9156
- coa: Wo,
9157
- rentals: Go,
9158
- fieldOptions: Ho,
9159
- hints: Qo
9160
- }, Jo = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, Zo = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", cancelBooking: "Buchung stornieren", cancelBookingConfirm: "Ja, stornieren", keepBooking: "Behalten", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", showDisabled: "Deaktivierte anzeigen", columns: "Spalten", searchPlaceholder: "Suchen…", noRecords: "Keine Einträge gefunden", active: "Aktiv", disabled: "Deaktiviert", sortByColumn: "Nach dieser Spalte sortieren", 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" }, Xo = { today: "Heute", thisWeek: "Diese Woche", thisMonth: "Dieser Monat", thisQuarter: "Dieses Quartal", thisYear: "Dieses Jahr", lastMonth: "Letzter Monat", lastQuarter: "Letztes Quartal", lastYear: "Letztes Jahr", endOfThisMonth: "Ende dieses Monats", endOfLastMonth: "Ende des letzten Monats", endOfThisQuarter: "Ende dieses Quartals", endOfThisYear: "Ende dieses Jahres", endOfLastYear: "Ende des letzten Jahres" }, el = { title: "Kontoauszug importieren", subtitle: "ISO-20022-CAMT-Kontoauszüge prüfen und ohne automatische Verbuchung importieren.", selectFiles: "CAMT-Dateien", chooseFiles: "XML- oder ZIP-Dateien auswählen", dropFiles: "XML- oder ZIP-Dateien hier ablegen", unsupportedFiles: "Es werden nur CAMT-XML- oder ZIP-Dateien unterstützt: {{files}}", fileHint: "camt.053.001.04 und camt.053.001.08 · mehrere Dateien möglich", preview: "Vorschau anzeigen", noPosting: "Vorschau und Import erzeugen keine Buchungssätze.", alreadyImported: "Bereits importiert", period: "Zeitraum", openingBalance: "Anfangssaldo", closingBalance: "Endsaldo", entries: "Buchungen", credits: "Gutschriften", debits: "Belastungen", details: "Transaktionsdetails", batches: "Sammelbuchungen", qrReferences: "QR-Referenzen", mapping: "Bankkonto-Zuordnung", selectBankAccount: "Bankkonto auswählen…", noBankAccounts: "Es wurde noch kein Bankkonto eingerichtet.", createBankAccount: "Bankkonto einrichten", mappingRequired: "Ordnen Sie vor dem Import jeden neuen Auszug einem Bankkonto zu.", import: "Kontoauszüge importieren", importComplete: "Import abgeschlossen", importCounts: "{{imported}} Buchungen importiert, {{duplicates}} Duplikate übersprungen", history: "Letzte Importe", importId: "Import", bankAccount: "Bankkonto", source: "Quelldatei", openReconciliation: "Bankabstimmung öffnen" }, tl = { title: "Bankabstimmung", subtitle: "Importierte Banktransaktionen mit Buchungen, offenen Rechnungen oder Sachkonten abstimmen.", status: "Status", unreconciled: "Nicht abgestimmt", reconciled: "Abgestimmt", transactions: "Banktransaktionen", empty: "In dieser Ansicht sind keine Banktransaktionen vorhanden.", remittance: "Zahlungsinformation", reference: "Referenz", openTransaction: "Banktransaktion öffnen", conversionRate: "Wechselkurs (1 {{currency}} in {{base}})", conversionRateHint: "Erforderlich, wenn für das Transaktionsdatum kein Wechselkurs hinterlegt ist.", existingVouchers: "Bestehende Buchungen", existingVouchersHint: "Diese eingereichten Belege enthalten eine exakt passende Bewegung auf diesem Bankkonto. Bei der Zuordnung wird nichts erneut gebucht.", match: "Zuordnen", openInvoices: "Offene Rechnungen", openInvoicesHint: "Wähle eine oder mehrere Rechnungen derselben Partei. Nach der Bestätigung wird eine Zahlung erstellt und eingereicht.", outstanding: "Offen", allocation: "Zuweisung", noInvoiceSuggestions: "Es wurde keine plausible offene Rechnung gefunden.", allocated: "{{amount}} von {{total}} zugewiesen", createPayment: "Zahlung erstellen und abstimmen", directPosting: "Auf ein Sachkonto buchen", directPostingHint: "Für Gebühren, Zinsen und andere Bewegungen ohne Rechnung. Debitoren-, Kreditoren-, Bank- und Kassenkonten sind bewusst ausgeschlossen.", counterpartyAccount: "Gegenkonto", remarks: "Bemerkung", createJournal: "Buchungssatz erstellen und abstimmen", activeMatch: "Aktive Abstimmung", undo: "Abstimmung rückgängig machen", confirmExistingTitle: "Bestehende Buchung zuordnen?", confirmExistingBody: "{{transaction}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", confirmGroupBody: "Alle {{count}} Transaktionen über insgesamt {{amount}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", groupedTransactions: "{{count}} gruppierte Transaktionen", confirmPaymentTitle: "Zahlung buchen und abstimmen?", confirmPaymentBody: "Damit wird für {{transaction}} eine Zahlung über {{amount}} eingereicht und auf {{count}} Rechnung(en) verteilt.", onAccountWarning: "{{amount}} bleibt als nicht zugewiesene Zahlung bei dieser Partei bestehen.", confirmJournalTitle: "Buchungssatz erstellen und abstimmen?", confirmJournalBody: "Damit werden {{amount}} für {{transaction}} gegen {{account}} gebucht.", postAndReconcile: "Buchen und abstimmen", undoTitle: "Abstimmung rückgängig machen?", undoCreatedBody: "Der durch diese Abstimmung erstellte Beleg wird storniert, seine Hauptbuchungen werden umgekehrt und Rechnungszuweisungen wiederhergestellt.", undoExistingBody: "Der bestehende Beleg wird nur von der Banktransaktion getrennt. Er bleibt eingereicht und seine Buchungen werden nicht verändert.", undoExistingGroupBody: "Alle {{count}} gruppierten Banktransaktionen ({{transactions}}) werden gemeinsam vom Beleg getrennt. Der bestehende Beleg bleibt eingereicht und seine Buchungen werden nicht verändert.", reconciledNotice: "Banktransaktion wurde abgestimmt.", groupReconciledNotice: "{{count}} Banktransaktionen wurden als Gruppe abgestimmt.", undoneNotice: "Abstimmung wurde rückgängig gemacht." }, nl = { placeholder: "Suchen oder Feld:Wert eingeben…", search: "Suchen", addFilter: "+ Filter", availableFields: "Verfügbare Felder", fieldHelp: "Feld auswählen oder den technischen Namen mit Doppelpunkt eingeben.", field: "Feld", valueFor: "Wert für {{label}}", allFields: "Alle Felder", typeForValues: "Tippen, um Werte in diesem Feld zu finden.", noValues: "Keine passenden Werte gefunden.", noFields: "Keine passenden Felder gefunden.", useValue: "„{{value}}“ verwenden", removeFilter: "Filter {{label}} entfernen", types: { text: "Text", textarea: "Langtext", select: "Auswahl", link: "Verknüpfter Eintrag", date: "Datum", datetime: "Datum und Uhrzeit", number: "Zahl", currency: "Betrag" } }, al = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, rl = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, sl = { 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" }, il = { 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" }, "bank-account": { one: "Bankkonto", other: "Bankkonten" }, 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" } }, ol = { 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" } }, ll = { 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", Rentals: "Vermietung" }, 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", "Bank Account": "Bankkonten", "Bank Statement Import": "Kontoauszug importieren", "Bank Reconciliation": "Bankabstimmung", 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", "Fleet Calendar": "Flottenkalender", "Fleet (Assets)": "Flotte (Geräte)", Reservations: "Reservationen" } }, cl = { 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." } }, dl = { 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}}" }, ul = { 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" }, ml = { periodRange: "Berichtszeitraum: {{from}} – {{to}}", periodFrom: "Berichtszeitraum ab {{from}}", periodThrough: "Berichtszeitraum bis {{to}}", asOfDate: "Stichtag: {{date}}", 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" }, pl = { 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." }, hl = { "Last modified": "Zuletzt geändert", Created: "Erstellt", 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", "Item (type)": "Artikel (Typ)", "Asset Tag / Plate": "Kennung / Kennzeichen", "Home Yard": "Heimdepot", "Purchase Value": "Kaufwert", "Meter Reading": "Zählerstand", "Meter Unit": "Zählereinheit", Yard: "Depot", "Asset (specific unit)": "Gerät (bestimmte Einheit)", Allocation: "Zuweisung", From: "Von", To: "Bis", Purpose: "Zweck", "Purchase Date": "Kaufdatum", Notes: "Notizen" }, gl = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, fl = { "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" }, yl = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, bl = { 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." }, vl = /* @__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?"}'), xl = { 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." }, kl = { 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" } }, Nl = { fleetCalendar: "Flottenkalender", yard: "Depot", machineType: "Maschinentyp", prev: "Zurück", today: "Heute", next: "Weiter", weeks: "Wochen", newBooking: "Neue Reservation", reserved: "Reserviert", onHire: "Vermietet", machine: "Maschine", loadError: "Flottenkalender konnte nicht geladen werden.", noAssets: "Keine Geräte vorhanden. Maschinen unter Vermietung → Flotte hinzufügen.", pooledNote: "{{count}} Pool-Reservation(en) noch ohne Maschinenzuordnung", unassigned: "Pool — noch nicht zugeordnet", poolWarning: "Die Pool-Kapazität ist reserviert. Eine konkrete Maschine ist noch nicht zugeordnet; vor der Ausgabe eine Maschine auswählen." }, wl = { Unit: "Bestimmte Maschine", Pool: "Pool – Maschine später zuweisen", Available: "Verfügbar", "On Hire": "Vermietet", Out: "Ausgeliefert", Maintenance: "Wartung", Retired: "Ausgemustert", Reserved: "Reserviert", Returned: "Zurückgegeben", Cancelled: "Storniert", Customer: "Kunde", Supplier: "Lieferant" }, Cl = { asset: { item_code: "Der Artikel ist der Maschinen-TYP und trägt den Tarif; ein Gerät ist eine physische Einheit davon. Der Artikel muss is_asset_tracked = 1 haben.", asset_tag: "Kennzeichen oder Seriennummer — muss über alle Geräte eindeutig sein.", status: "Aktueller Zustand der Einheit (kein Zeitraum). Ausgemusterte Einheiten verlassen den Pool.", meter_reading: "Betriebsstunden / km." }, reservation: { item_code: "Pool-Reservation ('ein 1.7t-Bagger'): Artikel + Depot + Menge setzen. Für eine bestimmte Maschine stattdessen Gerät setzen.", asset: "Eine bestimmte Maschine buchen. Eine Einheiten-Buchung belegt auch einen Platz im Artikel+Depot-Pool.", from_datetime: "Genauer Beginn — Datum und Uhrzeit (z. B. 14:27). Ein reines Datum bedeutet 00:00.", to_datetime: "Genaues Ende. Fenster sind halboffen [von, bis): eine Miete, die um 09:00 endet, und die nächste um 09:00 beginnende, kollidieren NICHT." } }, Sl = {
9161
- proposal: Jo,
9162
- common: Zo,
9163
- datePresets: Xo,
9164
- bankStatements: el,
9165
- bankReconciliation: tl,
9166
- smartSearch: nl,
9167
- language: al,
9168
- header: rl,
9169
- titles: sl,
9170
- doctypes: il,
9171
- masters: ol,
9172
- nav: ll,
9173
- login: cl,
9174
- settings: dl,
9175
- status: ul,
9176
- reports: ml,
9177
- masterForm: pl,
9178
- fields: hl,
9179
- tables: gl,
9180
- conversions: fl,
9181
- dashboard: yl,
9182
- chat: bl,
9183
- tutorial: vl,
9184
- notesMarkup: xl,
9185
- coa: kl,
9186
- rentals: Nl,
9187
- fieldOptions: wl,
9188
- hints: Cl
9189
- }, Al = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, _l = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", cancelBooking: "Annuler la réservation", cancelBookingConfirm: "Oui, annuler", keepBooking: "Conserver", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", showDisabled: "Afficher les désactivés", columns: "Colonnes", searchPlaceholder: "Rechercher…", noRecords: "Aucun enregistrement trouvé", active: "Actif", disabled: "Désactivé", sortByColumn: "Trier par cette colonne", 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" }, Dl = { today: "Aujourd’hui", thisWeek: "Cette semaine", thisMonth: "Ce mois-ci", thisQuarter: "Ce trimestre", thisYear: "Cette année", lastMonth: "Mois dernier", lastQuarter: "Trimestre dernier", lastYear: "Année dernière", endOfThisMonth: "Fin du mois en cours", endOfLastMonth: "Fin du mois dernier", endOfThisQuarter: "Fin du trimestre en cours", endOfThisYear: "Fin de l’année en cours", endOfLastYear: "Fin de l’année dernière" }, Pl = { title: "Importer un relevé bancaire", subtitle: "Prévisualisez et importez des relevés ISO 20022 CAMT sans écriture comptable automatique.", selectFiles: "Fichiers CAMT", chooseFiles: "Choisir des fichiers XML ou ZIP", dropFiles: "Déposez les fichiers XML ou ZIP ici", unsupportedFiles: "Seuls les fichiers CAMT XML ou ZIP sont acceptés : {{files}}", fileHint: "camt.053.001.04 et camt.053.001.08 · plusieurs fichiers acceptés", preview: "Afficher l’aperçu", noPosting: "L’aperçu et l’importation ne génèrent aucune écriture comptable.", alreadyImported: "Déjà importé", period: "Période", openingBalance: "Solde initial", closingBalance: "Solde final", entries: "Opérations", credits: "Crédits", debits: "Débits", details: "Détails des transactions", batches: "lots", qrReferences: "Références QR", mapping: "Affectation du compte bancaire", selectBankAccount: "Sélectionner un compte bancaire…", noBankAccounts: "Aucun compte bancaire n’a encore été configuré.", createBankAccount: "Configurer un compte bancaire", mappingRequired: "Affectez chaque nouveau relevé à un compte bancaire avant l’importation.", import: "Importer les relevés", importComplete: "Importation terminée", importCounts: "{{imported}} opérations importées, {{duplicates}} doublons ignorés", history: "Importations récentes", importId: "Importation", bankAccount: "Compte bancaire", source: "Fichier source", openReconciliation: "Ouvrir le rapprochement bancaire" }, Tl = { title: "Rapprochement bancaire", subtitle: "Rapprochez les transactions importées avec des écritures, des factures ouvertes ou des comptes comptables.", status: "Statut", unreconciled: "Non rapprochée", reconciled: "Rapprochée", transactions: "Transactions bancaires", empty: "Aucune transaction bancaire dans cette vue.", remittance: "Information de paiement", reference: "Référence", openTransaction: "Ouvrir la transaction bancaire", conversionRate: "Taux de change (1 {{currency}} en {{base}})", conversionRateHint: "Requis si aucun taux de change n’existe à la date de la transaction.", existingVouchers: "Écritures existantes", existingVouchersHint: "Ces pièces validées contiennent un mouvement exact sur ce compte bancaire. Le rapprochement ne les comptabilise pas une seconde fois.", match: "Rapprocher", openInvoices: "Factures ouvertes", openInvoicesHint: "Sélectionnez une ou plusieurs factures du même tiers. La confirmation crée et valide un paiement.", outstanding: "Solde ouvert", allocation: "Affectation", noInvoiceSuggestions: "Aucune facture ouverte plausible n’a été trouvée.", allocated: "{{amount}} affectés sur {{total}}", createPayment: "Créer le paiement et rapprocher", directPosting: "Comptabiliser sur un compte", directPostingHint: "Pour les frais, intérêts et autres mouvements sans facture. Les comptes clients, fournisseurs, bancaires et de caisse sont volontairement exclus.", counterpartyAccount: "Compte de contrepartie", remarks: "Remarque", createJournal: "Créer l’écriture et rapprocher", activeMatch: "Rapprochement actif", undo: "Annuler le rapprochement", confirmExistingTitle: "Rapprocher l’écriture existante ?", confirmExistingBody: "Rapprocher {{transaction}} avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", confirmGroupBody: "Rapprocher les {{count}} transactions, pour un total de {{amount}}, avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", groupedTransactions: "{{count}} transactions groupées", confirmPaymentTitle: "Comptabiliser le paiement et rapprocher ?", confirmPaymentBody: "Cette action valide un paiement de {{amount}} pour {{transaction}} et l’affecte à {{count}} facture(s).", onAccountWarning: "{{amount}} resteront comme paiement non affecté pour ce tiers.", confirmJournalTitle: "Comptabiliser l’écriture et rapprocher ?", confirmJournalBody: "Cette action comptabilise {{amount}} pour {{transaction}} sur {{account}}.", postAndReconcile: "Comptabiliser et rapprocher", undoTitle: "Annuler le rapprochement ?", undoCreatedBody: "La pièce créée par ce rapprochement sera annulée, ses écritures extournées et les affectations aux factures restaurées.", undoExistingBody: "La pièce existante sera uniquement dissociée. Elle restera validée et ses écritures ne seront pas modifiées.", undoExistingGroupBody: "Les {{count}} transactions groupées ({{transactions}}) seront toutes dissociées ensemble. La pièce existante restera validée et ses écritures ne seront pas modifiées.", reconciledNotice: "Transaction bancaire rapprochée.", groupReconciledNotice: "{{count}} transactions bancaires ont été rapprochées en groupe.", undoneNotice: "Rapprochement annulé." }, Rl = { placeholder: "Rechercher ou saisir champ:valeur…", search: "Rechercher", addFilter: "+ Filtre", availableFields: "Champs disponibles", fieldHelp: "Choisissez un champ ou saisissez son nom technique suivi de deux-points.", field: "Champ", valueFor: "Valeur pour {{label}}", allFields: "Tous les champs", typeForValues: "Commencez à saisir pour rechercher des valeurs dans ce champ.", noValues: "Aucune valeur correspondante.", noFields: "Aucun champ correspondant.", useValue: "Utiliser « {{value}} »", removeFilter: "Supprimer le filtre {{label}}", types: { text: "Texte", textarea: "Texte long", select: "Sélection", link: "Enregistrement lié", date: "Date", datetime: "Date et heure", number: "Nombre", currency: "Montant" } }, Bl = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Il = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, El = { 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" }, Ll = { 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" }, "bank-account": { one: "Compte bancaire", other: "Comptes 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" } }, Ol = { 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" } }, Fl = { 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", Rentals: "Locations" }, 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", "Bank Account": "Comptes bancaires", "Bank Statement Import": "Importer un relevé bancaire", "Bank Reconciliation": "Rapprochement 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", "Fleet Calendar": "Calendrier de flotte", "Fleet (Assets)": "Flotte (matériel)", Reservations: "Réservations" } }, Ml = { 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." } }, ql = { 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}}" }, zl = { 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é" }, $l = { periodRange: "Période du rapport : {{from}} – {{to}}", periodFrom: "Période du rapport à partir du {{from}}", periodThrough: "Période du rapport jusqu’au {{to}}", asOfDate: "Date de référence : {{date}}", 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é" }, Vl = { 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}}." }, Ul = { "Last modified": "Dernière modification", Created: "Créé", 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é", "Item (type)": "Article (type)", "Asset Tag / Plate": "Étiquette / plaque", "Home Yard": "Dépôt d'attache", "Purchase Value": "Valeur d'achat", "Meter Reading": "Relevé compteur", "Meter Unit": "Unité compteur", Yard: "Dépôt", "Asset (specific unit)": "Équipement (unité spécifique)", Allocation: "Affectation", From: "Du", To: "Au", Purpose: "Objet", "Purchase Date": "Date d'achat", Notes: "Notes" }, Kl = { 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" }, jl = { "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" }, Wl = { 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" }, Gl = { 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." }, Hl = /* @__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 ?"}`), Ql = { 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." }, Yl = { 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" } }, Jl = { fleetCalendar: "Calendrier de flotte", yard: "Dépôt", machineType: "Type de machine", prev: "Préc.", today: "Aujourd'hui", next: "Suiv.", weeks: "semaines", newBooking: "Nouvelle réservation", reserved: "Réservé", onHire: "En location", machine: "Machine", loadError: "Impossible de charger le calendrier de flotte.", noAssets: "Aucun équipement à afficher. Ajoutez des machines sous Locations → Flotte.", pooledNote: "{{count}} réservation(s) en attente d’attribution", unassigned: "Pool — non attribué", poolWarning: "La capacité est réservée. Aucune machine précise n’est encore attribuée ; attribuez une machine avant la sortie." }, Zl = { Unit: "Machine spécifique", Pool: "Pool – machine à affecter", Available: "Disponible", "On Hire": "En location", Out: "Sorti", Maintenance: "Maintenance", Retired: "Retiré", Reserved: "Réservé", Returned: "Retourné", Cancelled: "Annulé", Customer: "Client", Supplier: "Fournisseur" }, Xl = { asset: { item_code: "L'article est le TYPE de machine et porte le tarif ; un équipement en est une unité physique. L'article doit avoir is_asset_tracked = 1.", asset_tag: "Plaque ou numéro de série — doit être unique sur tous les équipements.", status: "État actuel de l'unité (pas une période). Les unités retirées quittent le pool.", meter_reading: "Heures de fonctionnement / km." }, reservation: { item_code: "Réservation de pool ('une pelle de 1,7 t') : renseigner Article + Dépôt + Qté. Pour une machine précise, renseigner Équipement.", asset: "Réserver une machine précise. Une réservation d'unité consomme aussi une place du pool Article+Dépôt.", from_datetime: "Début exact — date et heure (p. ex. 14:27). Une date seule signifie 00:00.", to_datetime: "Fin exacte. Les fenêtres sont semi-ouvertes [de, à) : une location finissant à 09:00 et la suivante commençant à 09:00 ne se chevauchent PAS." } }, ec = {
9190
- proposal: Al,
9191
- common: _l,
9192
- datePresets: Dl,
9193
- bankStatements: Pl,
9194
- bankReconciliation: Tl,
9195
- smartSearch: Rl,
9196
- language: Bl,
9197
- header: Il,
9198
- titles: El,
9199
- doctypes: Ll,
9200
- masters: Ol,
9201
- nav: Fl,
9202
- login: Ml,
9203
- settings: ql,
9204
- status: zl,
9205
- reports: $l,
9206
- masterForm: Vl,
9207
- fields: Ul,
9208
- tables: Kl,
9209
- conversions: jl,
9210
- dashboard: Wl,
9211
- chat: Gl,
9212
- tutorial: Hl,
9213
- notesMarkup: Ql,
9214
- coa: Yl,
9215
- rentals: Jl,
9216
- fieldOptions: Zl,
9217
- hints: Xl
9179
+ const wo = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, Co = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", cancelBooking: "Cancel booking", cancelBookingConfirm: "Yes, cancel booking", keepBooking: "Keep booking", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", showDisabled: "Show disabled", columns: "Columns", searchPlaceholder: "Search…", noRecords: "No records found", active: "Active", disabled: "Disabled", sortByColumn: "Sort by this column", 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" }, So = { today: "Today", thisWeek: "This Week", thisMonth: "This Month", thisQuarter: "This Quarter", thisYear: "This Year", lastMonth: "Last Month", lastQuarter: "Last Quarter", lastYear: "Last Year", endOfThisMonth: "End of This Month", endOfLastMonth: "End of Last Month", endOfThisQuarter: "End of This Quarter", endOfThisYear: "End of This Year", endOfLastYear: "End of Last Year" }, Ao = { title: "Bank statement import", subtitle: "Preview and import ISO 20022 CAMT statements without posting to the ledger.", selectFiles: "CAMT files", chooseFiles: "Choose XML or ZIP files", dropFiles: "Drop XML or ZIP files here", unsupportedFiles: "Only CAMT XML or ZIP files are supported: {{files}}", fileHint: "camt.053.001.04 and camt.053.001.08 · multiple files supported", preview: "Show preview", noPosting: "Previewing and importing do not post accounting entries.", alreadyImported: "Already imported", period: "Period", openingBalance: "Opening balance", closingBalance: "Closing balance", entries: "Entries", credits: "Credits", debits: "Debits", details: "Transaction details", batches: "batches", qrReferences: "QR references", mapping: "Bank account mapping", selectBankAccount: "Select a Bank Account…", noBankAccounts: "No Bank Account has been configured yet.", createBankAccount: "Create Bank Account", mappingRequired: "Map every new statement to a Bank Account before importing.", import: "Import bank statements", importComplete: "Import completed", importCounts: "{{imported}} entries imported, {{duplicates}} duplicates skipped", history: "Recent imports", importId: "Import", bankAccount: "Bank account", source: "Source file", openReconciliation: "Open bank reconciliation" }, _o = { title: "Bank reconciliation", subtitle: "Match imported bank transactions to posted vouchers, open invoices, or ledger accounts.", status: "Status", unreconciled: "Unreconciled", reconciled: "Reconciled", transactions: "Bank transactions", empty: "No bank transactions in this view.", remittance: "Remittance information", reference: "Reference", openTransaction: "Open bank transaction", conversionRate: "Exchange rate (1 {{currency}} in {{base}})", conversionRateHint: "Required when no exchange rate exists for the transaction date.", existingVouchers: "Existing accounting entries", existingVouchersHint: "These submitted vouchers contain an exact movement on this bank account. Matching does not post them again.", match: "Match", openInvoices: "Open invoices", openInvoicesHint: "Select one or more invoices belonging to the same party. Confirmation creates and submits a Payment Entry.", outstanding: "Outstanding", allocation: "Allocation", noInvoiceSuggestions: "No plausible open invoice was found.", allocated: "Allocated {{amount}} of {{total}}", createPayment: "Create payment and reconcile", directPosting: "Post to a ledger account", directPostingHint: "For fees, interest and other non-invoice movements. Receivable, payable, bank and cash control accounts are intentionally excluded.", counterpartyAccount: "Counter account", remarks: "Remarks", createJournal: "Create journal entry and reconcile", activeMatch: "Active reconciliation", undo: "Undo reconciliation", confirmExistingTitle: "Match existing entry?", confirmExistingBody: "Match {{transaction}} to {{voucher}}? No new ledger entry will be posted.", confirmGroupBody: "Match all {{count}} transactions totalling {{amount}} to {{voucher}}? No new ledger entry will be posted.", groupedTransactions: "{{count}} grouped transactions", confirmPaymentTitle: "Post payment and reconcile?", confirmPaymentBody: "This submits a payment of {{amount}} for {{transaction}} and allocates it across {{count}} invoice(s).", onAccountWarning: "{{amount}} will remain as an on-account payment for this party.", confirmJournalTitle: "Post journal entry and reconcile?", confirmJournalBody: "This posts {{amount}} for {{transaction}} against {{account}}.", postAndReconcile: "Post and reconcile", undoTitle: "Undo reconciliation?", undoCreatedBody: "The voucher created by this reconciliation will be cancelled, its ledger entries reversed, and invoice allocations restored.", undoExistingBody: "The existing voucher will only be unlinked. It remains submitted and its ledger entries are not changed.", undoExistingGroupBody: "All {{count}} grouped transactions ({{transactions}}) will be unlinked together. The existing voucher remains submitted and its ledger entries are not changed.", reconciledNotice: "Bank transaction reconciled.", groupReconciledNotice: "{{count}} bank transactions reconciled as one group.", undoneNotice: "Reconciliation reversed." }, Do = { placeholder: "Search or enter field:value…", search: "Search", addFilter: "+ Filter", availableFields: "Available fields", fieldHelp: "Choose a field or type its technical name followed by a colon.", field: "Field", valueFor: "Value for {{label}}", allFields: "All fields", typeForValues: "Start typing to find values in this field.", noValues: "No matching values found.", noFields: "No matching fields found.", useValue: "Use “{{value}}”", removeFilter: "Remove {{label}} filter", types: { text: "Text", textarea: "Long text", select: "Selection", link: "Linked record", date: "Date", datetime: "Date and time", number: "Number", currency: "Amount" } }, Po = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, To = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Ro = { 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" }, Bo = { 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" }, "bank-account": { one: "Bank Account", other: "Bank Accounts" }, 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" } }, Io = { 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" } }, Eo = { 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", Rentals: "Rentals" }, 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", "Bank Account": "Bank Accounts", "Bank Statement Import": "Bank Statement Import", "Bank Reconciliation": "Bank Reconciliation", 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", "Fleet Calendar": "Fleet Calendar", "Fleet (Assets)": "Fleet (Assets)", Reservations: "Reservations" } }, Lo = { 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." } }, Oo = { 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}}" }, Fo = { 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" }, Mo = { periodRange: "Reporting period: {{from}} – {{to}}", periodFrom: "Reporting period from {{from}}", periodThrough: "Reporting period through {{to}}", asOfDate: "As of: {{date}}", 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" }, qo = { 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}}." }, zo = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, $o = { 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." }, Vo = { "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" }, Uo = { "Last modified": "Last modified", Created: "Created", "% 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", "Item (type)": "Item (type)", "Asset Tag / Plate": "Asset Tag / Plate", "Home Yard": "Home Yard", "Purchase Value": "Purchase Value", "Meter Reading": "Meter Reading", "Meter Unit": "Meter Unit", Yard: "Yard", "Asset (specific unit)": "Asset (specific unit)", Allocation: "Allocation", From: "From", To: "To", Purpose: "Purpose", "Purchase Date": "Purchase Date", Notes: "Notes" }, Ko = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, jo = /* @__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 report-specialist model that creates a validated declarative report 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?"}`), Wo = { 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." }, Go = { 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" } }, Ho = { fleetCalendar: "Fleet Calendar", yard: "Yard", machineType: "Machine type", prev: "Prev", today: "Today", next: "Next", weeks: "weeks", newBooking: "New booking", reserved: "Reserved", onHire: "On Hire", machine: "Machine", loadError: "Could not load the fleet calendar.", noAssets: "No assets to show. Add machines under Rentals → Fleet.", pooledNote: "{{count}} pool booking(s) awaiting assignment", unassigned: "Pool — unassigned", poolWarning: "Pool capacity is reserved. No specific machine has been assigned yet; assign a machine before dispatch." }, Qo = { Unit: "Specific machine", Pool: "Pool – assign machine later", Available: "Available", "On Hire": "On Hire", Out: "Out", Maintenance: "Maintenance", Retired: "Retired", Reserved: "Reserved", Returned: "Returned", Cancelled: "Cancelled", Customer: "Customer", Supplier: "Supplier" }, Yo = { asset: { item_code: "The Item is the machine TYPE and carries the rate; an Asset is one physical unit of it. The Item must have is_asset_tracked = 1.", asset_tag: "Plate or serial — must be unique across assets.", status: "The unit's state today (not a date range). Retired units leave the pool.", meter_reading: "Operating hours / km." }, reservation: { item_code: "Pooled booking ('a 1.7t excavator'): set Item + Yard + Qty. For a specific machine, set Asset instead.", asset: "Book one specific machine. A unit booking also consumes a slot of its Item+Yard pool.", from_datetime: "Exact start — date and time (e.g. 14:27). A bare date means 00:00.", to_datetime: "Exact end. Windows are half-open [from, to): a hire ending 09:00 and the next starting 09:00 do NOT clash." } }, Jo = { label: "Default sales tax", none: "No automatic tax application", hint: "Applied to new quotations, orders and invoices when taxes are not explicitly provided. Existing documents remain unchanged. Use Save to apply.", saveFirst: "Save the company first, then select one of its sales tax templates.", loadError: "Tax templates could not be loaded. The saved selection is preserved.", retry: "Try again", unavailable: "The saved template is not available as a sales tax template for this company. Please check the selection.", empty: "This company has no sales tax templates yet." }, Zo = {
9180
+ proposal: wo,
9181
+ common: Co,
9182
+ datePresets: So,
9183
+ bankStatements: Ao,
9184
+ bankReconciliation: _o,
9185
+ smartSearch: Do,
9186
+ language: Po,
9187
+ header: To,
9188
+ titles: Ro,
9189
+ doctypes: Bo,
9190
+ masters: Io,
9191
+ nav: Eo,
9192
+ login: Lo,
9193
+ settings: Oo,
9194
+ status: Fo,
9195
+ reports: Mo,
9196
+ masterForm: qo,
9197
+ dashboard: zo,
9198
+ chat: $o,
9199
+ conversions: Vo,
9200
+ fields: Uo,
9201
+ tables: Ko,
9202
+ tutorial: jo,
9203
+ notesMarkup: Wo,
9204
+ coa: Go,
9205
+ rentals: Ho,
9206
+ fieldOptions: Qo,
9207
+ hints: Yo,
9208
+ companyTax: Jo
9209
+ }, Xo = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, el = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", cancelBooking: "Buchung stornieren", cancelBookingConfirm: "Ja, stornieren", keepBooking: "Behalten", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", showDisabled: "Deaktivierte anzeigen", columns: "Spalten", searchPlaceholder: "Suchen…", noRecords: "Keine Einträge gefunden", active: "Aktiv", disabled: "Deaktiviert", sortByColumn: "Nach dieser Spalte sortieren", 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" }, tl = { today: "Heute", thisWeek: "Diese Woche", thisMonth: "Dieser Monat", thisQuarter: "Dieses Quartal", thisYear: "Dieses Jahr", lastMonth: "Letzter Monat", lastQuarter: "Letztes Quartal", lastYear: "Letztes Jahr", endOfThisMonth: "Ende dieses Monats", endOfLastMonth: "Ende des letzten Monats", endOfThisQuarter: "Ende dieses Quartals", endOfThisYear: "Ende dieses Jahres", endOfLastYear: "Ende des letzten Jahres" }, nl = { title: "Kontoauszug importieren", subtitle: "ISO-20022-CAMT-Kontoauszüge prüfen und ohne automatische Verbuchung importieren.", selectFiles: "CAMT-Dateien", chooseFiles: "XML- oder ZIP-Dateien auswählen", dropFiles: "XML- oder ZIP-Dateien hier ablegen", unsupportedFiles: "Es werden nur CAMT-XML- oder ZIP-Dateien unterstützt: {{files}}", fileHint: "camt.053.001.04 und camt.053.001.08 · mehrere Dateien möglich", preview: "Vorschau anzeigen", noPosting: "Vorschau und Import erzeugen keine Buchungssätze.", alreadyImported: "Bereits importiert", period: "Zeitraum", openingBalance: "Anfangssaldo", closingBalance: "Endsaldo", entries: "Buchungen", credits: "Gutschriften", debits: "Belastungen", details: "Transaktionsdetails", batches: "Sammelbuchungen", qrReferences: "QR-Referenzen", mapping: "Bankkonto-Zuordnung", selectBankAccount: "Bankkonto auswählen…", noBankAccounts: "Es wurde noch kein Bankkonto eingerichtet.", createBankAccount: "Bankkonto einrichten", mappingRequired: "Ordnen Sie vor dem Import jeden neuen Auszug einem Bankkonto zu.", import: "Kontoauszüge importieren", importComplete: "Import abgeschlossen", importCounts: "{{imported}} Buchungen importiert, {{duplicates}} Duplikate übersprungen", history: "Letzte Importe", importId: "Import", bankAccount: "Bankkonto", source: "Quelldatei", openReconciliation: "Bankabstimmung öffnen" }, al = { title: "Bankabstimmung", subtitle: "Importierte Banktransaktionen mit Buchungen, offenen Rechnungen oder Sachkonten abstimmen.", status: "Status", unreconciled: "Nicht abgestimmt", reconciled: "Abgestimmt", transactions: "Banktransaktionen", empty: "In dieser Ansicht sind keine Banktransaktionen vorhanden.", remittance: "Zahlungsinformation", reference: "Referenz", openTransaction: "Banktransaktion öffnen", conversionRate: "Wechselkurs (1 {{currency}} in {{base}})", conversionRateHint: "Erforderlich, wenn für das Transaktionsdatum kein Wechselkurs hinterlegt ist.", existingVouchers: "Bestehende Buchungen", existingVouchersHint: "Diese eingereichten Belege enthalten eine exakt passende Bewegung auf diesem Bankkonto. Bei der Zuordnung wird nichts erneut gebucht.", match: "Zuordnen", openInvoices: "Offene Rechnungen", openInvoicesHint: "Wähle eine oder mehrere Rechnungen derselben Partei. Nach der Bestätigung wird eine Zahlung erstellt und eingereicht.", outstanding: "Offen", allocation: "Zuweisung", noInvoiceSuggestions: "Es wurde keine plausible offene Rechnung gefunden.", allocated: "{{amount}} von {{total}} zugewiesen", createPayment: "Zahlung erstellen und abstimmen", directPosting: "Auf ein Sachkonto buchen", directPostingHint: "Für Gebühren, Zinsen und andere Bewegungen ohne Rechnung. Debitoren-, Kreditoren-, Bank- und Kassenkonten sind bewusst ausgeschlossen.", counterpartyAccount: "Gegenkonto", remarks: "Bemerkung", createJournal: "Buchungssatz erstellen und abstimmen", activeMatch: "Aktive Abstimmung", undo: "Abstimmung rückgängig machen", confirmExistingTitle: "Bestehende Buchung zuordnen?", confirmExistingBody: "{{transaction}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", confirmGroupBody: "Alle {{count}} Transaktionen über insgesamt {{amount}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", groupedTransactions: "{{count}} gruppierte Transaktionen", confirmPaymentTitle: "Zahlung buchen und abstimmen?", confirmPaymentBody: "Damit wird für {{transaction}} eine Zahlung über {{amount}} eingereicht und auf {{count}} Rechnung(en) verteilt.", onAccountWarning: "{{amount}} bleibt als nicht zugewiesene Zahlung bei dieser Partei bestehen.", confirmJournalTitle: "Buchungssatz erstellen und abstimmen?", confirmJournalBody: "Damit werden {{amount}} für {{transaction}} gegen {{account}} gebucht.", postAndReconcile: "Buchen und abstimmen", undoTitle: "Abstimmung rückgängig machen?", undoCreatedBody: "Der durch diese Abstimmung erstellte Beleg wird storniert, seine Hauptbuchungen werden umgekehrt und Rechnungszuweisungen wiederhergestellt.", undoExistingBody: "Der bestehende Beleg wird nur von der Banktransaktion getrennt. Er bleibt eingereicht und seine Buchungen werden nicht verändert.", undoExistingGroupBody: "Alle {{count}} gruppierten Banktransaktionen ({{transactions}}) werden gemeinsam vom Beleg getrennt. Der bestehende Beleg bleibt eingereicht und seine Buchungen werden nicht verändert.", reconciledNotice: "Banktransaktion wurde abgestimmt.", groupReconciledNotice: "{{count}} Banktransaktionen wurden als Gruppe abgestimmt.", undoneNotice: "Abstimmung wurde rückgängig gemacht." }, rl = { placeholder: "Suchen oder Feld:Wert eingeben…", search: "Suchen", addFilter: "+ Filter", availableFields: "Verfügbare Felder", fieldHelp: "Feld auswählen oder den technischen Namen mit Doppelpunkt eingeben.", field: "Feld", valueFor: "Wert für {{label}}", allFields: "Alle Felder", typeForValues: "Tippen, um Werte in diesem Feld zu finden.", noValues: "Keine passenden Werte gefunden.", noFields: "Keine passenden Felder gefunden.", useValue: "„{{value}}“ verwenden", removeFilter: "Filter {{label}} entfernen", types: { text: "Text", textarea: "Langtext", select: "Auswahl", link: "Verknüpfter Eintrag", date: "Datum", datetime: "Datum und Uhrzeit", number: "Zahl", currency: "Betrag" } }, sl = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, il = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, ol = { 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" }, ll = { 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" }, "bank-account": { one: "Bankkonto", other: "Bankkonten" }, 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" } }, cl = { 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" } }, dl = { 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", Rentals: "Vermietung" }, 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", "Bank Account": "Bankkonten", "Bank Statement Import": "Kontoauszug importieren", "Bank Reconciliation": "Bankabstimmung", 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", "Fleet Calendar": "Flottenkalender", "Fleet (Assets)": "Flotte (Geräte)", Reservations: "Reservationen" } }, ul = { 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." } }, ml = { 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}}" }, pl = { 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" }, hl = { periodRange: "Berichtszeitraum: {{from}} – {{to}}", periodFrom: "Berichtszeitraum ab {{from}}", periodThrough: "Berichtszeitraum bis {{to}}", asOfDate: "Stichtag: {{date}}", 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" }, gl = { 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." }, fl = { "Last modified": "Zuletzt geändert", Created: "Erstellt", 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", "Item (type)": "Artikel (Typ)", "Asset Tag / Plate": "Kennung / Kennzeichen", "Home Yard": "Heimdepot", "Purchase Value": "Kaufwert", "Meter Reading": "Zählerstand", "Meter Unit": "Zählereinheit", Yard: "Depot", "Asset (specific unit)": "Gerät (bestimmte Einheit)", Allocation: "Zuweisung", From: "Von", To: "Bis", Purpose: "Zweck", "Purchase Date": "Kaufdatum", Notes: "Notizen" }, yl = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, bl = { "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" }, vl = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, xl = { 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." }, kl = /* @__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?"}'), Nl = { 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." }, wl = { 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" } }, Cl = { fleetCalendar: "Flottenkalender", yard: "Depot", machineType: "Maschinentyp", prev: "Zurück", today: "Heute", next: "Weiter", weeks: "Wochen", newBooking: "Neue Reservation", reserved: "Reserviert", onHire: "Vermietet", machine: "Maschine", loadError: "Flottenkalender konnte nicht geladen werden.", noAssets: "Keine Geräte vorhanden. Maschinen unter Vermietung → Flotte hinzufügen.", pooledNote: "{{count}} Pool-Reservation(en) noch ohne Maschinenzuordnung", unassigned: "Pool — noch nicht zugeordnet", poolWarning: "Die Pool-Kapazität ist reserviert. Eine konkrete Maschine ist noch nicht zugeordnet; vor der Ausgabe eine Maschine auswählen." }, Sl = { Unit: "Bestimmte Maschine", Pool: "Pool – Maschine später zuweisen", Available: "Verfügbar", "On Hire": "Vermietet", Out: "Ausgeliefert", Maintenance: "Wartung", Retired: "Ausgemustert", Reserved: "Reserviert", Returned: "Zurückgegeben", Cancelled: "Storniert", Customer: "Kunde", Supplier: "Lieferant" }, Al = { asset: { item_code: "Der Artikel ist der Maschinen-TYP und trägt den Tarif; ein Gerät ist eine physische Einheit davon. Der Artikel muss is_asset_tracked = 1 haben.", asset_tag: "Kennzeichen oder Seriennummer — muss über alle Geräte eindeutig sein.", status: "Aktueller Zustand der Einheit (kein Zeitraum). Ausgemusterte Einheiten verlassen den Pool.", meter_reading: "Betriebsstunden / km." }, reservation: { item_code: "Pool-Reservation ('ein 1.7t-Bagger'): Artikel + Depot + Menge setzen. Für eine bestimmte Maschine stattdessen Gerät setzen.", asset: "Eine bestimmte Maschine buchen. Eine Einheiten-Buchung belegt auch einen Platz im Artikel+Depot-Pool.", from_datetime: "Genauer Beginn — Datum und Uhrzeit (z. B. 14:27). Ein reines Datum bedeutet 00:00.", to_datetime: "Genaues Ende. Fenster sind halboffen [von, bis): eine Miete, die um 09:00 endet, und die nächste um 09:00 beginnende, kollidieren NICHT." } }, _l = { label: "Standard-Verkaufssteuer", none: "Keine automatische Übernahme", hint: "Wird bei neuen Offerten, Aufträgen und Rechnungen übernommen, sofern keine Steuern ausdrücklich vorgegeben werden. Bestehende Belege bleiben unverändert. Mit „Speichern“ übernehmen.", saveFirst: "Firma zuerst speichern. Anschliessend können Sie eine ihrer Verkaufsteuervorlagen auswählen.", loadError: "Steuervorlagen konnten nicht geladen werden. Die gespeicherte Auswahl bleibt erhalten.", retry: "Erneut versuchen", unavailable: "Die gespeicherte Vorlage ist für diese Firma nicht als Verkaufsteuervorlage verfügbar. Bitte prüfen Sie die Auswahl.", empty: "Für diese Firma sind noch keine Verkaufsteuervorlagen hinterlegt." }, Dl = {
9210
+ proposal: Xo,
9211
+ common: el,
9212
+ datePresets: tl,
9213
+ bankStatements: nl,
9214
+ bankReconciliation: al,
9215
+ smartSearch: rl,
9216
+ language: sl,
9217
+ header: il,
9218
+ titles: ol,
9219
+ doctypes: ll,
9220
+ masters: cl,
9221
+ nav: dl,
9222
+ login: ul,
9223
+ settings: ml,
9224
+ status: pl,
9225
+ reports: hl,
9226
+ masterForm: gl,
9227
+ fields: fl,
9228
+ tables: yl,
9229
+ conversions: bl,
9230
+ dashboard: vl,
9231
+ chat: xl,
9232
+ tutorial: kl,
9233
+ notesMarkup: Nl,
9234
+ coa: wl,
9235
+ rentals: Cl,
9236
+ fieldOptions: Sl,
9237
+ hints: Al,
9238
+ companyTax: _l
9239
+ }, Pl = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, Tl = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", cancelBooking: "Annuler la réservation", cancelBookingConfirm: "Oui, annuler", keepBooking: "Conserver", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", showDisabled: "Afficher les désactivés", columns: "Colonnes", searchPlaceholder: "Rechercher…", noRecords: "Aucun enregistrement trouvé", active: "Actif", disabled: "Désactivé", sortByColumn: "Trier par cette colonne", 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" }, Rl = { today: "Aujourd’hui", thisWeek: "Cette semaine", thisMonth: "Ce mois-ci", thisQuarter: "Ce trimestre", thisYear: "Cette année", lastMonth: "Mois dernier", lastQuarter: "Trimestre dernier", lastYear: "Année dernière", endOfThisMonth: "Fin du mois en cours", endOfLastMonth: "Fin du mois dernier", endOfThisQuarter: "Fin du trimestre en cours", endOfThisYear: "Fin de l’année en cours", endOfLastYear: "Fin de l’année dernière" }, Bl = { title: "Importer un relevé bancaire", subtitle: "Prévisualisez et importez des relevés ISO 20022 CAMT sans écriture comptable automatique.", selectFiles: "Fichiers CAMT", chooseFiles: "Choisir des fichiers XML ou ZIP", dropFiles: "Déposez les fichiers XML ou ZIP ici", unsupportedFiles: "Seuls les fichiers CAMT XML ou ZIP sont acceptés : {{files}}", fileHint: "camt.053.001.04 et camt.053.001.08 · plusieurs fichiers acceptés", preview: "Afficher l’aperçu", noPosting: "L’aperçu et l’importation ne génèrent aucune écriture comptable.", alreadyImported: "Déjà importé", period: "Période", openingBalance: "Solde initial", closingBalance: "Solde final", entries: "Opérations", credits: "Crédits", debits: "Débits", details: "Détails des transactions", batches: "lots", qrReferences: "Références QR", mapping: "Affectation du compte bancaire", selectBankAccount: "Sélectionner un compte bancaire…", noBankAccounts: "Aucun compte bancaire n’a encore été configuré.", createBankAccount: "Configurer un compte bancaire", mappingRequired: "Affectez chaque nouveau relevé à un compte bancaire avant l’importation.", import: "Importer les relevés", importComplete: "Importation terminée", importCounts: "{{imported}} opérations importées, {{duplicates}} doublons ignorés", history: "Importations récentes", importId: "Importation", bankAccount: "Compte bancaire", source: "Fichier source", openReconciliation: "Ouvrir le rapprochement bancaire" }, Il = { title: "Rapprochement bancaire", subtitle: "Rapprochez les transactions importées avec des écritures, des factures ouvertes ou des comptes comptables.", status: "Statut", unreconciled: "Non rapprochée", reconciled: "Rapprochée", transactions: "Transactions bancaires", empty: "Aucune transaction bancaire dans cette vue.", remittance: "Information de paiement", reference: "Référence", openTransaction: "Ouvrir la transaction bancaire", conversionRate: "Taux de change (1 {{currency}} en {{base}})", conversionRateHint: "Requis si aucun taux de change n’existe à la date de la transaction.", existingVouchers: "Écritures existantes", existingVouchersHint: "Ces pièces validées contiennent un mouvement exact sur ce compte bancaire. Le rapprochement ne les comptabilise pas une seconde fois.", match: "Rapprocher", openInvoices: "Factures ouvertes", openInvoicesHint: "Sélectionnez une ou plusieurs factures du même tiers. La confirmation crée et valide un paiement.", outstanding: "Solde ouvert", allocation: "Affectation", noInvoiceSuggestions: "Aucune facture ouverte plausible n’a été trouvée.", allocated: "{{amount}} affectés sur {{total}}", createPayment: "Créer le paiement et rapprocher", directPosting: "Comptabiliser sur un compte", directPostingHint: "Pour les frais, intérêts et autres mouvements sans facture. Les comptes clients, fournisseurs, bancaires et de caisse sont volontairement exclus.", counterpartyAccount: "Compte de contrepartie", remarks: "Remarque", createJournal: "Créer l’écriture et rapprocher", activeMatch: "Rapprochement actif", undo: "Annuler le rapprochement", confirmExistingTitle: "Rapprocher l’écriture existante ?", confirmExistingBody: "Rapprocher {{transaction}} avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", confirmGroupBody: "Rapprocher les {{count}} transactions, pour un total de {{amount}}, avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", groupedTransactions: "{{count}} transactions groupées", confirmPaymentTitle: "Comptabiliser le paiement et rapprocher ?", confirmPaymentBody: "Cette action valide un paiement de {{amount}} pour {{transaction}} et l’affecte à {{count}} facture(s).", onAccountWarning: "{{amount}} resteront comme paiement non affecté pour ce tiers.", confirmJournalTitle: "Comptabiliser l’écriture et rapprocher ?", confirmJournalBody: "Cette action comptabilise {{amount}} pour {{transaction}} sur {{account}}.", postAndReconcile: "Comptabiliser et rapprocher", undoTitle: "Annuler le rapprochement ?", undoCreatedBody: "La pièce créée par ce rapprochement sera annulée, ses écritures extournées et les affectations aux factures restaurées.", undoExistingBody: "La pièce existante sera uniquement dissociée. Elle restera validée et ses écritures ne seront pas modifiées.", undoExistingGroupBody: "Les {{count}} transactions groupées ({{transactions}}) seront toutes dissociées ensemble. La pièce existante restera validée et ses écritures ne seront pas modifiées.", reconciledNotice: "Transaction bancaire rapprochée.", groupReconciledNotice: "{{count}} transactions bancaires ont été rapprochées en groupe.", undoneNotice: "Rapprochement annulé." }, El = { placeholder: "Rechercher ou saisir champ:valeur…", search: "Rechercher", addFilter: "+ Filtre", availableFields: "Champs disponibles", fieldHelp: "Choisissez un champ ou saisissez son nom technique suivi de deux-points.", field: "Champ", valueFor: "Valeur pour {{label}}", allFields: "Tous les champs", typeForValues: "Commencez à saisir pour rechercher des valeurs dans ce champ.", noValues: "Aucune valeur correspondante.", noFields: "Aucun champ correspondant.", useValue: "Utiliser « {{value}} »", removeFilter: "Supprimer le filtre {{label}}", types: { text: "Texte", textarea: "Texte long", select: "Sélection", link: "Enregistrement lié", date: "Date", datetime: "Date et heure", number: "Nombre", currency: "Montant" } }, Ll = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Ol = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Fl = { 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" }, Ml = { 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" }, "bank-account": { one: "Compte bancaire", other: "Comptes 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" } }, ql = { 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" } }, zl = { 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", Rentals: "Locations" }, 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", "Bank Account": "Comptes bancaires", "Bank Statement Import": "Importer un relevé bancaire", "Bank Reconciliation": "Rapprochement 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", "Fleet Calendar": "Calendrier de flotte", "Fleet (Assets)": "Flotte (matériel)", Reservations: "Réservations" } }, $l = { 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." } }, Vl = { 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}}" }, Ul = { 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é" }, Kl = { periodRange: "Période du rapport : {{from}} – {{to}}", periodFrom: "Période du rapport à partir du {{from}}", periodThrough: "Période du rapport jusqu’au {{to}}", asOfDate: "Date de référence : {{date}}", 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é" }, jl = { 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}}." }, Wl = { "Last modified": "Dernière modification", Created: "Créé", 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é", "Item (type)": "Article (type)", "Asset Tag / Plate": "Étiquette / plaque", "Home Yard": "Dépôt d'attache", "Purchase Value": "Valeur d'achat", "Meter Reading": "Relevé compteur", "Meter Unit": "Unité compteur", Yard: "Dépôt", "Asset (specific unit)": "Équipement (unité spécifique)", Allocation: "Affectation", From: "Du", To: "Au", Purpose: "Objet", "Purchase Date": "Date d'achat", Notes: "Notes" }, Gl = { 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" }, Hl = { "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" }, Ql = { 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" }, Yl = { 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." }, Jl = /* @__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 ?"}`), Zl = { 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." }, Xl = { 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" } }, ec = { fleetCalendar: "Calendrier de flotte", yard: "Dépôt", machineType: "Type de machine", prev: "Préc.", today: "Aujourd'hui", next: "Suiv.", weeks: "semaines", newBooking: "Nouvelle réservation", reserved: "Réservé", onHire: "En location", machine: "Machine", loadError: "Impossible de charger le calendrier de flotte.", noAssets: "Aucun équipement à afficher. Ajoutez des machines sous Locations → Flotte.", pooledNote: "{{count}} réservation(s) en attente d’attribution", unassigned: "Pool — non attribué", poolWarning: "La capacité est réservée. Aucune machine précise n’est encore attribuée ; attribuez une machine avant la sortie." }, tc = { Unit: "Machine spécifique", Pool: "Pool – machine à affecter", Available: "Disponible", "On Hire": "En location", Out: "Sorti", Maintenance: "Maintenance", Retired: "Retiré", Reserved: "Réservé", Returned: "Retourné", Cancelled: "Annulé", Customer: "Client", Supplier: "Fournisseur" }, nc = { asset: { item_code: "L'article est le TYPE de machine et porte le tarif ; un équipement en est une unité physique. L'article doit avoir is_asset_tracked = 1.", asset_tag: "Plaque ou numéro de série — doit être unique sur tous les équipements.", status: "État actuel de l'unité (pas une période). Les unités retirées quittent le pool.", meter_reading: "Heures de fonctionnement / km." }, reservation: { item_code: "Réservation de pool ('une pelle de 1,7 t') : renseigner Article + Dépôt + Qté. Pour une machine précise, renseigner Équipement.", asset: "Réserver une machine précise. Une réservation d'unité consomme aussi une place du pool Article+Dépôt.", from_datetime: "Début exact — date et heure (p. ex. 14:27). Une date seule signifie 00:00.", to_datetime: "Fin exacte. Les fenêtres sont semi-ouvertes [de, à) : une location finissant à 09:00 et la suivante commençant à 09:00 ne se chevauchent PAS." } }, ac = { label: "Taxe de vente par défaut", none: "Aucune application automatique", hint: "Appliquée aux nouveaux devis, commandes et factures si les taxes ne sont pas explicitement définies. Les documents existants restent inchangés. Cliquez sur Enregistrer pour appliquer.", saveFirst: "Enregistrez d’abord l’entreprise, puis sélectionnez un de ses modèles de taxes de vente.", loadError: "Impossible de charger les modèles de taxes. La sélection enregistrée est conservée.", retry: "Réessayer", unavailable: "Le modèle enregistré n’est pas disponible comme modèle de taxes de vente pour cette entreprise. Vérifiez la sélection.", empty: "Aucun modèle de taxes de vente n’est encore défini pour cette entreprise." }, rc = {
9240
+ proposal: Pl,
9241
+ common: Tl,
9242
+ datePresets: Rl,
9243
+ bankStatements: Bl,
9244
+ bankReconciliation: Il,
9245
+ smartSearch: El,
9246
+ language: Ll,
9247
+ header: Ol,
9248
+ titles: Fl,
9249
+ doctypes: Ml,
9250
+ masters: ql,
9251
+ nav: zl,
9252
+ login: $l,
9253
+ settings: Vl,
9254
+ status: Ul,
9255
+ reports: Kl,
9256
+ masterForm: jl,
9257
+ fields: Wl,
9258
+ tables: Gl,
9259
+ conversions: Hl,
9260
+ dashboard: Ql,
9261
+ chat: Yl,
9262
+ tutorial: Jl,
9263
+ notesMarkup: Zl,
9264
+ coa: Xl,
9265
+ rentals: ec,
9266
+ fieldOptions: tc,
9267
+ hints: nc,
9268
+ companyTax: ac
9218
9269
  }, yr = [
9219
9270
  { code: "en", label: "English" },
9220
9271
  { code: "de", label: "Deutsch" },
9221
9272
  { code: "fr", label: "Français" }
9222
9273
  ], br = "lambda-erp:language";
9223
- function tc(e) {
9274
+ function sc(e) {
9224
9275
  return !!e && yr.some((n) => n.code === e);
9225
9276
  }
9226
- function nc() {
9277
+ function ic() {
9227
9278
  try {
9228
9279
  const e = localStorage.getItem(br);
9229
- if (tc(e)) return e;
9280
+ if (sc(e)) return e;
9230
9281
  } catch {
9231
9282
  }
9232
9283
  return "en";
9233
9284
  }
9234
- function ac(e) {
9285
+ function oc(e) {
9235
9286
  try {
9236
9287
  localStorage.setItem(br, e);
9237
9288
  } catch {
@@ -9239,11 +9290,11 @@ function ac(e) {
9239
9290
  }
9240
9291
  Ma.use(Lr).init({
9241
9292
  resources: {
9242
- en: { translation: Yo },
9243
- de: { translation: Sl },
9244
- fr: { translation: ec }
9293
+ en: { translation: Zo },
9294
+ de: { translation: Dl },
9295
+ fr: { translation: rc }
9245
9296
  },
9246
- lng: nc(),
9297
+ lng: ic(),
9247
9298
  fallbackLng: "en",
9248
9299
  // any key missing in de/fr falls back to the English value
9249
9300
  interpolation: { escapeValue: !1 },
@@ -9251,10 +9302,10 @@ Ma.use(Lr).init({
9251
9302
  react: { useSuspense: !1 }
9252
9303
  // resources are bundled synchronously — no Suspense needed
9253
9304
  });
9254
- Ma.on("languageChanged", ac);
9255
- function rc({ label: e }) {
9305
+ Ma.on("languageChanged", oc);
9306
+ function lc({ label: e }) {
9256
9307
  var i;
9257
- const { t: n, i18n: a } = se(), { setSetting: s } = Zt(), o = ((i = a.language) == null ? void 0 : i.split("-")[0]) ?? "en";
9308
+ const { t: n, i18n: a } = re(), { setSetting: s } = Zt(), o = ((i = a.language) == null ? void 0 : i.split("-")[0]) ?? "en";
9258
9309
  return /* @__PURE__ */ t(
9259
9310
  Ge,
9260
9311
  {
@@ -9279,9 +9330,9 @@ const wa = [
9279
9330
  function at(e) {
9280
9331
  return e === 0 ? "$0.00" : e < 0.01 ? `$${e.toFixed(4)}` : `$${e.toFixed(2)}`;
9281
9332
  }
9282
- function sc({ demoActive: e }) {
9333
+ function cc({ demoActive: e }) {
9283
9334
  var S, x;
9284
- const { t: n } = se(), [a, s] = w("1h"), { data: o, isLoading: i, isFetching: l, error: c, refetch: h, dataUpdatedAt: d } = ve({
9335
+ const { t: n } = re(), [a, s] = w("1h"), { data: o, isLoading: i, isFetching: l, error: c, refetch: h, dataUpdatedAt: d } = ve({
9285
9336
  queryKey: ["demo-spend"],
9286
9337
  queryFn: () => F.getDemoSpend(),
9287
9338
  // Refresh once a minute — demo spend changes slowly; no need to poll harder.
@@ -9463,8 +9514,8 @@ function Tt({ label: e, value: n }) {
9463
9514
  /* @__PURE__ */ t("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-gray-900", children: n })
9464
9515
  ] });
9465
9516
  }
9466
- function ic() {
9467
- const { t: e } = se(), { user: n } = Ze(), [a, s] = w(""), [o, i] = w(""), [l, c] = w(""), [h, d] = w(""), [g, m] = w(!1), b = ke({
9517
+ function dc() {
9518
+ const { t: e } = re(), { user: n } = Ze(), [a, s] = w(""), [o, i] = w(""), [l, c] = w(""), [h, d] = w(""), [g, m] = w(!1), b = ke({
9468
9519
  mutationFn: () => F.authChangePassword(a, o),
9469
9520
  onSuccess: () => {
9470
9521
  m(!0), d(""), s(""), i(""), c(""), setTimeout(() => m(!1), 4e3);
@@ -9540,8 +9591,8 @@ function ic() {
9540
9591
  /* @__PURE__ */ t(Y, { type: "submit", disabled: b.isPending || !a || !o || !l, children: b.isPending ? e("settings.changingPassword") : e("settings.changePassword") })
9541
9592
  ] }) });
9542
9593
  }
9543
- function oc() {
9544
- const { t: e } = se(), { user: n, refreshUser: a } = Ze(), [s, o] = w(""), [i, l] = w(""), [c, h] = w(""), [d, g] = w(!1), m = ke({
9594
+ function uc() {
9595
+ const { t: e } = re(), { user: n, refreshUser: a } = Ze(), [s, o] = w(""), [i, l] = w(""), [c, h] = w(""), [d, g] = w(!1), m = ke({
9545
9596
  mutationFn: () => F.authSetPassword(s),
9546
9597
  onSuccess: async () => {
9547
9598
  g(!0), h(""), o(""), l(""), await a();
@@ -9606,8 +9657,8 @@ function oc() {
9606
9657
  ] })
9607
9658
  ] });
9608
9659
  }
9609
- function lc() {
9610
- const { t: e } = se(), { data: n } = ve({
9660
+ function mc() {
9661
+ const { t: e } = re(), { data: n } = ve({
9611
9662
  queryKey: ["auth-setup-status"],
9612
9663
  queryFn: () => F.authSetupStatus()
9613
9664
  }), { data: a } = ve({
@@ -9642,8 +9693,8 @@ function lc() {
9642
9693
  }
9643
9694
  const fn = { viewer: 1, manager: 2, admin: 3 };
9644
9695
  function vr({ ownRole: e }) {
9645
- const { t: n } = se(), { user: a } = Ze(), s = et(), [o, i] = w(""), [l, c] = w(e in fn ? e : "viewer"), [h, d] = w(null), [g, m] = w(null), b = ["viewer", "manager", "admin"].filter(
9646
- (O) => fn[O] <= (fn[e] ?? 1)
9696
+ const { t: n } = re(), { user: a } = Ze(), s = et(), [o, i] = w(""), [l, c] = w(e in fn ? e : "viewer"), [h, d] = w(null), [g, m] = w(null), b = ["viewer", "manager", "admin"].filter(
9697
+ (L) => fn[L] <= (fn[e] ?? 1)
9647
9698
  ), v = `${window.location.origin}/api/mcp`, k = h ? `claude mcp add --transport http --scope user lambda-erp ${v} \\
9648
9699
  --header "Authorization: Bearer ${h}"` : "", y = h ? `# ~/.codex/config.toml
9649
9700
  [mcp_servers.lambda-erp]
@@ -9653,33 +9704,33 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9653
9704
  queryFn: () => F.getApiKeys()
9654
9705
  }), S = ke({
9655
9706
  mutationFn: () => F.createApiKey(o.trim(), l),
9656
- onSuccess: (O) => {
9657
- d(O.token), i(""), s.invalidateQueries({ queryKey: ["api-keys"] });
9707
+ onSuccess: (L) => {
9708
+ d(L.token), i(""), s.invalidateQueries({ queryKey: ["api-keys"] });
9658
9709
  }
9659
9710
  }), x = ke({
9660
- mutationFn: (O) => F.revokeApiKey(O),
9711
+ mutationFn: (L) => F.revokeApiKey(L),
9661
9712
  onSuccess: () => s.invalidateQueries({ queryKey: ["api-keys"] })
9662
9713
  }), p = ke({
9663
- mutationFn: (O) => F.deleteApiKey(O),
9714
+ mutationFn: (L) => F.deleteApiKey(L),
9664
9715
  onSuccess: () => s.invalidateQueries({ queryKey: ["api-keys"] })
9665
- }), f = (O) => O.is_mine ?? O.user === (a == null ? void 0 : a.name), B = (O) => O.owner_full_name || O.owner_email || O.user || n("settings.chatApiUnknownUser"), E = fe(() => {
9666
- const O = /* @__PURE__ */ new Map();
9716
+ }), f = (L) => L.is_mine ?? L.user === (a == null ? void 0 : a.name), B = (L) => L.owner_full_name || L.owner_email || L.user || n("settings.chatApiUnknownUser"), E = fe(() => {
9717
+ const L = /* @__PURE__ */ new Map();
9667
9718
  for (const q of A ?? []) {
9668
9719
  const Q = q.is_mine ?? q.user === (a == null ? void 0 : a.name), N = Q ? "__me__" : q.user ?? "__unknown__";
9669
- O.has(N) || O.set(N, {
9720
+ L.has(N) || L.set(N, {
9670
9721
  label: Q ? n("settings.chatApiYourKeys") : q.owner_full_name || q.owner_email || q.user || n("settings.chatApiUnknownUser"),
9671
9722
  sublabel: Q ? void 0 : q.owner_email ?? void 0,
9672
9723
  isMine: Q,
9673
9724
  keys: []
9674
- }), O.get(N).keys.push(q);
9725
+ }), L.get(N).keys.push(q);
9675
9726
  }
9676
- return Array.from(O.values()).sort(
9727
+ return Array.from(L.values()).sort(
9677
9728
  (q, Q) => q.isMine ? -1 : Q.isMine ? 1 : q.label.localeCompare(Q.label)
9678
9729
  );
9679
- }, [A, a, n]), J = (O, q) => {
9680
- q === "revoke" ? x.mutate(O) : p.mutate(O);
9681
- }, Z = (O, q) => {
9682
- f(O) ? J(O.id, q) : m({ id: O.id, action: q, owner: B(O), keyName: O.name });
9730
+ }, [A, a, n]), J = (L, q) => {
9731
+ q === "revoke" ? x.mutate(L) : p.mutate(L);
9732
+ }, Z = (L, q) => {
9733
+ f(L) ? J(L.id, q) : m({ id: L.id, action: q, owner: B(L), keyName: L.name });
9683
9734
  };
9684
9735
  return /* @__PURE__ */ r("div", { children: [
9685
9736
  h && /* @__PURE__ */ r("div", { className: "mb-3 rounded-lg bg-amber-50 p-3 ring-1 ring-inset ring-amber-200", children: [
@@ -9690,8 +9741,8 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9690
9741
  {
9691
9742
  className: "mt-2 text-xs font-medium text-brand hover:underline",
9692
9743
  onClick: () => {
9693
- var O;
9694
- return (O = navigator.clipboard) == null ? void 0 : O.writeText(h);
9744
+ var L;
9745
+ return (L = navigator.clipboard) == null ? void 0 : L.writeText(h);
9695
9746
  },
9696
9747
  children: n("settings.chatApiCopy")
9697
9748
  }
@@ -9720,12 +9771,12 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9720
9771
  ] })
9721
9772
  ] }),
9722
9773
  e === "admin" && /* @__PURE__ */ t("p", { className: "mb-3 text-xs text-fg-muted", children: n("settings.chatApiAdminAllNote") }),
9723
- E.length > 0 ? /* @__PURE__ */ t("div", { className: "mb-4 space-y-4", children: E.map((O) => /* @__PURE__ */ r("div", { children: [
9774
+ E.length > 0 ? /* @__PURE__ */ t("div", { className: "mb-4 space-y-4", children: E.map((L) => /* @__PURE__ */ r("div", { children: [
9724
9775
  /* @__PURE__ */ r("div", { className: "mb-1.5 flex items-baseline gap-2", children: [
9725
- /* @__PURE__ */ t("span", { className: "text-xs font-semibold text-fg", children: O.label }),
9726
- O.isMine ? /* @__PURE__ */ t(Ut, { variant: "default", children: n("settings.chatApiYouBadge") }) : O.sublabel && /* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: O.sublabel })
9776
+ /* @__PURE__ */ t("span", { className: "text-xs font-semibold text-fg", children: L.label }),
9777
+ L.isMine ? /* @__PURE__ */ t(Ut, { variant: "default", children: n("settings.chatApiYouBadge") }) : L.sublabel && /* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: L.sublabel })
9727
9778
  ] }),
9728
- /* @__PURE__ */ t("ul", { className: "divide-y divide-line rounded-lg ring-1 ring-line", children: O.keys.map((q) => /* @__PURE__ */ r(
9779
+ /* @__PURE__ */ t("ul", { className: "divide-y divide-line rounded-lg ring-1 ring-line", children: L.keys.map((q) => /* @__PURE__ */ r(
9729
9780
  "li",
9730
9781
  {
9731
9782
  className: "flex items-center justify-between gap-3 px-3 py-2 text-sm",
@@ -9754,14 +9805,14 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9754
9805
  },
9755
9806
  q.id
9756
9807
  )) })
9757
- ] }, O.label)) }) : /* @__PURE__ */ t("p", { className: "mb-4 text-xs text-fg-muted", children: n("settings.chatApiNoKeys") }),
9808
+ ] }, L.label)) }) : /* @__PURE__ */ t("p", { className: "mb-4 text-xs text-fg-muted", children: n("settings.chatApiNoKeys") }),
9758
9809
  /* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-3", children: [
9759
9810
  /* @__PURE__ */ t("div", { className: "w-48", children: /* @__PURE__ */ t(
9760
9811
  me,
9761
9812
  {
9762
9813
  label: n("settings.chatApiName"),
9763
9814
  value: o,
9764
- onChange: (O) => i(O.target.value),
9815
+ onChange: (L) => i(L.target.value),
9765
9816
  placeholder: "lambda-web"
9766
9817
  }
9767
9818
  ) }),
@@ -9771,7 +9822,7 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9771
9822
  label: n("settings.chatApiRole"),
9772
9823
  options: b,
9773
9824
  value: l,
9774
- onChange: (O) => c(O.target.value)
9825
+ onChange: (L) => c(L.target.value)
9775
9826
  }
9776
9827
  ),
9777
9828
  /* @__PURE__ */ t(Y, { onClick: () => S.mutate(), disabled: !o.trim() || S.isPending, children: n("settings.chatApiCreate") })
@@ -9788,7 +9839,7 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
9788
9839
  className: "w-full max-w-sm rounded-xl border border-line bg-surface p-5 shadow-xl",
9789
9840
  role: "dialog",
9790
9841
  "aria-modal": "true",
9791
- onClick: (O) => O.stopPropagation(),
9842
+ onClick: (L) => L.stopPropagation(),
9792
9843
  children: [
9793
9844
  /* @__PURE__ */ t("h3", { className: "text-sm font-semibold text-fg", children: n("settings.chatApiConfirmTitle") }),
9794
9845
  /* @__PURE__ */ t("p", { className: "mt-2 text-xs text-fg-muted", children: n(
@@ -9823,7 +9874,7 @@ function Ca({
9823
9874
  statusOn: s,
9824
9875
  statusOff: o
9825
9876
  }) {
9826
- const { t: i } = se();
9877
+ const { t: i } = re();
9827
9878
  return /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
9828
9879
  /* @__PURE__ */ r("div", { children: [
9829
9880
  /* @__PURE__ */ t("p", { className: "text-sm text-gray-700", children: a }),
@@ -9839,14 +9890,14 @@ function Ca({
9839
9890
  )
9840
9891
  ] });
9841
9892
  }
9842
- function cc({
9893
+ function pc({
9843
9894
  chatEnabled: e,
9844
9895
  restEnabled: n,
9845
9896
  onToggleChat: a,
9846
9897
  onToggleRest: s,
9847
9898
  ownRole: o
9848
9899
  }) {
9849
- const { t: i } = se(), [l, c] = w(null);
9900
+ const { t: i } = re(), [l, c] = w(null);
9850
9901
  return /* @__PURE__ */ r(H, { title: i("settings.apiTitle"), children: [
9851
9902
  /* @__PURE__ */ r("div", { className: "space-y-4", children: [
9852
9903
  /* @__PURE__ */ t(
@@ -9911,8 +9962,8 @@ function cc({
9911
9962
  )
9912
9963
  ] });
9913
9964
  }
9914
- function dc() {
9915
- const { user: e } = Ze(), { t: n } = se(), a = et(), s = (e == null ? void 0 : e.role) === "admin", { data: o, isLoading: i } = ve({
9965
+ function hc() {
9966
+ const { user: e } = Ze(), { t: n } = re(), a = et(), s = (e == null ? void 0 : e.role) === "admin", { data: o, isLoading: i } = ve({
9916
9967
  queryKey: ["settings"],
9917
9968
  queryFn: () => F.getSettings()
9918
9969
  }), l = ke({
@@ -9937,11 +9988,11 @@ function dc() {
9937
9988
  });
9938
9989
  return i ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: n("common.loading") }) : /* @__PURE__ */ r("div", { className: "space-y-6", children: [
9939
9990
  /* @__PURE__ */ r(H, { title: n("language.title"), children: [
9940
- /* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ t("div", { className: "w-64", children: /* @__PURE__ */ t(rc, {}) }) }),
9991
+ /* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ t("div", { className: "w-64", children: /* @__PURE__ */ t(lc, {}) }) }),
9941
9992
  /* @__PURE__ */ t("p", { className: "mt-2 text-xs text-gray-400", children: n("language.help") })
9942
9993
  ] }),
9943
- (e == null ? void 0 : e.role) !== "public_manager" && ((e == null ? void 0 : e.has_password) === !1 ? /* @__PURE__ */ t(oc, {}) : /* @__PURE__ */ t(ic, {})),
9944
- (e == null ? void 0 : e.role) !== "public_manager" && /* @__PURE__ */ t(lc, {}),
9994
+ (e == null ? void 0 : e.role) !== "public_manager" && ((e == null ? void 0 : e.has_password) === !1 ? /* @__PURE__ */ t(uc, {}) : /* @__PURE__ */ t(dc, {})),
9995
+ (e == null ? void 0 : e.role) !== "public_manager" && /* @__PURE__ */ t(mc, {}),
9945
9996
  /* @__PURE__ */ r(H, { title: n("settings.pdfTitle"), children: [
9946
9997
  /* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: s ? /* @__PURE__ */ t(
9947
9998
  Ge,
@@ -9990,7 +10041,7 @@ function dc() {
9990
10041
  )
9991
10042
  ] }) }),
9992
10043
  s && /* @__PURE__ */ t(
9993
- cc,
10044
+ pc,
9994
10045
  {
9995
10046
  chatEnabled: (o == null ? void 0 : o.chat_api_enabled) === "1",
9996
10047
  restEnabled: (o == null ? void 0 : o.rest_api_enabled) === "1",
@@ -10007,7 +10058,7 @@ function dc() {
10007
10058
  /* @__PURE__ */ t("p", { className: "mb-3 text-sm text-gray-700", children: n("settings.chatApiPersonal") }),
10008
10059
  /* @__PURE__ */ t(vr, { ownRole: (e == null ? void 0 : e.role) ?? "viewer" })
10009
10060
  ] }),
10010
- s && /* @__PURE__ */ t(sc, { demoActive: !!(c != null && c.active) }),
10061
+ s && /* @__PURE__ */ t(cc, { demoActive: !!(c != null && c.active) }),
10011
10062
  s && /* @__PURE__ */ t(H, { title: n("settings.publicTitle"), children: c != null && c.active ? /* @__PURE__ */ r("div", { children: [
10012
10063
  /* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
10013
10064
  /* @__PURE__ */ t("span", { className: "inline-block h-2 w-2 rounded-full bg-green-500" }),
@@ -10060,26 +10111,26 @@ function dc() {
10060
10111
  ] });
10061
10112
  }
10062
10113
  const xr = {};
10063
- function zc(e, n) {
10114
+ function Kc(e, n) {
10064
10115
  xr[e] = n;
10065
10116
  }
10066
- function uc(e, n) {
10117
+ function gc(e, n) {
10067
10118
  return xr[e] ?? n;
10068
10119
  }
10069
- function mc() {
10070
- const e = uc("Dashboard", Ls);
10120
+ function fc() {
10121
+ const e = gc("Dashboard", Ls);
10071
10122
  return /* @__PURE__ */ t(e, {});
10072
10123
  }
10073
- const pc = [
10074
- { path: "/login", element: /* @__PURE__ */ t(po, {}) },
10075
- { path: "/demo", element: /* @__PURE__ */ t(fo, {}) }
10076
- ], hc = [
10077
- { index: !0, element: /* @__PURE__ */ t(mc, {}) },
10078
- { path: "setup", element: /* @__PURE__ */ t(Gi, {}) },
10079
- { path: "setup/opening-balances", element: /* @__PURE__ */ t(Ts, { children: /* @__PURE__ */ t(yo, {}) }) },
10080
- { path: "accounting/bank-statements", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(vo, {}) }) },
10081
- { path: "accounting/bank-reconciliation", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(xo, {}) }) },
10082
- { path: "tutorial", element: /* @__PURE__ */ t(eo, {}) },
10124
+ const yc = [
10125
+ { path: "/login", element: /* @__PURE__ */ t(ho, {}) },
10126
+ { path: "/demo", element: /* @__PURE__ */ t(yo, {}) }
10127
+ ], bc = [
10128
+ { index: !0, element: /* @__PURE__ */ t(fc, {}) },
10129
+ { path: "setup", element: /* @__PURE__ */ t(Hi, {}) },
10130
+ { path: "setup/opening-balances", element: /* @__PURE__ */ t(Ts, { children: /* @__PURE__ */ t(bo, {}) }) },
10131
+ { path: "accounting/bank-statements", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(xo, {}) }) },
10132
+ { path: "accounting/bank-reconciliation", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(ko, {}) }) },
10133
+ { path: "tutorial", element: /* @__PURE__ */ t(to, {}) },
10083
10134
  { path: "chat", element: /* @__PURE__ */ t(va, {}) },
10084
10135
  { path: "chat/:sessionId", element: /* @__PURE__ */ t(va, {}) },
10085
10136
  // Proposal (Sammelofferte) — a custom builder; the list reuses the generic
@@ -10096,22 +10147,22 @@ const pc = [
10096
10147
  { path: "masters/:type/new", element: /* @__PURE__ */ t(ma, {}) },
10097
10148
  { path: "masters/:type/:name", element: /* @__PURE__ */ t(ma, {}) },
10098
10149
  // Reports
10099
- { path: "reports/chart-of-accounts", element: /* @__PURE__ */ t(yi, {}) },
10100
- { path: "reports/trial-balance", element: /* @__PURE__ */ t(gi, {}) },
10101
- { path: "reports/general-ledger", element: /* @__PURE__ */ t(xi, {}) },
10102
- { path: "reports/stock-balance", element: /* @__PURE__ */ t(ki, {}) },
10103
- { path: "reports/profit-and-loss", element: /* @__PURE__ */ t(Ni, {}) },
10104
- { path: "reports/balance-sheet", element: /* @__PURE__ */ t(wi, {}) },
10105
- { path: "reports/ar-aging", element: /* @__PURE__ */ t(Ci, {}) },
10106
- { path: "reports/ap-aging", element: /* @__PURE__ */ t(Si, {}) },
10107
- { path: "reports/analytics", element: /* @__PURE__ */ t(Bi, {}) },
10150
+ { path: "reports/chart-of-accounts", element: /* @__PURE__ */ t(bi, {}) },
10151
+ { path: "reports/trial-balance", element: /* @__PURE__ */ t(fi, {}) },
10152
+ { path: "reports/general-ledger", element: /* @__PURE__ */ t(ki, {}) },
10153
+ { path: "reports/stock-balance", element: /* @__PURE__ */ t(Ni, {}) },
10154
+ { path: "reports/profit-and-loss", element: /* @__PURE__ */ t(wi, {}) },
10155
+ { path: "reports/balance-sheet", element: /* @__PURE__ */ t(Ci, {}) },
10156
+ { path: "reports/ar-aging", element: /* @__PURE__ */ t(Si, {}) },
10157
+ { path: "reports/ap-aging", element: /* @__PURE__ */ t(Ai, {}) },
10158
+ { path: "reports/analytics", element: /* @__PURE__ */ t(Ii, {}) },
10108
10159
  // Rentals
10109
- { path: "rentals/calendar", element: /* @__PURE__ */ t(ji, {}) },
10160
+ { path: "rentals/calendar", element: /* @__PURE__ */ t(Wi, {}) },
10110
10161
  // Admin
10111
- { path: "admin/users", element: /* @__PURE__ */ t(ko, {}) },
10112
- { path: "admin/settings", element: /* @__PURE__ */ t(dc, {}) }
10162
+ { path: "admin/users", element: /* @__PURE__ */ t(No, {}) },
10163
+ { path: "admin/settings", element: /* @__PURE__ */ t(hc, {}) }
10113
10164
  ], kr = [], Nr = [];
10114
- function gc(e, n) {
10165
+ function vc(e, n) {
10115
10166
  (n == null ? void 0 : n.area) === "top" ? kr.push(e) : Nr.push(e);
10116
10167
  }
10117
10168
  const Sa = (e) => e.index ? "__index__" : e.path ?? "";
@@ -10123,17 +10174,17 @@ function Aa(e, n) {
10123
10174
  }
10124
10175
  return a;
10125
10176
  }
10126
- function fc() {
10177
+ function xc() {
10127
10178
  return [
10128
- ...Aa(pc, kr),
10179
+ ...Aa(yc, kr),
10129
10180
  {
10130
10181
  path: "/",
10131
10182
  element: /* @__PURE__ */ t(Ps, { children: /* @__PURE__ */ t(_s, {}) }),
10132
- children: Aa(hc, Nr)
10183
+ children: Aa(bc, Nr)
10133
10184
  }
10134
10185
  ];
10135
10186
  }
10136
- function yc({ slug: e, parentSlug: n, linkField: a }) {
10187
+ function kc({ slug: e, parentSlug: n, linkField: a }) {
10137
10188
  const { name: s = "" } = bt(), o = Ke();
10138
10189
  return ce(() => {
10139
10190
  let i = !0;
@@ -10148,7 +10199,7 @@ function yc({ slug: e, parentSlug: n, linkField: a }) {
10148
10199
  };
10149
10200
  }, [e, s, n, a, o]), /* @__PURE__ */ t("div", { className: "p-6 text-sm text-fg-muted", children: "…" });
10150
10201
  }
10151
- async function bc() {
10202
+ async function Nc() {
10152
10203
  try {
10153
10204
  const e = await z(
10154
10205
  "/chat-doctypes",
@@ -10156,33 +10207,33 @@ async function bc() {
10156
10207
  );
10157
10208
  for (const n of e.doctypes || []) {
10158
10209
  const a = n.page;
10159
- a && a.kind === "via" && gc({
10210
+ a && a.kind === "via" && vc({
10160
10211
  path: `app/${n.slug}/:name`,
10161
- element: /* @__PURE__ */ t(yc, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
10212
+ element: /* @__PURE__ */ t(kc, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
10162
10213
  });
10163
10214
  }
10164
10215
  } catch {
10165
10216
  }
10166
10217
  }
10167
- function vc() {
10218
+ function wc() {
10168
10219
  return new Rr({
10169
10220
  defaultOptions: {
10170
10221
  queries: { retry: 1, refetchOnWindowFocus: !1 }
10171
10222
  }
10172
10223
  });
10173
10224
  }
10174
- async function $c(e = {}) {
10225
+ async function jc(e = {}) {
10175
10226
  const n = e.rootElement ?? document.getElementById("root");
10176
10227
  if (!n)
10177
10228
  throw new Error('bootstrap: no mount element (pass rootElement or add <div id="root">)');
10178
- const a = e.queryClient ?? vc();
10179
- await bc();
10180
- const s = Ir(fc());
10229
+ const a = e.queryClient ?? wc();
10230
+ await Nc();
10231
+ const s = Ir(xc());
10181
10232
  Pr(n).render(
10182
10233
  /* @__PURE__ */ t(Dr, { children: /* @__PURE__ */ t(Tr, { client: a, children: /* @__PURE__ */ t(us, { children: /* @__PURE__ */ t(Er, { router: s }) }) }) })
10183
10234
  );
10184
10235
  }
10185
- function Vc({
10236
+ function Wc({
10186
10237
  onConfirm: e,
10187
10238
  children: n,
10188
10239
  confirmLabel: a,
@@ -10195,7 +10246,7 @@ function Vc({
10195
10246
  size: d = "sm",
10196
10247
  cancelSide: g = "left"
10197
10248
  }) {
10198
- const { t: m } = se(), [b, v] = w(!1), k = pe(void 0);
10249
+ const { t: m } = re(), [b, v] = w(!1), k = pe(void 0);
10199
10250
  if (ce(() => {
10200
10251
  if (b)
10201
10252
  return k.current = setTimeout(() => v(!1), h), () => clearTimeout(k.current);
@@ -10252,36 +10303,36 @@ export {
10252
10303
  We as ApiError,
10253
10304
  _s as AppShell,
10254
10305
  us as AuthProvider,
10255
- Vc as ConfirmButton,
10306
+ Wc as ConfirmButton,
10256
10307
  ys as DialogProvider,
10257
10308
  nr as DocPager,
10258
10309
  yr as SUPPORTED_LANGUAGES,
10259
10310
  F as api,
10260
- $c as bootstrap,
10261
- fc as buildRoutes,
10262
- Rc as configureApiBase,
10263
- Lc as configureBranding,
10264
- vc as createAppQueryClient,
10311
+ jc as bootstrap,
10312
+ xc as buildRoutes,
10313
+ Lc as configureApiBase,
10314
+ qc as configureBranding,
10315
+ wc as createAppQueryClient,
10265
10316
  rt as formatDate,
10266
10317
  De as formatLocalDate,
10267
- Fc as getAllDoctypeConfigs,
10268
- qc as getAllMasterConfigs,
10318
+ $c as getAllDoctypeConfigs,
10319
+ Uc as getAllMasterConfigs,
10269
10320
  Qa as getBranding,
10270
- uc as getComponent,
10321
+ gc as getComponent,
10271
10322
  er as getDoctypeConfig,
10272
10323
  kn as getListContext,
10273
10324
  lr as getMasterConfig,
10274
10325
  vs as getNavGroups,
10275
- nc as getStoredLanguage,
10276
- jc as i18n,
10277
- zc as registerComponent,
10278
- Oc as registerDoctype,
10279
- Mc as registerMaster,
10280
- Ic as registerNavGroup,
10281
- Ec as registerNavItem,
10282
- gc as registerRoute,
10326
+ ic as getStoredLanguage,
10327
+ Qc as i18n,
10328
+ Kc as registerComponent,
10329
+ zc as registerDoctype,
10330
+ Vc as registerMaster,
10331
+ Fc as registerNavGroup,
10332
+ Mc as registerNavItem,
10333
+ vc as registerRoute,
10283
10334
  z as request,
10284
- Bc as setDateLocale,
10335
+ Oc as setDateLocale,
10285
10336
  Xa as setListContext,
10286
10337
  Ze as useAuth,
10287
10338
  Tn as useConfirm,