@lambda-development/erp-core 0.6.8 → 0.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
1
  import { jsx as e, jsxs as r, Fragment as ke } from "react/jsx-runtime";
2
- import { useState as w, useEffect as se, useCallback as Te, useContext as Kn, createContext as jn, useRef as re, useMemo as Se, useLayoutEffect as un, StrictMode as Aa } from "react";
3
- import { createRoot as Pa } from "react-dom/client";
4
- import { useQueryClient as He, useQuery as de, useMutation as me, QueryClientProvider as _a, QueryClient as Ta } from "@tanstack/react-query";
5
- import { NavLink as qt, useLocation as vt, useNavigate as Be, Outlet as Ra, Navigate as Ia, Link as ve, useSearchParams as zt, useParams as ut, createBrowserRouter as Ba, RouterProvider as Ea } from "react-router-dom";
6
- import { useTranslation as te, initReactI18next as La } from "react-i18next";
7
- import { BookOpen as Oa, ShoppingCart as Gn, CreditCard as qa, FileText as nn, Package as Wn, BarChart3 as za, Database as Fa, Settings as Ma, MessageCircle as $a, ChevronDown as Ft, ChevronRight as Dt, Plus as Hn, Trash2 as Qn, LineChart as Ua, ArrowLeft as Va, TrendingUp as Ka, ArrowDownRight as ja, ArrowUpRight as Ga, Wallet as Wa, Receipt as mn, ChevronLeft as Ha, Info as Qa } from "lucide-react";
2
+ import { useState as w, useEffect as se, useCallback as Te, useContext as Kn, createContext as jn, useRef as re, useMemo as Se, useLayoutEffect as un, StrictMode as Pa } from "react";
3
+ import { createRoot as _a } from "react-dom/client";
4
+ import { useQueryClient as He, useQuery as de, useMutation as me, QueryClientProvider as Ta, QueryClient as Ra } from "@tanstack/react-query";
5
+ import { NavLink as qt, useLocation as vt, useNavigate as Be, Outlet as Ia, Navigate as Ba, Link as ve, useSearchParams as zt, useParams as ut, createBrowserRouter as Ea, RouterProvider as La } from "react-router-dom";
6
+ import { useTranslation as te, initReactI18next as Oa } from "react-i18next";
7
+ import { BookOpen as qa, ShoppingCart as Gn, CreditCard as za, FileText as nn, Package as Wn, BarChart3 as Fa, Database as Ma, Settings as $a, MessageCircle as Ua, ChevronDown as Ft, ChevronRight as Dt, Plus as Hn, Trash2 as Qn, LineChart as Va, ArrowLeft as Ka, TrendingUp as ja, ArrowDownRight as Ga, ArrowUpRight as Wa, Wallet as Ha, Receipt as mn, ChevronLeft as Qa, Info as Ya } from "lucide-react";
8
8
  import { createColumnHelper as Yn, useReactTable as Jn, getCoreRowModel as Zn, flexRender as Bt } from "@tanstack/react-table";
9
9
  import { createPortal as Xn } from "react-dom";
10
- import { ResponsiveContainer as Ya, LineChart as Ja, CartesianGrid as pn, XAxis as hn, YAxis as gn, Tooltip as Vt, Line as Za, PieChart as Xa, Pie as er, Cell as tr, BarChart as nr, Bar as ar } from "recharts";
10
+ import { ResponsiveContainer as Ja, LineChart as Za, CartesianGrid as pn, XAxis as hn, YAxis as gn, Tooltip as Vt, Line as Xa, PieChart as er, Pie as tr, Cell as nr, BarChart as ar, Bar as rr } from "recharts";
11
11
  import ea from "i18next";
12
- import { default as Qo } from "i18next";
12
+ import { default as Jo } from "i18next";
13
13
  let ct = "/api";
14
- function Fo(t) {
14
+ function Mo(t) {
15
15
  ct = t.replace(/\/+$/, "");
16
16
  }
17
- function rr(t) {
17
+ function sr(t) {
18
18
  return new URL(`${ct}${t}`, window.location.origin).toString();
19
19
  }
20
20
  class Ue extends Error {
@@ -22,7 +22,7 @@ class Ue extends Error {
22
22
  super(a), this.status = n;
23
23
  }
24
24
  }
25
- function sr(t) {
25
+ function ir(t) {
26
26
  if (!t) return "Request failed";
27
27
  if (typeof t == "string") return t;
28
28
  if (Array.isArray(t))
@@ -47,7 +47,7 @@ async function L(t, n) {
47
47
  if (a.status === 401 && !t.startsWith("/auth/"))
48
48
  throw window.location.href = "/login", new Ue(401, "Session expired");
49
49
  const s = await a.json().catch(() => ({ detail: a.statusText }));
50
- throw new Ue(a.status, sr(s.detail));
50
+ throw new Ue(a.status, ir(s.detail));
51
51
  }
52
52
  return a.json();
53
53
  }
@@ -202,7 +202,7 @@ const T = {
202
202
  const a = new URLSearchParams();
203
203
  n != null && n.link && a.set("link", "1"), n != null && n.invite && a.set("invite", n.invite);
204
204
  const s = a.toString() ? `?${a.toString()}` : "";
205
- return rr(`/auth/${encodeURIComponent(t)}/login${s}`);
205
+ return sr(`/auth/${encodeURIComponent(t)}/login${s}`);
206
206
  },
207
207
  oauthListIdentities: () => L("/auth/oauth/identities"),
208
208
  authRegister: (t) => L("/auth/register", { method: "POST", body: JSON.stringify(t) }),
@@ -241,7 +241,7 @@ const T = {
241
241
  ),
242
242
  getDemoSpend: () => L("/admin/demo-spend")
243
243
  }, ta = jn(null);
244
- function ir({ children: t }) {
244
+ function or({ children: t }) {
245
245
  const [n, a] = w(null), [s, o] = w(!0);
246
246
  se(() => {
247
247
  T.authMe().then((d) => a(d)).catch(() => a(null)).finally(() => o(!1));
@@ -298,7 +298,7 @@ const na = jn(null), fn = {
298
298
  function Kt(t) {
299
299
  return typeof t != "string" ? null : t.trim().toLowerCase().replace(/\s+/g, "-");
300
300
  }
301
- function or(t, n) {
301
+ function lr(t, n) {
302
302
  if (t === "create_custom_analytics_report" || t === "update_custom_analytics_report")
303
303
  return { group: "Custom Analytics", item: "" };
304
304
  if (!n) return null;
@@ -348,7 +348,7 @@ function vn(t) {
348
348
  const n = an();
349
349
  n.delete(t) && ra(n);
350
350
  }
351
- function lr() {
351
+ function cr() {
352
352
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `req-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
353
353
  }
354
354
  function tt(t) {
@@ -356,7 +356,7 @@ function tt(t) {
356
356
  const n = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(t) ? t.replace(" ", "T") : t, a = new Date(n).getTime();
357
357
  return Number.isNaN(a) ? 0 : a;
358
358
  }
359
- function cr({ children: t }) {
359
+ function dr({ children: t }) {
360
360
  const n = He(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [g, d] = w({}), [p, u] = w({}), [N, b] = w({}), [x, f] = w({}), [A, C] = w({}), [y, m] = w(null), [h, _] = w("connecting"), [v, B] = w(0), S = re(null), O = re(null), V = re(/* @__PURE__ */ new Map()), ie = re(null), K = re({}), D = re({}), j = re(null);
361
361
  function E(R) {
362
362
  for (const G of V.current.values())
@@ -413,7 +413,7 @@ function cr({ children: t }) {
413
413
  }
414
414
  function ae(R, G, Y) {
415
415
  return new Promise((xe, Ne) => {
416
- const _e = lr();
416
+ const _e = cr();
417
417
  V.current.set(_e, {
418
418
  expectedType: Y,
419
419
  resolve: xe,
@@ -626,7 +626,7 @@ function cr({ children: t }) {
626
626
  const Z = typeof W.report_id == "string" ? W.report_id : void 0, Fe = typeof ((ot = z.args) == null ? void 0 : ot.report_id) == "string" ? z.args.report_id : void 0;
627
627
  U("Custom Analytics", Z || Fe || ""), n.invalidateQueries({ queryKey: ["runtime-drafts"] });
628
628
  } else {
629
- const Z = or(z.tool, z.args);
629
+ const Z = lr(z.tool, z.args);
630
630
  Z && U(Z.group, Z.item);
631
631
  }
632
632
  D.current = {
@@ -803,7 +803,7 @@ function mt() {
803
803
  const dt = [
804
804
  {
805
805
  label: "Introduction",
806
- icon: /* @__PURE__ */ e(Oa, { className: "h-4 w-4" }),
806
+ icon: /* @__PURE__ */ e(qa, { className: "h-4 w-4" }),
807
807
  items: [
808
808
  { label: "Getting Started", path: "/tutorial" },
809
809
  { label: "Company Setup", path: "/setup" },
@@ -823,7 +823,7 @@ const dt = [
823
823
  },
824
824
  {
825
825
  label: "Buying",
826
- icon: /* @__PURE__ */ e(qa, { className: "h-4 w-4" }),
826
+ icon: /* @__PURE__ */ e(za, { className: "h-4 w-4" }),
827
827
  items: [
828
828
  { label: "Purchase Order", path: "/app/purchase-order" },
829
829
  { label: "Purchase Invoice", path: "/app/purchase-invoice" }
@@ -852,7 +852,7 @@ const dt = [
852
852
  },
853
853
  {
854
854
  label: "Reports",
855
- icon: /* @__PURE__ */ e(za, { className: "h-4 w-4" }),
855
+ icon: /* @__PURE__ */ e(Fa, { className: "h-4 w-4" }),
856
856
  items: [
857
857
  { label: "Trial Balance", path: "/reports/trial-balance" },
858
858
  { label: "Profit & Loss", path: "/reports/profit-and-loss" },
@@ -866,7 +866,7 @@ const dt = [
866
866
  },
867
867
  {
868
868
  label: "Masters",
869
- icon: /* @__PURE__ */ e(Fa, { className: "h-4 w-4" }),
869
+ icon: /* @__PURE__ */ e(Ma, { className: "h-4 w-4" }),
870
870
  items: [
871
871
  { label: "Company", path: "/masters/company" },
872
872
  { label: "Customer", path: "/masters/customer" },
@@ -877,7 +877,7 @@ const dt = [
877
877
  },
878
878
  {
879
879
  label: "Settings",
880
- icon: /* @__PURE__ */ e(Ma, { className: "h-4 w-4" }),
880
+ icon: /* @__PURE__ */ e($a, { className: "h-4 w-4" }),
881
881
  items: [
882
882
  { label: "General", path: "/admin/settings" },
883
883
  { label: "Pricing Rule", path: "/app/pricing-rule" },
@@ -885,10 +885,10 @@ const dt = [
885
885
  ]
886
886
  }
887
887
  ];
888
- function dr() {
888
+ function ur() {
889
889
  return dt;
890
890
  }
891
- function Mo(t, n) {
891
+ function $o(t, n) {
892
892
  const a = dt.findIndex((s) => s.label === t.label);
893
893
  if (a >= 0) {
894
894
  dt[a] = t;
@@ -896,19 +896,19 @@ function Mo(t, n) {
896
896
  }
897
897
  (n == null ? void 0 : n.index) != null ? dt.splice(n.index, 0, t) : dt.push(t);
898
898
  }
899
- function $o(t, n) {
899
+ function Uo(t, n) {
900
900
  const a = dt.find((s) => s.label === t);
901
901
  a ? a.items.push(n) : dt.push({ label: t, icon: null, items: [n] });
902
902
  }
903
903
  let Jt = { appName: "Lambda ERP" };
904
- function Uo(t) {
904
+ function Vo(t) {
905
905
  if (Jt = { ...Jt, ...t }, !(typeof document > "u") && (t.appName && (document.title = t.appName), t.tokens)) {
906
906
  const n = document.documentElement;
907
907
  for (const [a, s] of Object.entries(t.tokens))
908
908
  n.style.setProperty(a.startsWith("--") ? a : `--${a}`, s);
909
909
  }
910
910
  }
911
- function ur() {
911
+ function mr() {
912
912
  return Jt;
913
913
  }
914
914
  function Oe(...t) {
@@ -927,28 +927,32 @@ function Zt(t, n = 2) {
927
927
  maximumFractionDigits: n
928
928
  }).format(t ?? 0);
929
929
  }
930
+ let ia;
931
+ function Ko(t) {
932
+ ia = t;
933
+ }
930
934
  function Mt(t) {
931
- return t ? new Date(t).toLocaleDateString("en-US", {
935
+ return t ? new Date(t).toLocaleDateString(ia, {
932
936
  year: "numeric",
933
- month: "short",
934
- day: "numeric"
937
+ month: "2-digit",
938
+ day: "2-digit"
935
939
  }) : "";
936
940
  }
937
941
  function $e(t, n) {
938
942
  const a = parseFloat(String(t ?? 0)) || 0;
939
943
  return n !== void 0 ? parseFloat(a.toFixed(n)) : a;
940
944
  }
941
- const ia = "sidebar-collapsed";
945
+ const oa = "sidebar-collapsed";
942
946
  function jt() {
943
947
  try {
944
- const t = localStorage.getItem(ia);
948
+ const t = localStorage.getItem(oa);
945
949
  return t ? new Set(JSON.parse(t)) : /* @__PURE__ */ new Set();
946
950
  } catch {
947
951
  return /* @__PURE__ */ new Set();
948
952
  }
949
953
  }
950
954
  function xn(t) {
951
- localStorage.setItem(ia, JSON.stringify([...t]));
955
+ localStorage.setItem(oa, JSON.stringify([...t]));
952
956
  }
953
957
  function rn(t) {
954
958
  const [n, a] = w(() => !jt().has(t)), s = Te(() => {
@@ -976,7 +980,7 @@ const sn = {
976
980
  Settings: "bg-purple-300 text-purple-950 ring-2 ring-inset ring-purple-100",
977
981
  "Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
978
982
  };
979
- function mr() {
983
+ function pr() {
980
984
  const [t, n] = rn("chats"), a = vt(), s = Be(), { t: o } = te(), { sessions: i, createSession: l, deleteSession: c } = mt(), g = async () => {
981
985
  try {
982
986
  const p = await l();
@@ -998,7 +1002,7 @@ function mr() {
998
1002
  onClick: n,
999
1003
  className: "flex w-full items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-fg-muted transition-colors hover:text-fg",
1000
1004
  children: [
1001
- /* @__PURE__ */ e($a, { className: "h-4 w-4" }),
1005
+ /* @__PURE__ */ e(Ua, { className: "h-4 w-4" }),
1002
1006
  /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: o("nav.chats") }),
1003
1007
  t ? /* @__PURE__ */ e(Ft, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Dt, { className: "h-3.5 w-3.5" })
1004
1008
  ]
@@ -1054,7 +1058,7 @@ function on() {
1054
1058
  }
1055
1059
  );
1056
1060
  }
1057
- function pr() {
1061
+ function hr() {
1058
1062
  const [t, n, a] = rn("custom-analytics"), s = vt(), o = Be(), i = He(), { t: l } = te(), { navigationFlash: c, sessions: g, createSession: d } = mt(), p = (c == null ? void 0 : c.group) === "Custom Analytics", u = sn["Custom Analytics"], { data: N } = de({
1059
1063
  queryKey: ["runtime-drafts"],
1060
1064
  queryFn: () => T.listRuntimeDrafts(),
@@ -1094,7 +1098,7 @@ function pr() {
1094
1098
  p && u
1095
1099
  ),
1096
1100
  children: [
1097
- /* @__PURE__ */ e(Ua, { className: "h-4 w-4" }),
1101
+ /* @__PURE__ */ e(Va, { className: "h-4 w-4" }),
1098
1102
  /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: l("nav.customAnalytics") }),
1099
1103
  t ? /* @__PURE__ */ e(Ft, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Dt, { className: "h-3.5 w-3.5" })
1100
1104
  ]
@@ -1144,7 +1148,7 @@ function pr() {
1144
1148
  ] })
1145
1149
  ] });
1146
1150
  }
1147
- function hr({ group: t }) {
1151
+ function gr({ group: t }) {
1148
1152
  const [n, a] = rn(t.label), { t: s } = te(), { navigationFlash: o } = mt(), i = (o == null ? void 0 : o.group) === t.label, l = sn[t.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
1149
1153
  return /* @__PURE__ */ r("div", { children: [
1150
1154
  /* @__PURE__ */ r(
@@ -1187,10 +1191,10 @@ function hr({ group: t }) {
1187
1191
  }) })
1188
1192
  ] });
1189
1193
  }
1190
- const gr = {
1194
+ const fr = {
1191
1195
  "/setup/opening-balances": "opening_balances_enabled"
1192
1196
  };
1193
- function fr({ isMobileOpen: t = !1, onClose: n }) {
1197
+ function yr({ isMobileOpen: t = !1, onClose: n }) {
1194
1198
  var c;
1195
1199
  const { data: a } = de({
1196
1200
  queryKey: ["settings"],
@@ -1200,11 +1204,11 @@ function fr({ isMobileOpen: t = !1, onClose: n }) {
1200
1204
  queryKey: ["setup-status"],
1201
1205
  queryFn: () => T.setupStatus(),
1202
1206
  staleTime: 6e4
1203
- }), o = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], i = (o == null ? void 0 : o.company_name) || (o == null ? void 0 : o.name) || ur().appName, l = Se(() => dr().map((d) => ({
1207
+ }), o = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], i = (o == null ? void 0 : o.company_name) || (o == null ? void 0 : o.name) || mr().appName, l = Se(() => ur().map((d) => ({
1204
1208
  ...d,
1205
1209
  items: d.items.filter((p) => {
1206
1210
  if (p.path === "/setup" && (s != null && s.setup_complete)) return !1;
1207
- const u = gr[p.path];
1211
+ const u = fr[p.path];
1208
1212
  return !u || !a ? !0 : a[u] !== "0";
1209
1213
  })
1210
1214
  })), [a, s]);
@@ -1251,16 +1255,16 @@ function fr({ isMobileOpen: t = !1, onClose: n }) {
1251
1255
  )
1252
1256
  ] }),
1253
1257
  /* @__PURE__ */ r("nav", { className: "flex-1 overflow-y-auto py-3", children: [
1254
- /* @__PURE__ */ e(mr, {}),
1255
1258
  /* @__PURE__ */ e(pr, {}),
1256
- l.map((g) => /* @__PURE__ */ e(hr, { group: g }, g.label))
1259
+ /* @__PURE__ */ e(hr, {}),
1260
+ l.map((g) => /* @__PURE__ */ e(gr, { group: g }, g.label))
1257
1261
  ] })
1258
1262
  ]
1259
1263
  }
1260
1264
  );
1261
1265
  }
1262
1266
  const Nn = (t) => t.replace(/-/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
1263
- function yr(t, n) {
1267
+ function br(t, n) {
1264
1268
  const a = t.split("/").filter(Boolean);
1265
1269
  if (a[0] === "setup") return n("titles.setup");
1266
1270
  if (a[0] === "tutorial") return n("titles.tutorial");
@@ -1279,15 +1283,15 @@ function yr(t, n) {
1279
1283
  }
1280
1284
  return n("titles.dashboard");
1281
1285
  }
1282
- function br(t) {
1286
+ function vr(t) {
1283
1287
  const n = t.split("/").filter(Boolean);
1284
1288
  return (n[0] === "app" || n[0] === "masters") && n.length > 2 ? `/${n[0]}/${n[1]}` : n[0] === "setup" && n.length > 1 ? "/setup" : null;
1285
1289
  }
1286
- function vr() {
1287
- return /* @__PURE__ */ e(cr, { children: /* @__PURE__ */ e(xr, {}) });
1288
- }
1289
1290
  function xr() {
1290
- const { pathname: t } = vt(), n = Be(), { user: a, logout: s } = st(), { navigationFlash: o } = mt(), { t: i } = te(), l = yr(t, i), c = br(t), g = () => {
1291
+ return /* @__PURE__ */ e(dr, { children: /* @__PURE__ */ e(Nr, {}) });
1292
+ }
1293
+ function Nr() {
1294
+ const { pathname: t } = vt(), n = Be(), { user: a, logout: s } = st(), { navigationFlash: o } = mt(), { t: i } = te(), l = br(t, i), c = vr(t), g = () => {
1291
1295
  var N;
1292
1296
  c && (((N = window.history.state) == null ? void 0 : N.idx) > 0 ? n(-1) : n(c));
1293
1297
  }, [d, p] = w(!1);
@@ -1296,7 +1300,7 @@ function xr() {
1296
1300
  }, [t]);
1297
1301
  const u = o ? sn[o.group] : null;
1298
1302
  return /* @__PURE__ */ r("div", { className: "flex h-dvh bg-surface-muted", children: [
1299
- /* @__PURE__ */ e(fr, { isMobileOpen: d, onClose: () => p(!1) }),
1303
+ /* @__PURE__ */ e(yr, { isMobileOpen: d, onClose: () => p(!1) }),
1300
1304
  d && /* @__PURE__ */ e(
1301
1305
  "div",
1302
1306
  {
@@ -1326,7 +1330,7 @@ function xr() {
1326
1330
  onClick: g,
1327
1331
  className: "-ml-1 rounded p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-900",
1328
1332
  "aria-label": i("header.back"),
1329
- children: /* @__PURE__ */ e(Va, { className: "h-5 w-5" })
1333
+ children: /* @__PURE__ */ e(Ka, { className: "h-5 w-5" })
1330
1334
  }
1331
1335
  ),
1332
1336
  /* @__PURE__ */ e("h1", { className: "text-base font-semibold text-gray-500 md:text-lg", children: l })
@@ -1346,13 +1350,13 @@ function xr() {
1346
1350
  )
1347
1351
  ] })
1348
1352
  ] }),
1349
- /* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(Ra, {}) })
1353
+ /* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(Ia, {}) })
1350
1354
  ] })
1351
1355
  ] });
1352
1356
  }
1353
- function Nr({ children: t }) {
1357
+ function wr({ children: t }) {
1354
1358
  const { user: n, loading: a } = st();
1355
- return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(ke, { children: t }) : /* @__PURE__ */ e(Ia, { to: "/login", replace: !0 });
1359
+ return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(ke, { children: t }) : /* @__PURE__ */ e(Ba, { to: "/login", replace: !0 });
1356
1360
  }
1357
1361
  function F({ title: t, children: n, className: a, interactive: s }) {
1358
1362
  return /* @__PURE__ */ r(
@@ -1375,7 +1379,7 @@ function F({ title: t, children: n, className: a, interactive: s }) {
1375
1379
  }
1376
1380
  );
1377
1381
  }
1378
- const wr = {
1382
+ const kr = {
1379
1383
  default: "bg-brand/10 text-brand ring-1 ring-inset ring-brand/20",
1380
1384
  success: "bg-emerald-50 text-emerald-700 ring-1 ring-inset ring-emerald-200",
1381
1385
  warning: "bg-amber-50 text-amber-700 ring-1 ring-inset ring-amber-200",
@@ -1388,7 +1392,7 @@ function Rt({ variant: t = "default", dot: n, children: a, className: s }) {
1388
1392
  {
1389
1393
  className: Oe(
1390
1394
  "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
1391
- wr[t],
1395
+ kr[t],
1392
1396
  s
1393
1397
  ),
1394
1398
  children: [
@@ -1398,7 +1402,7 @@ function Rt({ variant: t = "default", dot: n, children: a, className: s }) {
1398
1402
  }
1399
1403
  );
1400
1404
  }
1401
- const kr = {
1405
+ const Sr = {
1402
1406
  Draft: "secondary",
1403
1407
  Open: "default",
1404
1408
  Submitted: "default",
@@ -1413,7 +1417,7 @@ const kr = {
1413
1417
  Overdue: "danger"
1414
1418
  };
1415
1419
  function ln({ status: t }) {
1416
- const { t: n } = te(), a = kr[t] ?? "secondary";
1420
+ const { t: n } = te(), a = Sr[t] ?? "secondary";
1417
1421
  return /* @__PURE__ */ e(Rt, { variant: a, children: n(`status.${t}`, { defaultValue: t }) });
1418
1422
  }
1419
1423
  function ze(t) {
@@ -1450,15 +1454,15 @@ function _t() {
1450
1454
  /* @__PURE__ */ e("div", { className: "h-9 w-9 shrink-0 animate-pulse rounded-lg bg-surface-subtle" })
1451
1455
  ] }) });
1452
1456
  }
1453
- const Sr = {
1457
+ const Cr = {
1454
1458
  "Sales Invoice": mn,
1455
1459
  "Purchase Invoice": mn,
1456
- "Payment Entry": Wa,
1460
+ "Payment Entry": Ha,
1457
1461
  "Sales Order": Gn,
1458
1462
  Quotation: nn
1459
1463
  };
1460
- function Cr({ doc: t }) {
1461
- const { t: n } = te(), a = t.doctype ?? t.type ?? "Document", s = t.creation ?? t.date, o = Sr[a] ?? nn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(t.name)}`;
1464
+ function Dr({ doc: t }) {
1465
+ const { t: n } = te(), a = t.doctype ?? t.type ?? "Document", s = t.creation ?? t.date, o = Cr[a] ?? nn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(t.name)}`;
1462
1466
  return /* @__PURE__ */ r(
1463
1467
  ve,
1464
1468
  {
@@ -1487,7 +1491,7 @@ function kt() {
1487
1491
  /* @__PURE__ */ e("div", { className: "hidden h-3 w-16 animate-pulse rounded bg-surface-subtle sm:block" })
1488
1492
  ] });
1489
1493
  }
1490
- function Dr() {
1494
+ function Ar() {
1491
1495
  const { t } = te(), { data: n, isLoading: a } = de({
1492
1496
  queryKey: ["dashboard-summary"],
1493
1497
  queryFn: () => T.dashboardSummary()
@@ -1504,7 +1508,7 @@ function Dr() {
1504
1508
  {
1505
1509
  title: t("dashboard.totalRevenue"),
1506
1510
  value: n == null ? void 0 : n.total_revenue,
1507
- icon: Ka,
1511
+ icon: ja,
1508
1512
  tone: "text-emerald-600 bg-emerald-500/10"
1509
1513
  }
1510
1514
  ),
@@ -1513,7 +1517,7 @@ function Dr() {
1513
1517
  {
1514
1518
  title: t("dashboard.outstandingReceivable"),
1515
1519
  value: n == null ? void 0 : n.outstanding_receivable,
1516
- icon: ja,
1520
+ icon: Ga,
1517
1521
  tone: "text-sky-600 bg-sky-500/10"
1518
1522
  }
1519
1523
  ),
@@ -1522,7 +1526,7 @@ function Dr() {
1522
1526
  {
1523
1527
  title: t("dashboard.outstandingPayable"),
1524
1528
  value: n == null ? void 0 : n.outstanding_payable,
1525
- icon: Ga,
1529
+ icon: Wa,
1526
1530
  tone: "text-amber-600 bg-amber-500/10"
1527
1531
  }
1528
1532
  ),
@@ -1542,28 +1546,28 @@ function Dr() {
1542
1546
  /* @__PURE__ */ e(kt, {}),
1543
1547
  /* @__PURE__ */ e(kt, {}),
1544
1548
  /* @__PURE__ */ e(kt, {})
1545
- ] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ e(Cr, { doc: s }, `${s.name}-${o}`)) : /* @__PURE__ */ e("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: t("dashboard.noRecentDocuments") }) }) })
1549
+ ] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ e(Dr, { doc: s }, `${s.name}-${o}`)) : /* @__PURE__ */ e("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: t("dashboard.noRecentDocuments") }) }) })
1546
1550
  ] });
1547
1551
  }
1548
- const oa = "lad.docListContext";
1549
- function la() {
1552
+ const la = "lad.docListContext";
1553
+ function ca() {
1550
1554
  try {
1551
- return JSON.parse(sessionStorage.getItem(oa) || "{}");
1555
+ return JSON.parse(sessionStorage.getItem(la) || "{}");
1552
1556
  } catch {
1553
1557
  return {};
1554
1558
  }
1555
1559
  }
1556
- function ca(t, n) {
1560
+ function da(t, n) {
1557
1561
  try {
1558
- const a = la();
1559
- a[t] = n, sessionStorage.setItem(oa, JSON.stringify(a));
1562
+ const a = ca();
1563
+ a[t] = n, sessionStorage.setItem(la, JSON.stringify(a));
1560
1564
  } catch {
1561
1565
  }
1562
1566
  }
1563
- function Ar(t) {
1564
- return la()[t];
1567
+ function Pr(t) {
1568
+ return ca()[t];
1565
1569
  }
1566
- function Pr(t, n) {
1570
+ function _r(t, n) {
1567
1571
  const { data: a, isLoading: s, error: o, refetch: i } = de({
1568
1572
  queryKey: ["documents", t, n],
1569
1573
  queryFn: () => T.listDocuments(t, n),
@@ -1622,7 +1626,7 @@ const rt = [
1622
1626
  { name: "qty", label: "Qty", type: "number", required: !0 },
1623
1627
  { name: "rate", label: "Rate", type: "currency", required: !0 },
1624
1628
  { name: "amount", label: "Amount", type: "currency", readOnly: !0 }
1625
- ], _r = [
1629
+ ], Tr = [
1626
1630
  ...rt,
1627
1631
  {
1628
1632
  name: "frequency",
@@ -1669,7 +1673,7 @@ const rt = [
1669
1673
  { name: "remarks", label: "Notes / Terms", type: "textarea" }
1670
1674
  ],
1671
1675
  childTables: [
1672
- { key: "items", label: "Items", fields: _r },
1676
+ { key: "items", label: "Items", fields: Tr },
1673
1677
  { key: "taxes", label: "Taxes", fields: at }
1674
1678
  ],
1675
1679
  listColumns: ["name", "customer", "transaction_date", "grand_total", "status"],
@@ -2256,17 +2260,17 @@ const rt = [
2256
2260
  conversions: []
2257
2261
  }
2258
2262
  };
2259
- function da(t) {
2263
+ function ua(t) {
2260
2264
  return cn[t];
2261
2265
  }
2262
- function Vo(t) {
2266
+ function jo(t) {
2263
2267
  cn[t.slug] = t;
2264
2268
  }
2265
- function Ko() {
2269
+ function Go() {
2266
2270
  return Object.values(cn);
2267
2271
  }
2268
- function ua({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2269
- const o = Be(), i = s === "master", l = Ar(i ? `master:${t}` : t), c = i ? `/masters/${t}` : `/app/${t}`, { data: g } = de({
2272
+ function ma({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2273
+ const o = Be(), i = s === "master", l = Pr(i ? `master:${t}` : t), c = i ? `/masters/${t}` : `/app/${t}`, { data: g } = de({
2270
2274
  queryKey: ["adjacent", s, t, n, (l == null ? void 0 : l.filters) ?? null],
2271
2275
  queryFn: () => i ? T.adjacentMaster(t, n) : T.adjacentDocument(t, n, l == null ? void 0 : l.filters)
2272
2276
  }), d = (g == null ? void 0 : g.prev) ?? null, p = (g == null ? void 0 : g.next) ?? null;
@@ -2291,7 +2295,7 @@ function ua({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2291
2295
  title: "Previous record (k / ←)",
2292
2296
  onClick: () => d && o(`${c}/${d}`),
2293
2297
  className: u,
2294
- children: /* @__PURE__ */ e(Ha, { className: "h-4 w-4" })
2298
+ children: /* @__PURE__ */ e(Qa, { className: "h-4 w-4" })
2295
2299
  }
2296
2300
  ),
2297
2301
  /* @__PURE__ */ e(
@@ -2307,7 +2311,7 @@ function ua({ slug: t, name: n, onSave: a, kind: s = "document" }) {
2307
2311
  )
2308
2312
  ] });
2309
2313
  }
2310
- const Tr = {
2314
+ const Rr = {
2311
2315
  // Primary: brand-coloured fill + a 1px inset top highlight for depth
2312
2316
  // (button-highlight shadow). On press, the button shifts down 1px —
2313
2317
  // tiny detail, large perceived "this is responsive".
@@ -2315,7 +2319,7 @@ const Tr = {
2315
2319
  secondary: "bg-surface text-fg ring-1 ring-line hover:bg-surface-subtle active:translate-y-px focus-visible:ring-fg/20",
2316
2320
  danger: "bg-red-600 text-white shadow-button-highlight hover:bg-red-700 active:translate-y-px focus-visible:ring-red-500/40",
2317
2321
  ghost: "bg-transparent text-fg-muted hover:bg-surface-subtle hover:text-fg focus-visible:ring-fg/20"
2318
- }, Rr = {
2322
+ }, Ir = {
2319
2323
  sm: "h-8 px-3 text-sm",
2320
2324
  md: "h-10 px-4 text-sm",
2321
2325
  lg: "h-11 px-5 text-sm"
@@ -2343,8 +2347,8 @@ function J({
2343
2347
  "transition-all duration-150",
2344
2348
  "focus-visible:outline-none focus-visible:ring-2",
2345
2349
  "disabled:cursor-not-allowed disabled:opacity-50 disabled:active:translate-y-0",
2346
- Tr[t],
2347
- Rr[n],
2350
+ Rr[t],
2351
+ Ir[n],
2348
2352
  i
2349
2353
  ),
2350
2354
  children: o
@@ -2397,7 +2401,7 @@ function X({ label: t, hint: n, error: a, className: s, id: o, ...i }) {
2397
2401
  )
2398
2402
  ] });
2399
2403
  }
2400
- function Ir(t) {
2404
+ function Br(t) {
2401
2405
  return typeof t == "string" ? { value: t, label: t } : t;
2402
2406
  }
2403
2407
  function Ve({ label: t, options: n, value: a, onChange: s, className: o, required: i, disabled: l }) {
@@ -2431,7 +2435,7 @@ function Ve({ label: t, options: n, value: a, onChange: s, className: o, require
2431
2435
  children: [
2432
2436
  /* @__PURE__ */ e("option", { value: "", children: "Select..." }),
2433
2437
  n.map((g) => {
2434
- const { value: d, label: p } = Ir(g);
2438
+ const { value: d, label: p } = Br(g);
2435
2439
  return /* @__PURE__ */ e("option", { value: d, children: p }, d);
2436
2440
  })
2437
2441
  ]
@@ -2439,7 +2443,7 @@ function Ve({ label: t, options: n, value: a, onChange: s, className: o, require
2439
2443
  )
2440
2444
  ] });
2441
2445
  }
2442
- function Br({ text: t }) {
2446
+ function Er({ text: t }) {
2443
2447
  const [n, a] = w(!1);
2444
2448
  return /* @__PURE__ */ r("span", { className: "relative ml-1 inline-flex", children: [
2445
2449
  /* @__PURE__ */ e(
@@ -2459,7 +2463,7 @@ function Br({ text: t }) {
2459
2463
  ] })
2460
2464
  ] });
2461
2465
  }
2462
- function Er() {
2466
+ function Lr() {
2463
2467
  const { t } = te(), [n, a] = w(!1), s = [
2464
2468
  ["# Heading", t("notesMarkup.heading", { defaultValue: "bold heading" })],
2465
2469
  ["*italic* **bold**", t("notesMarkup.emphasis", { defaultValue: "italic / bold" })],
@@ -2485,7 +2489,7 @@ function Er() {
2485
2489
  className: "inline-flex h-4 w-4 items-center justify-center rounded-full text-fg-muted hover:text-fg",
2486
2490
  onClick: () => a((o) => !o),
2487
2491
  "aria-label": t("notesMarkup.title", { defaultValue: "Formatting help" }),
2488
- children: /* @__PURE__ */ e(Qa, { className: "h-3.5 w-3.5" })
2492
+ children: /* @__PURE__ */ e(Ya, { className: "h-3.5 w-3.5" })
2489
2493
  }
2490
2494
  ),
2491
2495
  n && /* @__PURE__ */ r("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-80 rounded-md bg-gray-900 px-3 py-2.5 text-xs leading-relaxed text-white shadow-lg", children: [
@@ -2502,7 +2506,7 @@ function Er() {
2502
2506
  }
2503
2507
  );
2504
2508
  }
2505
- function Lr(t, n = !0) {
2509
+ function Or(t, n = !0) {
2506
2510
  const { data: a } = de({
2507
2511
  queryKey: ["currencies", ""],
2508
2512
  queryFn: () => T.currencies(t),
@@ -2511,23 +2515,23 @@ function Lr(t, n = !0) {
2511
2515
  });
2512
2516
  return (a == null ? void 0 : a.currencies) ?? [];
2513
2517
  }
2514
- const Or = /* @__PURE__ */ new Set([
2518
+ const qr = /* @__PURE__ */ new Set([
2515
2519
  "customer",
2516
2520
  "supplier",
2517
2521
  "item",
2518
2522
  "warehouse"
2519
2523
  ]);
2520
2524
  function Xt(t, n) {
2521
- return !t || !n ? null : Or.has(t) ? `/masters/${t}/${encodeURIComponent(n)}` : t === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
2525
+ return !t || !n ? null : qr.has(t) ? `/masters/${t}/${encodeURIComponent(n)}` : t === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
2522
2526
  }
2523
2527
  function wn({ label: t, hint: n, extra: a }) {
2524
2528
  return /* @__PURE__ */ r("label", { className: "mb-1.5 block text-sm font-medium text-fg", children: [
2525
2529
  t,
2526
- n && /* @__PURE__ */ e(Br, { text: n }),
2530
+ n && /* @__PURE__ */ e(Er, { text: n }),
2527
2531
  a
2528
2532
  ] });
2529
2533
  }
2530
- function qr({
2534
+ function zr({
2531
2535
  field: t,
2532
2536
  value: n,
2533
2537
  onChange: a,
@@ -2602,7 +2606,7 @@ function It({
2602
2606
  currency: l = "USD"
2603
2607
  }) {
2604
2608
  var b;
2605
- const { t: c } = te(), g = s || !!t.readOnly, d = () => i ? null : /* @__PURE__ */ e(wn, { label: c(`fields.${t.label}`, { defaultValue: t.label }), hint: t.hint }), p = t.type === "select" && t.optionsSource === "currency", u = Lr(void 0, p);
2609
+ const { t: c } = te(), g = s || !!t.readOnly, d = () => i ? null : /* @__PURE__ */ e(wn, { label: c(`fields.${t.label}`, { defaultValue: t.label }), hint: t.hint }), p = t.type === "select" && t.optionsSource === "currency", u = Or(void 0, p);
2606
2610
  if (g) {
2607
2611
  if (t.type === "link" && n) {
2608
2612
  const A = t.linkDoctypeField && o ? String(o[t.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : t.linkDoctype, C = Xt(A, String(n));
@@ -2635,7 +2639,7 @@ function It({
2635
2639
  return /* @__PURE__ */ r("div", { children: [
2636
2640
  /* @__PURE__ */ e(d, {}),
2637
2641
  /* @__PURE__ */ e(
2638
- qr,
2642
+ zr,
2639
2643
  {
2640
2644
  field: x,
2641
2645
  value: n ?? "",
@@ -2668,7 +2672,7 @@ function It({
2668
2672
  {
2669
2673
  label: c(`fields.${t.label}`, { defaultValue: t.label }),
2670
2674
  hint: t.hint,
2671
- extra: x ? /* @__PURE__ */ e(Er, {}) : void 0
2675
+ extra: x ? /* @__PURE__ */ e(Lr, {}) : void 0
2672
2676
  }
2673
2677
  ),
2674
2678
  /* @__PURE__ */ e(
@@ -2698,7 +2702,7 @@ function It({
2698
2702
  )
2699
2703
  ] });
2700
2704
  }
2701
- function zr({
2705
+ function Fr({
2702
2706
  tableDef: t,
2703
2707
  rows: n,
2704
2708
  onChange: a,
@@ -2760,7 +2764,7 @@ function zr({
2760
2764
  !s && /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e(J, { variant: "secondary", size: "sm", onClick: c, children: i("common.addRow") }) })
2761
2765
  ] });
2762
2766
  }
2763
- function Fr({
2767
+ function Mr({
2764
2768
  isNew: t,
2765
2769
  doctype: n,
2766
2770
  name: a,
@@ -2841,7 +2845,7 @@ function kn(t, n) {
2841
2845
  }
2842
2846
  function Sn() {
2843
2847
  var Ce;
2844
- const { doctype: t, name: n } = ut(), a = Be(), s = He(), { t: o } = te(), i = da(t ?? ""), l = !n, [c, g] = w({}), [d, p] = w(!1), { data: u, isLoading: N } = de({
2848
+ const { doctype: t, name: n } = ut(), a = Be(), s = He(), { t: o } = te(), i = ua(t ?? ""), l = !n, [c, g] = w({}), [d, p] = w(!1), { data: u, isLoading: N } = de({
2845
2849
  queryKey: ["document", t, n],
2846
2850
  queryFn: () => T.getDocument(t, n),
2847
2851
  enabled: !!t && !!n && !l
@@ -2950,7 +2954,7 @@ function Sn() {
2950
2954
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
2951
2955
  /* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
2952
2956
  /* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
2953
- !l && /* @__PURE__ */ e(ua, { slug: i.slug, name: n, onSave: V }),
2957
+ !l && /* @__PURE__ */ e(ma, { slug: i.slug, name: n, onSave: V }),
2954
2958
  !l && c.status && /* @__PURE__ */ e(ln, { status: c.status }),
2955
2959
  !l && c.currency && /* @__PURE__ */ r(
2956
2960
  "span",
@@ -2968,7 +2972,7 @@ function Sn() {
2968
2972
  )
2969
2973
  ] }),
2970
2974
  /* @__PURE__ */ e(
2971
- Fr,
2975
+ Mr,
2972
2976
  {
2973
2977
  isNew: l,
2974
2978
  doctype: t,
@@ -3013,7 +3017,7 @@ function Sn() {
3013
3017
  )) })
3014
3018
  ] }),
3015
3019
  i.childTables.map((I) => /* @__PURE__ */ e(
3016
- zr,
3020
+ Fr,
3017
3021
  {
3018
3022
  tableDef: I,
3019
3023
  rows: c[I.key] ?? [],
@@ -3040,12 +3044,12 @@ function Sn() {
3040
3044
  function be(t) {
3041
3045
  return t.toISOString().split("T")[0];
3042
3046
  }
3043
- function ma(t) {
3047
+ function pa(t) {
3044
3048
  const n = new Date(t), a = n.getDay(), s = a === 0 ? 6 : a - 1;
3045
3049
  return n.setDate(n.getDate() - s), n;
3046
3050
  }
3047
- function Mr(t) {
3048
- const n = ma(t);
3051
+ function $r(t) {
3052
+ const n = pa(t);
3049
3053
  return n.setDate(n.getDate() + 6), n;
3050
3054
  }
3051
3055
  function Cn(t) {
@@ -3068,7 +3072,7 @@ function Dn(t) {
3068
3072
  function Lt(t) {
3069
3073
  return new Date(t.getFullYear(), 11, 31);
3070
3074
  }
3071
- const $r = [
3075
+ const Ur = [
3072
3076
  {
3073
3077
  label: "Today",
3074
3078
  range: () => {
@@ -3078,7 +3082,7 @@ const $r = [
3078
3082
  },
3079
3083
  {
3080
3084
  label: "This Week",
3081
- range: () => [be(ma(/* @__PURE__ */ new Date())), be(Mr(/* @__PURE__ */ new Date()))]
3085
+ range: () => [be(pa(/* @__PURE__ */ new Date())), be($r(/* @__PURE__ */ new Date()))]
3082
3086
  },
3083
3087
  {
3084
3088
  label: "This Month",
@@ -3115,7 +3119,7 @@ const $r = [
3115
3119
  }
3116
3120
  ];
3117
3121
  function $t({ onSelect: t }) {
3118
- return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: $r.map((n) => /* @__PURE__ */ e(
3122
+ return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: Ur.map((n) => /* @__PURE__ */ e(
3119
3123
  "button",
3120
3124
  {
3121
3125
  type: "button",
@@ -3151,14 +3155,14 @@ function dn({ onSelect: t }) {
3151
3155
  a.label
3152
3156
  )) });
3153
3157
  }
3154
- const Ur = ["All", "Draft", "Submitted", "Cancelled"], Vr = /* @__PURE__ */ new Set([
3158
+ const Vr = ["All", "Draft", "Submitted", "Cancelled"], Kr = /* @__PURE__ */ new Set([
3155
3159
  "grand_total",
3156
3160
  "outstanding_amount",
3157
3161
  "paid_amount",
3158
3162
  "total_debit",
3159
3163
  "total_amount",
3160
3164
  "net_total"
3161
- ]), Kr = /* @__PURE__ */ new Set([
3165
+ ]), jr = /* @__PURE__ */ new Set([
3162
3166
  "transaction_date",
3163
3167
  "posting_date",
3164
3168
  "due_date",
@@ -3175,14 +3179,14 @@ const Ur = ["All", "Draft", "Submitted", "Cancelled"], Vr = /* @__PURE__ */ new
3175
3179
  account: "account",
3176
3180
  cost_center: "cost-center"
3177
3181
  };
3178
- function jr(t) {
3182
+ function Gr(t) {
3179
3183
  if (typeof t != "string") return null;
3180
3184
  const n = t.toLowerCase();
3181
3185
  return n === "customer" ? "customer" : n === "supplier" ? "supplier" : null;
3182
3186
  }
3183
- const Gr = ["25", "50", "100", "200"];
3184
- function Wr() {
3185
- const { t } = te(), n = ze(), { doctype: a } = ut(), s = da(a ?? ""), o = vt(), i = (s == null ? void 0 : s.listFilters) ?? [], l = Se(() => {
3187
+ const Wr = ["25", "50", "100", "200"];
3188
+ function Hr() {
3189
+ const { t } = te(), n = ze(), { doctype: a } = ut(), s = ua(a ?? ""), o = vt(), i = (s == null ? void 0 : s.listFilters) ?? [], l = Se(() => {
3186
3190
  const P = new URLSearchParams(o.search), U = {};
3187
3191
  for (const ee of i) U[ee] = P.get(ee) ?? "";
3188
3192
  return U;
@@ -3200,10 +3204,10 @@ function Wr() {
3200
3204
  for (const U of i)
3201
3205
  l[U] && (P[U] = l[U]);
3202
3206
  return N.length > 0 && b && (P.search = b, P.search_fields = N.join(",")), p && (P.include_discarded = "true"), P.limit = u, P.offset = C * u, P;
3203
- }, [c, g, d, p, u, C, s == null ? void 0 : s.dateField, i, l, N, b]), { data: V, isLoading: ie } = Pr(a ?? "", O), K = (V == null ? void 0 : V.rows) ?? [], D = (V == null ? void 0 : V.total) ?? 0;
3207
+ }, [c, g, d, p, u, C, s == null ? void 0 : s.dateField, i, l, N, b]), { data: V, isLoading: ie } = _r(a ?? "", O), K = (V == null ? void 0 : V.rows) ?? [], D = (V == null ? void 0 : V.total) ?? 0;
3204
3208
  se(() => {
3205
3209
  const { limit: P, offset: U, ...ee } = O;
3206
- ca(a ?? "", { filters: ee, search: o.search });
3210
+ da(a ?? "", { filters: ee, search: o.search });
3207
3211
  }, [a, O, o.search]);
3208
3212
  const j = Math.max(1, Math.ceil(D / u)), E = D === 0 ? 0 : C * u + 1, $ = Math.min(D, (C + 1) * u), le = Se(() => {
3209
3213
  if (!s) return [];
@@ -3229,7 +3233,7 @@ function Wr() {
3229
3233
  header: t("fields.Status", { defaultValue: "Status" }),
3230
3234
  cell: (Q) => /* @__PURE__ */ e(ln, { status: Q.getValue() })
3231
3235
  });
3232
- if (Vr.has(ee))
3236
+ if (Kr.has(ee))
3233
3237
  return P.accessor(ee, {
3234
3238
  header: U(ee),
3235
3239
  cell: (Q) => {
@@ -3243,7 +3247,7 @@ function Wr() {
3243
3247
  cell: (Q) => {
3244
3248
  const ce = Q.getValue();
3245
3249
  if (!ce) return "-";
3246
- const Ce = jr(Q.row.original.party_type), I = Ce ? Xt(Ce, String(ce)) : null;
3250
+ const Ce = Gr(Q.row.original.party_type), I = Ce ? Xt(Ce, String(ce)) : null;
3247
3251
  return I ? /* @__PURE__ */ e(
3248
3252
  ve,
3249
3253
  {
@@ -3275,7 +3279,7 @@ function Wr() {
3275
3279
  }
3276
3280
  });
3277
3281
  }
3278
- return Kr.has(ee) ? P.accessor(ee, {
3282
+ return jr.has(ee) ? P.accessor(ee, {
3279
3283
  header: U(ee),
3280
3284
  cell: (Q) => Mt(Q.getValue())
3281
3285
  }) : P.accessor(ee, {
@@ -3305,7 +3309,7 @@ function Wr() {
3305
3309
  Ve,
3306
3310
  {
3307
3311
  label: t("fields.Status", { defaultValue: "Status" }),
3308
- options: Ur.map((P) => ({
3312
+ options: Vr.map((P) => ({
3309
3313
  value: P,
3310
3314
  label: P === "All" ? t("common.all") : t(`status.${P}`, { defaultValue: P })
3311
3315
  })),
@@ -3400,7 +3404,7 @@ function Wr() {
3400
3404
  value: u,
3401
3405
  onChange: (P) => S(Number(P.target.value)),
3402
3406
  className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
3403
- children: Gr.map((P) => /* @__PURE__ */ e("option", { value: P, children: P }, P))
3407
+ children: Wr.map((P) => /* @__PURE__ */ e("option", { value: P, children: P }, P))
3404
3408
  }
3405
3409
  )
3406
3410
  ] }),
@@ -3547,7 +3551,7 @@ const Tt = () => ({
3547
3551
  position_title: "",
3548
3552
  position_blurb: "",
3549
3553
  is_recommended: 0
3550
- }), Hr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
3554
+ }), Qr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
3551
3555
  function Pn() {
3552
3556
  const { name: t } = ut(), n = !t, a = Be(), s = He(), { t: o } = te(), i = (D, j) => o(D, { defaultValue: j }), [l, c] = w({
3553
3557
  title: "Offerte",
@@ -3687,7 +3691,7 @@ function Pn() {
3687
3691
  ] }),
3688
3692
  g.map((D, j) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
3689
3693
  /* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
3690
- /* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children: Hr[j] ?? j + 1 }),
3694
+ /* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children: Qr[j] ?? j + 1 }),
3691
3695
  /* @__PURE__ */ e("div", { className: "flex-1", children: /* @__PURE__ */ e(Ae, { label: "", value: D.quotation, onChange: (E) => B(j, { quotation: E }), linkDoctype: "quotation", readOnly: !1 }) }),
3692
3696
  /* @__PURE__ */ e("button", { type: "button", onClick: () => V(j, -1), disabled: j === 0, className: "px-1 text-fg-muted disabled:opacity-30", children: "↑" }),
3693
3697
  /* @__PURE__ */ e("button", { type: "button", onClick: () => V(j, 1), disabled: j === g.length - 1, className: "px-1 text-fg-muted disabled:opacity-30", children: "↓" }),
@@ -3722,12 +3726,12 @@ function Pn() {
3722
3726
  ] })
3723
3727
  ] });
3724
3728
  }
3725
- const Qr = ["25", "50", "100", "200"];
3726
- function Yr() {
3729
+ const Yr = ["25", "50", "100", "200"];
3730
+ function Jr() {
3727
3731
  var m;
3728
3732
  const { type: t } = ut(), n = Be(), a = vt(), s = (m = a.state) == null ? void 0 : m.notice;
3729
3733
  se(() => {
3730
- t && ca(`master:${t}`, { filters: {}, search: a.search });
3734
+ t && da(`master:${t}`, { filters: {}, search: a.search });
3731
3735
  }, [t, a.search]);
3732
3736
  const [o] = oe("per_page", 50), [i] = oe("page", 1), l = i - 1, c = Ye(), g = (h) => c({ page: h === 0 ? null : h + 1 }), d = (h) => c({ per_page: h, page: null }), { data: p, isLoading: u } = de({
3733
3737
  queryKey: ["masters", t, l, o],
@@ -3815,7 +3819,7 @@ function Yr() {
3815
3819
  value: o,
3816
3820
  onChange: (h) => d(Number(h.target.value)),
3817
3821
  className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
3818
- children: Qr.map((h) => /* @__PURE__ */ e("option", { value: h, children: h }, h))
3822
+ children: Yr.map((h) => /* @__PURE__ */ e("option", { value: h, children: h }, h))
3819
3823
  }
3820
3824
  )
3821
3825
  ] }),
@@ -3849,7 +3853,7 @@ function Yr() {
3849
3853
  ] })
3850
3854
  ] });
3851
3855
  }
3852
- const Jr = {
3856
+ const Zr = {
3853
3857
  customer: [
3854
3858
  { name: "name", label: "ID", type: "text", required: !0 },
3855
3859
  { name: "customer_name", label: "Customer Name", type: "text", required: !0 },
@@ -3912,7 +3916,7 @@ const Jr = {
3912
3916
  { name: "tax_id", label: "Tax ID", type: "text" },
3913
3917
  { name: "iban", label: "IBAN", type: "text" }
3914
3918
  ]
3915
- }, Zr = {
3919
+ }, Xr = {
3916
3920
  customer: "Customer",
3917
3921
  supplier: "Supplier",
3918
3922
  item: "Item",
@@ -3921,7 +3925,7 @@ const Jr = {
3921
3925
  }, _n = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
3922
3926
  function Tn() {
3923
3927
  var B;
3924
- const { type: t, name: n } = ut(), a = Be(), s = He(), { t: o } = te(), i = !n || n === "new", l = Zr[t ?? ""] ?? t ?? "", c = o(`masters.${t}.one`, { defaultValue: l }), g = Jr[t ?? ""] ?? [], d = (S) => o(`fields.${S.label}`, { defaultValue: S.label }), [p, u] = w({}), { data: N, isLoading: b } = de({
3928
+ const { type: t, name: n } = ut(), a = Be(), s = He(), { t: o } = te(), i = !n || n === "new", l = Xr[t ?? ""] ?? t ?? "", c = o(`masters.${t}.one`, { defaultValue: l }), g = Zr[t ?? ""] ?? [], d = (S) => o(`fields.${S.label}`, { defaultValue: S.label }), [p, u] = w({}), { data: N, isLoading: b } = de({
3925
3929
  queryKey: ["master", t, n],
3926
3930
  queryFn: () => T.getMaster(t, n),
3927
3931
  enabled: !!t && !!n && !i
@@ -3987,7 +3991,7 @@ function Tn() {
3987
3991
  });
3988
3992
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
3989
3993
  /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
3990
- i ? /* @__PURE__ */ e("div", {}) : /* @__PURE__ */ e(ua, { kind: "master", slug: t, name: n, onSave: y }),
3994
+ i ? /* @__PURE__ */ e("div", {}) : /* @__PURE__ */ e(ma, { kind: "master", slug: t, name: n, onSave: y }),
3991
3995
  /* @__PURE__ */ r("div", { className: "flex gap-2", children: [
3992
3996
  /* @__PURE__ */ e(J, { onClick: y, disabled: _ || v.length > 0, children: o(_ ? "common.saving" : "common.save") }),
3993
3997
  !i && /* @__PURE__ */ e(
@@ -4057,67 +4061,67 @@ function Tn() {
4057
4061
  }) }) })
4058
4062
  ] });
4059
4063
  }
4060
- function Xr(t) {
4064
+ function es(t) {
4061
4065
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4062
4066
  queryKey: ["report", "trial-balance", t],
4063
4067
  queryFn: () => T.trialBalance(t)
4064
4068
  });
4065
4069
  return { data: n, isLoading: a, error: s, refetch: o };
4066
4070
  }
4067
- function es(t) {
4071
+ function ts(t) {
4068
4072
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4069
4073
  queryKey: ["report", "chart-of-accounts", t],
4070
4074
  queryFn: () => T.chartOfAccounts(t)
4071
4075
  });
4072
4076
  return { data: n, isLoading: a, error: s, refetch: o };
4073
4077
  }
4074
- function ts(t) {
4078
+ function ns(t) {
4075
4079
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4076
4080
  queryKey: ["report", "general-ledger", t],
4077
4081
  queryFn: () => T.generalLedger(t)
4078
4082
  });
4079
4083
  return { data: n, isLoading: a, error: s, refetch: o };
4080
4084
  }
4081
- function ns(t) {
4085
+ function as(t) {
4082
4086
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4083
4087
  queryKey: ["report", "stock-balance", t],
4084
4088
  queryFn: () => T.stockBalance(t)
4085
4089
  });
4086
4090
  return { data: n, isLoading: a, error: s, refetch: o };
4087
4091
  }
4088
- function as(t) {
4092
+ function rs(t) {
4089
4093
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4090
4094
  queryKey: ["report", "profit-and-loss", t],
4091
4095
  queryFn: () => T.profitAndLoss(t)
4092
4096
  });
4093
4097
  return { data: n, isLoading: a, error: s, refetch: o };
4094
4098
  }
4095
- function rs(t) {
4099
+ function ss(t) {
4096
4100
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4097
4101
  queryKey: ["report", "balance-sheet", t],
4098
4102
  queryFn: () => T.balanceSheet(t)
4099
4103
  });
4100
4104
  return { data: n, isLoading: a, error: s, refetch: o };
4101
4105
  }
4102
- function ss(t) {
4106
+ function is(t) {
4103
4107
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4104
4108
  queryKey: ["report", "ar-aging", t],
4105
4109
  queryFn: () => T.arAging(t)
4106
4110
  });
4107
4111
  return { data: n, isLoading: a, error: s, refetch: o };
4108
4112
  }
4109
- function is(t) {
4113
+ function os(t) {
4110
4114
  const { data: n, isLoading: a, error: s, refetch: o } = de({
4111
4115
  queryKey: ["report", "ap-aging", t],
4112
4116
  queryFn: () => T.apAging(t)
4113
4117
  });
4114
4118
  return { data: n, isLoading: a, error: s, refetch: o };
4115
4119
  }
4116
- function os() {
4120
+ function ls() {
4117
4121
  const { t } = te(), [n] = oe("company", ""), [a] = oe("from", ""), [s] = oe("to", ""), o = Ye(), [i, l] = w(n), [c, g] = w(a), [d, p] = w(s), u = ze(i), N = (m) => qe(m, u), b = Se(() => {
4118
4122
  const m = {};
4119
4123
  return n && (m.company = n), a && (m.from_date = a), s && (m.to_date = s), m;
4120
- }, [n, a, s]), { data: x, isLoading: f, refetch: A } = Xr(b), C = () => {
4124
+ }, [n, a, s]), { data: x, isLoading: f, refetch: A } = es(b), C = () => {
4121
4125
  o({
4122
4126
  company: i || null,
4123
4127
  from: c || null,
@@ -4190,8 +4194,8 @@ function os() {
4190
4194
  ] })
4191
4195
  ] });
4192
4196
  }
4193
- const ls = ["Asset", "Liability", "Equity", "Income", "Expense"];
4194
- function cs() {
4197
+ const cs = ["Asset", "Liability", "Equity", "Income", "Expense"];
4198
+ function ds() {
4195
4199
  const { t } = te(), n = (/* @__PURE__ */ new Date()).getFullYear(), [a, s] = w(String(n)), [o, i] = w(/* @__PURE__ */ new Set()), l = Se(() => {
4196
4200
  const y = [];
4197
4201
  for (let m = n; m >= n - 6; m--)
@@ -4200,7 +4204,7 @@ function cs() {
4200
4204
  }, [n, t]), c = Se(() => {
4201
4205
  const y = {};
4202
4206
  return a !== "all" && (y.from_date = `${a}-01-01`, y.to_date = `${a}-12-31`), y;
4203
- }, [a]), { data: g, isLoading: d } = es(c), p = ze(""), u = (y) => qe(y, p), N = (g == null ? void 0 : g.accounts) ?? [], { childrenOf: b, rootsByType: x } = Se(() => {
4207
+ }, [a]), { data: g, isLoading: d } = ts(c), p = ze(""), u = (y) => qe(y, p), N = (g == null ? void 0 : g.accounts) ?? [], { childrenOf: b, rootsByType: x } = Se(() => {
4204
4208
  const y = new Map(N.map((_) => [_.name, _])), m = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map();
4205
4209
  for (const _ of N)
4206
4210
  if (_.parent_account && y.has(_.parent_account)) {
@@ -4270,21 +4274,21 @@ function cs() {
4270
4274
  ] }),
4271
4275
  d && /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("common.loading", { defaultValue: "Loading…" }) }) }),
4272
4276
  !d && N.length === 0 && /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("coa.empty", { defaultValue: "No accounts found. Complete the company setup first." }) }) }),
4273
- !d && ls.filter((y) => (x.get(y) ?? []).length > 0).map((y) => /* @__PURE__ */ r(F, { children: [
4277
+ !d && cs.filter((y) => (x.get(y) ?? []).length > 0).map((y) => /* @__PURE__ */ r(F, { children: [
4274
4278
  /* @__PURE__ */ e("h3", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-fg-muted", children: t(`coa.rootType.${y}`, { defaultValue: y }) }),
4275
4279
  /* @__PURE__ */ e("div", { children: (x.get(y) ?? []).map((m) => C(m, 0)) })
4276
4280
  ] }, y))
4277
4281
  ] });
4278
4282
  }
4279
- function ds(t) {
4283
+ function us(t) {
4280
4284
  return t.toLowerCase().replace(/\s+/g, "-");
4281
4285
  }
4282
- const us = ["25", "50", "100", "200"];
4283
- function ms() {
4286
+ const ms = ["25", "50", "100", "200"];
4287
+ function ps() {
4284
4288
  const { t } = te(), [n] = oe("account", ""), [a] = oe("party", ""), [s] = oe("from", ""), [o] = oe("to", ""), [i] = oe("per_page", 50), [l] = oe("page", 1), c = l - 1, g = Ye(), d = (E) => g({ page: E === 0 ? null : E + 1 }), p = (E) => g({ per_page: E, page: null }), [u, N] = w(n), [b, x] = w(a), [f, A] = w(s), [C, y] = w(o), m = ze(), h = (E) => qe(E, m), _ = Se(() => {
4285
4289
  const E = {};
4286
4290
  return n && (E.account = n), a && (E.party = a), s && (E.from_date = s), o && (E.to_date = o), E.limit = String(i), E.offset = String(c * i), E;
4287
- }, [n, a, s, o, i, c]), { data: v, isLoading: B, refetch: S } = ts(_), O = (v == null ? void 0 : v.rows) ?? [], V = (v == null ? void 0 : v.total) ?? 0, ie = Math.max(1, Math.ceil(V / i)), K = V === 0 ? 0 : c * i + 1, D = Math.min(V, (c + 1) * i), j = () => {
4291
+ }, [n, a, s, o, i, c]), { data: v, isLoading: B, refetch: S } = ns(_), O = (v == null ? void 0 : v.rows) ?? [], V = (v == null ? void 0 : v.total) ?? 0, ie = Math.max(1, Math.ceil(V / i)), K = V === 0 ? 0 : c * i + 1, D = Math.min(V, (c + 1) * i), j = () => {
4288
4292
  g({
4289
4293
  account: u || null,
4290
4294
  party: b || null,
@@ -4361,7 +4365,7 @@ function ms() {
4361
4365
  /* @__PURE__ */ e("td", { className: "px-4 py-2", children: E.voucher_type && E.voucher_no ? /* @__PURE__ */ e(
4362
4366
  ve,
4363
4367
  {
4364
- to: `/app/${ds(E.voucher_type)}/${E.voucher_no}`,
4368
+ to: `/app/${us(E.voucher_type)}/${E.voucher_no}`,
4365
4369
  className: "font-medium text-blue-600 hover:text-blue-800",
4366
4370
  children: E.voucher_no
4367
4371
  }
@@ -4391,7 +4395,7 @@ function ms() {
4391
4395
  value: i,
4392
4396
  onChange: (E) => p(Number(E.target.value)),
4393
4397
  className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
4394
- children: us.map((E) => /* @__PURE__ */ e("option", { value: E, children: E }, E))
4398
+ children: ms.map((E) => /* @__PURE__ */ e("option", { value: E, children: E }, E))
4395
4399
  }
4396
4400
  )
4397
4401
  ] }),
@@ -4427,11 +4431,11 @@ function ms() {
4427
4431
  ] })
4428
4432
  ] });
4429
4433
  }
4430
- function ps() {
4434
+ function hs() {
4431
4435
  const { t } = te(), [n] = oe("item_code", ""), [a] = oe("warehouse", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), g = ze(), d = (f) => qe(f, g), p = Se(() => {
4432
4436
  const f = {};
4433
4437
  return n && (f.item_code = n), a && (f.warehouse = a), f;
4434
- }, [n, a]), { data: u, isLoading: N, refetch: b } = ns(p), x = () => {
4438
+ }, [n, a]), { data: u, isLoading: N, refetch: b } = as(p), x = () => {
4435
4439
  s({
4436
4440
  item_code: o || null,
4437
4441
  warehouse: l || null
@@ -4481,11 +4485,11 @@ function ps() {
4481
4485
  ] }) }) })
4482
4486
  ] });
4483
4487
  }
4484
- function hs() {
4488
+ function gs() {
4485
4489
  const { t } = te(), [n] = oe("company", ""), [a] = oe("from", ""), [s] = oe("to", ""), o = Ye(), [i, l] = w(n), c = ze(i), g = (m) => qe(m, c), [d, p] = w(a), [u, N] = w(s), b = Se(() => {
4486
4490
  const m = {};
4487
4491
  return n && (m.company = n), a && (m.from_date = a), s && (m.to_date = s), m;
4488
- }, [n, a, s]), { data: x, isLoading: f, refetch: A } = as(b), C = () => {
4492
+ }, [n, a, s]), { data: x, isLoading: f, refetch: A } = rs(b), C = () => {
4489
4493
  o({
4490
4494
  company: i || null,
4491
4495
  from: d || null,
@@ -4565,12 +4569,12 @@ function Gt({ title: t, rows: n, total: a, totalLabel: s, currency: o }) {
4565
4569
  ] })
4566
4570
  ] });
4567
4571
  }
4568
- function gs() {
4572
+ function fs() {
4569
4573
  var C, y, m;
4570
4574
  const { t } = te(), [n] = oe("company", ""), [a] = oe("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), g = ze(o), d = (h) => qe(h, g), p = Se(() => {
4571
4575
  const h = {};
4572
4576
  return n && (h.company = n), a && (h.as_of_date = a), h;
4573
- }, [n, a]), { data: u, isLoading: N, refetch: b } = rs(p), x = () => {
4577
+ }, [n, a]), { data: u, isLoading: N, refetch: b } = ss(p), x = () => {
4574
4578
  s({ company: o || null, as_of_date: l || null }), b();
4575
4579
  }, f = u && (((C = u.assets) == null ? void 0 : C.length) > 0 || ((y = u.liabilities) == null ? void 0 : y.length) > 0 || ((m = u.equity) == null ? void 0 : m.length) > 0), A = u ? Math.abs(u.total_assets - u.total_liabilities_and_equity) < 0.01 : !1;
4576
4580
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4604,11 +4608,11 @@ function gs() {
4604
4608
  ] }) : /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noData") })
4605
4609
  ] });
4606
4610
  }
4607
- function fs() {
4611
+ function ys() {
4608
4612
  const { t } = te(), [n] = oe("company", ""), [a] = oe("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), g = ze(o), d = (f) => qe(f, g), p = Se(() => {
4609
4613
  const f = {};
4610
4614
  return n && (f.company = n), a && (f.as_of_date = a), f;
4611
- }, [n, a]), { data: u, isLoading: N, refetch: b } = ss(p), x = () => {
4615
+ }, [n, a]), { data: u, isLoading: N, refetch: b } = is(p), x = () => {
4612
4616
  s({ company: o || null, as_of_date: l || null }), b();
4613
4617
  };
4614
4618
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4662,11 +4666,11 @@ function fs() {
4662
4666
  ] }) }) })
4663
4667
  ] });
4664
4668
  }
4665
- function ys() {
4669
+ function bs() {
4666
4670
  const { t } = te(), [n] = oe("company", ""), [a] = oe("as_of_date", ""), s = Ye(), [o, i] = w(n), [l, c] = w(a), g = ze(o), d = (f) => qe(f, g), p = Se(() => {
4667
4671
  const f = {};
4668
4672
  return n && (f.company = n), a && (f.as_of_date = a), f;
4669
- }, [n, a]), { data: u, isLoading: N, refetch: b } = is(p), x = () => {
4673
+ }, [n, a]), { data: u, isLoading: N, refetch: b } = os(p), x = () => {
4670
4674
  s({ company: o || null, as_of_date: l || null }), b();
4671
4675
  };
4672
4676
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
@@ -4720,8 +4724,8 @@ function ys() {
4720
4724
  ] }) }) })
4721
4725
  ] });
4722
4726
  }
4723
- const pa = '(function(){"use strict";function u(r,t){const e=Number(r??0)||0;return t==null?e:Number(e.toFixed(t))}const p={flt:u,sum(r,t){return r.reduce((e,a)=>typeof t=="function"?e+u(t(a)):typeof t=="string"?e+u(a[t]):e+u(a),0)},count(r){return r.length},sortBy(r,t,e="asc"){const n=(e===!0?"desc":e===!1?"asc":e)==="desc"?-1:1;return[...r].sort((s,i)=>{const c=s[t],o=i[t];return c==null&&o==null?0:c==null?1:o==null?-1:c<o?-1*n:c>o?1*n:0})},topN(r,t,e=10){return typeof t=="number"?r.slice(0,t):p.sortBy(r,t,"desc").slice(0,e)},group(r,t,e){if(typeof t=="function"){const s=new Map;for(const i of r){const c=t(i),o=JSON.stringify(c);s.has(o)||s.set(o,{key:c,rows:[]}),s.get(o).rows.push(i)}return Array.from(s.values())}const a=t,n=new Map;for(const s of r){const i=a.map(f=>s[f]),c=JSON.stringify(i);if(!n.has(c)){const f={};a.forEach((l,m)=>{f[l]=i[m]});for(const[l,[m]]of Object.entries(e||{}))f[l]=0;n.set(c,f)}const o=n.get(c);for(const[f,[l,m]]of Object.entries(e||{}))l==="count"?o[f]=u(o[f])+1:o[f]=u(o[f])+u(s[m||f])}return Array.from(n.values())},leftJoin(r,t,e,a=e){const n=new Map(t.map(s=>[s[a],s]));return r.map(s=>({...s,...n.get(s[e])||{}}))},monthKey(r){return String(r??"").slice(0,7)},quarterKey(r){const t=String(r??""),e=t.slice(0,4),a=Number(t.slice(5,7));return!e||!a?"":`${e}-Q${Math.floor((a+2)/3)}`},yearKey(r){return String(r??"").slice(0,4)},pivot(r,t,e,a){const n=new Map;for(const s of r){const i=String(s[t]??"—"),c=String(s[e]??"—");n.has(i)||n.set(i,{[t]:i});const o=n.get(i);o[c]=u(o[c])+u(s[a])}return Array.from(n.values())}};function y(r){if(!r||typeof r!="object")throw new Error("Transform must return an object");if(r.tables&&!Array.isArray(r.tables))throw new Error("tables must be an array");if(r.charts&&!Array.isArray(r.charts))throw new Error("charts must be an array");if(r.kpis&&!Array.isArray(r.kpis))throw new Error("kpis must be an array");return r}self.onmessage=r=>{try{const t=Object.fromEntries(r.data.datasets.map(s=>[s.name,s.rows])),e=r.data.datasets.map(s=>s.name).filter(s=>/^[$A-Z_][0-9A-Z_$]*$/i.test(s)).map(s=>`const ${s} = datasets[${JSON.stringify(s)}];`).join(`\n`),n=new Function("datasets","params","helpers",`"use strict";\n${e}\n${r.data.transformJs}`)(t,r.data.params||{},p);self.postMessage({ok:!0,output:y(n)})}catch(t){self.postMessage({ok:!1,error:t instanceof Error?t.message:String(t)})}}})();\n//# sourceMappingURL=report-runtime.worker-DrBTCfV6.js.map\n', Rn = typeof self < "u" && self.Blob && new Blob([pa], { type: "text/javascript;charset=utf-8" });
4724
- function bs(t) {
4727
+ const ha = '(function(){"use strict";function u(r,t){const e=Number(r??0)||0;return t==null?e:Number(e.toFixed(t))}const p={flt:u,sum(r,t){return r.reduce((e,a)=>typeof t=="function"?e+u(t(a)):typeof t=="string"?e+u(a[t]):e+u(a),0)},count(r){return r.length},sortBy(r,t,e="asc"){const n=(e===!0?"desc":e===!1?"asc":e)==="desc"?-1:1;return[...r].sort((s,i)=>{const c=s[t],o=i[t];return c==null&&o==null?0:c==null?1:o==null?-1:c<o?-1*n:c>o?1*n:0})},topN(r,t,e=10){return typeof t=="number"?r.slice(0,t):p.sortBy(r,t,"desc").slice(0,e)},group(r,t,e){if(typeof t=="function"){const s=new Map;for(const i of r){const c=t(i),o=JSON.stringify(c);s.has(o)||s.set(o,{key:c,rows:[]}),s.get(o).rows.push(i)}return Array.from(s.values())}const a=t,n=new Map;for(const s of r){const i=a.map(f=>s[f]),c=JSON.stringify(i);if(!n.has(c)){const f={};a.forEach((l,m)=>{f[l]=i[m]});for(const[l,[m]]of Object.entries(e||{}))f[l]=0;n.set(c,f)}const o=n.get(c);for(const[f,[l,m]]of Object.entries(e||{}))l==="count"?o[f]=u(o[f])+1:o[f]=u(o[f])+u(s[m||f])}return Array.from(n.values())},leftJoin(r,t,e,a=e){const n=new Map(t.map(s=>[s[a],s]));return r.map(s=>({...s,...n.get(s[e])||{}}))},monthKey(r){return String(r??"").slice(0,7)},quarterKey(r){const t=String(r??""),e=t.slice(0,4),a=Number(t.slice(5,7));return!e||!a?"":`${e}-Q${Math.floor((a+2)/3)}`},yearKey(r){return String(r??"").slice(0,4)},pivot(r,t,e,a){const n=new Map;for(const s of r){const i=String(s[t]??"—"),c=String(s[e]??"—");n.has(i)||n.set(i,{[t]:i});const o=n.get(i);o[c]=u(o[c])+u(s[a])}return Array.from(n.values())}};function y(r){if(!r||typeof r!="object")throw new Error("Transform must return an object");if(r.tables&&!Array.isArray(r.tables))throw new Error("tables must be an array");if(r.charts&&!Array.isArray(r.charts))throw new Error("charts must be an array");if(r.kpis&&!Array.isArray(r.kpis))throw new Error("kpis must be an array");return r}self.onmessage=r=>{try{const t=Object.fromEntries(r.data.datasets.map(s=>[s.name,s.rows])),e=r.data.datasets.map(s=>s.name).filter(s=>/^[$A-Z_][0-9A-Z_$]*$/i.test(s)).map(s=>`const ${s} = datasets[${JSON.stringify(s)}];`).join(`\n`),n=new Function("datasets","params","helpers",`"use strict";\n${e}\n${r.data.transformJs}`)(t,r.data.params||{},p);self.postMessage({ok:!0,output:y(n)})}catch(t){self.postMessage({ok:!1,error:t instanceof Error?t.message:String(t)})}}})();\n//# sourceMappingURL=report-runtime.worker-DrBTCfV6.js.map\n', Rn = typeof self < "u" && self.Blob && new Blob([ha], { type: "text/javascript;charset=utf-8" });
4728
+ function vs(t) {
4725
4729
  let n;
4726
4730
  try {
4727
4731
  if (n = Rn && (self.URL || self.webkitURL).createObjectURL(Rn), !n) throw "";
@@ -4733,7 +4737,7 @@ function bs(t) {
4733
4737
  }), a;
4734
4738
  } catch {
4735
4739
  return new Worker(
4736
- "data:text/javascript;charset=utf-8," + encodeURIComponent(pa),
4740
+ "data:text/javascript;charset=utf-8," + encodeURIComponent(ha),
4737
4741
  {
4738
4742
  name: t == null ? void 0 : t.name
4739
4743
  }
@@ -4742,7 +4746,7 @@ function bs(t) {
4742
4746
  n && (self.URL || self.webkitURL).revokeObjectURL(n);
4743
4747
  }
4744
4748
  }
4745
- function vs() {
4749
+ function xs() {
4746
4750
  const t = /* @__PURE__ */ new Date(), n = t.toISOString().slice(0, 10), a = new Date(t);
4747
4751
  a.setMonth(a.getMonth() - 12);
4748
4752
  const s = a.toISOString().slice(0, 10);
@@ -4813,9 +4817,9 @@ return {
4813
4817
  2
4814
4818
  );
4815
4819
  }
4816
- const ha = vs();
4817
- function xs() {
4818
- const t = Be(), { sessions: n, createSession: a } = mt(), [s] = oe("report_id", ""), [o] = oe("metric", ""), [i] = oe("group_by", ""), [l] = oe("from", ""), [c] = oe("to", ""), [g] = oe("company", ""), [d, p] = w(ha), [u, N] = w([]), [b, x] = w(null), [f, A] = w(""), [C, y] = w(!1), [m, h] = w(!1), [_, v] = w(""), B = re(null), S = re(""), O = re(""), V = re(0), ie = Se(() => !o || !i ? "" : JSON.stringify(Ss({
4820
+ const ga = xs();
4821
+ function Ns() {
4822
+ const t = Be(), { sessions: n, createSession: a } = mt(), [s] = oe("report_id", ""), [o] = oe("metric", ""), [i] = oe("group_by", ""), [l] = oe("from", ""), [c] = oe("to", ""), [g] = oe("company", ""), [d, p] = w(ga), [u, N] = w([]), [b, x] = w(null), [f, A] = w(""), [C, y] = w(!1), [m, h] = w(!1), [_, v] = w(""), B = re(null), S = re(""), O = re(""), V = re(0), ie = Se(() => !o || !i ? "" : JSON.stringify(Cs({
4819
4823
  metric: o,
4820
4824
  groupBy: i,
4821
4825
  fromDate: l || void 0,
@@ -4829,7 +4833,7 @@ function xs() {
4829
4833
  const ee = JSON.parse($ ?? d), Q = await T.runtimeData({ requests: ee.data_requests || [] });
4830
4834
  if (!ue()) return;
4831
4835
  N(Q.datasets), (P = B.current) == null || P.terminate();
4832
- const ce = new bs();
4836
+ const ce = new vs();
4833
4837
  B.current = ce;
4834
4838
  const Ce = await new Promise((I, ae) => {
4835
4839
  const Ee = window.setTimeout(() => {
@@ -4869,7 +4873,7 @@ function xs() {
4869
4873
  $ = !0;
4870
4874
  });
4871
4875
  }, [s, ie]);
4872
- const D = !!(!s && ie), j = Se(() => ks(b), [b]), E = async () => {
4876
+ const D = !!(!s && ie), j = Se(() => Ss(b), [b]), E = async () => {
4873
4877
  var Q;
4874
4878
  const $ = d.trim() !== O.current.trim(), le = s || "unsaved-runtime-report", ue = u.map((ce) => ({
4875
4879
  name: ce.name,
@@ -4921,7 +4925,7 @@ function xs() {
4921
4925
  /* @__PURE__ */ e(J, { onClick: () => void K(), disabled: C, children: C ? "Running..." : "Run Report" })
4922
4926
  ] })
4923
4927
  ] }) }),
4924
- m ? /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : f ? /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: f }) }) : b ? /* @__PURE__ */ e(Ns, { output: b }) : /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
4928
+ m ? /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : f ? /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: f }) }) : b ? /* @__PURE__ */ e(ws, { output: b }) : /* @__PURE__ */ e(F, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
4925
4929
  u.length > 0 && /* @__PURE__ */ e(F, { title: "Fetched Datasets", children: /* @__PURE__ */ e("div", { className: "space-y-4", children: u.map(($) => /* @__PURE__ */ r("div", { className: "rounded-md border border-gray-200 p-4", children: [
4926
4930
  /* @__PURE__ */ r("div", { className: "flex items-baseline justify-between gap-4", children: [
4927
4931
  /* @__PURE__ */ r("div", { children: [
@@ -4950,12 +4954,12 @@ function xs() {
4950
4954
  ] })
4951
4955
  ] });
4952
4956
  }
4953
- function Ns({ output: t }) {
4957
+ function ws({ output: t }) {
4954
4958
  var o, i;
4955
4959
  const n = ze(), a = (t.tables ?? []).map((l, c) => ({
4956
4960
  ...l,
4957
4961
  id: l.id || `table_${c + 1}`
4958
- })), s = ga(a);
4962
+ })), s = fa(a);
4959
4963
  return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
4960
4964
  /* @__PURE__ */ r(F, { children: [
4961
4965
  /* @__PURE__ */ e("div", { className: "flex items-baseline justify-between gap-4", children: /* @__PURE__ */ r("div", { children: [
@@ -4971,10 +4975,10 @@ function Ns({ output: t }) {
4971
4975
  const g = l.dataTable ? s.get(l.dataTable) : void 0, d = l.data ?? (g == null ? void 0 : g.rows) ?? [];
4972
4976
  if (!d.length)
4973
4977
  return /* @__PURE__ */ e(F, { title: l.title, children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: "Chart has no usable data." }) }, l.id || `chart_${c + 1}`);
4974
- const p = l.type === "pie" ? [] : d.map((b) => String(b[l.x] ?? "")), u = Ps(p), N = Math.max(320, 200 + u.axisHeight);
4978
+ const p = l.type === "pie" ? [] : d.map((b) => String(b[l.x] ?? "")), u = _s(p), N = Math.max(320, 200 + u.axisHeight);
4975
4979
  return /* @__PURE__ */ r(F, { children: [
4976
4980
  /* @__PURE__ */ e("div", { className: "pb-3 text-sm font-semibold text-gray-700", children: l.title }),
4977
- /* @__PURE__ */ e("div", { style: { height: N }, className: "w-full", children: /* @__PURE__ */ e(Ya, { width: "100%", height: "100%", children: l.type === "line" ? /* @__PURE__ */ r(Ja, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
4981
+ /* @__PURE__ */ e("div", { style: { height: N }, className: "w-full", children: /* @__PURE__ */ e(Ja, { width: "100%", height: "100%", children: l.type === "line" ? /* @__PURE__ */ r(Za, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
4978
4982
  /* @__PURE__ */ e(pn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
4979
4983
  /* @__PURE__ */ e(
4980
4984
  hn,
@@ -4989,11 +4993,11 @@ function Ns({ output: t }) {
4989
4993
  ),
4990
4994
  /* @__PURE__ */ e(gn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: In }),
4991
4995
  /* @__PURE__ */ e(Vt, { formatter: (b) => St(b, Wt(g, l.y), n) }),
4992
- /* @__PURE__ */ e(Za, { type: "monotone", dataKey: l.y, stroke: "#3b82f6", strokeWidth: 2, dot: { r: 3 } })
4993
- ] }) : l.type === "pie" ? /* @__PURE__ */ r(Xa, { children: [
4996
+ /* @__PURE__ */ e(Xa, { type: "monotone", dataKey: l.y, stroke: "#3b82f6", strokeWidth: 2, dot: { r: 3 } })
4997
+ ] }) : l.type === "pie" ? /* @__PURE__ */ r(er, { children: [
4994
4998
  /* @__PURE__ */ e(Vt, { formatter: (b) => St(b, Wt(g, l.y), n) }),
4995
- /* @__PURE__ */ e(er, { data: d, dataKey: l.y, nameKey: l.x, outerRadius: 110, children: d.map((b, x) => /* @__PURE__ */ e(tr, { fill: Bn[x % Bn.length] }, x)) })
4996
- ] }) : /* @__PURE__ */ r(nr, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
4999
+ /* @__PURE__ */ e(tr, { data: d, dataKey: l.y, nameKey: l.x, outerRadius: 110, children: d.map((b, x) => /* @__PURE__ */ e(nr, { fill: Bn[x % Bn.length] }, x)) })
5000
+ ] }) : /* @__PURE__ */ r(ar, { data: d, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
4997
5001
  /* @__PURE__ */ e(pn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
4998
5002
  /* @__PURE__ */ e(
4999
5003
  hn,
@@ -5008,7 +5012,7 @@ function Ns({ output: t }) {
5008
5012
  ),
5009
5013
  /* @__PURE__ */ e(gn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: In }),
5010
5014
  /* @__PURE__ */ e(Vt, { formatter: (b) => St(b, Wt(g, l.y), n) }),
5011
- /* @__PURE__ */ e(ar, { dataKey: l.y, fill: "#3b82f6", radius: [4, 4, 0, 0] })
5015
+ /* @__PURE__ */ e(rr, { dataKey: l.y, fill: "#3b82f6", radius: [4, 4, 0, 0] })
5012
5016
  ] }) }) })
5013
5017
  ] }, l.id || `chart_${c + 1}`);
5014
5018
  }),
@@ -5018,21 +5022,21 @@ function Ns({ output: t }) {
5018
5022
  ] }) }) }, l.id))
5019
5023
  ] });
5020
5024
  }
5021
- function ws(t) {
5025
+ function ks(t) {
5022
5026
  return t.replace(/_/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
5023
5027
  }
5024
- function ga(t) {
5028
+ function fa(t) {
5025
5029
  const n = /* @__PURE__ */ new Map();
5026
5030
  for (const a of t)
5027
5031
  n.set(a.id, a), a.title && n.set(a.title, a);
5028
5032
  return n;
5029
5033
  }
5030
- function ks(t) {
5034
+ function Ss(t) {
5031
5035
  if (!t) return [];
5032
5036
  const n = (t.tables ?? []).map((o, i) => ({
5033
5037
  ...o,
5034
5038
  id: o.id || `table_${i + 1}`
5035
- })), a = ga(n), s = [];
5039
+ })), a = fa(n), s = [];
5036
5040
  for (const o of t.charts ?? []) {
5037
5041
  const i = o.dataTable ? a.get(o.dataTable) : void 0, l = o.data ?? (i == null ? void 0 : i.rows) ?? [];
5038
5042
  if (!l.length) {
@@ -5043,8 +5047,8 @@ function ks(t) {
5043
5047
  }
5044
5048
  return s;
5045
5049
  }
5046
- function Ss(t) {
5047
- const n = `${Cs(t.metric)} by ${ws(t.groupBy)}`, a = t.groupBy === "month" ? "helpers.monthKey" : t.groupBy === "quarter" ? "helpers.quarterKey" : "helpers.yearKey";
5050
+ function Cs(t) {
5051
+ const n = `${Ds(t.metric)} by ${ks(t.groupBy)}`, a = t.groupBy === "month" ? "helpers.monthKey" : t.groupBy === "quarter" ? "helpers.quarterKey" : "helpers.yearKey";
5048
5052
  if (t.metric === "sales_revenue")
5049
5053
  return bt({
5050
5054
  title: n,
@@ -5147,7 +5151,7 @@ function Ss(t) {
5147
5151
  },
5148
5152
  fields: [t.groupBy === "warehouse" ? "warehouse" : "item_code", "stock_value"],
5149
5153
  chartType: "bar"
5150
- }) : JSON.parse(ha);
5154
+ }) : JSON.parse(ga);
5151
5155
  }
5152
5156
  function bt(t) {
5153
5157
  const n = Object.fromEntries(Object.entries(t.filters).filter(([, s]) => s !== void 0)), a = ["month", "quarter", "year"].includes(t.groupBy) ? `${t.timeBucket}(row.${t.keyField})` : `row.${t.keyField} || "—"`;
@@ -5203,7 +5207,7 @@ return {
5203
5207
  };`
5204
5208
  };
5205
5209
  }
5206
- function Cs(t) {
5210
+ function Ds(t) {
5207
5211
  return {
5208
5212
  sales_revenue: "Sales Revenue",
5209
5213
  sales_returns: "Sales Returns",
@@ -5226,24 +5230,24 @@ function In(t) {
5226
5230
  const n = Math.abs(t);
5227
5231
  return n >= 1e6 ? `${(t / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(t / 1e3).toFixed(0)}k` : String(t);
5228
5232
  }
5229
- const Bn = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], Ds = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
5233
+ const Bn = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], As = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
5230
5234
  let Ht = null;
5231
- function As(t, n = Ds) {
5235
+ function Ps(t, n = As) {
5232
5236
  if (typeof document > "u") return t.length * 7;
5233
5237
  Ht || (Ht = document.createElement("canvas"));
5234
5238
  const a = Ht.getContext("2d");
5235
5239
  return a ? (a.font = n, a.measureText(t).width) : t.length * 7;
5236
5240
  }
5237
- function Ps(t) {
5241
+ function _s(t) {
5238
5242
  if (!t.length) return { angle: 0, axisHeight: 30, maxWidth: 0 };
5239
- const n = t.map((c) => As(c)), a = Math.max(1, ...n);
5243
+ const n = t.map((c) => Ps(c)), a = Math.max(1, ...n);
5240
5244
  let s = 0;
5241
5245
  a > 55 && (s = -30), a > 110 && (s = -45), a > 200 && (s = -60), a > 300 && (s = -90);
5242
5246
  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));
5243
5247
  return { angle: s, axisHeight: l, maxWidth: a };
5244
5248
  }
5245
- const _s = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
5246
- function Ts() {
5249
+ const Ts = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
5250
+ function Rs() {
5247
5251
  const t = He(), { data: n, isLoading: a } = de({
5248
5252
  queryKey: ["setup-status"],
5249
5253
  queryFn: () => T.setupStatus()
@@ -5276,7 +5280,7 @@ function Ts() {
5276
5280
  return /* @__PURE__ */ e("p", { className: "text-gray-500", children: "Loading..." });
5277
5281
  if (n != null && n.setup_complete && !N)
5278
5282
  return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
5279
- /* @__PURE__ */ e(F, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((v, B) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(Rs, { company: v }) }, B)) }) : /* @__PURE__ */ e("p", { className: "text-gray-400", children: "No companies found" }) }),
5283
+ /* @__PURE__ */ e(F, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((v, B) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(Is, { company: v }) }, B)) }) : /* @__PURE__ */ e("p", { className: "text-gray-400", children: "No companies found" }) }),
5280
5284
  /* @__PURE__ */ e(ve, { to: "/", className: "text-blue-600 hover:text-blue-800 text-sm font-medium", children: "Go to Dashboard" })
5281
5285
  ] });
5282
5286
  if (N)
@@ -5311,7 +5315,7 @@ function Ts() {
5311
5315
  Ve,
5312
5316
  {
5313
5317
  label: "Currency",
5314
- options: _s,
5318
+ options: Ts,
5315
5319
  value: i,
5316
5320
  onChange: (v) => l(v.target.value)
5317
5321
  }
@@ -5406,7 +5410,7 @@ function Ts() {
5406
5410
  ] }) })
5407
5411
  ] });
5408
5412
  }
5409
- function Rs({ company: t }) {
5413
+ function Is({ company: t }) {
5410
5414
  const n = [
5411
5415
  [t.city, t.zip_code].filter(Boolean).join(" "),
5412
5416
  t.country
@@ -5447,7 +5451,7 @@ function Rs({ company: t }) {
5447
5451
  t.default_currency && /* @__PURE__ */ e("span", { className: "shrink-0 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: t.default_currency })
5448
5452
  ] });
5449
5453
  }
5450
- const Is = [
5454
+ const Bs = [
5451
5455
  {
5452
5456
  number: 1,
5453
5457
  title: "Set Up Your Company",
@@ -5584,7 +5588,7 @@ const Is = [
5584
5588
  ]
5585
5589
  }
5586
5590
  ];
5587
- function fa() {
5591
+ function ya() {
5588
5592
  const t = Be(), { sessions: n, createSession: a } = mt();
5589
5593
  return async (s) => {
5590
5594
  var i;
@@ -5599,8 +5603,8 @@ function fa() {
5599
5603
  t(`/chat/${o}`, { state: { prefillMessage: s } });
5600
5604
  };
5601
5605
  }
5602
- function Bs() {
5603
- const { t } = te(), n = fa();
5606
+ function Es() {
5607
+ const { t } = te(), n = ya();
5604
5608
  return /* @__PURE__ */ e(F, { 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: [
5605
5609
  /* @__PURE__ */ e("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-lg font-bold text-emerald-700", children: "▶" }),
5606
5610
  /* @__PURE__ */ r("div", { className: "flex-1 space-y-3", children: [
@@ -5635,8 +5639,8 @@ function Bs() {
5635
5639
  ] })
5636
5640
  ] }) });
5637
5641
  }
5638
- function Es() {
5639
- const { t } = te(), n = fa(), a = [
5642
+ function Ls() {
5643
+ const { t } = te(), n = ya(), a = [
5640
5644
  t("tutorial.caPrompt1"),
5641
5645
  t("tutorial.caPrompt2"),
5642
5646
  t("tutorial.caPrompt3"),
@@ -5694,7 +5698,7 @@ function Es() {
5694
5698
  ] })
5695
5699
  ] }) });
5696
5700
  }
5697
- function Ls() {
5701
+ function Os() {
5698
5702
  const { t } = te(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
5699
5703
  return /* @__PURE__ */ r(F, { children: [
5700
5704
  /* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.flowTitle") }),
@@ -5765,7 +5769,7 @@ function Ls() {
5765
5769
  ] })
5766
5770
  ] });
5767
5771
  }
5768
- function Os() {
5772
+ function qs() {
5769
5773
  const { t } = te(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
5770
5774
  return /* @__PURE__ */ r(F, { children: [
5771
5775
  /* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.lifecycleTitle") }),
@@ -5801,7 +5805,7 @@ function Os() {
5801
5805
  ] })
5802
5806
  ] });
5803
5807
  }
5804
- function qs() {
5808
+ function zs() {
5805
5809
  const { t } = te();
5806
5810
  return /* @__PURE__ */ r("div", { className: "mx-auto max-w-3xl space-y-6", children: [
5807
5811
  /* @__PURE__ */ r("div", { children: [
@@ -5825,11 +5829,11 @@ function qs() {
5825
5829
  ] }),
5826
5830
  /* @__PURE__ */ e("p", { className: "mt-4 text-sm text-gray-500", children: t("tutorial.manualIntro") })
5827
5831
  ] }),
5828
- /* @__PURE__ */ e(Bs, {}),
5829
5832
  /* @__PURE__ */ e(Es, {}),
5830
5833
  /* @__PURE__ */ e(Ls, {}),
5831
5834
  /* @__PURE__ */ e(Os, {}),
5832
- Is.map((n) => {
5835
+ /* @__PURE__ */ e(qs, {}),
5836
+ Bs.map((n) => {
5833
5837
  var a;
5834
5838
  return /* @__PURE__ */ e(F, { children: /* @__PURE__ */ r("div", { className: "flex gap-4", children: [
5835
5839
  /* @__PURE__ */ e("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-sm font-bold text-blue-700", children: n.number }),
@@ -5890,17 +5894,17 @@ function qs() {
5890
5894
  ] }) })
5891
5895
  ] });
5892
5896
  }
5893
- const Qt = 5, zs = 10 * 1024 * 1024, Fs = /* @__PURE__ */ new Set([
5897
+ const Qt = 5, Fs = 10 * 1024 * 1024, Ms = /* @__PURE__ */ new Set([
5894
5898
  "image/png",
5895
5899
  "image/jpeg",
5896
5900
  "image/gif",
5897
5901
  "image/webp",
5898
5902
  "application/pdf"
5899
5903
  ]);
5900
- function Ms(t) {
5904
+ function $s(t) {
5901
5905
  return new Promise((n) => window.setTimeout(n, t));
5902
5906
  }
5903
- function $s(t) {
5907
+ function Us(t) {
5904
5908
  return new Promise((n, a) => {
5905
5909
  const s = new FileReader();
5906
5910
  s.onloadend = () => {
@@ -6048,7 +6052,7 @@ function On() {
6048
6052
  c("");
6049
6053
  for (const yt of M) {
6050
6054
  if (ye !== Pe.current) return;
6051
- c((Ge) => Ge + yt), await Ms(ne);
6055
+ c((Ge) => Ge + yt), await $s(ne);
6052
6056
  }
6053
6057
  ye === Pe.current && W.current(k, he);
6054
6058
  }
@@ -6067,11 +6071,11 @@ function On() {
6067
6071
  b(`Maximum ${Qt} attachments per message.`);
6068
6072
  break;
6069
6073
  }
6070
- if (!Fs.has(ye.type)) {
6074
+ if (!Ms.has(ye.type)) {
6071
6075
  b(`Unsupported file type: ${ye.type || ye.name}`);
6072
6076
  continue;
6073
6077
  }
6074
- if (ye.size > zs) {
6078
+ if (ye.size > Fs) {
6075
6079
  b(`"${ye.name}" is too large (max 10 MB).`);
6076
6080
  continue;
6077
6081
  }
@@ -6132,7 +6136,7 @@ function On() {
6132
6136
  ne && (ne.focus(), ne.style.height = "auto", ne.style.height = Math.min(Math.max(ne.scrollHeight, 48), 120) + "px");
6133
6137
  }, 0));
6134
6138
  }
6135
- async function Sa() {
6139
+ async function Ca() {
6136
6140
  if (A !== "idle") return;
6137
6141
  let k;
6138
6142
  try {
@@ -6156,7 +6160,7 @@ function On() {
6156
6160
  const he = M.mimeType || ((yt = ne[0]) == null ? void 0 : yt.type) || "audio/webm", ye = new Blob(ne, { type: he }), et = (he.split(";")[0].split("/")[1] || "webm").toLowerCase();
6157
6161
  C("transcribing");
6158
6162
  try {
6159
- const Ge = await $s(ye), lt = await D(Ge, et, n);
6163
+ const Ge = await Us(ye), lt = await D(Ge, et, n);
6160
6164
  Xe(lt);
6161
6165
  } catch (Ge) {
6162
6166
  b(Ge instanceof Error ? Ge.message : t("chat.transcribeFailed"));
@@ -6165,12 +6169,12 @@ function On() {
6165
6169
  }
6166
6170
  }, M.start(), C("recording");
6167
6171
  }
6168
- function Ca() {
6172
+ function Da() {
6169
6173
  const k = m.current;
6170
6174
  k && k.state !== "inactive" && k.stop();
6171
6175
  }
6172
- function Da() {
6173
- A === "recording" ? Ca() : A === "idle" && Sa();
6176
+ function Aa() {
6177
+ A === "recording" ? Da() : A === "idle" && Ca();
6174
6178
  }
6175
6179
  return n ? /* @__PURE__ */ r(
6176
6180
  "div",
@@ -6224,7 +6228,7 @@ function On() {
6224
6228
  k
6225
6229
  )) })
6226
6230
  ] }),
6227
- Je.map((k, M) => /* @__PURE__ */ e(Vs, { message: k }, M)),
6231
+ Je.map((k, M) => /* @__PURE__ */ e(Ks, { message: k }, M)),
6228
6232
  /* @__PURE__ */ e("div", { ref: ee })
6229
6233
  ]
6230
6234
  }
@@ -6310,7 +6314,7 @@ function On() {
6310
6314
  /* @__PURE__ */ e(
6311
6315
  "button",
6312
6316
  {
6313
- onClick: Da,
6317
+ onClick: Aa,
6314
6318
  disabled: !De || !n || Re || Le || A === "transcribing",
6315
6319
  className: `flex h-11 w-11 shrink-0 items-center justify-center rounded-lg transition-all disabled:cursor-not-allowed disabled:opacity-40 md:h-10 md:w-10 ${A === "recording" ? "bg-rose-500/10 text-rose-600 hover:bg-rose-500/20" : "text-fg-muted hover:bg-surface-subtle hover:text-fg"}`,
6316
6320
  title: t(A === "recording" ? "chat.voiceStop" : A === "transcribing" ? "chat.voiceTranscribing" : "chat.voiceStart"),
@@ -6357,7 +6361,7 @@ function On() {
6357
6361
  }
6358
6362
  ) : /* @__PURE__ */ e("div", { className: "flex h-full items-center justify-center text-fg-muted", children: t("chat.creating") });
6359
6363
  }
6360
- function Us({ attachments: t }) {
6364
+ function Vs({ attachments: t }) {
6361
6365
  return !t || t.length === 0 ? null : /* @__PURE__ */ e("div", { className: "mt-1 flex flex-wrap gap-1.5", children: t.map((n) => {
6362
6366
  const a = T.getChatAttachmentUrl(n.id), s = n.mime_type.startsWith("image/");
6363
6367
  return /* @__PURE__ */ r(
@@ -6377,13 +6381,13 @@ function Us({ attachments: t }) {
6377
6381
  );
6378
6382
  }) });
6379
6383
  }
6380
- function Vs({ message: t }) {
6384
+ function Ks({ message: t }) {
6381
6385
  return t.type === "user" ? /* @__PURE__ */ e("div", { className: "flex justify-end", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-br-md bg-gradient-to-b from-brand to-brand/90 px-4 py-2.5 text-sm text-brand-fg ring-1 ring-black/10 shadow-bubble-user", children: [
6382
6386
  /* @__PURE__ */ e("div", { className: "whitespace-pre-wrap", children: t.content }),
6383
- /* @__PURE__ */ e(Us, { attachments: t.attachments }),
6387
+ /* @__PURE__ */ e(Vs, { attachments: t.attachments }),
6384
6388
  t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: Ln(t.timestamp), children: En(t.timestamp) })
6385
6389
  ] }) }) : t.type === "assistant" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-bl-md bg-surface px-4 py-2.5 text-sm text-fg ring-1 ring-line shadow-card", children: [
6386
- /* @__PURE__ */ e(Ks, { content: t.content }),
6390
+ /* @__PURE__ */ e(js, { content: t.content }),
6387
6391
  t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: Ln(t.timestamp), children: En(t.timestamp) })
6388
6392
  ] }) }) : t.type === "thinking" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line shadow-card", children: [
6389
6393
  /* @__PURE__ */ e("span", { className: "inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-brand" }),
@@ -6423,7 +6427,7 @@ function Vs({ message: t }) {
6423
6427
  }
6424
6428
  ) }) : t.type === "error" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ e("div", { className: "max-w-[80%] rounded-2xl rounded-bl-md bg-rose-50 px-4 py-2.5 text-sm text-rose-700 ring-1 ring-rose-200 shadow-card", children: t.content }) }) : null;
6425
6429
  }
6426
- function Ks({ content: t }) {
6430
+ function js({ content: t }) {
6427
6431
  const n = t.split(`
6428
6432
  `), a = [];
6429
6433
  let s = !1, o = [];
@@ -6467,7 +6471,7 @@ function Ks({ content: t }) {
6467
6471
  );
6468
6472
  }), /* @__PURE__ */ e("div", { children: a });
6469
6473
  }
6470
- function ya(t, n, a) {
6474
+ function ba(t, n, a) {
6471
6475
  const s = t.startsWith("/") && !t.startsWith("/api/"), o = "font-medium text-brand underline decoration-brand/40 underline-offset-2 transition-colors hover:decoration-brand";
6472
6476
  return s ? /* @__PURE__ */ e(ve, { to: t, className: o, children: n }, a) : /* @__PURE__ */ e(
6473
6477
  "a",
@@ -6481,13 +6485,13 @@ function ya(t, n, a) {
6481
6485
  a
6482
6486
  );
6483
6487
  }
6484
- const js = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
6488
+ const Gs = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
6485
6489
  function Ot(t) {
6486
6490
  return t.split(/(\[[^\]]+\]\([^)]+\)|\*\*[^*]+?\*\*|`[^`]+`)/g).flatMap((a, s) => {
6487
6491
  const o = a.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
6488
6492
  if (o) {
6489
6493
  const [, i, l] = o;
6490
- return ya(l, Ot(i), s);
6494
+ return ba(l, Ot(i), s);
6491
6495
  }
6492
6496
  return a.startsWith("**") && a.endsWith("**") && a.length > 4 ? /* @__PURE__ */ e("strong", { className: "font-semibold", children: Ot(a.slice(2, -2)) }, s) : a.startsWith("`") && a.endsWith("`") ? /* @__PURE__ */ e(
6493
6497
  "code",
@@ -6496,24 +6500,24 @@ function Ot(t) {
6496
6500
  children: a.slice(1, -1)
6497
6501
  },
6498
6502
  s
6499
- ) : Gs(a, `${s}`);
6503
+ ) : Ws(a, `${s}`);
6500
6504
  });
6501
6505
  }
6502
- function Gs(t, n) {
6506
+ function Ws(t, n) {
6503
6507
  const a = [];
6504
6508
  let s = 0, o;
6505
- const i = new RegExp(js.source, "g");
6509
+ const i = new RegExp(Gs.source, "g");
6506
6510
  let l = 0;
6507
6511
  for (; (o = i.exec(t)) !== null; ) {
6508
6512
  const c = o.index;
6509
6513
  let g = o[0], d = "";
6510
6514
  for (; g.length > 0 && /[.,;:!?]$/.test(g); )
6511
6515
  d = g.slice(-1) + d, g = g.slice(0, -1);
6512
- c > s && a.push(t.slice(s, c)), a.push(ya(g, g, `${n}-u${l}`)), d && a.push(d), s = c + o[0].length, l += 1;
6516
+ c > s && a.push(t.slice(s, c)), a.push(ba(g, g, `${n}-u${l}`)), d && a.push(d), s = c + o[0].length, l += 1;
6513
6517
  }
6514
6518
  return s < t.length && a.push(t.slice(s)), a.length > 0 ? a : [t];
6515
6519
  }
6516
- function Ws() {
6520
+ function Hs() {
6517
6521
  const t = Be(), [n] = zt(), { user: a, login: s, register: o } = st(), { t: i } = te(), l = n.get("invite") || "", [c, g] = w(l ? "register" : "login"), [d, p] = w(!1), [u, N] = w(!1), [b, x] = w([]), [f, A] = w(!0), [C, y] = w(""), [m, h] = w(""), [_, v] = w(""), [B, S] = w(""), [O, V] = w("");
6518
6522
  se(() => {
6519
6523
  a && a.role !== "public_manager" && t("/", { replace: !0 });
@@ -6613,8 +6617,8 @@ function Ws() {
6613
6617
  },
6614
6618
  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",
6615
6619
  children: [
6616
- /* @__PURE__ */ e(Qs, { provider: K }),
6617
- i("login.continueWithProvider", { provider: Hs(K) })
6620
+ /* @__PURE__ */ e(Ys, { provider: K }),
6621
+ i("login.continueWithProvider", { provider: Qs(K) })
6618
6622
  ]
6619
6623
  },
6620
6624
  K
@@ -6647,10 +6651,10 @@ function Ws() {
6647
6651
  ] }) })
6648
6652
  ] }) });
6649
6653
  }
6650
- function Hs(t) {
6654
+ function Qs(t) {
6651
6655
  return t.charAt(0).toUpperCase() + t.slice(1);
6652
6656
  }
6653
- function Qs({ provider: t }) {
6657
+ function Ys({ provider: t }) {
6654
6658
  return t === "google" ? /* @__PURE__ */ r("svg", { className: "h-4 w-4", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
6655
6659
  /* @__PURE__ */ e("path", { fill: "#EA4335", d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" }),
6656
6660
  /* @__PURE__ */ e("path", { fill: "#4285F4", d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" }),
@@ -6658,7 +6662,7 @@ function Qs({ provider: t }) {
6658
6662
  /* @__PURE__ */ e("path", { fill: "#34A853", d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" })
6659
6663
  ] }) : t === "apple" ? /* @__PURE__ */ e("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ e("path", { d: "M16.365 1.43c0 1.14-.42 2.22-1.14 3.03-.78.9-2.06 1.6-3.12 1.5-.13-1.1.42-2.28 1.08-3.03.78-.9 2.13-1.56 3.18-1.5zM20.7 17.1c-.56 1.3-.83 1.88-1.55 3.03-1 1.6-2.42 3.6-4.18 3.62-1.56.02-1.96-1.02-4.07-1-2.12.01-2.56 1.02-4.12 1.01-1.76-.02-3.1-1.82-4.1-3.42C-.3 16.9-.6 11.16 1.7 8.1c1.16-1.54 3-2.51 4.85-2.51 1.87 0 3.05 1.02 4.6 1.02 1.5 0 2.42-1.02 4.6-1.02 1.62 0 3.34.88 4.56 2.4-4.01 2.2-3.36 7.92 0 9.11z" }) }) : null;
6660
6664
  }
6661
- function Ys() {
6665
+ function Js() {
6662
6666
  const t = Be(), n = re(!1), [a, s] = w("");
6663
6667
  return se(() => {
6664
6668
  n.current || (n.current = !0, T.createChatSession().then((o) => {
@@ -6690,7 +6694,7 @@ function zn() {
6690
6694
  function Fn() {
6691
6695
  return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
6692
6696
  }
6693
- function Js() {
6697
+ function Zs() {
6694
6698
  const t = Be(), n = He(), [a, s] = w(""), [o, i] = w((/* @__PURE__ */ new Date()).toISOString().split("T")[0]), [l, c] = w(""), [g, d] = w([qn()]), [p, u] = w([zn()]), [N, b] = w([Fn()]), [x, f] = w({}), A = me({
6695
6699
  mutationFn: () => T.importAccountBalances({
6696
6700
  company: a,
@@ -6856,7 +6860,7 @@ function Js() {
6856
6860
  ] })
6857
6861
  ] });
6858
6862
  }
6859
- function Zs() {
6863
+ function Xs() {
6860
6864
  const { user: t } = st(), n = He(), { data: a, isLoading: s } = de({
6861
6865
  queryKey: ["auth-users"],
6862
6866
  queryFn: () => T.authListUsers()
@@ -7017,98 +7021,98 @@ function Zs() {
7017
7021
  ] }) })
7018
7022
  ] });
7019
7023
  }
7020
- const Xs = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, ei = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, ti = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, ni = { 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" }, ai = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, ri = { 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" } }, si = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, ii = { 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." } }, oi = { 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}}" }, li = { 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" }, ci = { 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" }, di = { 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}}." }, ui = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, mi = { 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." }, pi = { "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" }, hi = { "% 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" }, gi = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, fi = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), yi = { 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." }, bi = { 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" } }, vi = {
7021
- common: Xs,
7022
- language: ei,
7023
- header: ti,
7024
- titles: ni,
7025
- doctypes: ai,
7026
- masters: ri,
7027
- nav: si,
7028
- login: ii,
7029
- settings: oi,
7030
- status: li,
7031
- reports: ci,
7032
- masterForm: di,
7033
- dashboard: ui,
7034
- chat: mi,
7035
- conversions: pi,
7036
- fields: hi,
7037
- tables: gi,
7038
- tutorial: fi,
7039
- notesMarkup: yi,
7040
- coa: bi
7041
- }, xi = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, Ni = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, wi = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, ki = { 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" }, Si = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, Ci = { 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" } }, Di = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, Ai = { 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." } }, Pi = { 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}}" }, _i = { 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" }, Ti = { 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" }, Ri = { 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." }, Ii = { 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" }, Bi = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Ei = { "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" }, Li = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Oi = { 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." }, qi = /* @__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?"}'), zi = { 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." }, Fi = { 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" } }, Mi = {
7042
- common: xi,
7043
- language: Ni,
7044
- header: wi,
7045
- titles: ki,
7046
- doctypes: Si,
7047
- masters: Ci,
7048
- nav: Di,
7049
- login: Ai,
7050
- settings: Pi,
7051
- status: _i,
7052
- reports: Ti,
7053
- masterForm: Ri,
7054
- fields: Ii,
7055
- tables: Bi,
7056
- conversions: Ei,
7057
- dashboard: Li,
7058
- chat: Oi,
7059
- tutorial: qi,
7060
- notesMarkup: zi,
7061
- coa: Fi
7062
- }, $i = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Ui = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Vi = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Ki = { 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" }, ji = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, Gi = { 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" } }, Wi = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, Hi = { 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." } }, Qi = { 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}}" }, Yi = { 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é" }, Ji = { 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é" }, Zi = { 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}}." }, Xi = { 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é" }, eo = { 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" }, to = { "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" }, no = { 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" }, ao = { 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." }, ro = /* @__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 ?"}`), so = { 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." }, io = { 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" } }, oo = {
7063
- common: $i,
7064
- language: Ui,
7065
- header: Vi,
7066
- titles: Ki,
7067
- doctypes: ji,
7068
- masters: Gi,
7069
- nav: Wi,
7070
- login: Hi,
7071
- settings: Qi,
7072
- status: Yi,
7073
- reports: Ji,
7074
- masterForm: Zi,
7075
- fields: Xi,
7076
- tables: eo,
7077
- conversions: to,
7078
- dashboard: no,
7079
- chat: ao,
7080
- tutorial: ro,
7081
- notesMarkup: so,
7082
- coa: io
7083
- }, ba = [
7024
+ const ei = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, ti = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, ni = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, ai = { 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" }, ri = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, si = { 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" } }, ii = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, oi = { 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." } }, li = { 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}}" }, ci = { 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" }, di = { 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" }, ui = { 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}}." }, mi = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, pi = { 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." }, hi = { "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" }, gi = { "% 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" }, fi = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, yi = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), bi = { 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." }, vi = { 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" } }, xi = {
7025
+ common: ei,
7026
+ language: ti,
7027
+ header: ni,
7028
+ titles: ai,
7029
+ doctypes: ri,
7030
+ masters: si,
7031
+ nav: ii,
7032
+ login: oi,
7033
+ settings: li,
7034
+ status: ci,
7035
+ reports: di,
7036
+ masterForm: ui,
7037
+ dashboard: mi,
7038
+ chat: pi,
7039
+ conversions: hi,
7040
+ fields: gi,
7041
+ tables: fi,
7042
+ tutorial: yi,
7043
+ notesMarkup: bi,
7044
+ coa: vi
7045
+ }, Ni = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, wi = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, ki = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, Si = { 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" }, Ci = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, Di = { 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" } }, Ai = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, Pi = { 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." } }, _i = { 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}}" }, Ti = { 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" }, Ri = { 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" }, Ii = { 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." }, Bi = { 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" }, Ei = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Li = { "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" }, Oi = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, qi = { 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." }, zi = /* @__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?"}'), Fi = { 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." }, Mi = { 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" } }, $i = {
7046
+ common: Ni,
7047
+ language: wi,
7048
+ header: ki,
7049
+ titles: Si,
7050
+ doctypes: Ci,
7051
+ masters: Di,
7052
+ nav: Ai,
7053
+ login: Pi,
7054
+ settings: _i,
7055
+ status: Ti,
7056
+ reports: Ri,
7057
+ masterForm: Ii,
7058
+ fields: Bi,
7059
+ tables: Ei,
7060
+ conversions: Li,
7061
+ dashboard: Oi,
7062
+ chat: qi,
7063
+ tutorial: zi,
7064
+ notesMarkup: Fi,
7065
+ coa: Mi
7066
+ }, Ui = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Vi = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Ki = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, ji = { dashboard: "Tableau de bord", setup: "Configuration de l'entreprise", tutorial: "Premiers pas", chat: "Chat", reports: "Rapports", "trial-balance": "Balance comptable", "general-ledger": "Grand livre", "stock-balance": "Solde de stock", "profit-and-loss": "Compte de résultat", "balance-sheet": "Bilan", "ar-aging": "Balance âgée clients", "ap-aging": "Balance âgée fournisseurs", analytics: "Analyses", "chart-of-accounts": "Plan comptable" }, Gi = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, Wi = { 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" } }, Hi = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, Qi = { 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." } }, Yi = { 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}}" }, Ji = { 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é" }, Zi = { 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é" }, Xi = { 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}}." }, eo = { 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é" }, to = { 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" }, no = { "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" }, ao = { 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" }, ro = { 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." }, so = /* @__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 ?"}`), io = { 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." }, oo = { 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" } }, lo = {
7067
+ common: Ui,
7068
+ language: Vi,
7069
+ header: Ki,
7070
+ titles: ji,
7071
+ doctypes: Gi,
7072
+ masters: Wi,
7073
+ nav: Hi,
7074
+ login: Qi,
7075
+ settings: Yi,
7076
+ status: Ji,
7077
+ reports: Zi,
7078
+ masterForm: Xi,
7079
+ fields: eo,
7080
+ tables: to,
7081
+ conversions: no,
7082
+ dashboard: ao,
7083
+ chat: ro,
7084
+ tutorial: so,
7085
+ notesMarkup: io,
7086
+ coa: oo
7087
+ }, va = [
7084
7088
  { code: "en", label: "English" },
7085
7089
  { code: "de", label: "Deutsch" },
7086
7090
  { code: "fr", label: "Français" }
7087
- ], va = "lambda-erp:language";
7088
- function lo(t) {
7089
- return !!t && ba.some((n) => n.code === t);
7091
+ ], xa = "lambda-erp:language";
7092
+ function co(t) {
7093
+ return !!t && va.some((n) => n.code === t);
7090
7094
  }
7091
- function co() {
7095
+ function uo() {
7092
7096
  try {
7093
- const t = localStorage.getItem(va);
7094
- if (lo(t)) return t;
7097
+ const t = localStorage.getItem(xa);
7098
+ if (co(t)) return t;
7095
7099
  } catch {
7096
7100
  }
7097
7101
  return "en";
7098
7102
  }
7099
- function uo(t) {
7103
+ function mo(t) {
7100
7104
  try {
7101
- localStorage.setItem(va, t);
7105
+ localStorage.setItem(xa, t);
7102
7106
  } catch {
7103
7107
  }
7104
7108
  }
7105
- ea.use(La).init({
7109
+ ea.use(Oa).init({
7106
7110
  resources: {
7107
- en: { translation: vi },
7108
- de: { translation: Mi },
7109
- fr: { translation: oo }
7111
+ en: { translation: xi },
7112
+ de: { translation: $i },
7113
+ fr: { translation: lo }
7110
7114
  },
7111
- lng: co(),
7115
+ lng: uo(),
7112
7116
  fallbackLng: "en",
7113
7117
  // any key missing in de/fr falls back to the English value
7114
7118
  interpolation: { escapeValue: !1 },
@@ -7116,15 +7120,15 @@ ea.use(La).init({
7116
7120
  react: { useSuspense: !1 }
7117
7121
  // resources are bundled synchronously — no Suspense needed
7118
7122
  });
7119
- ea.on("languageChanged", uo);
7120
- function mo({ label: t }) {
7123
+ ea.on("languageChanged", mo);
7124
+ function po({ label: t }) {
7121
7125
  var o;
7122
7126
  const { t: n, i18n: a } = te(), s = ((o = a.language) == null ? void 0 : o.split("-")[0]) ?? "en";
7123
7127
  return /* @__PURE__ */ e(
7124
7128
  Ve,
7125
7129
  {
7126
7130
  label: t === null ? void 0 : t ?? n("language.label"),
7127
- options: ba.map((i) => ({ value: i.code, label: i.label })),
7131
+ options: va.map((i) => ({ value: i.code, label: i.label })),
7128
7132
  value: s,
7129
7133
  onChange: (i) => a.changeLanguage(i.target.value)
7130
7134
  }
@@ -7141,7 +7145,7 @@ const Mn = [
7141
7145
  function We(t) {
7142
7146
  return t === 0 ? "$0.00" : t < 0.01 ? `$${t.toFixed(4)}` : `$${t.toFixed(2)}`;
7143
7147
  }
7144
- function po({ demoActive: t }) {
7148
+ function ho({ demoActive: t }) {
7145
7149
  var C, y;
7146
7150
  const { t: n } = te(), [a, s] = w("1h"), { data: o, isLoading: i, isFetching: l, error: c, refetch: g, dataUpdatedAt: d } = de({
7147
7151
  queryKey: ["demo-spend"],
@@ -7325,7 +7329,7 @@ function Ct({ label: t, value: n }) {
7325
7329
  /* @__PURE__ */ e("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-gray-900", children: n })
7326
7330
  ] });
7327
7331
  }
7328
- function ho() {
7332
+ function go() {
7329
7333
  const { t } = te(), { user: n } = st(), [a, s] = w(""), [o, i] = w(""), [l, c] = w(""), [g, d] = w(""), [p, u] = w(!1), N = me({
7330
7334
  mutationFn: () => T.authChangePassword(a, o),
7331
7335
  onSuccess: () => {
@@ -7402,7 +7406,7 @@ function ho() {
7402
7406
  /* @__PURE__ */ e(J, { type: "submit", disabled: N.isPending || !a || !o || !l, children: N.isPending ? t("settings.changingPassword") : t("settings.changePassword") })
7403
7407
  ] }) });
7404
7408
  }
7405
- function go() {
7409
+ function fo() {
7406
7410
  const { t } = te(), { user: n, refreshUser: a } = st(), [s, o] = w(""), [i, l] = w(""), [c, g] = w(""), [d, p] = w(!1), u = me({
7407
7411
  mutationFn: () => T.authSetPassword(s),
7408
7412
  onSuccess: async () => {
@@ -7468,7 +7472,7 @@ function go() {
7468
7472
  ] })
7469
7473
  ] });
7470
7474
  }
7471
- function fo() {
7475
+ function yo() {
7472
7476
  const { t } = te(), { data: n } = de({
7473
7477
  queryKey: ["auth-setup-status"],
7474
7478
  queryFn: () => T.authSetupStatus()
@@ -7503,7 +7507,7 @@ function fo() {
7503
7507
  ] });
7504
7508
  }
7505
7509
  const Yt = { viewer: 1, manager: 2, admin: 3 };
7506
- function xa({ ownRole: t }) {
7510
+ function Na({ ownRole: t }) {
7507
7511
  const { t: n } = te(), { user: a } = st(), s = He(), [o, i] = w(""), [l, c] = w(t in Yt ? t : "viewer"), [g, d] = w(null), [p, u] = w(null), N = ["viewer", "manager", "admin"].filter(
7508
7512
  (v) => Yt[v] <= (Yt[t] ?? 1)
7509
7513
  ), { data: b } = de({
@@ -7683,7 +7687,7 @@ function $n({
7683
7687
  )
7684
7688
  ] });
7685
7689
  }
7686
- function yo({
7690
+ function bo({
7687
7691
  chatEnabled: t,
7688
7692
  restEnabled: n,
7689
7693
  onToggleChat: a,
@@ -7717,7 +7721,7 @@ function yo({
7717
7721
  ] }),
7718
7722
  (t || n) && /* @__PURE__ */ r("div", { className: "mt-4 border-t border-gray-100 pt-4", children: [
7719
7723
  /* @__PURE__ */ e("div", { className: "mb-2 text-xs font-medium text-gray-500", children: i("settings.chatApiKeysTitle") }),
7720
- /* @__PURE__ */ e(xa, { ownRole: o })
7724
+ /* @__PURE__ */ e(Na, { ownRole: o })
7721
7725
  ] }),
7722
7726
  l && /* @__PURE__ */ e(
7723
7727
  "div",
@@ -7755,7 +7759,7 @@ function yo({
7755
7759
  )
7756
7760
  ] });
7757
7761
  }
7758
- function bo() {
7762
+ function vo() {
7759
7763
  const { user: t } = st(), { t: n } = te(), a = He(), s = (t == null ? void 0 : t.role) === "admin", { data: o, isLoading: i } = de({
7760
7764
  queryKey: ["settings"],
7761
7765
  queryFn: () => T.getSettings()
@@ -7781,11 +7785,11 @@ function bo() {
7781
7785
  });
7782
7786
  return i ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: n("common.loading") }) : /* @__PURE__ */ r("div", { className: "space-y-6", children: [
7783
7787
  /* @__PURE__ */ r(F, { title: n("language.title"), children: [
7784
- /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(mo, {}) }) }),
7788
+ /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(po, {}) }) }),
7785
7789
  /* @__PURE__ */ e("p", { className: "mt-2 text-xs text-gray-400", children: n("language.help") })
7786
7790
  ] }),
7787
- (t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(go, {}) : /* @__PURE__ */ e(ho, {})),
7788
- (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(fo, {}),
7791
+ (t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(fo, {}) : /* @__PURE__ */ e(go, {})),
7792
+ (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(yo, {}),
7789
7793
  /* @__PURE__ */ r(F, { title: n("settings.pdfTitle"), children: [
7790
7794
  /* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: s ? /* @__PURE__ */ e(
7791
7795
  Ve,
@@ -7834,7 +7838,7 @@ function bo() {
7834
7838
  )
7835
7839
  ] }) }),
7836
7840
  s && /* @__PURE__ */ e(
7837
- yo,
7841
+ bo,
7838
7842
  {
7839
7843
  chatEnabled: (o == null ? void 0 : o.chat_api_enabled) === "1",
7840
7844
  restEnabled: (o == null ? void 0 : o.rest_api_enabled) === "1",
@@ -7849,9 +7853,9 @@ function bo() {
7849
7853
  ),
7850
7854
  !s && (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ r(F, { title: n("settings.chatApiKeysTitle"), children: [
7851
7855
  /* @__PURE__ */ e("p", { className: "mb-3 text-sm text-gray-700", children: n("settings.chatApiPersonal") }),
7852
- /* @__PURE__ */ e(xa, { ownRole: (t == null ? void 0 : t.role) ?? "viewer" })
7856
+ /* @__PURE__ */ e(Na, { ownRole: (t == null ? void 0 : t.role) ?? "viewer" })
7853
7857
  ] }),
7854
- s && /* @__PURE__ */ e(po, { demoActive: !!(c != null && c.active) }),
7858
+ s && /* @__PURE__ */ e(ho, { demoActive: !!(c != null && c.active) }),
7855
7859
  s && /* @__PURE__ */ e(F, { title: n("settings.publicTitle"), children: c != null && c.active ? /* @__PURE__ */ r("div", { children: [
7856
7860
  /* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
7857
7861
  /* @__PURE__ */ e("span", { className: "inline-block h-2 w-2 rounded-full bg-green-500" }),
@@ -7903,25 +7907,25 @@ function bo() {
7903
7907
  (g == null ? void 0 : g.version) && /* @__PURE__ */ e("p", { className: "pt-2 text-center text-xs text-gray-400", children: n("settings.version", { version: g.version }) })
7904
7908
  ] });
7905
7909
  }
7906
- const Na = {};
7907
- function jo(t, n) {
7908
- Na[t] = n;
7910
+ const wa = {};
7911
+ function Wo(t, n) {
7912
+ wa[t] = n;
7909
7913
  }
7910
- function vo(t, n) {
7911
- return Na[t] ?? n;
7914
+ function xo(t, n) {
7915
+ return wa[t] ?? n;
7912
7916
  }
7913
- function xo() {
7914
- const t = vo("Dashboard", Dr);
7917
+ function No() {
7918
+ const t = xo("Dashboard", Ar);
7915
7919
  return /* @__PURE__ */ e(t, {});
7916
7920
  }
7917
- const No = [
7918
- { path: "/login", element: /* @__PURE__ */ e(Ws, {}) },
7919
- { path: "/demo", element: /* @__PURE__ */ e(Ys, {}) }
7920
- ], wo = [
7921
- { index: !0, element: /* @__PURE__ */ e(xo, {}) },
7922
- { path: "setup", element: /* @__PURE__ */ e(Ts, {}) },
7923
- { path: "setup/opening-balances", element: /* @__PURE__ */ e(Js, {}) },
7924
- { path: "tutorial", element: /* @__PURE__ */ e(qs, {}) },
7921
+ const wo = [
7922
+ { path: "/login", element: /* @__PURE__ */ e(Hs, {}) },
7923
+ { path: "/demo", element: /* @__PURE__ */ e(Js, {}) }
7924
+ ], ko = [
7925
+ { index: !0, element: /* @__PURE__ */ e(No, {}) },
7926
+ { path: "setup", element: /* @__PURE__ */ e(Rs, {}) },
7927
+ { path: "setup/opening-balances", element: /* @__PURE__ */ e(Zs, {}) },
7928
+ { path: "tutorial", element: /* @__PURE__ */ e(zs, {}) },
7925
7929
  { path: "chat", element: /* @__PURE__ */ e(On, {}) },
7926
7930
  { path: "chat/:sessionId", element: /* @__PURE__ */ e(On, {}) },
7927
7931
  // Proposal (Sammelofferte) — a custom builder; the list reuses the generic
@@ -7930,29 +7934,29 @@ const No = [
7930
7934
  { path: "app/proposal/new", element: /* @__PURE__ */ e(Pn, {}) },
7931
7935
  { path: "app/proposal/:name", element: /* @__PURE__ */ e(Pn, {}) },
7932
7936
  // Documents
7933
- { path: "app/:doctype", element: /* @__PURE__ */ e(Wr, {}) },
7937
+ { path: "app/:doctype", element: /* @__PURE__ */ e(Hr, {}) },
7934
7938
  { path: "app/:doctype/new", element: /* @__PURE__ */ e(Sn, {}) },
7935
7939
  { path: "app/:doctype/:name", element: /* @__PURE__ */ e(Sn, {}) },
7936
7940
  // Masters (reuse same routes - the components detect whether it's a doctype or master)
7937
- { path: "masters/:type", element: /* @__PURE__ */ e(Yr, {}) },
7941
+ { path: "masters/:type", element: /* @__PURE__ */ e(Jr, {}) },
7938
7942
  { path: "masters/:type/new", element: /* @__PURE__ */ e(Tn, {}) },
7939
7943
  { path: "masters/:type/:name", element: /* @__PURE__ */ e(Tn, {}) },
7940
7944
  // Reports
7941
- { path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(cs, {}) },
7942
- { path: "reports/trial-balance", element: /* @__PURE__ */ e(os, {}) },
7943
- { path: "reports/general-ledger", element: /* @__PURE__ */ e(ms, {}) },
7944
- { path: "reports/stock-balance", element: /* @__PURE__ */ e(ps, {}) },
7945
- { path: "reports/profit-and-loss", element: /* @__PURE__ */ e(hs, {}) },
7946
- { path: "reports/balance-sheet", element: /* @__PURE__ */ e(gs, {}) },
7947
- { path: "reports/ar-aging", element: /* @__PURE__ */ e(fs, {}) },
7948
- { path: "reports/ap-aging", element: /* @__PURE__ */ e(ys, {}) },
7949
- { path: "reports/analytics", element: /* @__PURE__ */ e(xs, {}) },
7945
+ { path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(ds, {}) },
7946
+ { path: "reports/trial-balance", element: /* @__PURE__ */ e(ls, {}) },
7947
+ { path: "reports/general-ledger", element: /* @__PURE__ */ e(ps, {}) },
7948
+ { path: "reports/stock-balance", element: /* @__PURE__ */ e(hs, {}) },
7949
+ { path: "reports/profit-and-loss", element: /* @__PURE__ */ e(gs, {}) },
7950
+ { path: "reports/balance-sheet", element: /* @__PURE__ */ e(fs, {}) },
7951
+ { path: "reports/ar-aging", element: /* @__PURE__ */ e(ys, {}) },
7952
+ { path: "reports/ap-aging", element: /* @__PURE__ */ e(bs, {}) },
7953
+ { path: "reports/analytics", element: /* @__PURE__ */ e(Ns, {}) },
7950
7954
  // Admin
7951
- { path: "admin/users", element: /* @__PURE__ */ e(Zs, {}) },
7952
- { path: "admin/settings", element: /* @__PURE__ */ e(bo, {}) }
7953
- ], wa = [], ka = [];
7954
- function ko(t, n) {
7955
- (n == null ? void 0 : n.area) === "top" ? wa.push(t) : ka.push(t);
7955
+ { path: "admin/users", element: /* @__PURE__ */ e(Xs, {}) },
7956
+ { path: "admin/settings", element: /* @__PURE__ */ e(vo, {}) }
7957
+ ], ka = [], Sa = [];
7958
+ function So(t, n) {
7959
+ (n == null ? void 0 : n.area) === "top" ? ka.push(t) : Sa.push(t);
7956
7960
  }
7957
7961
  const Un = (t) => t.index ? "__index__" : t.path ?? "";
7958
7962
  function Vn(t, n) {
@@ -7963,17 +7967,17 @@ function Vn(t, n) {
7963
7967
  }
7964
7968
  return a;
7965
7969
  }
7966
- function So() {
7970
+ function Co() {
7967
7971
  return [
7968
- ...Vn(No, wa),
7972
+ ...Vn(wo, ka),
7969
7973
  {
7970
7974
  path: "/",
7971
- element: /* @__PURE__ */ e(Nr, { children: /* @__PURE__ */ e(vr, {}) }),
7972
- children: Vn(wo, ka)
7975
+ element: /* @__PURE__ */ e(wr, { children: /* @__PURE__ */ e(xr, {}) }),
7976
+ children: Vn(ko, Sa)
7973
7977
  }
7974
7978
  ];
7975
7979
  }
7976
- function Co({ slug: t, parentSlug: n, linkField: a }) {
7980
+ function Do({ slug: t, parentSlug: n, linkField: a }) {
7977
7981
  const { name: s = "" } = ut(), o = Be();
7978
7982
  return se(() => {
7979
7983
  let i = !0;
@@ -7988,7 +7992,7 @@ function Co({ slug: t, parentSlug: n, linkField: a }) {
7988
7992
  };
7989
7993
  }, [t, s, n, a, o]), /* @__PURE__ */ e("div", { className: "p-6 text-sm text-fg-muted", children: "…" });
7990
7994
  }
7991
- async function Do() {
7995
+ async function Ao() {
7992
7996
  try {
7993
7997
  const t = await L(
7994
7998
  "/chat-doctypes",
@@ -7996,59 +8000,61 @@ async function Do() {
7996
8000
  );
7997
8001
  for (const n of t.doctypes || []) {
7998
8002
  const a = n.page;
7999
- a && a.kind === "via" && ko({
8003
+ a && a.kind === "via" && So({
8000
8004
  path: `app/${n.slug}/:name`,
8001
- element: /* @__PURE__ */ e(Co, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
8005
+ element: /* @__PURE__ */ e(Do, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
8002
8006
  });
8003
8007
  }
8004
8008
  } catch {
8005
8009
  }
8006
8010
  }
8007
- function Ao() {
8008
- return new Ta({
8011
+ function Po() {
8012
+ return new Ra({
8009
8013
  defaultOptions: {
8010
8014
  queries: { retry: 1, refetchOnWindowFocus: !1 }
8011
8015
  }
8012
8016
  });
8013
8017
  }
8014
- async function Go(t = {}) {
8018
+ async function Ho(t = {}) {
8015
8019
  const n = t.rootElement ?? document.getElementById("root");
8016
8020
  if (!n)
8017
8021
  throw new Error('bootstrap: no mount element (pass rootElement or add <div id="root">)');
8018
- const a = t.queryClient ?? Ao();
8019
- await Do();
8020
- const s = Ba(So());
8021
- Pa(n).render(
8022
- /* @__PURE__ */ e(Aa, { children: /* @__PURE__ */ e(_a, { client: a, children: /* @__PURE__ */ e(ir, { children: /* @__PURE__ */ e(Ea, { router: s }) }) }) })
8022
+ const a = t.queryClient ?? Po();
8023
+ await Ao();
8024
+ const s = Ea(Co());
8025
+ _a(n).render(
8026
+ /* @__PURE__ */ e(Pa, { children: /* @__PURE__ */ e(Ta, { client: a, children: /* @__PURE__ */ e(or, { children: /* @__PURE__ */ e(La, { router: s }) }) }) })
8023
8027
  );
8024
8028
  }
8025
8029
  export {
8026
8030
  Ue as ApiError,
8027
- vr as AppShell,
8028
- ir as AuthProvider,
8029
- ua as DocPager,
8030
- ba as SUPPORTED_LANGUAGES,
8031
+ xr as AppShell,
8032
+ or as AuthProvider,
8033
+ ma as DocPager,
8034
+ va as SUPPORTED_LANGUAGES,
8031
8035
  T as api,
8032
- Go as bootstrap,
8033
- So as buildRoutes,
8034
- Fo as configureApiBase,
8035
- Uo as configureBranding,
8036
- Ao as createAppQueryClient,
8037
- Ko as getAllDoctypeConfigs,
8038
- ur as getBranding,
8039
- vo as getComponent,
8040
- da as getDoctypeConfig,
8041
- Ar as getListContext,
8042
- dr as getNavGroups,
8043
- co as getStoredLanguage,
8044
- Qo as i18n,
8045
- jo as registerComponent,
8046
- Vo as registerDoctype,
8047
- Mo as registerNavGroup,
8048
- $o as registerNavItem,
8049
- ko as registerRoute,
8036
+ Ho as bootstrap,
8037
+ Co as buildRoutes,
8038
+ Mo as configureApiBase,
8039
+ Vo as configureBranding,
8040
+ Po as createAppQueryClient,
8041
+ Mt as formatDate,
8042
+ Go as getAllDoctypeConfigs,
8043
+ mr as getBranding,
8044
+ xo as getComponent,
8045
+ ua as getDoctypeConfig,
8046
+ Pr as getListContext,
8047
+ ur as getNavGroups,
8048
+ uo as getStoredLanguage,
8049
+ Jo as i18n,
8050
+ Wo as registerComponent,
8051
+ jo as registerDoctype,
8052
+ $o as registerNavGroup,
8053
+ Uo as registerNavItem,
8054
+ So as registerRoute,
8050
8055
  L as request,
8051
- ca as setListContext,
8056
+ Ko as setDateLocale,
8057
+ da as setListContext,
8052
8058
  st as useAuth
8053
8059
  };
8054
8060
  //# sourceMappingURL=index.js.map