@lambda-development/erp-core 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -3,15 +3,15 @@ import { useState as w, useEffect as ce, useCallback as Ue, useContext as Sn, cr
|
|
|
3
3
|
import { createRoot as Pr } from "react-dom/client";
|
|
4
4
|
import { useQueryClient as et, useQuery as ve, useMutation as ke, QueryClientProvider as Tr, QueryClient as Rr } from "@tanstack/react-query";
|
|
5
5
|
import { NavLink as Yt, useLocation as Ct, useNavigate as Ke, Outlet as Br, Navigate as Bt, Link as Ce, useSearchParams as Jt, useParams as bt, createBrowserRouter as Ir, RouterProvider as Er } from "react-router-dom";
|
|
6
|
-
import { useTranslation as
|
|
6
|
+
import { useTranslation as re, initReactI18next as Lr } from "react-i18next";
|
|
7
7
|
import { BookOpen as Or, ShoppingCart as _a, CreditCard as Fr, FileText as _n, Package as Da, BarChart3 as Mr, CalendarRange as qr, Database as zr, Settings as $r, MessageCircle as Vr, ChevronDown as St, ChevronRight as It, Plus as Pa, Trash2 as Ta, LineChart as Ur, ArrowLeft as Kr, TrendingUp as jr, ArrowDownRight as Wr, ArrowUpRight as Gr, Wallet as Hr, Receipt as zn, ChevronLeft as Qr, Info as Yr, Search as $n, Filter as Jr, X as Zr, SlidersHorizontal as Ra, ChevronUp as Ba, ChevronsUpDown as Ia, FileUp as Xr, Loader2 as yn, CheckCircle2 as bn, AlertTriangle as es, RefreshCw as ts, Undo2 as ns } from "lucide-react";
|
|
8
8
|
import { createColumnHelper as Ea, useReactTable as La, getCoreRowModel as Oa, flexRender as Wt } from "@tanstack/react-table";
|
|
9
9
|
import { createPortal as Fa } from "react-dom";
|
|
10
10
|
import { ResponsiveContainer as as, LineChart as rs, CartesianGrid as Vn, XAxis as Un, YAxis as Kn, Tooltip as an, Legend as jn, Line as ss, PieChart as is, Pie as os, Cell as ls, BarChart as cs, Bar as ds } from "recharts";
|
|
11
11
|
import Ma from "i18next";
|
|
12
|
-
import { default as
|
|
12
|
+
import { default as Qc } from "i18next";
|
|
13
13
|
let ot = "/api";
|
|
14
|
-
function
|
|
14
|
+
function Lc(e) {
|
|
15
15
|
ot = e.replace(/\/+$/, "");
|
|
16
16
|
}
|
|
17
17
|
function qa(e) {
|
|
@@ -415,7 +415,7 @@ function ut(e) {
|
|
|
415
415
|
return Number.isNaN(a) ? 0 : a;
|
|
416
416
|
}
|
|
417
417
|
function hs({ children: e }) {
|
|
418
|
-
const n = et(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [h, d] = w({}), [g, m] = w({}), [b, v] = w({}), [k, y] = w({}), [A, S] = w({}), [x, p] = w(null), [f, B] = w("connecting"), [E, J] = w(0), Z = pe(null),
|
|
418
|
+
const n = et(), [a, s] = w([]), [o, i] = w({}), [l, c] = w({}), [h, d] = w({}), [g, m] = w({}), [b, v] = w({}), [k, y] = w({}), [A, S] = w({}), [x, p] = w(null), [f, B] = w("connecting"), [E, J] = w(0), Z = pe(null), L = pe(null), q = pe(/* @__PURE__ */ new Map()), Q = pe(null), N = pe({}), D = pe({}), $ = pe(null);
|
|
419
419
|
function u(C) {
|
|
420
420
|
for (const j of q.current.values())
|
|
421
421
|
j.reject(new Error(C));
|
|
@@ -450,7 +450,7 @@ function hs({ children: e }) {
|
|
|
450
450
|
function Ne(C) {
|
|
451
451
|
s((j) => ue(C(j)));
|
|
452
452
|
}
|
|
453
|
-
function
|
|
453
|
+
function be(C, j) {
|
|
454
454
|
const G = j || (/* @__PURE__ */ new Date()).toISOString(), ye = N.current[C];
|
|
455
455
|
ut(G) >= ut(ye) && (N.current = {
|
|
456
456
|
...N.current,
|
|
@@ -499,13 +499,13 @@ function hs({ children: e }) {
|
|
|
499
499
|
}, we.onmessage = ($e) => {
|
|
500
500
|
var Te;
|
|
501
501
|
try {
|
|
502
|
-
const
|
|
502
|
+
const se = JSON.parse($e.data), gt = typeof se.request_id == "string" ? se.request_id : null, Le = typeof se.type == "string" ? se.type : null, X = typeof se.session_id == "string" ? se.session_id : null;
|
|
503
503
|
if (gt) {
|
|
504
504
|
const ee = q.current.get(gt);
|
|
505
|
-
ee && (Le === "error" ? (q.current.delete(gt), ee.reject(new Error(String(
|
|
505
|
+
ee && (Le === "error" ? (q.current.delete(gt), ee.reject(new Error(String(se.content || "Request failed.")))) : Le === ee.expectedType && (q.current.delete(gt), ee.resolve(se)));
|
|
506
506
|
}
|
|
507
507
|
if (Le === "sessions_list") {
|
|
508
|
-
const ee = Array.isArray(
|
|
508
|
+
const ee = Array.isArray(se.sessions) ? se.sessions : [];
|
|
509
509
|
qe(ee), s(
|
|
510
510
|
ue(
|
|
511
511
|
ee
|
|
@@ -531,7 +531,7 @@ function hs({ children: e }) {
|
|
|
531
531
|
return;
|
|
532
532
|
}
|
|
533
533
|
if (Le === "session_created") {
|
|
534
|
-
const ee =
|
|
534
|
+
const ee = se.session;
|
|
535
535
|
if (!ee) return;
|
|
536
536
|
ja(ee.id), qe([ee]), Ne((ie) => [ee, ...ie.filter((de) => de.id !== ee.id)]);
|
|
537
537
|
return;
|
|
@@ -564,7 +564,7 @@ function hs({ children: e }) {
|
|
|
564
564
|
return;
|
|
565
565
|
}
|
|
566
566
|
if (Le === "history_loaded" && X) {
|
|
567
|
-
const ee = Array.isArray(
|
|
567
|
+
const ee = Array.isArray(se.messages) ? se.messages.map(Qn) : [], ie = se.before_id != null, de = !!se.has_more, Je = typeof se.oldest_id == "number" ? se.oldest_id : null;
|
|
568
568
|
i((Se) => {
|
|
569
569
|
if (ie) {
|
|
570
570
|
const Oe = Se[X] ?? [], At = new Set(
|
|
@@ -576,12 +576,12 @@ function hs({ children: e }) {
|
|
|
576
576
|
}
|
|
577
577
|
return { ...Se, [X]: ee };
|
|
578
578
|
}), c((Se) => ({ ...Se, [X]: de })), d((Se) => ({ ...Se, [X]: Je })), m((Se) => ({ ...Se, [X]: !1 }));
|
|
579
|
-
const Ve = typeof
|
|
579
|
+
const Ve = typeof se.title == "string" ? se.title : null;
|
|
580
580
|
if (Ve && Ne(
|
|
581
581
|
(Se) => Se.map((Oe) => Oe.id === X ? { ...Oe, title: Ve } : Oe)
|
|
582
582
|
), !ie) {
|
|
583
583
|
const Se = ee[ee.length - 1];
|
|
584
|
-
Se != null && Se.timestamp && (
|
|
584
|
+
Se != null && Se.timestamp && (be(X, Se.timestamp), Ne((Oe) => Oe));
|
|
585
585
|
}
|
|
586
586
|
return;
|
|
587
587
|
}
|
|
@@ -590,9 +590,9 @@ function hs({ children: e }) {
|
|
|
590
590
|
return;
|
|
591
591
|
}
|
|
592
592
|
if (Le === "message_added" && X) {
|
|
593
|
-
const ee =
|
|
593
|
+
const ee = se.message;
|
|
594
594
|
if (!ee) return;
|
|
595
|
-
|
|
595
|
+
be(X, ee.created_at), ee.role === "user" && W(X, null), P(X, (ie) => [
|
|
596
596
|
...ie.filter((de) => de.type !== "thinking"),
|
|
597
597
|
Qn(ee)
|
|
598
598
|
]), Ne((ie) => ie);
|
|
@@ -604,9 +604,9 @@ function hs({ children: e }) {
|
|
|
604
604
|
}
|
|
605
605
|
if (Le === "demo_typing" && X) {
|
|
606
606
|
T(X, "running"), W(X, {
|
|
607
|
-
content: String(
|
|
608
|
-
seq: Math.max(0, Number(
|
|
609
|
-
typingMs: Math.max(0, Number(
|
|
607
|
+
content: String(se.content || ""),
|
|
608
|
+
seq: Math.max(0, Number(se.seq || 0)),
|
|
609
|
+
typingMs: Math.max(0, Number(se.typing_ms || 0))
|
|
610
610
|
});
|
|
611
611
|
return;
|
|
612
612
|
}
|
|
@@ -615,12 +615,12 @@ function hs({ children: e }) {
|
|
|
615
615
|
return;
|
|
616
616
|
}
|
|
617
617
|
if (Le === "navigation_flash") {
|
|
618
|
-
const ee = typeof
|
|
618
|
+
const ee = typeof se.group == "string" ? se.group : "", ie = typeof se.item == "string" ? se.item : void 0;
|
|
619
619
|
ee && le(ee, ie);
|
|
620
620
|
return;
|
|
621
621
|
}
|
|
622
622
|
if (Le === "session_title_updated" && X) {
|
|
623
|
-
const ee = typeof
|
|
623
|
+
const ee = typeof se.title == "string" ? se.title : "";
|
|
624
624
|
Ne(
|
|
625
625
|
(ie) => ie.map((de) => de.id === X ? { ...de, title: ee } : de)
|
|
626
626
|
);
|
|
@@ -633,7 +633,7 @@ function hs({ children: e }) {
|
|
|
633
633
|
...ee.filter((de) => de.type !== "thinking"),
|
|
634
634
|
{
|
|
635
635
|
type: "thinking",
|
|
636
|
-
content: `Thinking (step ${
|
|
636
|
+
content: `Thinking (step ${se.iteration})...`,
|
|
637
637
|
provider: ie == null ? void 0 : ie.provider,
|
|
638
638
|
model: ie == null ? void 0 : ie.model
|
|
639
639
|
}
|
|
@@ -642,7 +642,7 @@ function hs({ children: e }) {
|
|
|
642
642
|
return;
|
|
643
643
|
}
|
|
644
644
|
if (Le === "llm_provider" && X) {
|
|
645
|
-
const ee = typeof
|
|
645
|
+
const ee = typeof se.provider == "string" ? se.provider : void 0, ie = typeof se.model == "string" ? se.model : void 0, de = typeof se.role == "string" ? se.role : void 0, Je = de === "report_specialist" || de === "code_specialist" ? "Delegating to report specialist..." : void 0;
|
|
646
646
|
V(X, !0), P(X, (Ve) => Ve.some((Oe) => Oe.type === "thinking") ? Ve.map((Oe) => Oe.type === "thinking" ? {
|
|
647
647
|
...Oe,
|
|
648
648
|
provider: ee,
|
|
@@ -663,25 +663,25 @@ function hs({ children: e }) {
|
|
|
663
663
|
D.current = {
|
|
664
664
|
...D.current,
|
|
665
665
|
[X]: {
|
|
666
|
-
tool: String(
|
|
667
|
-
args:
|
|
666
|
+
tool: String(se.tool || ""),
|
|
667
|
+
args: se.args
|
|
668
668
|
}
|
|
669
669
|
}, P(X, (ee) => [
|
|
670
670
|
...ee.filter((ie) => ie.type !== "thinking"),
|
|
671
671
|
{
|
|
672
672
|
type: "tool_call",
|
|
673
|
-
content: `Calling ${
|
|
674
|
-
tool:
|
|
675
|
-
args:
|
|
673
|
+
content: `Calling ${se.tool}...`,
|
|
674
|
+
tool: se.tool,
|
|
675
|
+
args: se.args
|
|
676
676
|
}
|
|
677
677
|
]);
|
|
678
678
|
return;
|
|
679
679
|
}
|
|
680
680
|
if (Le === "tool_result" && X) {
|
|
681
681
|
const ee = D.current[X];
|
|
682
|
-
if (ee && ee.tool === String(
|
|
682
|
+
if (ee && ee.tool === String(se.tool || "") && se.success)
|
|
683
683
|
if (ee.tool === "create_custom_analytics_report" || ee.tool === "update_custom_analytics_report") {
|
|
684
|
-
const de = typeof
|
|
684
|
+
const de = typeof se.report_id == "string" ? se.report_id : void 0, Je = typeof ((Te = ee.args) == null ? void 0 : Te.report_id) == "string" ? ee.args.report_id : void 0;
|
|
685
685
|
le("Custom Analytics", de || Je || ""), n.invalidateQueries({ queryKey: ["runtime-drafts"] });
|
|
686
686
|
} else {
|
|
687
687
|
const de = ms(ee.tool, ee.args);
|
|
@@ -694,9 +694,9 @@ function hs({ children: e }) {
|
|
|
694
694
|
...ie,
|
|
695
695
|
{
|
|
696
696
|
type: "tool_result",
|
|
697
|
-
content: String(
|
|
698
|
-
tool:
|
|
699
|
-
success: !!
|
|
697
|
+
content: String(se.summary || ""),
|
|
698
|
+
tool: se.tool,
|
|
699
|
+
success: !!se.success
|
|
700
700
|
}
|
|
701
701
|
]);
|
|
702
702
|
return;
|
|
@@ -710,7 +710,7 @@ function hs({ children: e }) {
|
|
|
710
710
|
return;
|
|
711
711
|
X && (V(X, !1), P(X, (ee) => [
|
|
712
712
|
...ee.filter((ie) => ie.type !== "thinking"),
|
|
713
|
-
{ type: "error", content: String(
|
|
713
|
+
{ type: "error", content: String(se.content || "Chat error.") }
|
|
714
714
|
]));
|
|
715
715
|
}
|
|
716
716
|
} catch {
|
|
@@ -723,18 +723,18 @@ function hs({ children: e }) {
|
|
|
723
723
|
window.location.href = "/login";
|
|
724
724
|
return;
|
|
725
725
|
}
|
|
726
|
-
|
|
726
|
+
L.current = window.setTimeout(j, 3e3);
|
|
727
727
|
}
|
|
728
728
|
};
|
|
729
729
|
}
|
|
730
730
|
return j(), () => {
|
|
731
|
-
if (C = !0,
|
|
731
|
+
if (C = !0, L.current !== null && window.clearTimeout(L.current), $.current !== null && window.clearTimeout($.current), u("Chat disconnected."), Z.current) {
|
|
732
732
|
const G = Z.current;
|
|
733
733
|
Z.current = null, G.close();
|
|
734
734
|
}
|
|
735
735
|
};
|
|
736
736
|
}, []);
|
|
737
|
-
async function
|
|
737
|
+
async function xe() {
|
|
738
738
|
if (Q.current)
|
|
739
739
|
return Q.current;
|
|
740
740
|
const C = ae("create_session", {}, "session_created").then((j) => j.session).finally(() => {
|
|
@@ -742,7 +742,7 @@ function hs({ children: e }) {
|
|
|
742
742
|
});
|
|
743
743
|
return Q.current = C, C;
|
|
744
744
|
}
|
|
745
|
-
async function
|
|
745
|
+
async function O(C) {
|
|
746
746
|
T(C, "running"), W(C, null);
|
|
747
747
|
try {
|
|
748
748
|
await ae("start_demo", { session_id: C }, "demo_started");
|
|
@@ -832,8 +832,8 @@ function hs({ children: e }) {
|
|
|
832
832
|
connectionStatus: f,
|
|
833
833
|
connectionVersion: E,
|
|
834
834
|
navigationFlash: x,
|
|
835
|
-
createSession:
|
|
836
|
-
startDemo:
|
|
835
|
+
createSession: xe,
|
|
836
|
+
startDemo: O,
|
|
837
837
|
completeDemoTyping: oe,
|
|
838
838
|
deleteSession: Ie,
|
|
839
839
|
loadHistory: Ae,
|
|
@@ -875,7 +875,7 @@ function vn(e, n = 2) {
|
|
|
875
875
|
}).format(e ?? 0);
|
|
876
876
|
}
|
|
877
877
|
let Pn;
|
|
878
|
-
function
|
|
878
|
+
function Oc(e) {
|
|
879
879
|
Pn = e;
|
|
880
880
|
}
|
|
881
881
|
function De(e = /* @__PURE__ */ new Date()) {
|
|
@@ -998,7 +998,7 @@ function me({ label: e, hint: n, error: a, className: s, id: o, ...i }) {
|
|
|
998
998
|
}
|
|
999
999
|
const Ga = An(null);
|
|
1000
1000
|
function ys({ children: e }) {
|
|
1001
|
-
const { t: n } =
|
|
1001
|
+
const { t: n } = re(), [a, s] = w(null), [o, i] = w(""), l = Ue(
|
|
1002
1002
|
(b) => new Promise((v) => s({ kind: "confirm", opts: b, resolve: v })),
|
|
1003
1003
|
[]
|
|
1004
1004
|
), c = Ue(
|
|
@@ -1160,7 +1160,7 @@ const yt = [
|
|
|
1160
1160
|
function vs() {
|
|
1161
1161
|
return yt;
|
|
1162
1162
|
}
|
|
1163
|
-
function
|
|
1163
|
+
function Fc(e, n) {
|
|
1164
1164
|
const a = yt.findIndex((s) => s.label === e.label);
|
|
1165
1165
|
if (a >= 0) {
|
|
1166
1166
|
yt[a] = e;
|
|
@@ -1168,12 +1168,12 @@ function Ic(e, n) {
|
|
|
1168
1168
|
}
|
|
1169
1169
|
(n == null ? void 0 : n.index) != null ? yt.splice(n.index, 0, e) : yt.push(e);
|
|
1170
1170
|
}
|
|
1171
|
-
function
|
|
1171
|
+
function Mc(e, n) {
|
|
1172
1172
|
const a = yt.find((s) => s.label === e);
|
|
1173
1173
|
a ? a.items.push(n) : yt.push({ label: e, icon: null, items: [n] });
|
|
1174
1174
|
}
|
|
1175
1175
|
let xn = { appName: "Lambda ERP" };
|
|
1176
|
-
function
|
|
1176
|
+
function qc(e) {
|
|
1177
1177
|
if (xn = { ...xn, ...e }, !(typeof document > "u") && (e.appName && (document.title = e.appName), e.tokens)) {
|
|
1178
1178
|
const n = document.documentElement;
|
|
1179
1179
|
for (const [a, s] of Object.entries(e.tokens))
|
|
@@ -1222,7 +1222,7 @@ const Bn = {
|
|
|
1222
1222
|
"Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
|
|
1223
1223
|
};
|
|
1224
1224
|
function xs() {
|
|
1225
|
-
const [e, n] = Rn("chats"), a = Ct(), s = Ke(), { t: o } =
|
|
1225
|
+
const [e, n] = Rn("chats"), a = Ct(), s = Ke(), { t: o } = re(), { sessions: i, createSession: l, deleteSession: c } = vt(), h = async () => {
|
|
1226
1226
|
try {
|
|
1227
1227
|
const g = await l();
|
|
1228
1228
|
s(`/chat/${g.id}`);
|
|
@@ -1300,7 +1300,7 @@ function In() {
|
|
|
1300
1300
|
);
|
|
1301
1301
|
}
|
|
1302
1302
|
function ks() {
|
|
1303
|
-
const [e, n, a] = Rn("custom-analytics"), s = Ct(), o = Ke(), i = et(), { t: l } =
|
|
1303
|
+
const [e, n, a] = Rn("custom-analytics"), s = Ct(), o = Ke(), i = et(), { t: l } = re(), { navigationFlash: c, sessions: h, createSession: d } = vt(), g = (c == null ? void 0 : c.group) === "Custom Analytics", m = Bn["Custom Analytics"], { data: b } = ve({
|
|
1304
1304
|
queryKey: ["runtime-drafts"],
|
|
1305
1305
|
queryFn: () => F.listRuntimeDrafts(),
|
|
1306
1306
|
staleTime: 3e4
|
|
@@ -1390,7 +1390,7 @@ function ks() {
|
|
|
1390
1390
|
] });
|
|
1391
1391
|
}
|
|
1392
1392
|
function Ns({ group: e }) {
|
|
1393
|
-
const [n, a] = Rn(e.label), { t: s } =
|
|
1393
|
+
const [n, a] = Rn(e.label), { t: s } = re(), { navigationFlash: o } = vt(), i = (o == null ? void 0 : o.group) === e.label, l = Bn[e.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
|
|
1394
1394
|
return /* @__PURE__ */ r("div", { children: [
|
|
1395
1395
|
/* @__PURE__ */ r(
|
|
1396
1396
|
"button",
|
|
@@ -1568,7 +1568,7 @@ function _s() {
|
|
|
1568
1568
|
return /* @__PURE__ */ t(ys, { children: /* @__PURE__ */ t(hs, { children: /* @__PURE__ */ t(Ds, {}) }) });
|
|
1569
1569
|
}
|
|
1570
1570
|
function Ds() {
|
|
1571
|
-
const { pathname: e } = Ct(), n = Ke(), { user: a, logout: s } = Ze(), { navigationFlash: o } = vt(), { t: i, i18n: l } =
|
|
1571
|
+
const { pathname: e } = Ct(), n = Ke(), { user: a, logout: s } = Ze(), { navigationFlash: o } = vt(), { t: i, i18n: l } = re(), { settings: c } = Zt();
|
|
1572
1572
|
ce(() => {
|
|
1573
1573
|
const k = c.language;
|
|
1574
1574
|
k && k !== (l.language || "").split("-")[0] && l.changeLanguage(k);
|
|
@@ -1718,7 +1718,7 @@ const Bs = {
|
|
|
1718
1718
|
Overdue: "danger"
|
|
1719
1719
|
};
|
|
1720
1720
|
function En({ status: e }) {
|
|
1721
|
-
const { t: n } =
|
|
1721
|
+
const { t: n } = re(), a = Bs[e] ?? "secondary";
|
|
1722
1722
|
return /* @__PURE__ */ t(Ut, { variant: a, children: n(`status.${e}`, { defaultValue: e }) });
|
|
1723
1723
|
}
|
|
1724
1724
|
function Qe(e) {
|
|
@@ -1763,7 +1763,7 @@ const Is = {
|
|
|
1763
1763
|
Quotation: _n
|
|
1764
1764
|
};
|
|
1765
1765
|
function Es({ doc: e }) {
|
|
1766
|
-
const { t: n } =
|
|
1766
|
+
const { t: n } = re(), a = e.doctype ?? e.type ?? "Document", s = e.creation ?? e.date, o = Is[a] ?? _n, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(e.name)}`;
|
|
1767
1767
|
return /* @__PURE__ */ r(
|
|
1768
1768
|
Ce,
|
|
1769
1769
|
{
|
|
@@ -1793,7 +1793,7 @@ function Dt() {
|
|
|
1793
1793
|
] });
|
|
1794
1794
|
}
|
|
1795
1795
|
function Ls() {
|
|
1796
|
-
const { t: e } =
|
|
1796
|
+
const { t: e } = re();
|
|
1797
1797
|
Me(e("titles.dashboard"));
|
|
1798
1798
|
const { data: n, isLoading: a } = ve({
|
|
1799
1799
|
queryKey: ["dashboard-summary"],
|
|
@@ -2716,15 +2716,15 @@ const ht = [
|
|
|
2716
2716
|
function er(e) {
|
|
2717
2717
|
return Ln[e];
|
|
2718
2718
|
}
|
|
2719
|
-
function
|
|
2719
|
+
function zc(e) {
|
|
2720
2720
|
Ln[e.slug] = e;
|
|
2721
2721
|
}
|
|
2722
|
-
function
|
|
2722
|
+
function $c() {
|
|
2723
2723
|
return Object.values(Ln);
|
|
2724
2724
|
}
|
|
2725
2725
|
function tr({ doctype: e, name: n }) {
|
|
2726
2726
|
var d;
|
|
2727
|
-
const { t: a } =
|
|
2727
|
+
const { t: a } = re(), [s, o] = w(null), [i, l] = w(!1), { data: c } = ve({
|
|
2728
2728
|
queryKey: ["document-fields", e],
|
|
2729
2729
|
queryFn: () => F.documentFields(e)
|
|
2730
2730
|
});
|
|
@@ -2852,7 +2852,7 @@ function qs({ text: e }) {
|
|
|
2852
2852
|
] });
|
|
2853
2853
|
}
|
|
2854
2854
|
function zs() {
|
|
2855
|
-
const { t: e } =
|
|
2855
|
+
const { t: e } = re(), [n, a] = w(!1), s = [
|
|
2856
2856
|
["# Heading", e("notesMarkup.heading", { defaultValue: "bold heading" })],
|
|
2857
2857
|
["*italic* **bold**", e("notesMarkup.emphasis", { defaultValue: "italic / bold" })],
|
|
2858
2858
|
["---", e("notesMarkup.rule", { defaultValue: "horizontal divider line" })],
|
|
@@ -2995,7 +2995,7 @@ function Kt({
|
|
|
2995
2995
|
doctype: c
|
|
2996
2996
|
}) {
|
|
2997
2997
|
var y;
|
|
2998
|
-
const { t: h } =
|
|
2998
|
+
const { t: h } = re(), d = s || !!e.readOnly, g = () => i ? null : /* @__PURE__ */ t(
|
|
2999
2999
|
ea,
|
|
3000
3000
|
{
|
|
3001
3001
|
label: h(`fields.${e.label}`, { defaultValue: e.label }),
|
|
@@ -3114,7 +3114,7 @@ function Ks({
|
|
|
3114
3114
|
readOnly: s,
|
|
3115
3115
|
currency: o = "USD"
|
|
3116
3116
|
}) {
|
|
3117
|
-
const { t: i } =
|
|
3117
|
+
const { t: i } = re(), l = (d, g, m) => {
|
|
3118
3118
|
const b = n.map(
|
|
3119
3119
|
(v, k) => k === d ? { ...v, [g]: m } : v
|
|
3120
3120
|
);
|
|
@@ -3186,7 +3186,7 @@ function js({
|
|
|
3186
3186
|
softCancelDone: v,
|
|
3187
3187
|
draftReadOnly: k
|
|
3188
3188
|
}) {
|
|
3189
|
-
const { t: y } =
|
|
3189
|
+
const { t: y } = re(), [A, S] = w(!1), [x, p] = w(!1), [f, B] = w(!1);
|
|
3190
3190
|
if (!l) return null;
|
|
3191
3191
|
const E = !e && l.canCancel && s === 1;
|
|
3192
3192
|
return /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -3266,15 +3266,15 @@ function ta(e, n) {
|
|
|
3266
3266
|
return a;
|
|
3267
3267
|
}
|
|
3268
3268
|
function na() {
|
|
3269
|
-
var ae,
|
|
3270
|
-
const { doctype: e, name: n } = bt(), a = Ke(), s = et(), { t: o } =
|
|
3269
|
+
var ae, xe;
|
|
3270
|
+
const { doctype: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = re(), i = er(e ?? ""), l = !n;
|
|
3271
3271
|
Me(l ? (i == null ? void 0 : i.label) ?? null : n ?? (i == null ? void 0 : i.label) ?? null);
|
|
3272
3272
|
const [c, h] = w({}), [d, g] = w(!1), { data: m, isLoading: b } = ve({
|
|
3273
3273
|
queryKey: ["document", e, n],
|
|
3274
3274
|
queryFn: () => F.getDocument(e, n),
|
|
3275
3275
|
enabled: !!e && !!n && !l
|
|
3276
3276
|
}), v = fe(
|
|
3277
|
-
() => !!(i != null && i.fields.some((
|
|
3277
|
+
() => !!(i != null && i.fields.some((O) => O.name === "currency")),
|
|
3278
3278
|
[i]
|
|
3279
3279
|
), k = i == null ? void 0 : i.partyField, y = k ? c[k] : void 0, A = Qe(c.company), { data: S } = ve({
|
|
3280
3280
|
queryKey: ["master", k, y],
|
|
@@ -3284,13 +3284,13 @@ function na() {
|
|
|
3284
3284
|
});
|
|
3285
3285
|
ce(() => {
|
|
3286
3286
|
if (!l || !v || d) return;
|
|
3287
|
-
let
|
|
3287
|
+
let O;
|
|
3288
3288
|
if (y) {
|
|
3289
3289
|
if (!S) return;
|
|
3290
|
-
|
|
3290
|
+
O = S.default_currency || A;
|
|
3291
3291
|
} else
|
|
3292
|
-
|
|
3293
|
-
|
|
3292
|
+
O = A;
|
|
3293
|
+
O && O !== c.currency && h((oe) => ({ ...oe, currency: O }));
|
|
3294
3294
|
}, [
|
|
3295
3295
|
l,
|
|
3296
3296
|
v,
|
|
@@ -3301,33 +3301,33 @@ function na() {
|
|
|
3301
3301
|
c.currency
|
|
3302
3302
|
]), ce(() => {
|
|
3303
3303
|
if (l && i) {
|
|
3304
|
-
const
|
|
3304
|
+
const O = {};
|
|
3305
3305
|
i.fields.forEach((oe) => {
|
|
3306
|
-
oe.type === "date" ?
|
|
3306
|
+
oe.type === "date" ? O[oe.name] = De() : O[oe.name] = oe.default ?? "";
|
|
3307
3307
|
}), i.childTables.forEach((oe) => {
|
|
3308
|
-
|
|
3309
|
-
}),
|
|
3308
|
+
O[oe.key] = [];
|
|
3309
|
+
}), O.docstatus = 0, h(O);
|
|
3310
3310
|
} else m && h(m);
|
|
3311
3311
|
}, [l, m, i]);
|
|
3312
3312
|
const x = ke({
|
|
3313
|
-
mutationFn: (
|
|
3314
|
-
onSuccess: (
|
|
3315
|
-
s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}/${
|
|
3313
|
+
mutationFn: (O) => F.createDocument(e, O),
|
|
3314
|
+
onSuccess: (O) => {
|
|
3315
|
+
s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}/${O.name}`, { replace: !0 });
|
|
3316
3316
|
}
|
|
3317
3317
|
}), p = ke({
|
|
3318
|
-
mutationFn: (
|
|
3319
|
-
onSuccess: (
|
|
3320
|
-
s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), h(
|
|
3318
|
+
mutationFn: (O) => F.updateDocument(e, n, O),
|
|
3319
|
+
onSuccess: (O) => {
|
|
3320
|
+
s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), h(O);
|
|
3321
3321
|
}
|
|
3322
3322
|
}), f = ke({
|
|
3323
3323
|
mutationFn: () => F.submitDocument(e, n),
|
|
3324
|
-
onSuccess: (
|
|
3325
|
-
h(
|
|
3324
|
+
onSuccess: (O) => {
|
|
3325
|
+
h(O), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
|
|
3326
3326
|
}
|
|
3327
3327
|
}), B = ke({
|
|
3328
3328
|
mutationFn: () => F.cancelDocument(e, n),
|
|
3329
|
-
onSuccess: (
|
|
3330
|
-
h(
|
|
3329
|
+
onSuccess: (O) => {
|
|
3330
|
+
h(O), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
|
|
3331
3331
|
}
|
|
3332
3332
|
}), E = ke({
|
|
3333
3333
|
mutationFn: () => F.discardDocument(e, n),
|
|
@@ -3335,23 +3335,23 @@ function na() {
|
|
|
3335
3335
|
s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] })), a(`/app/${e}`, { replace: !0 });
|
|
3336
3336
|
}
|
|
3337
3337
|
}), J = ke({
|
|
3338
|
-
mutationFn: (
|
|
3339
|
-
onSuccess: (
|
|
3338
|
+
mutationFn: (O) => F.convertDocument(e, n, O),
|
|
3339
|
+
onSuccess: (O, oe) => {
|
|
3340
3340
|
const Ie = oe.toLowerCase().replace(/\s+/g, "-");
|
|
3341
|
-
a(`/app/${Ie}/${
|
|
3341
|
+
a(`/app/${Ie}/${O.name}`);
|
|
3342
3342
|
}
|
|
3343
3343
|
}), Z = Ue(
|
|
3344
|
-
(
|
|
3345
|
-
|
|
3346
|
-
const Ae = { ...Ie, [
|
|
3347
|
-
return
|
|
3344
|
+
(O, oe) => {
|
|
3345
|
+
O === "currency" && g(!0), h((Ie) => {
|
|
3346
|
+
const Ae = { ...Ie, [O]: oe };
|
|
3347
|
+
return O === "currency" && (Ae.conversion_rate = 0), e === "reservation" && O === "asset" && oe && (Ae.allocation_mode = "Unit"), ta(Ae, i);
|
|
3348
3348
|
});
|
|
3349
3349
|
},
|
|
3350
3350
|
[i, e]
|
|
3351
|
-
),
|
|
3352
|
-
(
|
|
3351
|
+
), L = Ue(
|
|
3352
|
+
(O, oe) => {
|
|
3353
3353
|
h((Ie) => {
|
|
3354
|
-
const Ae = { ...Ie, [
|
|
3354
|
+
const Ae = { ...Ie, [O]: oe };
|
|
3355
3355
|
return ta(Ae, i);
|
|
3356
3356
|
});
|
|
3357
3357
|
},
|
|
@@ -3362,8 +3362,8 @@ function na() {
|
|
|
3362
3362
|
f.mutate();
|
|
3363
3363
|
}, N = () => {
|
|
3364
3364
|
B.mutate();
|
|
3365
|
-
}, D = (
|
|
3366
|
-
J.mutate(
|
|
3365
|
+
}, D = (O) => {
|
|
3366
|
+
J.mutate(O);
|
|
3367
3367
|
}, $ = () => {
|
|
3368
3368
|
E.mutate();
|
|
3369
3369
|
}, u = () => {
|
|
@@ -3376,7 +3376,7 @@ function na() {
|
|
|
3376
3376
|
] });
|
|
3377
3377
|
if (!l && b)
|
|
3378
3378
|
return /* @__PURE__ */ t("p", { className: "text-fg-muted", children: o("common.loading") });
|
|
3379
|
-
const P = c.docstatus ?? 0, V = !!c.discarded, T = e === "bank-transaction" && !!c.bank_statement_import, W = P >= 1 || V || T, le = c.currency || A, ue = Xe(c.conversion_rate ?? 1), Ne = i.fields.filter((
|
|
3379
|
+
const P = c.docstatus ?? 0, V = !!c.discarded, T = e === "bank-transaction" && !!c.bank_statement_import, W = P >= 1 || V || T, le = c.currency || A, ue = Xe(c.conversion_rate ?? 1), Ne = i.fields.filter((O) => !O.readOnly), be = Ne.filter((O) => O.type !== "textarea"), qe = Ne.filter((O) => O.type === "textarea"), R = i.fields.filter((O) => O.readOnly);
|
|
3380
3380
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
3381
3381
|
/* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
3382
3382
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
|
|
@@ -3419,57 +3419,57 @@ function na() {
|
|
|
3419
3419
|
)
|
|
3420
3420
|
] }),
|
|
3421
3421
|
(x.error || p.error || f.error || B.error) && /* @__PURE__ */ t("div", { className: "rounded-lg bg-rose-50 p-4 text-sm text-rose-700 ring-1 ring-rose-200", children: ((ae = x.error ?? p.error ?? f.error ?? B.error) == null ? void 0 : ae.message) ?? o("common.errorOccurred") }),
|
|
3422
|
-
(((
|
|
3422
|
+
(((xe = c._validation) == null ? void 0 : xe.warnings) ?? []).map((O) => /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-900", role: "status", children: O.code === "asset_unassigned" ? o("rentals.poolWarning") : O.message }, O.code)),
|
|
3423
3423
|
/* @__PURE__ */ r(H, { children: [
|
|
3424
|
-
/* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children:
|
|
3424
|
+
/* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: be.map((O) => /* @__PURE__ */ t(
|
|
3425
3425
|
Kt,
|
|
3426
3426
|
{
|
|
3427
|
-
field:
|
|
3428
|
-
value: c[
|
|
3429
|
-
onChange: (oe) => Z(
|
|
3427
|
+
field: O,
|
|
3428
|
+
value: c[O.name],
|
|
3429
|
+
onChange: (oe) => Z(O.name, oe),
|
|
3430
3430
|
readOnly: W,
|
|
3431
3431
|
rowData: c,
|
|
3432
3432
|
currency: le,
|
|
3433
3433
|
doctype: e
|
|
3434
3434
|
},
|
|
3435
|
-
|
|
3435
|
+
O.name
|
|
3436
3436
|
)) }),
|
|
3437
|
-
qe.length > 0 && /* @__PURE__ */ t("div", { className: "mt-4 space-y-4", children: qe.map((
|
|
3437
|
+
qe.length > 0 && /* @__PURE__ */ t("div", { className: "mt-4 space-y-4", children: qe.map((O) => /* @__PURE__ */ t(
|
|
3438
3438
|
Kt,
|
|
3439
3439
|
{
|
|
3440
|
-
field:
|
|
3441
|
-
value: c[
|
|
3442
|
-
onChange: (oe) => Z(
|
|
3440
|
+
field: O,
|
|
3441
|
+
value: c[O.name],
|
|
3442
|
+
onChange: (oe) => Z(O.name, oe),
|
|
3443
3443
|
readOnly: W,
|
|
3444
3444
|
rowData: c,
|
|
3445
3445
|
currency: le,
|
|
3446
3446
|
doctype: e
|
|
3447
3447
|
},
|
|
3448
|
-
|
|
3448
|
+
O.name
|
|
3449
3449
|
)) })
|
|
3450
3450
|
] }),
|
|
3451
|
-
i.childTables.map((
|
|
3451
|
+
i.childTables.map((O) => /* @__PURE__ */ t(
|
|
3452
3452
|
Ks,
|
|
3453
3453
|
{
|
|
3454
|
-
tableDef:
|
|
3455
|
-
rows: c[
|
|
3456
|
-
onChange: (oe) => O
|
|
3454
|
+
tableDef: O,
|
|
3455
|
+
rows: c[O.key] ?? [],
|
|
3456
|
+
onChange: (oe) => L(O.key, oe),
|
|
3457
3457
|
readOnly: W,
|
|
3458
3458
|
currency: le
|
|
3459
3459
|
},
|
|
3460
|
-
|
|
3460
|
+
O.key
|
|
3461
3461
|
)),
|
|
3462
|
-
R.length > 0 && /* @__PURE__ */ t(H, { title: o("common.totals"), children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: R.map((
|
|
3462
|
+
R.length > 0 && /* @__PURE__ */ t(H, { title: o("common.totals"), children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: R.map((O) => /* @__PURE__ */ t(
|
|
3463
3463
|
Kt,
|
|
3464
3464
|
{
|
|
3465
|
-
field:
|
|
3466
|
-
value: c[
|
|
3465
|
+
field: O,
|
|
3466
|
+
value: c[O.name],
|
|
3467
3467
|
onChange: () => {
|
|
3468
3468
|
},
|
|
3469
3469
|
readOnly: !0,
|
|
3470
3470
|
currency: le
|
|
3471
3471
|
},
|
|
3472
|
-
|
|
3472
|
+
O.name
|
|
3473
3473
|
)) }) })
|
|
3474
3474
|
] });
|
|
3475
3475
|
}
|
|
@@ -3484,7 +3484,7 @@ function Gt({
|
|
|
3484
3484
|
setPage: l,
|
|
3485
3485
|
setPageSize: c
|
|
3486
3486
|
}) {
|
|
3487
|
-
const { t: h } =
|
|
3487
|
+
const { t: h } = re(), [d, g] = w(String(e + 1));
|
|
3488
3488
|
ce(() => g(String(e + 1)), [e]);
|
|
3489
3489
|
const m = () => {
|
|
3490
3490
|
const b = Number.parseInt(d, 10);
|
|
@@ -3617,13 +3617,13 @@ function sr({
|
|
|
3617
3617
|
hiddenChipFields: h = [],
|
|
3618
3618
|
className: d
|
|
3619
3619
|
}) {
|
|
3620
|
-
const { t: g } =
|
|
3620
|
+
const { t: g } = re(), m = pe(null), b = pe(null), [v, k] = w(!1), [y, A] = w(!1), [S, x] = w({ field: "", value: "" }), p = fe(() => Gs(n, s), [n, s]), f = n.trimEnd().split(/\s+/).pop() ?? "", B = y || p || f.includes(":") ? "" : f.toLowerCase(), E = fe(() => s.filter(
|
|
3621
3621
|
(W) => !B || W.name.toLowerCase().includes(B) || W.label.toLowerCase().includes(B)
|
|
3622
3622
|
).sort((W, le) => {
|
|
3623
3623
|
const ue = o[W.name] || o[`${W.name}${Nt}`] ? 1 : 0, Ne = o[le.name] || o[`${le.name}${Nt}`] ? 1 : 0;
|
|
3624
3624
|
if (ue !== Ne) return Ne - ue;
|
|
3625
|
-
const
|
|
3626
|
-
return
|
|
3625
|
+
const be = W.suggestOnEmpty ? 1 : 0, qe = le.suggestOnEmpty ? 1 : 0;
|
|
3626
|
+
return be !== qe ? qe - be : W.label.localeCompare(le.label);
|
|
3627
3627
|
}), [s, B, o]), J = (p == null ? void 0 : p.field.options) ?? [];
|
|
3628
3628
|
ce(() => {
|
|
3629
3629
|
const T = setTimeout(() => x({
|
|
@@ -3632,10 +3632,10 @@ function sr({
|
|
|
3632
3632
|
}), 200);
|
|
3633
3633
|
return () => clearTimeout(T);
|
|
3634
3634
|
}, [p == null ? void 0 : p.field.name, p == null ? void 0 : p.value]);
|
|
3635
|
-
const
|
|
3635
|
+
const L = !!p && S.field === p.field.name && J.length === 0 && (!!S.value || !!p.field.suggestOnEmpty), { data: q = [], isFetching: Q } = ve({
|
|
3636
3636
|
queryKey: ["smart-list-values", e, p == null ? void 0 : p.field.name, S.value],
|
|
3637
3637
|
queryFn: () => c(p.field.name, S.value),
|
|
3638
|
-
enabled:
|
|
3638
|
+
enabled: L,
|
|
3639
3639
|
staleTime: 6e4
|
|
3640
3640
|
}), N = J.length ? J.filter(
|
|
3641
3641
|
(T) => !(p != null && p.value) || T.label.toLowerCase().includes(p.value.toLowerCase()) || T.value.toLowerCase().startsWith(p.value.toLowerCase())
|
|
@@ -3775,7 +3775,7 @@ function sr({
|
|
|
3775
3775
|
},
|
|
3776
3776
|
Mt(T)
|
|
3777
3777
|
)),
|
|
3778
|
-
!Q &&
|
|
3778
|
+
!Q && L && N.length === 0 && /* @__PURE__ */ t("div", { className: "px-3 py-4 text-sm text-fg-muted", children: g("smartSearch.noValues") }),
|
|
3779
3779
|
!!p.value && /* @__PURE__ */ t(
|
|
3780
3780
|
"button",
|
|
3781
3781
|
{
|
|
@@ -3902,7 +3902,7 @@ const Js = [
|
|
|
3902
3902
|
}
|
|
3903
3903
|
];
|
|
3904
3904
|
function Xt({ onSelect: e }) {
|
|
3905
|
-
const { t: n } =
|
|
3905
|
+
const { t: n } = re();
|
|
3906
3906
|
return /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1.5", children: Js.map((a) => /* @__PURE__ */ t(
|
|
3907
3907
|
"button",
|
|
3908
3908
|
{
|
|
@@ -3918,7 +3918,7 @@ function Xt({ onSelect: e }) {
|
|
|
3918
3918
|
)) });
|
|
3919
3919
|
}
|
|
3920
3920
|
function On({ onSelect: e }) {
|
|
3921
|
-
const { t: n } =
|
|
3921
|
+
const { t: n } = re();
|
|
3922
3922
|
return /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
3923
3923
|
{ id: "today", labelKey: "datePresets.today", value: (s) => De(s) },
|
|
3924
3924
|
{ id: "endOfThisMonth", labelKey: "datePresets.endOfThisMonth", value: (s) => De(Ht(s)) },
|
|
@@ -3970,7 +3970,7 @@ function ei(e) {
|
|
|
3970
3970
|
return n === "customer" ? "customer" : n === "supplier" ? "supplier" : null;
|
|
3971
3971
|
}
|
|
3972
3972
|
function ti() {
|
|
3973
|
-
const { t: e } =
|
|
3973
|
+
const { t: e } = re(), n = Qe(), { doctype: a } = bt(), s = er(a ?? ""), o = Ct();
|
|
3974
3974
|
Me((s == null ? void 0 : s.label) ?? a ?? null);
|
|
3975
3975
|
const i = (s == null ? void 0 : s.listFilters) ?? [], l = fe(() => {
|
|
3976
3976
|
const _ = new URLSearchParams(o.search), M = {}, K = /* @__PURE__ */ new Set(["q", "page", "per_page", "from", "to", "discarded", "order_by", "order"]);
|
|
@@ -3981,7 +3981,7 @@ function ti() {
|
|
|
3981
3981
|
const _ = {};
|
|
3982
3982
|
for (const M of i) _[M] = l[M] ?? "";
|
|
3983
3983
|
return _;
|
|
3984
|
-
}, [i, l]), [h] = he("status", "All"), [d] = he("from", ""), [g] = he("to", ""), [m] = he("discarded", ""), [b] = he("per_page", 50), v = (s == null ? void 0 : s.searchFields) ?? [], [k] = he("q", ""), [y, A] = w(k), [S] = he("page", 1), x = S - 1, p = lt(), { settings: f, setSetting: B } = Zt(), [E] = he("order_by", ""), [J] = he("order", ""), [Z,
|
|
3984
|
+
}, [i, l]), [h] = he("status", "All"), [d] = he("from", ""), [g] = he("to", ""), [m] = he("discarded", ""), [b] = he("per_page", 50), v = (s == null ? void 0 : s.searchFields) ?? [], [k] = he("q", ""), [y, A] = w(k), [S] = he("page", 1), x = S - 1, p = lt(), { settings: f, setSetting: B } = Zt(), [E] = he("order_by", ""), [J] = he("order", ""), [Z, L] = (f[`sort.${a}`] || "").split(":"), q = E || Z || "", Q = (E ? J : L) || "desc", N = (_) => {
|
|
3985
3985
|
const M = q === _ ? Q === "desc" ? "asc" : "desc" : oa(_) ? "desc" : "asc";
|
|
3986
3986
|
p({ order_by: _, order: M, page: null }), B(`sort.${a}`, `${_}:${M}`);
|
|
3987
3987
|
}, [D, $] = w(!1), u = pe(null), P = fe(
|
|
@@ -4007,11 +4007,11 @@ function ti() {
|
|
|
4007
4007
|
};
|
|
4008
4008
|
return document.addEventListener("mousedown", _), () => document.removeEventListener("mousedown", _);
|
|
4009
4009
|
}, [D]);
|
|
4010
|
-
const ue = (_) => p({ page: _ === 0 ? null : _ + 1 }), Ne = (_) => p({ status: _ === "All" ? null : _, page: null }),
|
|
4010
|
+
const ue = (_) => p({ page: _ === 0 ? null : _ + 1 }), Ne = (_) => p({ status: _ === "All" ? null : _, page: null }), be = (_) => p({ from: _ || null, page: null }), qe = (_) => p({ to: _ || null, page: null }), R = (_) => p({ discarded: _ ? "1" : null, page: null }), ae = (_) => p({ per_page: _, page: null });
|
|
4011
4011
|
ce(() => {
|
|
4012
4012
|
A(k);
|
|
4013
4013
|
}, [k]);
|
|
4014
|
-
const
|
|
4014
|
+
const xe = fe(() => {
|
|
4015
4015
|
const _ = {};
|
|
4016
4016
|
i.length === 0 && h !== "All" && (_.status = h), d && (_.from_date = d), g && (_.to_date = g), s != null && s.dateField && (_.date_field = s.dateField);
|
|
4017
4017
|
for (const M of i)
|
|
@@ -4019,7 +4019,7 @@ function ti() {
|
|
|
4019
4019
|
for (const [M, K] of Object.entries(l))
|
|
4020
4020
|
_[M] = K;
|
|
4021
4021
|
return v.length > 0 && k && (_.search = k, _.search_fields = v.join(",")), m && (_.include_discarded = "true"), q && (_.order_by = q, _.order = Q), T && (_.fields = T), _.limit = b, _.offset = x * b, _;
|
|
4022
|
-
}, [h, d, g, m, b, x, s == null ? void 0 : s.dateField, i, c, l, v, k, q, Q, T]), { data:
|
|
4022
|
+
}, [h, d, g, m, b, x, s == null ? void 0 : s.dateField, i, c, l, v, k, q, Q, T]), { data: O, isLoading: oe } = Os(a ?? "", xe), Ie = (O == null ? void 0 : O.rows) ?? [], Ae = (O == null ? void 0 : O.total) ?? 0, Ye = fe(() => new Set((O == null ? void 0 : O.text_fields) ?? []), [O == null ? void 0 : O.text_fields]), tt = fe(() => {
|
|
4023
4023
|
if (!s) return [];
|
|
4024
4024
|
const _ = new Map(s.fields.map((K) => [K.name, K]));
|
|
4025
4025
|
return [.../* @__PURE__ */ new Set([
|
|
@@ -4044,9 +4044,9 @@ function ti() {
|
|
|
4044
4044
|
});
|
|
4045
4045
|
}, [W, s, i, v, e, Ye]);
|
|
4046
4046
|
ce(() => {
|
|
4047
|
-
const { limit: _, offset: M, ...K } =
|
|
4047
|
+
const { limit: _, offset: M, ...K } = xe;
|
|
4048
4048
|
Xa(a ?? "", { filters: K, search: o.search });
|
|
4049
|
-
}, [a,
|
|
4049
|
+
}, [a, xe, o.search]);
|
|
4050
4050
|
const je = Math.max(1, Math.ceil(Ae / b)), st = Ae === 0 ? 0 : x * b + 1, U = Math.min(Ae, (x + 1) * b), te = fe(() => {
|
|
4051
4051
|
if (!s) return [];
|
|
4052
4052
|
const _ = Ea(), M = (K) => {
|
|
@@ -4224,7 +4224,7 @@ function ti() {
|
|
|
4224
4224
|
label: e("fields.From Date", { defaultValue: "From Date" }),
|
|
4225
4225
|
type: "date",
|
|
4226
4226
|
value: d,
|
|
4227
|
-
onChange: (_) =>
|
|
4227
|
+
onChange: (_) => be(_.target.value)
|
|
4228
4228
|
}
|
|
4229
4229
|
),
|
|
4230
4230
|
/* @__PURE__ */ t(
|
|
@@ -4322,21 +4322,21 @@ function ze({
|
|
|
4322
4322
|
}, [n]);
|
|
4323
4323
|
const f = Ue(() => {
|
|
4324
4324
|
if (x.current) {
|
|
4325
|
-
const
|
|
4325
|
+
const L = x.current.getBoundingClientRect();
|
|
4326
4326
|
k({
|
|
4327
4327
|
position: "fixed",
|
|
4328
|
-
top:
|
|
4329
|
-
left:
|
|
4330
|
-
width:
|
|
4328
|
+
top: L.bottom + 4,
|
|
4329
|
+
left: L.left,
|
|
4330
|
+
width: L.width,
|
|
4331
4331
|
zIndex: 9999
|
|
4332
4332
|
});
|
|
4333
4333
|
}
|
|
4334
4334
|
}, []), B = Ue(
|
|
4335
|
-
(
|
|
4335
|
+
(L) => {
|
|
4336
4336
|
y.current && clearTimeout(y.current), y.current = setTimeout(async () => {
|
|
4337
4337
|
b(!0);
|
|
4338
4338
|
try {
|
|
4339
|
-
const q = await F.searchLink(s,
|
|
4339
|
+
const q = await F.searchLink(s, L);
|
|
4340
4340
|
h(q), g(!0);
|
|
4341
4341
|
} catch {
|
|
4342
4342
|
h([]);
|
|
@@ -4346,11 +4346,11 @@ function ze({
|
|
|
4346
4346
|
}, 300);
|
|
4347
4347
|
},
|
|
4348
4348
|
[s]
|
|
4349
|
-
), E = (
|
|
4350
|
-
const q =
|
|
4349
|
+
), E = (L) => {
|
|
4350
|
+
const q = L.target.value;
|
|
4351
4351
|
l(q), B(q);
|
|
4352
|
-
}, J = (
|
|
4353
|
-
const q =
|
|
4352
|
+
}, J = (L) => {
|
|
4353
|
+
const q = L.name ?? L.id ?? String(L);
|
|
4354
4354
|
l(q), a(q), g(!1), h([]);
|
|
4355
4355
|
}, Z = () => {
|
|
4356
4356
|
setTimeout(() => {
|
|
@@ -4362,12 +4362,12 @@ function ze({
|
|
|
4362
4362
|
}, 150);
|
|
4363
4363
|
};
|
|
4364
4364
|
return ce(() => {
|
|
4365
|
-
const
|
|
4365
|
+
const L = (q) => {
|
|
4366
4366
|
var N, D;
|
|
4367
4367
|
const Q = q.target;
|
|
4368
4368
|
(N = A.current) != null && N.contains(Q) || (D = S.current) != null && D.contains(Q) || g(!1);
|
|
4369
4369
|
};
|
|
4370
|
-
return document.addEventListener("mousedown",
|
|
4370
|
+
return document.addEventListener("mousedown", L), () => document.removeEventListener("mousedown", L);
|
|
4371
4371
|
}, []), o ? /* @__PURE__ */ r("div", { children: [
|
|
4372
4372
|
e && /* @__PURE__ */ t("span", { className: "mb-1.5 block text-sm font-medium text-fg", children: e }),
|
|
4373
4373
|
/* @__PURE__ */ t("span", { className: "text-sm text-fg", children: n || "—" })
|
|
@@ -4392,8 +4392,8 @@ function ze({
|
|
|
4392
4392
|
}
|
|
4393
4393
|
),
|
|
4394
4394
|
d && c.length > 0 && Fa(
|
|
4395
|
-
/* @__PURE__ */ t("div", { ref: S, style: v, className: "max-h-48 overflow-y-auto rounded-lg bg-surface ring-1 ring-line shadow-card-hover", children: c.map((
|
|
4396
|
-
const Q =
|
|
4395
|
+
/* @__PURE__ */ t("div", { ref: S, style: v, className: "max-h-48 overflow-y-auto rounded-lg bg-surface ring-1 ring-line shadow-card-hover", children: c.map((L, q) => {
|
|
4396
|
+
const Q = L.name ?? L.id ?? String(L);
|
|
4397
4397
|
return /* @__PURE__ */ t(
|
|
4398
4398
|
"button",
|
|
4399
4399
|
{
|
|
@@ -4401,7 +4401,7 @@ function ze({
|
|
|
4401
4401
|
onMouseDown: () => {
|
|
4402
4402
|
p.current = !0;
|
|
4403
4403
|
},
|
|
4404
|
-
onClick: () => J(
|
|
4404
|
+
onClick: () => J(L),
|
|
4405
4405
|
className: "block w-full px-3 py-1.5 text-left text-sm text-fg transition-colors hover:bg-surface-subtle",
|
|
4406
4406
|
children: Q
|
|
4407
4407
|
},
|
|
@@ -4420,7 +4420,7 @@ const qt = () => ({
|
|
|
4420
4420
|
}), ni = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
4421
4421
|
function ca() {
|
|
4422
4422
|
var $;
|
|
4423
|
-
const { name: e } = bt(), n = !e, a = Ke(), s = et(), { t: o } =
|
|
4423
|
+
const { name: e } = bt(), n = !e, a = Ke(), s = et(), { t: o } = re();
|
|
4424
4424
|
Me(o("titles.proposal"));
|
|
4425
4425
|
const i = (u, P) => o(u, { defaultValue: P }), l = Tn(), [c, h] = w({
|
|
4426
4426
|
title: "Offerte",
|
|
@@ -4474,7 +4474,7 @@ function ca() {
|
|
|
4474
4474
|
s.invalidateQueries({ queryKey: ["documents", "proposal"] }), a("/app/proposal");
|
|
4475
4475
|
},
|
|
4476
4476
|
onError: (u) => A((u == null ? void 0 : u.message) ?? "Discard failed")
|
|
4477
|
-
}), Z = (u, P) => g((V) => V.map((T, W) => W === u ? { ...T, ...P } : T)),
|
|
4477
|
+
}), Z = (u, P) => g((V) => V.map((T, W) => W === u ? { ...T, ...P } : T)), L = () => g((u) => [...u, qt()]), q = (u) => g((P) => P.length > 1 ? P.filter((V, T) => T !== u) : P), Q = (u, P) => g((V) => {
|
|
4478
4478
|
const T = u + P;
|
|
4479
4479
|
if (T < 0 || T >= V.length) return V;
|
|
4480
4480
|
const W = [...V];
|
|
@@ -4561,7 +4561,7 @@ function ca() {
|
|
|
4561
4561
|
/* @__PURE__ */ r(H, { className: "space-y-4 p-5", children: [
|
|
4562
4562
|
/* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
|
|
4563
4563
|
/* @__PURE__ */ t("h2", { className: "font-semibold text-fg", children: i("proposal.offers", "Offers") }),
|
|
4564
|
-
/* @__PURE__ */ t(Y, { size: "sm", variant: "secondary", onClick:
|
|
4564
|
+
/* @__PURE__ */ t(Y, { size: "sm", variant: "secondary", onClick: L, children: i("proposal.addOffer", "Add offer") })
|
|
4565
4565
|
] }),
|
|
4566
4566
|
d.map((u, P) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
|
|
4567
4567
|
/* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
|
|
@@ -4601,13 +4601,13 @@ function ca() {
|
|
|
4601
4601
|
] });
|
|
4602
4602
|
}
|
|
4603
4603
|
const Fn = {};
|
|
4604
|
-
function
|
|
4604
|
+
function Vc(e) {
|
|
4605
4605
|
Fn[e.slug] = e;
|
|
4606
4606
|
}
|
|
4607
4607
|
function lr(e) {
|
|
4608
4608
|
return Fn[e];
|
|
4609
4609
|
}
|
|
4610
|
-
function
|
|
4610
|
+
function Uc() {
|
|
4611
4611
|
return Object.values(Fn);
|
|
4612
4612
|
}
|
|
4613
4613
|
const cr = {
|
|
@@ -4670,6 +4670,7 @@ const cr = {
|
|
|
4670
4670
|
{ name: "zip_code", label: "Zip Code", type: "text" },
|
|
4671
4671
|
{ name: "country", label: "Country", type: "text" },
|
|
4672
4672
|
{ name: "tax_id", label: "Tax ID", type: "text" },
|
|
4673
|
+
{ name: "default_sales_tax_template", label: "Default sales tax", type: "text" },
|
|
4673
4674
|
{ name: "iban", label: "IBAN", type: "text" }
|
|
4674
4675
|
]
|
|
4675
4676
|
}, ai = {
|
|
@@ -4689,10 +4690,10 @@ function si() {
|
|
|
4689
4690
|
var st;
|
|
4690
4691
|
const { type: e } = bt(), n = Ke(), a = Ct(), s = lr(e ?? ""), o = (s == null ? void 0 : s.label) ?? ai[e ?? ""] ?? e ?? "";
|
|
4691
4692
|
Me(o || null);
|
|
4692
|
-
const { t: i } =
|
|
4693
|
+
const { t: i } = re(), l = (st = a.state) == null ? void 0 : st.notice, [c] = he("per_page", 50), [h] = he("page", 1), [d] = he("include_disabled", ""), g = h - 1, m = lt(), b = (U) => m({ page: U === 0 ? null : U + 1 }), v = (U) => m({ per_page: U, page: null }), k = (U) => m({ include_disabled: U ? "1" : null, page: null }), { settings: y, setSetting: A } = Zt(), [S] = he("order_by", ""), [x] = he("order", ""), [p, f] = (y[`sort.master:${e}`] || "").split(":"), B = S || p || "", E = (S ? x : f) || "asc", J = (U) => {
|
|
4693
4694
|
const te = B === U ? E === "desc" ? "asc" : "desc" : da(U) ? "desc" : "asc";
|
|
4694
4695
|
m({ order_by: U, order: te, page: null }), A(`sort.master:${e}`, `${U}:${te}`);
|
|
4695
|
-
}, [Z] = he("q", ""), [
|
|
4696
|
+
}, [Z] = he("q", ""), [L, q] = w(Z);
|
|
4696
4697
|
ce(() => {
|
|
4697
4698
|
q(Z);
|
|
4698
4699
|
}, [Z]);
|
|
@@ -4723,10 +4724,10 @@ function si() {
|
|
|
4723
4724
|
const { limit: U, offset: te, fields: _e, ..._ } = D;
|
|
4724
4725
|
Xa(`master:${e}`, { filters: _, search: a.search });
|
|
4725
4726
|
}, [e, D, a.search]);
|
|
4726
|
-
const P = ($ == null ? void 0 : $.rows) ?? [], V = ($ == null ? void 0 : $.total) ?? 0, T = fe(() => new Set(($ == null ? void 0 : $.text_fields) ?? []), [$ == null ? void 0 : $.text_fields]), W = Math.max(1, Math.ceil(V / c)), le = V === 0 ? 0 : g * c + 1, ue = Math.min(V, (g + 1) * c), Ne = pe({}),
|
|
4727
|
+
const P = ($ == null ? void 0 : $.rows) ?? [], V = ($ == null ? void 0 : $.total) ?? 0, T = fe(() => new Set(($ == null ? void 0 : $.text_fields) ?? []), [$ == null ? void 0 : $.text_fields]), W = Math.max(1, Math.ceil(V / c)), le = V === 0 ? 0 : g * c + 1, ue = Math.min(V, (g + 1) * c), Ne = pe({}), be = fe(() => s != null && s.columnOptions ? s.columnOptions : (e && P.length && (Ne.current[e] = Object.keys(P[0])), e ? Ne.current[e] ?? [] : []), [s, P, e]), qe = fe(() => {
|
|
4727
4728
|
const U = (s == null ? void 0 : s.fields) ?? cr[e ?? ""] ?? [], te = new Map(U.map((_) => [_.name, _]));
|
|
4728
4729
|
return [.../* @__PURE__ */ new Set([
|
|
4729
|
-
...
|
|
4730
|
+
...be,
|
|
4730
4731
|
...U.map((_) => _.name),
|
|
4731
4732
|
...Q.map((_) => _.field)
|
|
4732
4733
|
])].map((_) => {
|
|
@@ -4743,11 +4744,11 @@ function si() {
|
|
|
4743
4744
|
suggestOnEmpty: !!(C != null && C.length) || Q.some((G) => G.field === _)
|
|
4744
4745
|
};
|
|
4745
4746
|
});
|
|
4746
|
-
}, [
|
|
4747
|
+
}, [be, s, Q, i, T, e]), ae = fe(
|
|
4747
4748
|
() => (y[`columns.master:${e}`] || "").split(",").map((U) => U.trim()).filter(Boolean),
|
|
4748
4749
|
[y, e]
|
|
4749
|
-
).filter((U) =>
|
|
4750
|
-
const te =
|
|
4750
|
+
).filter((U) => be.includes(U)), xe = ((s == null ? void 0 : s.listColumns) ?? []).filter((U) => be.includes(U)), O = ae.length ? ae : xe.length ? xe : be, oe = (U) => {
|
|
4751
|
+
const te = O.includes(U) ? O.filter((_e) => _e !== U) : [...O, U];
|
|
4751
4752
|
te.length !== 0 && A(`columns.master:${e}`, te.join(","));
|
|
4752
4753
|
}, [Ie, Ae] = w(!1), Ye = pe(null);
|
|
4753
4754
|
ce(() => {
|
|
@@ -4760,7 +4761,7 @@ function si() {
|
|
|
4760
4761
|
const tt = fe(() => {
|
|
4761
4762
|
if (!P || P.length === 0) return [];
|
|
4762
4763
|
const U = Ea();
|
|
4763
|
-
return
|
|
4764
|
+
return O.map(
|
|
4764
4765
|
(te) => {
|
|
4765
4766
|
var _e, _;
|
|
4766
4767
|
return U.accessor(te, {
|
|
@@ -4799,7 +4800,7 @@ function si() {
|
|
|
4799
4800
|
});
|
|
4800
4801
|
}
|
|
4801
4802
|
);
|
|
4802
|
-
}, [P, e,
|
|
4803
|
+
}, [P, e, O.join(","), i, s]), je = La({
|
|
4803
4804
|
data: P,
|
|
4804
4805
|
columns: tt,
|
|
4805
4806
|
getCoreRowModel: Oa()
|
|
@@ -4811,7 +4812,7 @@ function si() {
|
|
|
4811
4812
|
sr,
|
|
4812
4813
|
{
|
|
4813
4814
|
scope: `master:${e}`,
|
|
4814
|
-
value:
|
|
4815
|
+
value: L,
|
|
4815
4816
|
onChange: q,
|
|
4816
4817
|
fields: qe,
|
|
4817
4818
|
filters: N,
|
|
@@ -4837,16 +4838,16 @@ function si() {
|
|
|
4837
4838
|
i("common.showDisabled")
|
|
4838
4839
|
] }),
|
|
4839
4840
|
/* @__PURE__ */ r("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
4840
|
-
|
|
4841
|
+
be.length > 0 && /* @__PURE__ */ r("div", { className: "relative", ref: Ye, children: [
|
|
4841
4842
|
/* @__PURE__ */ t(Y, { variant: "secondary", onClick: () => Ae((U) => !U), children: /* @__PURE__ */ r("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
4842
4843
|
/* @__PURE__ */ t(Ra, { className: "h-4 w-4" }),
|
|
4843
4844
|
i("common.columns", { defaultValue: "Columns" })
|
|
4844
4845
|
] }) }),
|
|
4845
4846
|
Ie && /* @__PURE__ */ r("div", { className: "absolute right-0 z-20 mt-2 max-h-80 w-60 overflow-y-auto rounded-lg border border-line bg-surface p-2 shadow-card", children: [
|
|
4846
4847
|
/* @__PURE__ */ t("div", { className: "px-2 py-1 text-xs font-medium uppercase tracking-wide text-fg-muted", children: i("common.columns", { defaultValue: "Columns" }) }),
|
|
4847
|
-
|
|
4848
|
+
be.map((U) => {
|
|
4848
4849
|
var _, M;
|
|
4849
|
-
const te =
|
|
4850
|
+
const te = O.includes(U), _e = te && O.length === 1;
|
|
4850
4851
|
return /* @__PURE__ */ r(
|
|
4851
4852
|
"label",
|
|
4852
4853
|
{
|
|
@@ -4939,7 +4940,44 @@ function si() {
|
|
|
4939
4940
|
] })
|
|
4940
4941
|
] });
|
|
4941
4942
|
}
|
|
4942
|
-
|
|
4943
|
+
function ii({ company: e, value: n, onChange: a }) {
|
|
4944
|
+
const { t: s } = re(), o = ve({
|
|
4945
|
+
queryKey: ["company-sales-tax-templates", e],
|
|
4946
|
+
queryFn: () => z(
|
|
4947
|
+
`/masters/company/${encodeURIComponent(e)}/sales-tax-templates`
|
|
4948
|
+
),
|
|
4949
|
+
enabled: !!e
|
|
4950
|
+
}), i = o.data ?? [], l = !!n && !i.some((c) => c.name === n);
|
|
4951
|
+
return /* @__PURE__ */ r("div", { className: "sm:col-span-2", children: [
|
|
4952
|
+
/* @__PURE__ */ t("label", { htmlFor: "company-sales-tax", className: "mb-1.5 block text-sm font-medium text-fg", children: s("companyTax.label") }),
|
|
4953
|
+
/* @__PURE__ */ r(
|
|
4954
|
+
"select",
|
|
4955
|
+
{
|
|
4956
|
+
id: "company-sales-tax",
|
|
4957
|
+
"aria-describedby": "company-sales-tax-hint",
|
|
4958
|
+
className: "block h-10 w-full rounded-lg bg-surface px-3 text-sm text-fg ring-1 ring-line focus:outline-none focus:ring-2 focus:ring-brand/30 disabled:cursor-not-allowed disabled:text-fg-muted",
|
|
4959
|
+
value: n,
|
|
4960
|
+
disabled: !e || o.isPending || o.isError,
|
|
4961
|
+
onChange: (c) => a(c.target.value),
|
|
4962
|
+
children: [
|
|
4963
|
+
/* @__PURE__ */ t("option", { value: "", children: s("companyTax.none") }),
|
|
4964
|
+
l && /* @__PURE__ */ t("option", { value: n, children: n }),
|
|
4965
|
+
i.map((c) => /* @__PURE__ */ t("option", { value: c.name, children: c.title || c.name }, c.name))
|
|
4966
|
+
]
|
|
4967
|
+
}
|
|
4968
|
+
),
|
|
4969
|
+
/* @__PURE__ */ t("p", { id: "company-sales-tax-hint", className: "mt-2 text-xs text-fg-muted", children: s(e ? "companyTax.hint" : "companyTax.saveFirst") }),
|
|
4970
|
+
e && o.isPending && /* @__PURE__ */ t("p", { className: "mt-1 text-xs text-fg-muted", role: "status", children: s("common.loading") }),
|
|
4971
|
+
o.isError && /* @__PURE__ */ r("p", { className: "mt-2 text-sm text-rose-700", role: "alert", children: [
|
|
4972
|
+
s("companyTax.loadError"),
|
|
4973
|
+
" ",
|
|
4974
|
+
/* @__PURE__ */ t("button", { type: "button", className: "underline", onClick: () => o.refetch(), children: s("companyTax.retry") })
|
|
4975
|
+
] }),
|
|
4976
|
+
e && o.isSuccess && l && /* @__PURE__ */ t("p", { className: "mt-2 text-sm text-amber-700", role: "alert", children: s("companyTax.unavailable") }),
|
|
4977
|
+
e && o.isSuccess && i.length === 0 && /* @__PURE__ */ t("p", { className: "mt-2 text-xs text-fg-muted", children: s("companyTax.empty") })
|
|
4978
|
+
] });
|
|
4979
|
+
}
|
|
4980
|
+
const oi = {
|
|
4943
4981
|
customer: "Customer",
|
|
4944
4982
|
supplier: "Supplier",
|
|
4945
4983
|
item: "Item",
|
|
@@ -4948,7 +4986,7 @@ const ii = {
|
|
|
4948
4986
|
}, ua = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
|
|
4949
4987
|
function ma() {
|
|
4950
4988
|
var N, D, $;
|
|
4951
|
-
const { type: e, name: n } = bt(), a = Ke(), s = et(), { t: o } =
|
|
4989
|
+
const { type: e, name: n } = bt(), a = Ke(), s = et(), { t: o } = re(), i = !n || n === "new", l = lr(e ?? ""), c = (l == null ? void 0 : l.label) ?? oi[e ?? ""] ?? e ?? "", h = o(`masters.${e}.one`, { defaultValue: c }), d = (l == null ? void 0 : l.fields) ?? cr[e ?? ""] ?? [], g = (u) => o(`fields.${u.label}`, { defaultValue: u.label }), [m, b] = w({}), { data: v, isLoading: k } = ve({
|
|
4952
4990
|
queryKey: ["master", e, n],
|
|
4953
4991
|
queryFn: () => F.getMaster(e, n),
|
|
4954
4992
|
enabled: !!e && !!n && !i
|
|
@@ -5020,7 +5058,7 @@ function ma() {
|
|
|
5020
5058
|
confirmLabel: o("common.delete", { defaultValue: "Delete" }),
|
|
5021
5059
|
danger: !0
|
|
5022
5060
|
}) && f.mutate();
|
|
5023
|
-
},
|
|
5061
|
+
}, L = (u, P) => {
|
|
5024
5062
|
b((V) => ({ ...V, [u]: P }));
|
|
5025
5063
|
};
|
|
5026
5064
|
if (!i && k)
|
|
@@ -5067,6 +5105,16 @@ function ma() {
|
|
|
5067
5105
|
m.disabled === 1 && /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-800 ring-1 ring-amber-200", children: o("masterForm.disabledNotice", { label: h }) }),
|
|
5068
5106
|
/* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: d.map((u) => {
|
|
5069
5107
|
var ue, Ne;
|
|
5108
|
+
if (e === "company" && u.name === "default_sales_tax_template")
|
|
5109
|
+
return /* @__PURE__ */ t(
|
|
5110
|
+
ii,
|
|
5111
|
+
{
|
|
5112
|
+
company: i ? void 0 : n,
|
|
5113
|
+
value: m[u.name] ?? "",
|
|
5114
|
+
onChange: (be) => L(u.name, be)
|
|
5115
|
+
},
|
|
5116
|
+
u.name
|
|
5117
|
+
);
|
|
5070
5118
|
const V = u.name === "name" && !i || u.readOnly, T = u.required && !(i && u.name === "name" && (l != null && l.autoName || ua.has(e ?? ""))), W = V && m[u.name] ? (Ne = (ue = l == null ? void 0 : l.columnLinks) == null ? void 0 : ue[u.name]) == null ? void 0 : Ne.call(ue, m[u.name], m) : null;
|
|
5071
5119
|
if (W)
|
|
5072
5120
|
return /* @__PURE__ */ r("div", { children: [
|
|
@@ -5074,7 +5122,7 @@ function ma() {
|
|
|
5074
5122
|
/* @__PURE__ */ t(Ce, { className: "py-2 text-sm text-sky-600 hover:underline", to: W, children: String(m[u.name]) })
|
|
5075
5123
|
] }, u.name);
|
|
5076
5124
|
if (u.type === "select" && u.options) {
|
|
5077
|
-
const
|
|
5125
|
+
const be = m[u.name], qe = typeof be == "string" && be !== "" && !u.options.includes(be) ? [...u.options, be] : u.options;
|
|
5078
5126
|
return /* @__PURE__ */ t("div", { children: /* @__PURE__ */ t(
|
|
5079
5127
|
Ge,
|
|
5080
5128
|
{
|
|
@@ -5083,7 +5131,7 @@ function ma() {
|
|
|
5083
5131
|
value: m[u.name] ?? "",
|
|
5084
5132
|
required: T,
|
|
5085
5133
|
disabled: V,
|
|
5086
|
-
onChange: (R) =>
|
|
5134
|
+
onChange: (R) => L(u.name, R.target.value)
|
|
5087
5135
|
}
|
|
5088
5136
|
) }, u.name);
|
|
5089
5137
|
}
|
|
@@ -5099,7 +5147,7 @@ function ma() {
|
|
|
5099
5147
|
required: T,
|
|
5100
5148
|
readOnly: V,
|
|
5101
5149
|
disabled: V,
|
|
5102
|
-
onChange: (
|
|
5150
|
+
onChange: (be) => L(u.name, be.target.value)
|
|
5103
5151
|
}
|
|
5104
5152
|
)
|
|
5105
5153
|
] }, u.name);
|
|
@@ -5114,9 +5162,9 @@ function ma() {
|
|
|
5114
5162
|
readOnly: V,
|
|
5115
5163
|
disabled: V,
|
|
5116
5164
|
value: m[u.name] ?? "",
|
|
5117
|
-
onChange: (
|
|
5165
|
+
onChange: (be) => L(
|
|
5118
5166
|
u.name,
|
|
5119
|
-
le === "number" ? parseFloat(
|
|
5167
|
+
le === "number" ? parseFloat(be.target.value) || 0 : be.target.value
|
|
5120
5168
|
)
|
|
5121
5169
|
},
|
|
5122
5170
|
u.name
|
|
@@ -5124,56 +5172,56 @@ function ma() {
|
|
|
5124
5172
|
}) }) })
|
|
5125
5173
|
] });
|
|
5126
5174
|
}
|
|
5127
|
-
function
|
|
5175
|
+
function li(e) {
|
|
5128
5176
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5129
5177
|
queryKey: ["report", "trial-balance", e],
|
|
5130
5178
|
queryFn: () => F.trialBalance(e)
|
|
5131
5179
|
});
|
|
5132
5180
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5133
5181
|
}
|
|
5134
|
-
function
|
|
5182
|
+
function ci(e) {
|
|
5135
5183
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5136
5184
|
queryKey: ["report", "chart-of-accounts", e],
|
|
5137
5185
|
queryFn: () => F.chartOfAccounts(e)
|
|
5138
5186
|
});
|
|
5139
5187
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5140
5188
|
}
|
|
5141
|
-
function
|
|
5189
|
+
function di(e) {
|
|
5142
5190
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5143
5191
|
queryKey: ["report", "general-ledger", e],
|
|
5144
5192
|
queryFn: () => F.generalLedger(e)
|
|
5145
5193
|
});
|
|
5146
5194
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5147
5195
|
}
|
|
5148
|
-
function
|
|
5196
|
+
function ui(e) {
|
|
5149
5197
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5150
5198
|
queryKey: ["report", "stock-balance", e],
|
|
5151
5199
|
queryFn: () => F.stockBalance(e)
|
|
5152
5200
|
});
|
|
5153
5201
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5154
5202
|
}
|
|
5155
|
-
function
|
|
5203
|
+
function mi(e) {
|
|
5156
5204
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5157
5205
|
queryKey: ["report", "profit-and-loss", e],
|
|
5158
5206
|
queryFn: () => F.profitAndLoss(e)
|
|
5159
5207
|
});
|
|
5160
5208
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5161
5209
|
}
|
|
5162
|
-
function
|
|
5210
|
+
function pi(e) {
|
|
5163
5211
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5164
5212
|
queryKey: ["report", "balance-sheet", e],
|
|
5165
5213
|
queryFn: () => F.balanceSheet(e)
|
|
5166
5214
|
});
|
|
5167
5215
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5168
5216
|
}
|
|
5169
|
-
function
|
|
5217
|
+
function hi(e) {
|
|
5170
5218
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5171
5219
|
queryKey: ["report", "ar-aging", e],
|
|
5172
5220
|
queryFn: () => F.arAging(e)
|
|
5173
5221
|
});
|
|
5174
5222
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5175
5223
|
}
|
|
5176
|
-
function
|
|
5224
|
+
function gi(e) {
|
|
5177
5225
|
const { data: n, isLoading: a, error: s, refetch: o } = ve({
|
|
5178
5226
|
queryKey: ["report", "ap-aging", e],
|
|
5179
5227
|
queryFn: () => F.apAging(e)
|
|
@@ -5181,17 +5229,17 @@ function hi(e) {
|
|
|
5181
5229
|
return { data: n, isLoading: a, error: s, refetch: o };
|
|
5182
5230
|
}
|
|
5183
5231
|
function en({ from: e, to: n, asOf: a }) {
|
|
5184
|
-
const { t: s } =
|
|
5232
|
+
const { t: s } = re();
|
|
5185
5233
|
let o = "";
|
|
5186
5234
|
return a ? o = s("reports.asOfDate", { date: rt(a) }) : e && n ? o = s("reports.periodRange", { from: rt(e), to: rt(n) }) : e ? o = s("reports.periodFrom", { from: rt(e) }) : n && (o = s("reports.periodThrough", { to: rt(n) })), o ? /* @__PURE__ */ t("div", { className: "rounded-lg border border-line bg-surface-subtle px-4 py-2 text-sm font-medium text-fg", children: o }) : null;
|
|
5187
5235
|
}
|
|
5188
|
-
function
|
|
5189
|
-
const { t: e } =
|
|
5236
|
+
function fi() {
|
|
5237
|
+
const { t: e } = re();
|
|
5190
5238
|
Me(e("titles.trial-balance"));
|
|
5191
5239
|
const [n] = he("company", ""), [a] = he("from", ""), [s] = he("to", ""), o = lt(), [i, l] = w(n), [c, h] = w(a), [d, g] = w(s), m = Qe(i), b = (p) => He(p, m), v = fe(() => {
|
|
5192
5240
|
const p = {};
|
|
5193
5241
|
return n && (p.company = n), a && (p.from_date = a), s && (p.to_date = s), p;
|
|
5194
|
-
}, [n, a, s]), { data: k, isLoading: y, refetch: A } =
|
|
5242
|
+
}, [n, a, s]), { data: k, isLoading: y, refetch: A } = li(v), S = () => {
|
|
5195
5243
|
o({
|
|
5196
5244
|
company: i || null,
|
|
5197
5245
|
from: c || null,
|
|
@@ -5265,9 +5313,9 @@ function gi() {
|
|
|
5265
5313
|
] })
|
|
5266
5314
|
] });
|
|
5267
5315
|
}
|
|
5268
|
-
const
|
|
5269
|
-
function
|
|
5270
|
-
const { t: e } =
|
|
5316
|
+
const yi = ["Asset", "Liability", "Equity", "Income", "Expense"];
|
|
5317
|
+
function bi() {
|
|
5318
|
+
const { t: e } = re();
|
|
5271
5319
|
Me(e("titles.chart-of-accounts", { defaultValue: "Chart of Accounts" }));
|
|
5272
5320
|
const n = (/* @__PURE__ */ new Date()).getFullYear(), [a, s] = w(String(n)), [o, i] = w(/* @__PURE__ */ new Set()), l = fe(() => {
|
|
5273
5321
|
const x = [];
|
|
@@ -5277,7 +5325,7 @@ function yi() {
|
|
|
5277
5325
|
}, [n, e]), c = fe(() => {
|
|
5278
5326
|
const x = {};
|
|
5279
5327
|
return a !== "all" && (x.from_date = `${a}-01-01`, x.to_date = `${a}-12-31`), x;
|
|
5280
|
-
}, [a]), { data: h, isLoading: d } =
|
|
5328
|
+
}, [a]), { data: h, isLoading: d } = ci(c), g = Qe(""), m = (x) => He(x, g), b = (h == null ? void 0 : h.accounts) ?? [], { childrenOf: v, rootsByType: k } = fe(() => {
|
|
5281
5329
|
const x = new Map(b.map((B) => [B.name, B])), p = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
5282
5330
|
for (const B of b)
|
|
5283
5331
|
if (B.parent_account && x.has(B.parent_account)) {
|
|
@@ -5347,23 +5395,23 @@ function yi() {
|
|
|
5347
5395
|
] }),
|
|
5348
5396
|
d && /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("common.loading", { defaultValue: "Loading…" }) }) }),
|
|
5349
5397
|
!d && b.length === 0 && /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("coa.empty", { defaultValue: "No accounts found. Complete the company setup first." }) }) }),
|
|
5350
|
-
!d &&
|
|
5398
|
+
!d && yi.filter((x) => (k.get(x) ?? []).length > 0).map((x) => /* @__PURE__ */ r(H, { children: [
|
|
5351
5399
|
/* @__PURE__ */ t("h3", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-fg-muted", children: e(`coa.rootType.${x}`, { defaultValue: x }) }),
|
|
5352
5400
|
/* @__PURE__ */ t("div", { children: (k.get(x) ?? []).map((p) => S(p, 0)) })
|
|
5353
5401
|
] }, x))
|
|
5354
5402
|
] });
|
|
5355
5403
|
}
|
|
5356
|
-
function
|
|
5404
|
+
function vi(e) {
|
|
5357
5405
|
return e.toLowerCase().replace(/\s+/g, "-");
|
|
5358
5406
|
}
|
|
5359
|
-
const
|
|
5360
|
-
function
|
|
5361
|
-
const { t: e } =
|
|
5407
|
+
const xi = ["25", "50", "100", "200"];
|
|
5408
|
+
function ki() {
|
|
5409
|
+
const { t: e } = re();
|
|
5362
5410
|
Me(e("titles.general-ledger"));
|
|
5363
5411
|
const [n] = he("account", ""), [a] = he("party", ""), [s] = he("from", ""), [o] = he("to", ""), [i] = he("per_page", 50), [l] = he("page", 1), c = l - 1, h = lt(), d = (u) => h({ page: u === 0 ? null : u + 1 }), g = (u) => h({ per_page: u, page: null }), [m, b] = w(n), [v, k] = w(a), [y, A] = w(s), [S, x] = w(o), p = Qe(), f = (u) => He(u, p), B = fe(() => {
|
|
5364
5412
|
const u = {};
|
|
5365
5413
|
return n && (u.account = n), a && (u.party = a), s && (u.from_date = s), o && (u.to_date = o), u.limit = String(i), u.offset = String(c * i), u;
|
|
5366
|
-
}, [n, a, s, o, i, c]), { data: E, isLoading: J, refetch: Z } =
|
|
5414
|
+
}, [n, a, s, o, i, c]), { data: E, isLoading: J, refetch: Z } = di(B), L = (E == null ? void 0 : E.rows) ?? [], q = (E == null ? void 0 : E.total) ?? 0, Q = Math.max(1, Math.ceil(q / i)), N = q === 0 ? 0 : c * i + 1, D = Math.min(q, (c + 1) * i), $ = () => {
|
|
5367
5415
|
h({
|
|
5368
5416
|
account: m || null,
|
|
5369
5417
|
party: v || null,
|
|
@@ -5418,7 +5466,7 @@ function xi() {
|
|
|
5418
5466
|
A(u), x(P), h({ from: u, to: P, page: null });
|
|
5419
5467
|
} }),
|
|
5420
5468
|
/* @__PURE__ */ t(en, { from: s, to: o }),
|
|
5421
|
-
J ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) :
|
|
5469
|
+
J ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : L.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noEntries") }) : /* @__PURE__ */ r(Pe, { children: [
|
|
5422
5470
|
/* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
5423
5471
|
/* @__PURE__ */ t("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
|
|
5424
5472
|
/* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Date", { defaultValue: "Date" }) }),
|
|
@@ -5430,7 +5478,7 @@ function xi() {
|
|
|
5430
5478
|
/* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Voucher Type", { defaultValue: "Voucher Type" }) }),
|
|
5431
5479
|
/* @__PURE__ */ t("th", { className: "px-4 py-3 text-left font-medium text-gray-500", children: e("fields.Voucher No", { defaultValue: "Voucher No" }) })
|
|
5432
5480
|
] }) }),
|
|
5433
|
-
/* @__PURE__ */ t("tbody", { className: "divide-y divide-gray-100", children:
|
|
5481
|
+
/* @__PURE__ */ t("tbody", { className: "divide-y divide-gray-100", children: L.map((u, P) => /* @__PURE__ */ r("tr", { className: "hover:bg-gray-50", children: [
|
|
5434
5482
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-500", children: rt(u.posting_date ?? u.date) }),
|
|
5435
5483
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-900", children: u.account }),
|
|
5436
5484
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-700", children: u.party ?? "-" }),
|
|
@@ -5441,7 +5489,7 @@ function xi() {
|
|
|
5441
5489
|
/* @__PURE__ */ t("td", { className: "px-4 py-2", children: u.voucher_type && u.voucher_no ? /* @__PURE__ */ t(
|
|
5442
5490
|
Ce,
|
|
5443
5491
|
{
|
|
5444
|
-
to: `/app/${
|
|
5492
|
+
to: `/app/${vi(u.voucher_type)}/${u.voucher_no}`,
|
|
5445
5493
|
className: "font-medium text-blue-600 hover:text-blue-800",
|
|
5446
5494
|
children: u.voucher_no
|
|
5447
5495
|
}
|
|
@@ -5471,7 +5519,7 @@ function xi() {
|
|
|
5471
5519
|
value: i,
|
|
5472
5520
|
onChange: (u) => g(Number(u.target.value)),
|
|
5473
5521
|
className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
|
|
5474
|
-
children:
|
|
5522
|
+
children: xi.map((u) => /* @__PURE__ */ t("option", { value: u, children: u }, u))
|
|
5475
5523
|
}
|
|
5476
5524
|
)
|
|
5477
5525
|
] }),
|
|
@@ -5507,13 +5555,13 @@ function xi() {
|
|
|
5507
5555
|
] })
|
|
5508
5556
|
] });
|
|
5509
5557
|
}
|
|
5510
|
-
function
|
|
5511
|
-
const { t: e } =
|
|
5558
|
+
function Ni() {
|
|
5559
|
+
const { t: e } = re();
|
|
5512
5560
|
Me(e("titles.stock-balance"));
|
|
5513
5561
|
const [n] = he("item_code", ""), [a] = he("warehouse", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(), d = (y) => He(y, h), g = fe(() => {
|
|
5514
5562
|
const y = {};
|
|
5515
5563
|
return n && (y.item_code = n), a && (y.warehouse = a), y;
|
|
5516
|
-
}, [n, a]), { data: m, isLoading: b, refetch: v } =
|
|
5564
|
+
}, [n, a]), { data: m, isLoading: b, refetch: v } = ui(g), k = () => {
|
|
5517
5565
|
s({
|
|
5518
5566
|
item_code: o || null,
|
|
5519
5567
|
warehouse: l || null
|
|
@@ -5563,13 +5611,13 @@ function ki() {
|
|
|
5563
5611
|
] }) }) })
|
|
5564
5612
|
] });
|
|
5565
5613
|
}
|
|
5566
|
-
function
|
|
5567
|
-
const { t: e } =
|
|
5614
|
+
function wi() {
|
|
5615
|
+
const { t: e } = re();
|
|
5568
5616
|
Me(e("titles.profit-and-loss"));
|
|
5569
5617
|
const [n] = he("company", ""), [a] = he("from", ""), [s] = he("to", ""), o = lt(), [i, l] = w(n), c = Qe(i), h = (p) => He(p, c), [d, g] = w(a), [m, b] = w(s), v = fe(() => {
|
|
5570
5618
|
const p = {};
|
|
5571
5619
|
return n && (p.company = n), a && (p.from_date = a), s && (p.to_date = s), p;
|
|
5572
|
-
}, [n, a, s]), { data: k, isLoading: y, refetch: A } =
|
|
5620
|
+
}, [n, a, s]), { data: k, isLoading: y, refetch: A } = mi(v), S = () => {
|
|
5573
5621
|
o({
|
|
5574
5622
|
company: i || null,
|
|
5575
5623
|
from: d || null,
|
|
@@ -5631,7 +5679,7 @@ function Ni() {
|
|
|
5631
5679
|
] });
|
|
5632
5680
|
}
|
|
5633
5681
|
function on({ title: e, rows: n, total: a, totalLabel: s, currency: o }) {
|
|
5634
|
-
const { t: i } =
|
|
5682
|
+
const { t: i } = re(), l = (c) => He(c, o);
|
|
5635
5683
|
return /* @__PURE__ */ r(H, { children: [
|
|
5636
5684
|
/* @__PURE__ */ t("h3", { className: "mb-3 text-base font-semibold text-gray-800", children: e }),
|
|
5637
5685
|
/* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
@@ -5650,14 +5698,14 @@ function on({ title: e, rows: n, total: a, totalLabel: s, currency: o }) {
|
|
|
5650
5698
|
] })
|
|
5651
5699
|
] });
|
|
5652
5700
|
}
|
|
5653
|
-
function
|
|
5701
|
+
function Ci() {
|
|
5654
5702
|
var S, x, p;
|
|
5655
|
-
const { t: e } =
|
|
5703
|
+
const { t: e } = re();
|
|
5656
5704
|
Me(e("titles.balance-sheet"));
|
|
5657
5705
|
const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (f) => He(f, h), g = fe(() => {
|
|
5658
5706
|
const f = {};
|
|
5659
5707
|
return n && (f.company = n), a && (f.as_of_date = a), f;
|
|
5660
|
-
}, [n, a]), { data: m, isLoading: b, refetch: v } =
|
|
5708
|
+
}, [n, a]), { data: m, isLoading: b, refetch: v } = pi(g), k = () => {
|
|
5661
5709
|
s({ company: o || null, as_of_date: l || null }), v();
|
|
5662
5710
|
}, y = m && (((S = m.assets) == null ? void 0 : S.length) > 0 || ((x = m.liabilities) == null ? void 0 : x.length) > 0 || ((p = m.equity) == null ? void 0 : p.length) > 0), A = m ? Math.abs(m.total_assets - m.total_liabilities_and_equity) < 0.01 : !1;
|
|
5663
5711
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
@@ -5692,13 +5740,13 @@ function wi() {
|
|
|
5692
5740
|
] }) : /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noData") })
|
|
5693
5741
|
] });
|
|
5694
5742
|
}
|
|
5695
|
-
function
|
|
5696
|
-
const { t: e } =
|
|
5743
|
+
function Si() {
|
|
5744
|
+
const { t: e } = re();
|
|
5697
5745
|
Me(e("titles.ar-aging"));
|
|
5698
5746
|
const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (y) => He(y, h), g = fe(() => {
|
|
5699
5747
|
const y = {};
|
|
5700
5748
|
return n && (y.company = n), a && (y.as_of_date = a), y;
|
|
5701
|
-
}, [n, a]), { data: m, isLoading: b, refetch: v } =
|
|
5749
|
+
}, [n, a]), { data: m, isLoading: b, refetch: v } = hi(g), k = () => {
|
|
5702
5750
|
s({ company: o || null, as_of_date: l || null }), v();
|
|
5703
5751
|
};
|
|
5704
5752
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
@@ -5752,13 +5800,13 @@ function Ci() {
|
|
|
5752
5800
|
] }) }) })
|
|
5753
5801
|
] });
|
|
5754
5802
|
}
|
|
5755
|
-
function
|
|
5756
|
-
const { t: e } =
|
|
5803
|
+
function Ai() {
|
|
5804
|
+
const { t: e } = re();
|
|
5757
5805
|
Me(e("titles.ap-aging"));
|
|
5758
5806
|
const [n] = he("company", ""), [a] = he("as_of_date", ""), s = lt(), [o, i] = w(n), [l, c] = w(a), h = Qe(o), d = (y) => He(y, h), g = fe(() => {
|
|
5759
5807
|
const y = {};
|
|
5760
5808
|
return n && (y.company = n), a && (y.as_of_date = a), y;
|
|
5761
|
-
}, [n, a]), { data: m, isLoading: b, refetch: v } =
|
|
5809
|
+
}, [n, a]), { data: m, isLoading: b, refetch: v } = gi(g), k = () => {
|
|
5762
5810
|
s({ company: o || null, as_of_date: l || null }), v();
|
|
5763
5811
|
};
|
|
5764
5812
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
@@ -5812,11 +5860,11 @@ function Si() {
|
|
|
5812
5860
|
] }) }) })
|
|
5813
5861
|
] });
|
|
5814
5862
|
}
|
|
5815
|
-
function
|
|
5863
|
+
function _i(e) {
|
|
5816
5864
|
const n = Number(e ?? 0);
|
|
5817
5865
|
return Number.isFinite(n) ? n : 0;
|
|
5818
5866
|
}
|
|
5819
|
-
function
|
|
5867
|
+
function Di(e, n) {
|
|
5820
5868
|
if (!n) return e;
|
|
5821
5869
|
const a = String(e ?? "");
|
|
5822
5870
|
if (n === "month") return a.slice(0, 7);
|
|
@@ -5826,13 +5874,13 @@ function _i(e, n) {
|
|
|
5826
5874
|
}
|
|
5827
5875
|
function dr(e, n, a) {
|
|
5828
5876
|
if (n === "count") return a ? e.filter((o) => o[a] != null).length : e.length;
|
|
5829
|
-
const s = a ? e.filter((o) => o[a] != null).map((o) =>
|
|
5877
|
+
const s = a ? e.filter((o) => o[a] != null).map((o) => _i(o[a])) : [];
|
|
5830
5878
|
return s.length ? n === "sum" ? s.reduce((o, i) => o + i, 0) : n === "avg" ? s.reduce((o, i) => o + i, 0) / s.length : n === "min" ? Math.min(...s) : Math.max(...s) : 0;
|
|
5831
5879
|
}
|
|
5832
|
-
function
|
|
5880
|
+
function Pi(e, n) {
|
|
5833
5881
|
return e == null && n == null ? 0 : e == null ? 1 : n == null ? -1 : typeof e == "number" && typeof n == "number" ? e - n : String(e).localeCompare(String(n), void 0, { numeric: !0 });
|
|
5834
5882
|
}
|
|
5835
|
-
function
|
|
5883
|
+
function Ti(e, n) {
|
|
5836
5884
|
const a = n.get(e.source);
|
|
5837
5885
|
if (!a) throw new Error(`Unknown report source: ${e.source}`);
|
|
5838
5886
|
const s = e.dimensions ?? [], o = e.measures ?? [];
|
|
@@ -5844,7 +5892,7 @@ function Pi(e, n) {
|
|
|
5844
5892
|
for (const c of a) {
|
|
5845
5893
|
const h = {};
|
|
5846
5894
|
for (const m of s) {
|
|
5847
|
-
const b = m.key || m.field, v =
|
|
5895
|
+
const b = m.key || m.field, v = Di(c[m.field], m.bucket);
|
|
5848
5896
|
h[b] = v == null || v === "" ? m.fallback ?? v : v;
|
|
5849
5897
|
}
|
|
5850
5898
|
const d = JSON.stringify(s.map((m) => h[m.key || m.field])), g = l.get(d) ?? { values: h, rows: [] };
|
|
@@ -5859,7 +5907,7 @@ function Pi(e, n) {
|
|
|
5859
5907
|
}
|
|
5860
5908
|
for (const l of [...e.sort ?? []].reverse()) {
|
|
5861
5909
|
const c = l.direction === "desc" ? -1 : 1;
|
|
5862
|
-
i.sort((h, d) =>
|
|
5910
|
+
i.sort((h, d) => Pi(h[l.field], d[l.field]) * c);
|
|
5863
5911
|
}
|
|
5864
5912
|
return e.limit && (i = i.slice(0, e.limit)), {
|
|
5865
5913
|
id: e.id,
|
|
@@ -5868,12 +5916,12 @@ function Pi(e, n) {
|
|
|
5868
5916
|
rows: i
|
|
5869
5917
|
};
|
|
5870
5918
|
}
|
|
5871
|
-
function
|
|
5919
|
+
function Ri(e, n) {
|
|
5872
5920
|
if (!e.report || e.report.version !== 1 || !Array.isArray(e.report.tables))
|
|
5873
5921
|
throw new Error("Unsupported custom report definition. Create a new version 1 report.");
|
|
5874
5922
|
const a = new Map(n.map((l) => [l.name, l.rows])), s = e.report.tables.map((l) => {
|
|
5875
5923
|
if (a.has(l.id)) throw new Error(`Duplicate report source/table id: ${l.id}`);
|
|
5876
|
-
const c =
|
|
5924
|
+
const c = Ti(l, a);
|
|
5877
5925
|
return a.set(l.id, c.rows), c;
|
|
5878
5926
|
}), o = new Set(s.map((l) => l.id)), i = (e.report.charts ?? []).map((l) => {
|
|
5879
5927
|
if (!o.has(l.data_table))
|
|
@@ -5896,7 +5944,7 @@ function Ti(e, n) {
|
|
|
5896
5944
|
charts: i
|
|
5897
5945
|
};
|
|
5898
5946
|
}
|
|
5899
|
-
function
|
|
5947
|
+
function Bi() {
|
|
5900
5948
|
const e = /* @__PURE__ */ new Date(), n = De(e), a = new Date(e);
|
|
5901
5949
|
a.setMonth(a.getMonth() - 12);
|
|
5902
5950
|
const s = De(a);
|
|
@@ -5965,23 +6013,23 @@ function Ri() {
|
|
|
5965
6013
|
2
|
|
5966
6014
|
);
|
|
5967
6015
|
}
|
|
5968
|
-
const ur =
|
|
5969
|
-
function
|
|
6016
|
+
const ur = Bi();
|
|
6017
|
+
function Ii() {
|
|
5970
6018
|
Me("Analytics");
|
|
5971
|
-
const e = Ke(), { sessions: n, createSession: a } = vt(), [s] = he("report_id", ""), [o] = he("metric", ""), [i] = he("group_by", ""), [l] = he("from", ""), [c] = he("to", ""), [h] = he("company", ""), [d, g] = w(ur), [m, b] = w([]), [v, k] = w(null), [y, A] = w(""), [S, x] = w(!1), [p, f] = w(!1), [B, E] = w(""), J = pe(""), Z = pe(""),
|
|
6019
|
+
const e = Ke(), { sessions: n, createSession: a } = vt(), [s] = he("report_id", ""), [o] = he("metric", ""), [i] = he("group_by", ""), [l] = he("from", ""), [c] = he("to", ""), [h] = he("company", ""), [d, g] = w(ur), [m, b] = w([]), [v, k] = w(null), [y, A] = w(""), [S, x] = w(!1), [p, f] = w(!1), [B, E] = w(""), J = pe(""), Z = pe(""), L = pe(0), q = fe(() => !o || !i ? "" : JSON.stringify(Fi({
|
|
5972
6020
|
metric: o,
|
|
5973
6021
|
groupBy: i,
|
|
5974
6022
|
fromDate: l || void 0,
|
|
5975
6023
|
toDate: c || void 0,
|
|
5976
6024
|
company: h || void 0
|
|
5977
6025
|
}), null, 2), [o, i, l, c, h]), Q = async (u) => {
|
|
5978
|
-
const P = ++
|
|
6026
|
+
const P = ++L.current, V = () => L.current === P;
|
|
5979
6027
|
A(""), x(!0);
|
|
5980
6028
|
try {
|
|
5981
6029
|
const W = JSON.parse(u ?? d), le = await F.runtimeData({ requests: W.data_requests || [] });
|
|
5982
6030
|
if (!V()) return;
|
|
5983
6031
|
b(le.datasets);
|
|
5984
|
-
const ue =
|
|
6032
|
+
const ue = Ri(W, le.datasets);
|
|
5985
6033
|
if (!V()) return;
|
|
5986
6034
|
k(ue);
|
|
5987
6035
|
} catch (T) {
|
|
@@ -6007,7 +6055,7 @@ function Bi() {
|
|
|
6007
6055
|
u = !0;
|
|
6008
6056
|
});
|
|
6009
6057
|
}, [s, q]);
|
|
6010
|
-
const N = !!(!s && q), D = fe(() =>
|
|
6058
|
+
const N = !!(!s && q), D = fe(() => Oi(v), [v]), $ = async () => {
|
|
6011
6059
|
var ue;
|
|
6012
6060
|
const u = d.trim() !== Z.current.trim(), P = s || "unsaved-runtime-report", V = m.map((Ne) => ({
|
|
6013
6061
|
name: Ne.name,
|
|
@@ -6059,7 +6107,7 @@ function Bi() {
|
|
|
6059
6107
|
/* @__PURE__ */ t(Y, { onClick: () => void Q(), disabled: S, children: S ? "Running..." : "Run Report" })
|
|
6060
6108
|
] })
|
|
6061
6109
|
] }) }),
|
|
6062
|
-
p ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : y ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: y }) }) : v ? /* @__PURE__ */ t(
|
|
6110
|
+
p ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : y ? /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: y }) }) : v ? /* @__PURE__ */ t(Ei, { output: v }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
|
|
6063
6111
|
m.length > 0 && /* @__PURE__ */ t(H, { title: "Fetched Datasets", children: /* @__PURE__ */ t("div", { className: "space-y-4", children: m.map((u) => /* @__PURE__ */ r("div", { className: "rounded-md border border-gray-200 p-4", children: [
|
|
6064
6112
|
/* @__PURE__ */ r("div", { className: "flex items-baseline justify-between gap-4", children: [
|
|
6065
6113
|
/* @__PURE__ */ r("div", { children: [
|
|
@@ -6088,7 +6136,7 @@ function Bi() {
|
|
|
6088
6136
|
] })
|
|
6089
6137
|
] });
|
|
6090
6138
|
}
|
|
6091
|
-
function
|
|
6139
|
+
function Ei({ output: e }) {
|
|
6092
6140
|
var o, i;
|
|
6093
6141
|
const n = Qe(), a = (e.tables ?? []).map((l, c) => ({
|
|
6094
6142
|
...l,
|
|
@@ -6110,11 +6158,11 @@ function Ii({ output: e }) {
|
|
|
6110
6158
|
const h = l.dataTable ? s.get(l.dataTable) : void 0, d = l.data ?? (h == null ? void 0 : h.rows) ?? [];
|
|
6111
6159
|
if (!d.length)
|
|
6112
6160
|
return /* @__PURE__ */ t(H, { title: l.title, children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: "Chart has no usable data." }) }, l.id || `chart_${c + 1}`);
|
|
6113
|
-
const g = l.type === "pie" ? [] : d.map((S) => String(S[l.x] ?? "")), m =
|
|
6161
|
+
const g = l.type === "pie" ? [] : d.map((S) => String(S[l.x] ?? "")), m = Vi(g), b = Math.max(320, 200 + m.axisHeight), v = (y = l.series) != null && y.length ? l.series : l.y ? [{ key: l.y, label: void 0 }] : [], k = (S, x, p) => {
|
|
6114
6162
|
var f;
|
|
6115
6163
|
return ln(
|
|
6116
6164
|
S,
|
|
6117
|
-
|
|
6165
|
+
qi(h, String((p == null ? void 0 : p.dataKey) ?? ((f = v[0]) == null ? void 0 : f.key) ?? "")),
|
|
6118
6166
|
n
|
|
6119
6167
|
);
|
|
6120
6168
|
};
|
|
@@ -6186,7 +6234,7 @@ function Ii({ output: e }) {
|
|
|
6186
6234
|
] }) }) }, l.id))
|
|
6187
6235
|
] });
|
|
6188
6236
|
}
|
|
6189
|
-
function
|
|
6237
|
+
function Li(e) {
|
|
6190
6238
|
return e.replace(/_/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
|
|
6191
6239
|
}
|
|
6192
6240
|
function mr(e) {
|
|
@@ -6195,7 +6243,7 @@ function mr(e) {
|
|
|
6195
6243
|
n.set(a.id, a), a.title && n.set(a.title, a);
|
|
6196
6244
|
return n;
|
|
6197
6245
|
}
|
|
6198
|
-
function
|
|
6246
|
+
function Oi(e) {
|
|
6199
6247
|
var o;
|
|
6200
6248
|
if (!e) return [];
|
|
6201
6249
|
const n = (e.tables ?? []).map((i, l) => ({
|
|
@@ -6218,8 +6266,8 @@ function Li(e) {
|
|
|
6218
6266
|
}
|
|
6219
6267
|
return s;
|
|
6220
6268
|
}
|
|
6221
|
-
function
|
|
6222
|
-
const n = `${
|
|
6269
|
+
function Fi(e) {
|
|
6270
|
+
const n = `${Mi(e.metric)} by ${Li(e.groupBy)}`;
|
|
6223
6271
|
if (e.metric === "sales_revenue")
|
|
6224
6272
|
return kt({
|
|
6225
6273
|
title: n,
|
|
@@ -6367,7 +6415,7 @@ function kt(e) {
|
|
|
6367
6415
|
}
|
|
6368
6416
|
};
|
|
6369
6417
|
}
|
|
6370
|
-
function
|
|
6418
|
+
function Mi(e) {
|
|
6371
6419
|
return {
|
|
6372
6420
|
sales_revenue: "Sales Revenue",
|
|
6373
6421
|
sales_returns: "Sales Returns",
|
|
@@ -6379,7 +6427,7 @@ function Fi(e) {
|
|
|
6379
6427
|
stock_value: "Stock Value"
|
|
6380
6428
|
}[e] || "Analytics";
|
|
6381
6429
|
}
|
|
6382
|
-
function
|
|
6430
|
+
function qi(e, n) {
|
|
6383
6431
|
var a, s;
|
|
6384
6432
|
return ((a = e == null ? void 0 : e.columns.find((o) => o.key === n)) == null ? void 0 : a.type) || ((s = e == null ? void 0 : e.columns.find((o) => o.key === n)) == null ? void 0 : s.format);
|
|
6385
6433
|
}
|
|
@@ -6390,23 +6438,23 @@ function pa(e) {
|
|
|
6390
6438
|
const n = Math.abs(e);
|
|
6391
6439
|
return n >= 1e6 ? `${(e / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(e / 1e3).toFixed(0)}k` : String(e);
|
|
6392
6440
|
}
|
|
6393
|
-
const Rt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], ha = Rt,
|
|
6441
|
+
const Rt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], ha = Rt, zi = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
6394
6442
|
let cn = null;
|
|
6395
|
-
function
|
|
6443
|
+
function $i(e, n = zi) {
|
|
6396
6444
|
if (typeof document > "u") return e.length * 7;
|
|
6397
6445
|
cn || (cn = document.createElement("canvas"));
|
|
6398
6446
|
const a = cn.getContext("2d");
|
|
6399
6447
|
return a ? (a.font = n, a.measureText(e).width) : e.length * 7;
|
|
6400
6448
|
}
|
|
6401
|
-
function
|
|
6449
|
+
function Vi(e) {
|
|
6402
6450
|
if (!e.length) return { angle: 0, axisHeight: 30, maxWidth: 0 };
|
|
6403
|
-
const n = e.map((c) =>
|
|
6451
|
+
const n = e.map((c) => $i(c)), a = Math.max(1, ...n);
|
|
6404
6452
|
let s = 0;
|
|
6405
6453
|
a > 55 && (s = -30), a > 110 && (s = -45), a > 200 && (s = -60), a > 300 && (s = -90);
|
|
6406
6454
|
const o = Math.abs(s) * Math.PI / 180, i = s === 0 ? 20 : Math.abs(s) === 90 ? a : Math.ceil(a * Math.sin(o)), l = Math.min(280, Math.max(30, i + 18));
|
|
6407
6455
|
return { angle: s, axisHeight: l, maxWidth: a };
|
|
6408
6456
|
}
|
|
6409
|
-
function
|
|
6457
|
+
function Ui(e) {
|
|
6410
6458
|
return ve({
|
|
6411
6459
|
queryKey: ["fleet-calendar", e],
|
|
6412
6460
|
queryFn: () => F.fleetCalendar(e)
|
|
@@ -6427,24 +6475,24 @@ function mn(e, n) {
|
|
|
6427
6475
|
function fa(e) {
|
|
6428
6476
|
return new Date(e.replace(" ", "T")).getTime();
|
|
6429
6477
|
}
|
|
6430
|
-
const
|
|
6478
|
+
const Ki = {
|
|
6431
6479
|
Reserved: "bg-amber-400 text-amber-950",
|
|
6432
6480
|
"On Hire": "bg-blue-500 text-white",
|
|
6433
6481
|
Returned: "bg-gray-300 text-gray-700",
|
|
6434
6482
|
Cancelled: "bg-gray-200 text-gray-500 line-through"
|
|
6435
|
-
},
|
|
6483
|
+
}, ji = {
|
|
6436
6484
|
Available: "bg-green-500",
|
|
6437
6485
|
"On Hire": "bg-blue-500",
|
|
6438
6486
|
Maintenance: "bg-amber-500",
|
|
6439
6487
|
Retired: "bg-gray-400"
|
|
6440
6488
|
};
|
|
6441
|
-
function
|
|
6442
|
-
const { t: e } =
|
|
6489
|
+
function Wi() {
|
|
6490
|
+
const { t: e } = re();
|
|
6443
6491
|
Me(e("rentals.fleetCalendar", { defaultValue: "Fleet Calendar" }));
|
|
6444
6492
|
const n = Ke(), [a, s] = w(28), [o, i] = w(ga()), [l, c] = w(""), [h, d] = w(""), [g, m] = w(""), [b, v] = w(""), k = fe(() => mn(o, a), [o, a]), y = o.getTime(), A = a * pr, S = fe(
|
|
6445
6493
|
() => Array.from({ length: a }, ($, u) => mn(o, u)),
|
|
6446
6494
|
[o, a]
|
|
6447
|
-
), { data: x, isLoading: p, error: f } =
|
|
6495
|
+
), { data: x, isLoading: p, error: f } = Ui({
|
|
6448
6496
|
from: zt(o),
|
|
6449
6497
|
to: zt(k),
|
|
6450
6498
|
warehouse: g || void 0,
|
|
@@ -6456,7 +6504,7 @@ function ji() {
|
|
|
6456
6504
|
V.push(u), $.set(P, V);
|
|
6457
6505
|
}
|
|
6458
6506
|
return $;
|
|
6459
|
-
}, [x]), J = ((x == null ? void 0 : x.reservations) ?? []).filter(($) => !$.asset), Z = J.length,
|
|
6507
|
+
}, [x]), J = ((x == null ? void 0 : x.reservations) ?? []).filter(($) => !$.asset), Z = J.length, L = [...B, ...J.map(($) => ({
|
|
6460
6508
|
name: `pool:${$.name}`,
|
|
6461
6509
|
asset_tag: e("rentals.unassigned"),
|
|
6462
6510
|
item_code: $.item_code,
|
|
@@ -6530,7 +6578,7 @@ function ji() {
|
|
|
6530
6578
|
e("rentals.pooledNote", { count: Z, defaultValue: "{{count}} pool booking(s) awaiting assignment" })
|
|
6531
6579
|
] })
|
|
6532
6580
|
] }),
|
|
6533
|
-
f ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-red-500", children: e("rentals.loadError", { defaultValue: "Could not load the fleet calendar." }) }) : p ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("common.loading", { defaultValue: "Loading…" }) }) :
|
|
6581
|
+
f ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-red-500", children: e("rentals.loadError", { defaultValue: "Could not load the fleet calendar." }) }) : p ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("common.loading", { defaultValue: "Loading…" }) }) : L.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("rentals.noAssets", { defaultValue: "No assets to show. Add machines under Rentals → Fleet." }) }) : /* @__PURE__ */ t(H, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("div", { style: { minWidth: un + D }, children: [
|
|
6534
6582
|
/* @__PURE__ */ r("div", { className: "flex border-b bg-gray-50 text-xs text-gray-500", children: [
|
|
6535
6583
|
/* @__PURE__ */ t("div", { className: "shrink-0 px-3 py-2 font-medium", style: { width: un }, children: e("rentals.machine", { defaultValue: "Machine" }) }),
|
|
6536
6584
|
/* @__PURE__ */ t("div", { className: "flex", style: { width: D }, children: S.map(($) => /* @__PURE__ */ r("div", { className: "shrink-0 border-l py-2 text-center", style: { width: dn }, children: [
|
|
@@ -6538,12 +6586,12 @@ function ji() {
|
|
|
6538
6586
|
/* @__PURE__ */ t("div", { className: "text-[10px] uppercase", children: $.toLocaleDateString(void 0, { weekday: "short" }) })
|
|
6539
6587
|
] }, $.getTime())) })
|
|
6540
6588
|
] }),
|
|
6541
|
-
|
|
6589
|
+
L.map(($) => {
|
|
6542
6590
|
const u = E.get($.name) ?? [];
|
|
6543
6591
|
return /* @__PURE__ */ r("div", { className: "flex border-b hover:bg-gray-50", children: [
|
|
6544
6592
|
/* @__PURE__ */ r("div", { className: "shrink-0 px-3 py-2", style: { width: un }, children: [
|
|
6545
6593
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
6546
|
-
/* @__PURE__ */ t("span", { className: `inline-block h-2.5 w-2.5 rounded-full ${
|
|
6594
|
+
/* @__PURE__ */ t("span", { className: `inline-block h-2.5 w-2.5 rounded-full ${ji[$.status ?? ""] ?? "bg-gray-300"}` }),
|
|
6547
6595
|
$.asset_tag ?? $.name
|
|
6548
6596
|
] }),
|
|
6549
6597
|
/* @__PURE__ */ r("div", { className: "text-xs text-gray-500", children: [
|
|
@@ -6555,7 +6603,7 @@ function ji() {
|
|
|
6555
6603
|
/* @__PURE__ */ r("div", { className: "relative", style: { width: D, height: 44 }, children: [
|
|
6556
6604
|
/* @__PURE__ */ t("div", { className: "absolute inset-0 flex", children: S.map((P) => /* @__PURE__ */ t("div", { className: "shrink-0 border-l", style: { width: dn } }, P.getTime())) }),
|
|
6557
6605
|
u.map((P) => {
|
|
6558
|
-
const { left: V, width: T } = q(P), W =
|
|
6606
|
+
const { left: V, width: T } = q(P), W = Ki[P.status ?? ""] ?? "bg-slate-400 text-white";
|
|
6559
6607
|
return /* @__PURE__ */ t(
|
|
6560
6608
|
"button",
|
|
6561
6609
|
{
|
|
@@ -6574,8 +6622,8 @@ function ji() {
|
|
|
6574
6622
|
] }) }) })
|
|
6575
6623
|
] });
|
|
6576
6624
|
}
|
|
6577
|
-
const
|
|
6578
|
-
function
|
|
6625
|
+
const Gi = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
|
|
6626
|
+
function Hi() {
|
|
6579
6627
|
Me("Company Setup");
|
|
6580
6628
|
const e = et(), { data: n, isLoading: a } = ve({
|
|
6581
6629
|
queryKey: ["setup-status"],
|
|
@@ -6609,7 +6657,7 @@ function Gi() {
|
|
|
6609
6657
|
return /* @__PURE__ */ t("p", { className: "text-gray-500", children: "Loading..." });
|
|
6610
6658
|
if (n != null && n.setup_complete && !b)
|
|
6611
6659
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
6612
|
-
/* @__PURE__ */ t(H, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ t("ul", { className: "divide-y divide-gray-100", children: n.companies.map((E, J) => /* @__PURE__ */ t("li", { className: "py-3", children: /* @__PURE__ */ t(
|
|
6660
|
+
/* @__PURE__ */ t(H, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ t("ul", { className: "divide-y divide-gray-100", children: n.companies.map((E, J) => /* @__PURE__ */ t("li", { className: "py-3", children: /* @__PURE__ */ t(Qi, { company: E }) }, J)) }) : /* @__PURE__ */ t("p", { className: "text-gray-400", children: "No companies found" }) }),
|
|
6613
6661
|
/* @__PURE__ */ t(Ce, { to: "/", className: "text-blue-600 hover:text-blue-800 text-sm font-medium", children: "Go to Dashboard" })
|
|
6614
6662
|
] });
|
|
6615
6663
|
if (b)
|
|
@@ -6644,7 +6692,7 @@ function Gi() {
|
|
|
6644
6692
|
Ge,
|
|
6645
6693
|
{
|
|
6646
6694
|
label: "Currency",
|
|
6647
|
-
options:
|
|
6695
|
+
options: Gi,
|
|
6648
6696
|
value: i,
|
|
6649
6697
|
onChange: (E) => l(E.target.value)
|
|
6650
6698
|
}
|
|
@@ -6739,7 +6787,7 @@ function Gi() {
|
|
|
6739
6787
|
] }) })
|
|
6740
6788
|
] });
|
|
6741
6789
|
}
|
|
6742
|
-
function
|
|
6790
|
+
function Qi({ company: e }) {
|
|
6743
6791
|
const n = [
|
|
6744
6792
|
[e.city, e.zip_code].filter(Boolean).join(" "),
|
|
6745
6793
|
e.country
|
|
@@ -6780,7 +6828,7 @@ function Hi({ company: e }) {
|
|
|
6780
6828
|
e.default_currency && /* @__PURE__ */ t("span", { className: "shrink-0 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: e.default_currency })
|
|
6781
6829
|
] });
|
|
6782
6830
|
}
|
|
6783
|
-
const
|
|
6831
|
+
const Yi = [
|
|
6784
6832
|
{
|
|
6785
6833
|
number: 1,
|
|
6786
6834
|
title: "Set Up Your Company",
|
|
@@ -6932,8 +6980,8 @@ function hr() {
|
|
|
6932
6980
|
e(`/chat/${o}`, { state: { prefillMessage: s } });
|
|
6933
6981
|
};
|
|
6934
6982
|
}
|
|
6935
|
-
function
|
|
6936
|
-
const { t: e } =
|
|
6983
|
+
function Ji() {
|
|
6984
|
+
const { t: e } = re(), n = hr();
|
|
6937
6985
|
return /* @__PURE__ */ t(H, { className: "border-emerald-200 bg-gradient-to-br from-emerald-50 to-white", children: /* @__PURE__ */ r("div", { className: "flex flex-col gap-4 md:flex-row md:items-start", children: [
|
|
6938
6986
|
/* @__PURE__ */ t("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-lg font-bold text-emerald-700", children: "▶" }),
|
|
6939
6987
|
/* @__PURE__ */ r("div", { className: "flex-1 space-y-3", children: [
|
|
@@ -6968,8 +7016,8 @@ function Yi() {
|
|
|
6968
7016
|
] })
|
|
6969
7017
|
] }) });
|
|
6970
7018
|
}
|
|
6971
|
-
function
|
|
6972
|
-
const { t: e } =
|
|
7019
|
+
function Zi() {
|
|
7020
|
+
const { t: e } = re(), n = hr(), a = [
|
|
6973
7021
|
e("tutorial.caPrompt1"),
|
|
6974
7022
|
e("tutorial.caPrompt2"),
|
|
6975
7023
|
e("tutorial.caPrompt3"),
|
|
@@ -7027,8 +7075,8 @@ function Ji() {
|
|
|
7027
7075
|
] })
|
|
7028
7076
|
] }) });
|
|
7029
7077
|
}
|
|
7030
|
-
function
|
|
7031
|
-
const { t: e } =
|
|
7078
|
+
function Xi() {
|
|
7079
|
+
const { t: e } = re(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
|
|
7032
7080
|
return /* @__PURE__ */ r(H, { children: [
|
|
7033
7081
|
/* @__PURE__ */ t("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: e("tutorial.flowTitle") }),
|
|
7034
7082
|
/* @__PURE__ */ r("div", { className: "space-y-4 text-sm text-gray-600", children: [
|
|
@@ -7098,8 +7146,8 @@ function Zi() {
|
|
|
7098
7146
|
] })
|
|
7099
7147
|
] });
|
|
7100
7148
|
}
|
|
7101
|
-
function
|
|
7102
|
-
const { t: e } =
|
|
7149
|
+
function eo() {
|
|
7150
|
+
const { t: e } = re(), n = (a) => e(`tutorial.chips.${a}`, { defaultValue: a });
|
|
7103
7151
|
return /* @__PURE__ */ r(H, { children: [
|
|
7104
7152
|
/* @__PURE__ */ t("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: e("tutorial.lifecycleTitle") }),
|
|
7105
7153
|
/* @__PURE__ */ r("div", { className: "space-y-2 text-sm text-gray-600", children: [
|
|
@@ -7134,8 +7182,8 @@ function Xi() {
|
|
|
7134
7182
|
] })
|
|
7135
7183
|
] });
|
|
7136
7184
|
}
|
|
7137
|
-
function
|
|
7138
|
-
const { t: e } =
|
|
7185
|
+
function to() {
|
|
7186
|
+
const { t: e } = re();
|
|
7139
7187
|
return Me(e("titles.tutorial")), /* @__PURE__ */ r("div", { className: "mx-auto max-w-3xl space-y-6", children: [
|
|
7140
7188
|
/* @__PURE__ */ r("div", { children: [
|
|
7141
7189
|
/* @__PURE__ */ t("h2", { className: "text-xl font-semibold text-gray-900", children: e("tutorial.pageTitle") }),
|
|
@@ -7158,11 +7206,11 @@ function eo() {
|
|
|
7158
7206
|
] }),
|
|
7159
7207
|
/* @__PURE__ */ t("p", { className: "mt-4 text-sm text-gray-500", children: e("tutorial.manualIntro") })
|
|
7160
7208
|
] }),
|
|
7161
|
-
/* @__PURE__ */ t(Yi, {}),
|
|
7162
7209
|
/* @__PURE__ */ t(Ji, {}),
|
|
7163
7210
|
/* @__PURE__ */ t(Zi, {}),
|
|
7164
7211
|
/* @__PURE__ */ t(Xi, {}),
|
|
7165
|
-
|
|
7212
|
+
/* @__PURE__ */ t(eo, {}),
|
|
7213
|
+
Yi.map((n) => {
|
|
7166
7214
|
var a;
|
|
7167
7215
|
return /* @__PURE__ */ t(H, { children: /* @__PURE__ */ r("div", { className: "flex gap-4", children: [
|
|
7168
7216
|
/* @__PURE__ */ t("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-sm font-bold text-blue-700", children: n.number }),
|
|
@@ -7223,7 +7271,7 @@ function eo() {
|
|
|
7223
7271
|
] }) })
|
|
7224
7272
|
] });
|
|
7225
7273
|
}
|
|
7226
|
-
const pn = 5,
|
|
7274
|
+
const pn = 5, no = 10 * 1024 * 1024, ao = /* @__PURE__ */ new Set([
|
|
7227
7275
|
"image/png",
|
|
7228
7276
|
"image/jpeg",
|
|
7229
7277
|
"image/gif",
|
|
@@ -7258,7 +7306,7 @@ const pn = 5, to = 10 * 1024 * 1024, no = /* @__PURE__ */ new Set([
|
|
|
7258
7306
|
"text/xml",
|
|
7259
7307
|
"application/zip",
|
|
7260
7308
|
"application/x-zip-compressed"
|
|
7261
|
-
]),
|
|
7309
|
+
]), ro = /* @__PURE__ */ new Set([
|
|
7262
7310
|
"png",
|
|
7263
7311
|
"jpg",
|
|
7264
7312
|
"jpeg",
|
|
@@ -7279,10 +7327,10 @@ const pn = 5, to = 10 * 1024 * 1024, no = /* @__PURE__ */ new Set([
|
|
|
7279
7327
|
"xml",
|
|
7280
7328
|
"zip"
|
|
7281
7329
|
]);
|
|
7282
|
-
function
|
|
7330
|
+
function so(e) {
|
|
7283
7331
|
return new Promise((n) => window.setTimeout(n, e));
|
|
7284
7332
|
}
|
|
7285
|
-
function
|
|
7333
|
+
function io(e) {
|
|
7286
7334
|
return new Promise((n, a) => {
|
|
7287
7335
|
const s = new FileReader();
|
|
7288
7336
|
s.onloadend = () => {
|
|
@@ -7313,12 +7361,12 @@ function ba(e) {
|
|
|
7313
7361
|
}
|
|
7314
7362
|
function va() {
|
|
7315
7363
|
var Mn;
|
|
7316
|
-
const { t: e } =
|
|
7364
|
+
const { t: e } = re(), { sessionId: n } = bt(), a = Ke(), s = Ct(), [o] = Jt(), i = o.get("demo") === "1", [l, c] = w(""), [h, d] = w(""), [g, m] = w([]), [b, v] = w(""), [k, y] = w(!1), [A, S] = w("idle"), x = pe(null), p = pe(null), f = pe([]), {
|
|
7317
7365
|
sessions: B,
|
|
7318
7366
|
connectionStatus: E,
|
|
7319
7367
|
connectionVersion: J,
|
|
7320
7368
|
createSession: Z,
|
|
7321
|
-
startDemo:
|
|
7369
|
+
startDemo: L,
|
|
7322
7370
|
completeDemoTyping: q,
|
|
7323
7371
|
loadHistory: Q,
|
|
7324
7372
|
loadMoreHistory: N,
|
|
@@ -7330,7 +7378,7 @@ function va() {
|
|
|
7330
7378
|
isThinking: T,
|
|
7331
7379
|
getDemoStatus: W,
|
|
7332
7380
|
getDemoTypingCue: le
|
|
7333
|
-
} = vt(), ue = pe(null), Ne = pe(null),
|
|
7381
|
+
} = vt(), ue = pe(null), Ne = pe(null), be = pe(null), qe = pe(null), [R, ae] = w(0), xe = pe(!1), O = pe(null), oe = pe(0), Ie = pe(!0), Ae = pe(null), Ye = pe(!1), tt = pe(null), je = u(n), st = (Mn = B.find((I) => I.id === n)) == null ? void 0 : Mn.title;
|
|
7334
7382
|
Me(st || null);
|
|
7335
7383
|
const U = E === "connected", te = T(n), _e = W(n), _ = le(n), M = i || _e === "running", K = P(n), C = V(n), j = je[je.length - 1], G = j ? `${j.type}:${j.timestamp || ""}:${j.content}` : "empty", ye = Ue(() => {
|
|
7336
7384
|
Ye.current = !0, tt.current !== null && window.clearTimeout(tt.current), tt.current = window.setTimeout(() => {
|
|
@@ -7381,11 +7429,11 @@ function va() {
|
|
|
7381
7429
|
});
|
|
7382
7430
|
}, [n, C, K, N]), Te = pe(null);
|
|
7383
7431
|
ce(() => {
|
|
7384
|
-
d(""),
|
|
7432
|
+
d(""), O.current = null, oe.current += 1, n && ja(n);
|
|
7385
7433
|
const I = s.state;
|
|
7386
7434
|
I != null && I.prefillMessage && Te.current !== I ? (Te.current = I, c(I.prefillMessage), window.setTimeout(() => {
|
|
7387
7435
|
var ne;
|
|
7388
|
-
return (ne =
|
|
7436
|
+
return (ne = be.current) == null ? void 0 : ne.focus();
|
|
7389
7437
|
}, 50)) : I != null && I.prefillMessage || (Te.current = null, c(""));
|
|
7390
7438
|
}, [n, i, s.state]), ce(() => {
|
|
7391
7439
|
if (n || !U) return;
|
|
@@ -7397,17 +7445,17 @@ function va() {
|
|
|
7397
7445
|
I = !0;
|
|
7398
7446
|
};
|
|
7399
7447
|
}, [n, U, a]);
|
|
7400
|
-
const
|
|
7448
|
+
const se = pe(Q);
|
|
7401
7449
|
ce(() => {
|
|
7402
|
-
|
|
7450
|
+
se.current = Q;
|
|
7403
7451
|
}, [Q]), ce(() => {
|
|
7404
|
-
!n || !U || i || _e === "running" ||
|
|
7452
|
+
!n || !U || i || _e === "running" || se.current(n).catch(() => {
|
|
7405
7453
|
});
|
|
7406
7454
|
}, [n, U, J, i, _e]), ce(() => {
|
|
7407
|
-
|
|
7455
|
+
xe.current && !te && U && setTimeout(() => {
|
|
7408
7456
|
var I;
|
|
7409
|
-
return (I =
|
|
7410
|
-
}, 50),
|
|
7457
|
+
return (I = be.current) == null ? void 0 : I.focus();
|
|
7458
|
+
}, 50), xe.current = te;
|
|
7411
7459
|
}, [te, U]);
|
|
7412
7460
|
function gt(I) {
|
|
7413
7461
|
if (Ye.current) return;
|
|
@@ -7415,10 +7463,10 @@ function va() {
|
|
|
7415
7463
|
Ie.current = ge < 80;
|
|
7416
7464
|
}
|
|
7417
7465
|
ce(() => {
|
|
7418
|
-
!n || !U || !i ||
|
|
7419
|
-
|
|
7466
|
+
!n || !U || !i || O.current !== n && (O.current = n, d(""), L(n).catch((I) => {
|
|
7467
|
+
O.current = null, d(I instanceof Error ? I.message : e("chat.demoError"));
|
|
7420
7468
|
}));
|
|
7421
|
-
}, [n, U, i,
|
|
7469
|
+
}, [n, U, i, L]), ce(() => {
|
|
7422
7470
|
!n || !i || _e !== "complete" || (c(""), a(`/chat/${n}`, { replace: !0 }));
|
|
7423
7471
|
}, [n, i, _e, a]);
|
|
7424
7472
|
const Le = pe(q);
|
|
@@ -7434,7 +7482,7 @@ function va() {
|
|
|
7434
7482
|
c("");
|
|
7435
7483
|
for (const dt of ne) {
|
|
7436
7484
|
if (Be !== oe.current) return;
|
|
7437
|
-
c((nt) => nt + dt), await
|
|
7485
|
+
c((nt) => nt + dt), await so(ge);
|
|
7438
7486
|
}
|
|
7439
7487
|
Be === oe.current && Le.current(I, Re);
|
|
7440
7488
|
}
|
|
@@ -7454,11 +7502,11 @@ function va() {
|
|
|
7454
7502
|
break;
|
|
7455
7503
|
}
|
|
7456
7504
|
const xt = Be.name.includes(".") ? Be.name.split(".").pop().toLowerCase() : "";
|
|
7457
|
-
if (!
|
|
7505
|
+
if (!ao.has(Be.type) && !ro.has(xt)) {
|
|
7458
7506
|
v(`Unsupported file type: ${Be.type || Be.name}`);
|
|
7459
7507
|
continue;
|
|
7460
7508
|
}
|
|
7461
|
-
if (Be.size >
|
|
7509
|
+
if (Be.size > no) {
|
|
7462
7510
|
v(`"${Be.name}" is too large (max 10 MB).`);
|
|
7463
7511
|
continue;
|
|
7464
7512
|
}
|
|
@@ -7515,7 +7563,7 @@ function va() {
|
|
|
7515
7563
|
function Cr(I) {
|
|
7516
7564
|
const ne = I.trim();
|
|
7517
7565
|
ne && (c((ge) => ge.trim() ? `${ge.trim()} ${ne}` : ne), window.setTimeout(() => {
|
|
7518
|
-
const ge =
|
|
7566
|
+
const ge = be.current;
|
|
7519
7567
|
ge && (ge.focus(), ge.style.height = "auto", ge.style.height = Math.min(Math.max(ge.scrollHeight, 48), 120) + "px");
|
|
7520
7568
|
}, 0));
|
|
7521
7569
|
}
|
|
@@ -7543,7 +7591,7 @@ function va() {
|
|
|
7543
7591
|
const Re = ne.mimeType || ((dt = ge[0]) == null ? void 0 : dt.type) || "audio/webm", Be = new Blob(ge, { type: Re }), xt = (Re.split(";")[0].split("/")[1] || "webm").toLowerCase();
|
|
7544
7592
|
S("transcribing");
|
|
7545
7593
|
try {
|
|
7546
|
-
const nt = await
|
|
7594
|
+
const nt = await io(Be), tn = await $(nt, xt, n);
|
|
7547
7595
|
Cr(tn);
|
|
7548
7596
|
} catch (nt) {
|
|
7549
7597
|
v(nt instanceof Error ? nt.message : e("chat.transcribeFailed"));
|
|
@@ -7603,7 +7651,7 @@ function va() {
|
|
|
7603
7651
|
{
|
|
7604
7652
|
onClick: () => {
|
|
7605
7653
|
var ne;
|
|
7606
|
-
c(I), (ne =
|
|
7654
|
+
c(I), (ne = be.current) == null || ne.focus();
|
|
7607
7655
|
},
|
|
7608
7656
|
className: "rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line transition-all hover:bg-surface-subtle hover:text-fg hover:ring-brand/30",
|
|
7609
7657
|
children: I
|
|
@@ -7611,7 +7659,7 @@ function va() {
|
|
|
7611
7659
|
I
|
|
7612
7660
|
)) })
|
|
7613
7661
|
] }),
|
|
7614
|
-
je.map((I, ne) => /* @__PURE__ */ t(
|
|
7662
|
+
je.map((I, ne) => /* @__PURE__ */ t(lo, { message: I }, ne)),
|
|
7615
7663
|
/* @__PURE__ */ t("div", { ref: Ne })
|
|
7616
7664
|
]
|
|
7617
7665
|
}
|
|
@@ -7665,7 +7713,7 @@ function va() {
|
|
|
7665
7713
|
/* @__PURE__ */ t(
|
|
7666
7714
|
"textarea",
|
|
7667
7715
|
{
|
|
7668
|
-
ref:
|
|
7716
|
+
ref: be,
|
|
7669
7717
|
value: l,
|
|
7670
7718
|
onChange: (I) => c(I.target.value),
|
|
7671
7719
|
onKeyDown: wr,
|
|
@@ -7748,7 +7796,7 @@ function gr(e) {
|
|
|
7748
7796
|
const n = e.includes(".") ? e.split(".").pop().toUpperCase() : "";
|
|
7749
7797
|
return n ? n.slice(0, 4) : "FILE";
|
|
7750
7798
|
}
|
|
7751
|
-
function
|
|
7799
|
+
function oo({ attachments: e }) {
|
|
7752
7800
|
return !e || e.length === 0 ? null : /* @__PURE__ */ t("div", { className: "mt-1 flex flex-wrap gap-1.5", children: e.map((n) => {
|
|
7753
7801
|
const a = F.getChatAttachmentUrl(n.id), s = n.mime_type.startsWith("image/");
|
|
7754
7802
|
return /* @__PURE__ */ r(
|
|
@@ -7768,13 +7816,13 @@ function io({ attachments: e }) {
|
|
|
7768
7816
|
);
|
|
7769
7817
|
}) });
|
|
7770
7818
|
}
|
|
7771
|
-
function
|
|
7819
|
+
function lo({ message: e }) {
|
|
7772
7820
|
return e.type === "user" ? /* @__PURE__ */ t("div", { className: "flex justify-end", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-br-md bg-gradient-to-b from-brand to-brand/90 px-4 py-2.5 text-sm text-brand-fg ring-1 ring-black/10 shadow-bubble-user", children: [
|
|
7773
7821
|
/* @__PURE__ */ t("div", { className: "whitespace-pre-wrap", children: e.content }),
|
|
7774
|
-
/* @__PURE__ */ t(
|
|
7822
|
+
/* @__PURE__ */ t(oo, { attachments: e.attachments }),
|
|
7775
7823
|
e.timestamp && /* @__PURE__ */ t("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: ba(e.timestamp), children: ya(e.timestamp) })
|
|
7776
7824
|
] }) }) : e.type === "assistant" ? /* @__PURE__ */ t("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-bl-md bg-surface px-4 py-2.5 text-sm text-fg ring-1 ring-line shadow-card", children: [
|
|
7777
|
-
/* @__PURE__ */ t(
|
|
7825
|
+
/* @__PURE__ */ t(uo, { content: e.content }),
|
|
7778
7826
|
e.timestamp && /* @__PURE__ */ t("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: ba(e.timestamp), children: ya(e.timestamp) })
|
|
7779
7827
|
] }) }) : e.type === "thinking" ? /* @__PURE__ */ t("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line shadow-card", children: [
|
|
7780
7828
|
/* @__PURE__ */ t("span", { className: "inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-brand" }),
|
|
@@ -7832,7 +7880,7 @@ function hn(e) {
|
|
|
7832
7880
|
return a.startsWith(":") && a.endsWith(":") ? "center" : a.endsWith(":") ? "right" : "left";
|
|
7833
7881
|
});
|
|
7834
7882
|
}
|
|
7835
|
-
function
|
|
7883
|
+
function co({
|
|
7836
7884
|
header: e,
|
|
7837
7885
|
rows: n,
|
|
7838
7886
|
alignments: a
|
|
@@ -7859,7 +7907,7 @@ function lo({
|
|
|
7859
7907
|
)) }, o)) })
|
|
7860
7908
|
] }) });
|
|
7861
7909
|
}
|
|
7862
|
-
function
|
|
7910
|
+
function uo({ content: e }) {
|
|
7863
7911
|
const n = e.split(`
|
|
7864
7912
|
`), a = [];
|
|
7865
7913
|
let s = !1, o = [];
|
|
@@ -7910,7 +7958,7 @@ function co({ content: e }) {
|
|
|
7910
7958
|
}
|
|
7911
7959
|
a.push(
|
|
7912
7960
|
/* @__PURE__ */ t(
|
|
7913
|
-
|
|
7961
|
+
co,
|
|
7914
7962
|
{
|
|
7915
7963
|
header: c,
|
|
7916
7964
|
rows: g,
|
|
@@ -7957,7 +8005,7 @@ function fr(e, n, a) {
|
|
|
7957
8005
|
a
|
|
7958
8006
|
);
|
|
7959
8007
|
}
|
|
7960
|
-
const
|
|
8008
|
+
const mo = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
|
|
7961
8009
|
function wt(e) {
|
|
7962
8010
|
return e.split(/(\[[^\]]+\]\([^)]+\)|\*\*[^*]+?\*\*|`[^`]+`)/g).flatMap((a, s) => {
|
|
7963
8011
|
const o = a.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
|
|
@@ -7972,13 +8020,13 @@ function wt(e) {
|
|
|
7972
8020
|
children: a.slice(1, -1)
|
|
7973
8021
|
},
|
|
7974
8022
|
s
|
|
7975
|
-
) :
|
|
8023
|
+
) : po(a, `${s}`);
|
|
7976
8024
|
});
|
|
7977
8025
|
}
|
|
7978
|
-
function
|
|
8026
|
+
function po(e, n) {
|
|
7979
8027
|
const a = [];
|
|
7980
8028
|
let s = 0, o;
|
|
7981
|
-
const i = new RegExp(
|
|
8029
|
+
const i = new RegExp(mo.source, "g");
|
|
7982
8030
|
let l = 0;
|
|
7983
8031
|
for (; (o = i.exec(e)) !== null; ) {
|
|
7984
8032
|
const c = o.index;
|
|
@@ -7989,8 +8037,8 @@ function mo(e, n) {
|
|
|
7989
8037
|
}
|
|
7990
8038
|
return s < e.length && a.push(e.slice(s)), a.length > 0 ? a : [e];
|
|
7991
8039
|
}
|
|
7992
|
-
function
|
|
7993
|
-
const e = Ke(), [n] = Jt(), { user: a, login: s, register: o } = Ze(), { t: i } =
|
|
8040
|
+
function ho() {
|
|
8041
|
+
const e = Ke(), [n] = Jt(), { user: a, login: s, register: o } = Ze(), { t: i } = re(), l = n.get("invite") || "", [c, h] = w(l ? "register" : "login"), [d, g] = w(!1), [m, b] = w(!1), [v, k] = w([]), [y, A] = w(!0), [S, x] = w(""), [p, f] = w(""), [B, E] = w(""), [J, Z] = w(""), [L, q] = w("");
|
|
7994
8042
|
ce(() => {
|
|
7995
8043
|
a && a.role !== "public_manager" && e("/", { replace: !0 });
|
|
7996
8044
|
}, [a, e]), ce(() => {
|
|
@@ -8004,7 +8052,7 @@ function po() {
|
|
|
8004
8052
|
}, [n, i]);
|
|
8005
8053
|
const Q = async (N) => {
|
|
8006
8054
|
if (N.preventDefault(), x(""), c === "register") {
|
|
8007
|
-
if (J !==
|
|
8055
|
+
if (J !== L) {
|
|
8008
8056
|
x(i("login.passwordsNoMatch"));
|
|
8009
8057
|
return;
|
|
8010
8058
|
}
|
|
@@ -8067,7 +8115,7 @@ function po() {
|
|
|
8067
8115
|
{
|
|
8068
8116
|
label: i("login.confirmPassword"),
|
|
8069
8117
|
type: "password",
|
|
8070
|
-
value:
|
|
8118
|
+
value: L,
|
|
8071
8119
|
onChange: (N) => q(N.target.value),
|
|
8072
8120
|
required: !0
|
|
8073
8121
|
}
|
|
@@ -8089,8 +8137,8 @@ function po() {
|
|
|
8089
8137
|
},
|
|
8090
8138
|
className: "flex w-full items-center justify-center gap-2 rounded-lg border border-border bg-surface px-4 py-2 text-sm font-medium text-fg transition-colors hover:bg-surface-muted",
|
|
8091
8139
|
children: [
|
|
8092
|
-
/* @__PURE__ */ t(
|
|
8093
|
-
i("login.continueWithProvider", { provider:
|
|
8140
|
+
/* @__PURE__ */ t(fo, { provider: N }),
|
|
8141
|
+
i("login.continueWithProvider", { provider: go(N) })
|
|
8094
8142
|
]
|
|
8095
8143
|
},
|
|
8096
8144
|
N
|
|
@@ -8123,10 +8171,10 @@ function po() {
|
|
|
8123
8171
|
] }) })
|
|
8124
8172
|
] }) });
|
|
8125
8173
|
}
|
|
8126
|
-
function
|
|
8174
|
+
function go(e) {
|
|
8127
8175
|
return e.charAt(0).toUpperCase() + e.slice(1);
|
|
8128
8176
|
}
|
|
8129
|
-
function
|
|
8177
|
+
function fo({ provider: e }) {
|
|
8130
8178
|
return e === "google" ? /* @__PURE__ */ r("svg", { className: "h-4 w-4", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
|
|
8131
8179
|
/* @__PURE__ */ t("path", { fill: "#EA4335", d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" }),
|
|
8132
8180
|
/* @__PURE__ */ t("path", { fill: "#4285F4", d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" }),
|
|
@@ -8134,7 +8182,7 @@ function go({ provider: e }) {
|
|
|
8134
8182
|
/* @__PURE__ */ t("path", { fill: "#34A853", d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" })
|
|
8135
8183
|
] }) : e === "apple" ? /* @__PURE__ */ t("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ t("path", { d: "M16.365 1.43c0 1.14-.42 2.22-1.14 3.03-.78.9-2.06 1.6-3.12 1.5-.13-1.1.42-2.28 1.08-3.03.78-.9 2.13-1.56 3.18-1.5zM20.7 17.1c-.56 1.3-.83 1.88-1.55 3.03-1 1.6-2.42 3.6-4.18 3.62-1.56.02-1.96-1.02-4.07-1-2.12.01-2.56 1.02-4.12 1.01-1.76-.02-3.1-1.82-4.1-3.42C-.3 16.9-.6 11.16 1.7 8.1c1.16-1.54 3-2.51 4.85-2.51 1.87 0 3.05 1.02 4.6 1.02 1.5 0 2.42-1.02 4.6-1.02 1.62 0 3.34.88 4.56 2.4-4.01 2.2-3.36 7.92 0 9.11z" }) }) : null;
|
|
8136
8184
|
}
|
|
8137
|
-
function
|
|
8185
|
+
function yo() {
|
|
8138
8186
|
const e = Ke(), n = pe(!1), [a, s] = w("");
|
|
8139
8187
|
return ce(() => {
|
|
8140
8188
|
n.current || (n.current = !0, F.createChatSession().then((o) => {
|
|
@@ -8166,7 +8214,7 @@ function ka() {
|
|
|
8166
8214
|
function Na() {
|
|
8167
8215
|
return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
|
|
8168
8216
|
}
|
|
8169
|
-
function
|
|
8217
|
+
function bo() {
|
|
8170
8218
|
const e = Ke(), n = et(), [a, s] = w(""), [o, i] = w(De()), [l, c] = w(""), [h, d] = w([xa()]), [g, m] = w([ka()]), [b, v] = w([Na()]), [k, y] = w({}), A = ke({
|
|
8171
8219
|
mutationFn: () => F.importAccountBalances({
|
|
8172
8220
|
company: a,
|
|
@@ -8207,8 +8255,8 @@ function yo() {
|
|
|
8207
8255
|
onSuccess: (f) => y((B) => ({ ...B, invoices: f }))
|
|
8208
8256
|
});
|
|
8209
8257
|
function p(f, B, E, J, Z) {
|
|
8210
|
-
const
|
|
8211
|
-
|
|
8258
|
+
const L = [...f];
|
|
8259
|
+
L[E][J] = Z, B(L);
|
|
8212
8260
|
}
|
|
8213
8261
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
8214
8262
|
/* @__PURE__ */ t("p", { className: "text-sm text-gray-500", children: "Import balances from your previous system. Each section creates the appropriate documents (Journal Entry, Stock Entry, or Invoices) and submits them automatically." }),
|
|
@@ -8332,12 +8380,12 @@ function yo() {
|
|
|
8332
8380
|
] })
|
|
8333
8381
|
] });
|
|
8334
8382
|
}
|
|
8335
|
-
function
|
|
8383
|
+
function vo(e) {
|
|
8336
8384
|
const n = (e || "").replace(/\s/g, "");
|
|
8337
8385
|
return n.length > 8 ? `${n.slice(0, 4)} … ${n.slice(-4)}` : n;
|
|
8338
8386
|
}
|
|
8339
|
-
function
|
|
8340
|
-
const { t: e, i18n: n } =
|
|
8387
|
+
function xo() {
|
|
8388
|
+
const { t: e, i18n: n } = re();
|
|
8341
8389
|
Me(e("bankStatements.title"));
|
|
8342
8390
|
const [a, s] = w([]), [o, i] = w([]), [l, c] = w([]), [h, d] = w({}), [g, m] = w([]), [b, v] = w(!1), [k, y] = w(null), [A, S] = w(""), [x, p] = w(null), f = async () => {
|
|
8343
8391
|
const [N, D] = await Promise.all([
|
|
@@ -8359,7 +8407,7 @@ function vo() {
|
|
|
8359
8407
|
}, E = o.filter((N) => !N.already_imported), J = E.length > 0 && E.every((N) => !!h[N.statement_key]), Z = fe(
|
|
8360
8408
|
() => a.map((N) => N.name).join(", "),
|
|
8361
8409
|
[a]
|
|
8362
|
-
),
|
|
8410
|
+
), L = (N) => {
|
|
8363
8411
|
const D = Array.from(N), $ = D.filter((u) => {
|
|
8364
8412
|
const P = u.name.includes(".") ? u.name.split(".").pop().toLowerCase() : "";
|
|
8365
8413
|
return P !== "xml" && P !== "zip";
|
|
@@ -8420,7 +8468,7 @@ function vo() {
|
|
|
8420
8468
|
(!D || !N.currentTarget.contains(D)) && v(!1);
|
|
8421
8469
|
},
|
|
8422
8470
|
onDrop: (N) => {
|
|
8423
|
-
N.preventDefault(), v(!1), N.dataTransfer.files.length &&
|
|
8471
|
+
N.preventDefault(), v(!1), N.dataTransfer.files.length && L(N.dataTransfer.files);
|
|
8424
8472
|
},
|
|
8425
8473
|
children: [
|
|
8426
8474
|
/* @__PURE__ */ t(Xr, { className: "mb-2 h-7 w-7 text-brand" }),
|
|
@@ -8433,7 +8481,7 @@ function vo() {
|
|
|
8433
8481
|
type: "file",
|
|
8434
8482
|
multiple: !0,
|
|
8435
8483
|
accept: ".xml,.zip,application/xml,text/xml,application/zip,application/x-zip-compressed",
|
|
8436
|
-
onChange: (N) =>
|
|
8484
|
+
onChange: (N) => L(N.target.files || [])
|
|
8437
8485
|
}
|
|
8438
8486
|
)
|
|
8439
8487
|
]
|
|
@@ -8524,7 +8572,7 @@ function vo() {
|
|
|
8524
8572
|
l.map((D) => /* @__PURE__ */ r("option", { value: D.name, children: [
|
|
8525
8573
|
D.account_name,
|
|
8526
8574
|
" · ",
|
|
8527
|
-
|
|
8575
|
+
vo(D.iban),
|
|
8528
8576
|
" · ",
|
|
8529
8577
|
D.currency,
|
|
8530
8578
|
" · ",
|
|
@@ -8596,22 +8644,22 @@ const Vt = (e) => `${e.reference_doctype}:${e.reference_name}`;
|
|
|
8596
8644
|
function gn(e, n) {
|
|
8597
8645
|
return `/app/${e.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(n)}`;
|
|
8598
8646
|
}
|
|
8599
|
-
function
|
|
8647
|
+
function ko() {
|
|
8600
8648
|
var qe;
|
|
8601
|
-
const { t: e, i18n: n } =
|
|
8649
|
+
const { t: e, i18n: n } = re(), a = Tn();
|
|
8602
8650
|
Me(e("bankReconciliation.title"));
|
|
8603
|
-
const [s, o] = w("Unreconciled"), [i, l] = w([]), [c, h] = w(null), [d, g] = w(null), [m, b] = w([]), [v, k] = w({}), [y, A] = w(""), [S, x] = w(""), [p, f] = w(""), [B, E] = w(!1), [J, Z] = w(""), [
|
|
8651
|
+
const [s, o] = w("Unreconciled"), [i, l] = w([]), [c, h] = w(null), [d, g] = w(null), [m, b] = w([]), [v, k] = w({}), [y, A] = w(""), [S, x] = w(""), [p, f] = w(""), [B, E] = w(!1), [J, Z] = w(""), [L, q] = w(""), Q = (R, ae) => {
|
|
8604
8652
|
try {
|
|
8605
8653
|
return new Intl.NumberFormat(n.language, { style: "currency", currency: ae }).format(R);
|
|
8606
8654
|
} catch {
|
|
8607
8655
|
return `${ae} ${R.toFixed(2)}`;
|
|
8608
8656
|
}
|
|
8609
8657
|
}, N = async (R) => {
|
|
8610
|
-
var
|
|
8658
|
+
var O;
|
|
8611
8659
|
const ae = await F.listBankReconciliationTransactions(s, 200);
|
|
8612
8660
|
l(ae.rows);
|
|
8613
|
-
const
|
|
8614
|
-
h(
|
|
8661
|
+
const xe = R && ae.rows.some((oe) => oe.name === R) ? R : ((O = ae.rows[0]) == null ? void 0 : O.name) || null;
|
|
8662
|
+
h(xe), xe || g(null);
|
|
8615
8663
|
};
|
|
8616
8664
|
ce(() => {
|
|
8617
8665
|
Z(""), N().catch((R) => Z(R instanceof Error ? R.message : String(R)));
|
|
@@ -8636,10 +8684,10 @@ function xo() {
|
|
|
8636
8684
|
q(R), await N(c);
|
|
8637
8685
|
}, le = async (R) => {
|
|
8638
8686
|
if (!D) return;
|
|
8639
|
-
const ae = R.bank_transactions || [],
|
|
8687
|
+
const ae = R.bank_transactions || [], xe = R.kind === "existing_voucher_group" && ae.length > 1;
|
|
8640
8688
|
if (await a({
|
|
8641
8689
|
title: e("bankReconciliation.confirmExistingTitle"),
|
|
8642
|
-
body:
|
|
8690
|
+
body: xe ? /* @__PURE__ */ r("div", { className: "space-y-2", children: [
|
|
8643
8691
|
/* @__PURE__ */ t("p", { children: e("bankReconciliation.confirmGroupBody", {
|
|
8644
8692
|
count: ae.length,
|
|
8645
8693
|
amount: Q(R.amount, R.currency),
|
|
@@ -8661,11 +8709,11 @@ function xo() {
|
|
|
8661
8709
|
try {
|
|
8662
8710
|
await F.reconcileBankExistingVoucher({
|
|
8663
8711
|
bank_transaction: D.name,
|
|
8664
|
-
bank_transactions:
|
|
8712
|
+
bank_transactions: xe ? ae.map((oe) => oe.name) : void 0,
|
|
8665
8713
|
voucher_type: R.voucher_type,
|
|
8666
8714
|
voucher_no: R.voucher_no,
|
|
8667
8715
|
confirmed: !0
|
|
8668
|
-
}), await W(
|
|
8716
|
+
}), await W(xe ? e("bankReconciliation.groupReconciledNotice", { count: ae.length }) : e("bankReconciliation.reconciledNotice"));
|
|
8669
8717
|
} catch (oe) {
|
|
8670
8718
|
Z(oe instanceof Error ? oe.message : String(oe));
|
|
8671
8719
|
} finally {
|
|
@@ -8691,16 +8739,16 @@ function xo() {
|
|
|
8691
8739
|
try {
|
|
8692
8740
|
await F.reconcileBankPayment({
|
|
8693
8741
|
bank_transaction: D.name,
|
|
8694
|
-
allocations: $.map((
|
|
8695
|
-
reference_doctype:
|
|
8696
|
-
reference_name:
|
|
8697
|
-
allocated_amount: Number(v[Vt(
|
|
8742
|
+
allocations: $.map((xe) => ({
|
|
8743
|
+
reference_doctype: xe.reference_doctype,
|
|
8744
|
+
reference_name: xe.reference_name,
|
|
8745
|
+
allocated_amount: Number(v[Vt(xe)])
|
|
8698
8746
|
})),
|
|
8699
8747
|
conversion_rate: p ? Number(p) : void 0,
|
|
8700
8748
|
confirmed: !0
|
|
8701
8749
|
}), await W(e("bankReconciliation.reconciledNotice"));
|
|
8702
|
-
} catch (
|
|
8703
|
-
Z(
|
|
8750
|
+
} catch (xe) {
|
|
8751
|
+
Z(xe instanceof Error ? xe.message : String(xe));
|
|
8704
8752
|
} finally {
|
|
8705
8753
|
E(!1);
|
|
8706
8754
|
}
|
|
@@ -8730,7 +8778,7 @@ function xo() {
|
|
|
8730
8778
|
E(!1);
|
|
8731
8779
|
}
|
|
8732
8780
|
}
|
|
8733
|
-
},
|
|
8781
|
+
}, be = async () => {
|
|
8734
8782
|
if (!D || !(d != null && d.active_reconciliation)) return;
|
|
8735
8783
|
const R = d.active_reconciliation.mode !== "Existing Voucher", ae = d.active_reconciliation.bank_transactions || [D.name];
|
|
8736
8784
|
if (await a({
|
|
@@ -8745,8 +8793,8 @@ function xo() {
|
|
|
8745
8793
|
E(!0), Z(""), q("");
|
|
8746
8794
|
try {
|
|
8747
8795
|
await F.undoBankReconciliation(D.name), await W(e("bankReconciliation.undoneNotice"));
|
|
8748
|
-
} catch (
|
|
8749
|
-
Z(
|
|
8796
|
+
} catch (O) {
|
|
8797
|
+
Z(O instanceof Error ? O.message : String(O));
|
|
8750
8798
|
} finally {
|
|
8751
8799
|
E(!1);
|
|
8752
8800
|
}
|
|
@@ -8776,9 +8824,9 @@ function xo() {
|
|
|
8776
8824
|
] })
|
|
8777
8825
|
] }),
|
|
8778
8826
|
J && /* @__PURE__ */ t("div", { className: "rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700", children: J }),
|
|
8779
|
-
|
|
8827
|
+
L && /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800", children: [
|
|
8780
8828
|
/* @__PURE__ */ t(bn, { className: "h-4 w-4" }),
|
|
8781
|
-
|
|
8829
|
+
L
|
|
8782
8830
|
] }),
|
|
8783
8831
|
/* @__PURE__ */ r("div", { className: "grid gap-6 lg:grid-cols-[minmax(280px,0.8fr)_minmax(0,1.7fr)]", children: [
|
|
8784
8832
|
/* @__PURE__ */ r(H, { className: "self-start", children: [
|
|
@@ -8862,7 +8910,7 @@ function xo() {
|
|
|
8862
8910
|
" ",
|
|
8863
8911
|
d.active_reconciliation.voucher_no
|
|
8864
8912
|
] }),
|
|
8865
|
-
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(Y, { variant: "danger", disabled: B, onClick:
|
|
8913
|
+
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(Y, { variant: "danger", disabled: B, onClick: be, children: [
|
|
8866
8914
|
/* @__PURE__ */ t(ns, { className: "h-4 w-4" }),
|
|
8867
8915
|
e("bankReconciliation.undo")
|
|
8868
8916
|
] }) })
|
|
@@ -8893,14 +8941,14 @@ function xo() {
|
|
|
8893
8941
|
/* @__PURE__ */ t("p", { className: "mt-1 text-sm text-fg-muted", children: e("bankReconciliation.openInvoicesHint") }),
|
|
8894
8942
|
/* @__PURE__ */ r("div", { className: "mt-3 divide-y divide-line", children: [
|
|
8895
8943
|
d.invoices.map((R) => {
|
|
8896
|
-
const ae = Vt(R),
|
|
8897
|
-
return /* @__PURE__ */ r("div", { className: Fe("grid gap-3 py-3 sm:grid-cols-[auto_1fr_150px] sm:items-center", !
|
|
8944
|
+
const ae = Vt(R), xe = v[ae] != null, O = V(R);
|
|
8945
|
+
return /* @__PURE__ */ r("div", { className: Fe("grid gap-3 py-3 sm:grid-cols-[auto_1fr_150px] sm:items-center", !O && !xe && "opacity-45"), children: [
|
|
8898
8946
|
/* @__PURE__ */ t(
|
|
8899
8947
|
"input",
|
|
8900
8948
|
{
|
|
8901
8949
|
type: "checkbox",
|
|
8902
|
-
checked:
|
|
8903
|
-
disabled: !
|
|
8950
|
+
checked: xe,
|
|
8951
|
+
disabled: !O && !xe,
|
|
8904
8952
|
onChange: (oe) => k((Ie) => {
|
|
8905
8953
|
const Ae = { ...Ie };
|
|
8906
8954
|
return oe.target.checked ? Ae[ae] = R.suggested_allocation : delete Ae[ae], Ae;
|
|
@@ -8929,8 +8977,8 @@ function xo() {
|
|
|
8929
8977
|
type: "number",
|
|
8930
8978
|
min: "0.01",
|
|
8931
8979
|
step: "0.01",
|
|
8932
|
-
disabled: !
|
|
8933
|
-
value:
|
|
8980
|
+
disabled: !xe,
|
|
8981
|
+
value: xe ? v[ae] : "",
|
|
8934
8982
|
onChange: (oe) => k((Ie) => ({ ...Ie, [ae]: Number(oe.target.value) })),
|
|
8935
8983
|
"aria-label": e("bankReconciliation.allocation")
|
|
8936
8984
|
}
|
|
@@ -8966,7 +9014,7 @@ function xo() {
|
|
|
8966
9014
|
] })
|
|
8967
9015
|
] });
|
|
8968
9016
|
}
|
|
8969
|
-
function
|
|
9017
|
+
function No() {
|
|
8970
9018
|
Me("Users");
|
|
8971
9019
|
const { user: e } = Ze(), n = et(), { data: a, isLoading: s } = ve({
|
|
8972
9020
|
queryKey: ["auth-users"],
|
|
@@ -9128,110 +9176,113 @@ function ko() {
|
|
|
9128
9176
|
] }) })
|
|
9129
9177
|
] });
|
|
9130
9178
|
}
|
|
9131
|
-
const No = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, wo = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", cancelBooking: "Cancel booking", cancelBookingConfirm: "Yes, cancel booking", keepBooking: "Keep booking", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", showDisabled: "Show disabled", columns: "Columns", searchPlaceholder: "Search…", noRecords: "No records found", active: "Active", disabled: "Disabled", sortByColumn: "Sort by this column", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, Co = { today: "Today", thisWeek: "This Week", thisMonth: "This Month", thisQuarter: "This Quarter", thisYear: "This Year", lastMonth: "Last Month", lastQuarter: "Last Quarter", lastYear: "Last Year", endOfThisMonth: "End of This Month", endOfLastMonth: "End of Last Month", endOfThisQuarter: "End of This Quarter", endOfThisYear: "End of This Year", endOfLastYear: "End of Last Year" }, So = { title: "Bank statement import", subtitle: "Preview and import ISO 20022 CAMT statements without posting to the ledger.", selectFiles: "CAMT files", chooseFiles: "Choose XML or ZIP files", dropFiles: "Drop XML or ZIP files here", unsupportedFiles: "Only CAMT XML or ZIP files are supported: {{files}}", fileHint: "camt.053.001.04 and camt.053.001.08 · multiple files supported", preview: "Show preview", noPosting: "Previewing and importing do not post accounting entries.", alreadyImported: "Already imported", period: "Period", openingBalance: "Opening balance", closingBalance: "Closing balance", entries: "Entries", credits: "Credits", debits: "Debits", details: "Transaction details", batches: "batches", qrReferences: "QR references", mapping: "Bank account mapping", selectBankAccount: "Select a Bank Account…", noBankAccounts: "No Bank Account has been configured yet.", createBankAccount: "Create Bank Account", mappingRequired: "Map every new statement to a Bank Account before importing.", import: "Import bank statements", importComplete: "Import completed", importCounts: "{{imported}} entries imported, {{duplicates}} duplicates skipped", history: "Recent imports", importId: "Import", bankAccount: "Bank account", source: "Source file", openReconciliation: "Open bank reconciliation" }, Ao = { title: "Bank reconciliation", subtitle: "Match imported bank transactions to posted vouchers, open invoices, or ledger accounts.", status: "Status", unreconciled: "Unreconciled", reconciled: "Reconciled", transactions: "Bank transactions", empty: "No bank transactions in this view.", remittance: "Remittance information", reference: "Reference", openTransaction: "Open bank transaction", conversionRate: "Exchange rate (1 {{currency}} in {{base}})", conversionRateHint: "Required when no exchange rate exists for the transaction date.", existingVouchers: "Existing accounting entries", existingVouchersHint: "These submitted vouchers contain an exact movement on this bank account. Matching does not post them again.", match: "Match", openInvoices: "Open invoices", openInvoicesHint: "Select one or more invoices belonging to the same party. Confirmation creates and submits a Payment Entry.", outstanding: "Outstanding", allocation: "Allocation", noInvoiceSuggestions: "No plausible open invoice was found.", allocated: "Allocated {{amount}} of {{total}}", createPayment: "Create payment and reconcile", directPosting: "Post to a ledger account", directPostingHint: "For fees, interest and other non-invoice movements. Receivable, payable, bank and cash control accounts are intentionally excluded.", counterpartyAccount: "Counter account", remarks: "Remarks", createJournal: "Create journal entry and reconcile", activeMatch: "Active reconciliation", undo: "Undo reconciliation", confirmExistingTitle: "Match existing entry?", confirmExistingBody: "Match {{transaction}} to {{voucher}}? No new ledger entry will be posted.", confirmGroupBody: "Match all {{count}} transactions totalling {{amount}} to {{voucher}}? No new ledger entry will be posted.", groupedTransactions: "{{count}} grouped transactions", confirmPaymentTitle: "Post payment and reconcile?", confirmPaymentBody: "This submits a payment of {{amount}} for {{transaction}} and allocates it across {{count}} invoice(s).", onAccountWarning: "{{amount}} will remain as an on-account payment for this party.", confirmJournalTitle: "Post journal entry and reconcile?", confirmJournalBody: "This posts {{amount}} for {{transaction}} against {{account}}.", postAndReconcile: "Post and reconcile", undoTitle: "Undo reconciliation?", undoCreatedBody: "The voucher created by this reconciliation will be cancelled, its ledger entries reversed, and invoice allocations restored.", undoExistingBody: "The existing voucher will only be unlinked. It remains submitted and its ledger entries are not changed.", undoExistingGroupBody: "All {{count}} grouped transactions ({{transactions}}) will be unlinked together. The existing voucher remains submitted and its ledger entries are not changed.", reconciledNotice: "Bank transaction reconciled.", groupReconciledNotice: "{{count}} bank transactions reconciled as one group.", undoneNotice: "Reconciliation reversed." }, _o = { placeholder: "Search or enter field:value…", search: "Search", addFilter: "+ Filter", availableFields: "Available fields", fieldHelp: "Choose a field or type its technical name followed by a colon.", field: "Field", valueFor: "Value for {{label}}", allFields: "All fields", typeForValues: "Start typing to find values in this field.", noValues: "No matching values found.", noFields: "No matching fields found.", useValue: "Use “{{value}}”", removeFilter: "Remove {{label}} filter", types: { text: "Text", textarea: "Long text", select: "Selection", link: "Linked record", date: "Date", datetime: "Date and time", number: "Number", currency: "Amount" } }, Do = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Po = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, To = { dashboard: "Dashboard", setup: "Company Setup", tutorial: "Getting Started", chat: "Chat", reports: "Reports", "trial-balance": "Trial Balance", "general-ledger": "General Ledger", "stock-balance": "Stock Balance", "profit-and-loss": "Profit & Loss", "balance-sheet": "Balance Sheet", "ar-aging": "Accounts Receivable Aging", "ap-aging": "Accounts Payable Aging", analytics: "Analytics", "chart-of-accounts": "Chart of Accounts" }, Ro = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, "bank-account": { one: "Bank Account", other: "Bank Accounts" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, Bo = { company: { one: "Company", other: "Companies" }, customer: { one: "Customer", other: "Customers" }, supplier: { one: "Supplier", other: "Suppliers" }, item: { one: "Item", other: "Items" }, warehouse: { one: "Warehouse", other: "Warehouses" } }, Io = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings", Rentals: "Rentals" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", "Bank Account": "Bank Accounts", "Bank Statement Import": "Bank Statement Import", "Bank Reconciliation": "Bank Reconciliation", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts", "Fleet Calendar": "Fleet Calendar", "Fleet (Assets)": "Fleet (Assets)", Reservations: "Reservations" } }, Eo = { taglineFirstRun: "Create your admin account to get started", taglineRegister: "Create your account", taglineSignIn: "Sign in to your account", demoBanner: "Demo mode is active. Sign in with an admin account to manage settings or disable public access.", fullName: "Full Name", email: "Email", password: "Password", confirmPassword: "Confirm Password", createAdmin: "Create Admin Account", register: "Register", signIn: "Sign In", browsingTitle: "Just browsing?", browsingBody: "Start a fresh chat session and watch the live demo.", enterDemo: "Enter Live Demo", haveInvite: "Have an invite?", noAccountPrompt: "Need an account?", registerLink: "Register", alreadyHaveAccount: "Already have an account?", signInLink: "Sign in", passwordsNoMatch: "Passwords do not match", passwordTooShort: "Password must be at least 6 characters", registrationFailed: "Registration failed", loginFailed: "Login failed", orContinueWith: "or continue with", continueWithProvider: "Continue with {{provider}}", oauthError: { generic: "Sign-in failed. Please try again.", email_exists: "An account with this email already exists. Sign in, then link this provider from your account settings.", email_unverified: "Your provider did not confirm a verified email, so we can't sign you in.", registration_closed: "This email has no account yet and registration is invite-only.", invite_invalid: "That invite is invalid, already used, or issued for a different email.", identity_taken: "That provider account is already linked to a different user.", account_disabled: "This account has been disabled.", token_exchange_failed: "Sign-in failed while contacting the provider. Please try again." } }, Lo = { pdfTitle: "PDF & Print", pageSize: "Page Size", pdfHelp: "A4 is standard internationally (210 x 297 mm). Letter is standard in the US (8.5 x 11 in).", passwordTitle: "Change Password", currentPassword: "Current password", newPassword: "New password", confirmNewPassword: "Confirm new password", changePassword: "Change password", changingPassword: "Changing...", passwordChanged: "Password changed.", setPasswordTitle: "Set a Password", setPasswordBody: "Your account signs in with Google. Set a password to also sign in with email and password — a handy fallback if you ever lose access to your Google account.", setPassword: "Set password", passwordSet: "Password set.", linkedAccountsTitle: "Linked Accounts", linkedAccountsBody: "Link a Google or Apple account to sign in without a password.", linked: "Linked", linkProvider: "Link {{provider}}", openingTitle: "Opening Balances", openingBody: "The Opening Balances page allows importing account balances, stock, and outstanding invoices from a previous system.", openingEnabled: "Currently enabled — accessible under Introduction > Opening Balances.", openingDisabled: "Currently disabled — the page is hidden from the sidebar.", signupTitle: "Public Signup", signupBody: "Allow anyone to create their own account (as a viewer) without an invite. When off, new users can only join via an invite link.", signupEnabled: "Currently enabled — anyone with the URL can register as a viewer.", signupDisabled: "Currently disabled — registration is invite-only.", chatApiTitle: "Chat API", apiTitle: "Programmatic API", restApiBody: "Let connectors and scripts drive this ERP over its REST API (documents, masters, reports) with the same Bearer API keys. Off by default.", restApiEnabled: "Currently enabled — issued keys can call /api/documents, /api/masters, and the rest of the REST API.", restApiDisabled: "Currently disabled — the REST API only accepts the session cookie; keys are rejected.", restApiDeactivateTitle: "Deactivate the REST API?", restApiDeactivateBody: "Bearer-key access to the REST API will be switched off — connectors and scripts are rejected until you turn it back on. The web app (session cookie) is unaffected, and your API keys are NOT deleted: they start working again the instant you re-enable the API.", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API.", version: "Version {{version}}" }, Oo = { Draft: "Draft", Open: "Open", Submitted: "Submitted", "To Deliver and Bill": "To Deliver and Bill", "To Deliver": "To Deliver", "To Bill": "To Bill", Completed: "Completed", Ordered: "Ordered", Paid: "Paid", Unpaid: "Unpaid", Cancelled: "Cancelled", Discarded: "Discarded", Overdue: "Overdue", Return: "Return", Closed: "Closed" }, Fo = { periodRange: "Reporting period: {{from}} – {{to}}", periodFrom: "Reporting period from {{from}}", periodThrough: "Reporting period through {{to}}", asOfDate: "As of: {{date}}", balanced: "BALANCED", imbalanced: "IMBALANCED", income: "Income", expenses: "Expenses", totalIncome: "Total Income", totalExpenses: "Total Expenses", netProfit: "Net Profit", netLoss: "Net Loss", assets: "Assets", liabilities: "Liabilities", equity: "Equity", totalAssets: "Total Assets", totalLiabilities: "Total Liabilities", totalEquity: "Total Equity", totalLiabilitiesEquity: "Total Liabilities + Equity", current: "Current", noData: "No data found", noEntries: "No entries found", noStockData: "No stock data found", noReceivables: "No outstanding receivables", noPayables: "No outstanding payables", noDocuments: "No documents found" }, Mo = { required: "Required: {{fields}}", deleteConfirm: "Delete this {{label}}?", disabledNotice: "This {{label}} is disabled. It remains in the system because other records still reference it.", disabledOnDelete: "{{label}} {{name}} was disabled instead of deleted because it is referenced by {{reason}}." }, qo = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, zo = { title: "Lambda ERP Chat", subtitle: "Ask me to create documents, look up data, or run reports.", s1: "What customers do we have?", s2: "Show me the trial balance", s3: "Create a quotation for 10 Bolt Pack M8", s4: "List all unpaid invoices", loadOlder: "Load older messages", uploading: "Uploading...", failed: "Failed", remove: "Remove", placeholderDemo: "Running live demo...", placeholderType: "Type a message...", placeholderConnecting: "Connecting...", attachTitle: "Attach file (PDF or image, max 10 MB)", creating: "Creating chat...", dropToAttach: "Drop file to attach (images or PDF, max 10 MB each)", demoError: "Could not start demo", voiceStart: "Record voice message", voiceStop: "Stop recording", voiceTranscribing: "Transcribing...", micDenied: "Microphone access was denied.", transcribeFailed: "Transcription failed. Please try again." }, $o = { "Create Credit Note": "Create Credit Note", "Create Debit Note": "Create Debit Note", "Create Delivery Note": "Create Delivery Note", "Create Purchase Invoice": "Create Purchase Invoice", "Create Purchase Receipt": "Create Purchase Receipt", "Create Return": "Create Return", "Create Sales Invoice": "Create Sales Invoice", "Create Sales Order": "Create Sales Order" }, Vo = { "Last modified": "Last modified", Created: "Created", "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code", "Item (type)": "Item (type)", "Asset Tag / Plate": "Asset Tag / Plate", "Home Yard": "Home Yard", "Purchase Value": "Purchase Value", "Meter Reading": "Meter Reading", "Meter Unit": "Meter Unit", Yard: "Yard", "Asset (specific unit)": "Asset (specific unit)", Allocation: "Allocation", From: "From", To: "To", Purpose: "Purpose", "Purchase Date": "Purchase Date", Notes: "Notes" }, Uo = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, Ko = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a report-specialist model that creates a validated declarative report over your ERP data and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), jo = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, Wo = { period: "Period", allTime: "All time", semantics: "Balance-sheet accounts: closing balance at period end. P&L accounts: movement within the period. Click an account for its ledger.", empty: "No accounts found. Complete the company setup first.", disabled: "disabled", rootType: { Asset: "Assets", Liability: "Liabilities", Equity: "Equity", Income: "Income", Expense: "Expenses" } }, Go = { fleetCalendar: "Fleet Calendar", yard: "Yard", machineType: "Machine type", prev: "Prev", today: "Today", next: "Next", weeks: "weeks", newBooking: "New booking", reserved: "Reserved", onHire: "On Hire", machine: "Machine", loadError: "Could not load the fleet calendar.", noAssets: "No assets to show. Add machines under Rentals → Fleet.", pooledNote: "{{count}} pool booking(s) awaiting assignment", unassigned: "Pool — unassigned", poolWarning: "Pool capacity is reserved. No specific machine has been assigned yet; assign a machine before dispatch." }, Ho = { Unit: "Specific machine", Pool: "Pool – assign machine later", Available: "Available", "On Hire": "On Hire", Out: "Out", Maintenance: "Maintenance", Retired: "Retired", Reserved: "Reserved", Returned: "Returned", Cancelled: "Cancelled", Customer: "Customer", Supplier: "Supplier" }, Qo = { asset: { item_code: "The Item is the machine TYPE and carries the rate; an Asset is one physical unit of it. The Item must have is_asset_tracked = 1.", asset_tag: "Plate or serial — must be unique across assets.", status: "The unit's state today (not a date range). Retired units leave the pool.", meter_reading: "Operating hours / km." }, reservation: { item_code: "Pooled booking ('a 1.7t excavator'): set Item + Yard + Qty. For a specific machine, set Asset instead.", asset: "Book one specific machine. A unit booking also consumes a slot of its Item+Yard pool.", from_datetime: "Exact start — date and time (e.g. 14:27). A bare date means 00:00.", to_datetime: "Exact end. Windows are half-open [from, to): a hire ending 09:00 and the next starting 09:00 do NOT clash." } }, Yo = {
|
|
9132
|
-
proposal:
|
|
9133
|
-
common:
|
|
9134
|
-
datePresets:
|
|
9135
|
-
bankStatements:
|
|
9136
|
-
bankReconciliation:
|
|
9137
|
-
smartSearch:
|
|
9138
|
-
language:
|
|
9139
|
-
header:
|
|
9140
|
-
titles:
|
|
9141
|
-
doctypes:
|
|
9142
|
-
masters:
|
|
9143
|
-
nav:
|
|
9144
|
-
login:
|
|
9145
|
-
settings:
|
|
9146
|
-
status:
|
|
9147
|
-
reports:
|
|
9148
|
-
masterForm:
|
|
9149
|
-
dashboard:
|
|
9150
|
-
chat:
|
|
9151
|
-
conversions:
|
|
9152
|
-
fields:
|
|
9153
|
-
tables:
|
|
9154
|
-
tutorial:
|
|
9155
|
-
notesMarkup:
|
|
9156
|
-
coa:
|
|
9157
|
-
rentals:
|
|
9158
|
-
fieldOptions:
|
|
9159
|
-
hints:
|
|
9160
|
-
}, Jo = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, Zo = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", cancelBooking: "Buchung stornieren", cancelBookingConfirm: "Ja, stornieren", keepBooking: "Behalten", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", showDisabled: "Deaktivierte anzeigen", columns: "Spalten", searchPlaceholder: "Suchen…", noRecords: "Keine Einträge gefunden", active: "Aktiv", disabled: "Deaktiviert", sortByColumn: "Nach dieser Spalte sortieren", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, Xo = { today: "Heute", thisWeek: "Diese Woche", thisMonth: "Dieser Monat", thisQuarter: "Dieses Quartal", thisYear: "Dieses Jahr", lastMonth: "Letzter Monat", lastQuarter: "Letztes Quartal", lastYear: "Letztes Jahr", endOfThisMonth: "Ende dieses Monats", endOfLastMonth: "Ende des letzten Monats", endOfThisQuarter: "Ende dieses Quartals", endOfThisYear: "Ende dieses Jahres", endOfLastYear: "Ende des letzten Jahres" }, el = { title: "Kontoauszug importieren", subtitle: "ISO-20022-CAMT-Kontoauszüge prüfen und ohne automatische Verbuchung importieren.", selectFiles: "CAMT-Dateien", chooseFiles: "XML- oder ZIP-Dateien auswählen", dropFiles: "XML- oder ZIP-Dateien hier ablegen", unsupportedFiles: "Es werden nur CAMT-XML- oder ZIP-Dateien unterstützt: {{files}}", fileHint: "camt.053.001.04 und camt.053.001.08 · mehrere Dateien möglich", preview: "Vorschau anzeigen", noPosting: "Vorschau und Import erzeugen keine Buchungssätze.", alreadyImported: "Bereits importiert", period: "Zeitraum", openingBalance: "Anfangssaldo", closingBalance: "Endsaldo", entries: "Buchungen", credits: "Gutschriften", debits: "Belastungen", details: "Transaktionsdetails", batches: "Sammelbuchungen", qrReferences: "QR-Referenzen", mapping: "Bankkonto-Zuordnung", selectBankAccount: "Bankkonto auswählen…", noBankAccounts: "Es wurde noch kein Bankkonto eingerichtet.", createBankAccount: "Bankkonto einrichten", mappingRequired: "Ordnen Sie vor dem Import jeden neuen Auszug einem Bankkonto zu.", import: "Kontoauszüge importieren", importComplete: "Import abgeschlossen", importCounts: "{{imported}} Buchungen importiert, {{duplicates}} Duplikate übersprungen", history: "Letzte Importe", importId: "Import", bankAccount: "Bankkonto", source: "Quelldatei", openReconciliation: "Bankabstimmung öffnen" }, tl = { title: "Bankabstimmung", subtitle: "Importierte Banktransaktionen mit Buchungen, offenen Rechnungen oder Sachkonten abstimmen.", status: "Status", unreconciled: "Nicht abgestimmt", reconciled: "Abgestimmt", transactions: "Banktransaktionen", empty: "In dieser Ansicht sind keine Banktransaktionen vorhanden.", remittance: "Zahlungsinformation", reference: "Referenz", openTransaction: "Banktransaktion öffnen", conversionRate: "Wechselkurs (1 {{currency}} in {{base}})", conversionRateHint: "Erforderlich, wenn für das Transaktionsdatum kein Wechselkurs hinterlegt ist.", existingVouchers: "Bestehende Buchungen", existingVouchersHint: "Diese eingereichten Belege enthalten eine exakt passende Bewegung auf diesem Bankkonto. Bei der Zuordnung wird nichts erneut gebucht.", match: "Zuordnen", openInvoices: "Offene Rechnungen", openInvoicesHint: "Wähle eine oder mehrere Rechnungen derselben Partei. Nach der Bestätigung wird eine Zahlung erstellt und eingereicht.", outstanding: "Offen", allocation: "Zuweisung", noInvoiceSuggestions: "Es wurde keine plausible offene Rechnung gefunden.", allocated: "{{amount}} von {{total}} zugewiesen", createPayment: "Zahlung erstellen und abstimmen", directPosting: "Auf ein Sachkonto buchen", directPostingHint: "Für Gebühren, Zinsen und andere Bewegungen ohne Rechnung. Debitoren-, Kreditoren-, Bank- und Kassenkonten sind bewusst ausgeschlossen.", counterpartyAccount: "Gegenkonto", remarks: "Bemerkung", createJournal: "Buchungssatz erstellen und abstimmen", activeMatch: "Aktive Abstimmung", undo: "Abstimmung rückgängig machen", confirmExistingTitle: "Bestehende Buchung zuordnen?", confirmExistingBody: "{{transaction}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", confirmGroupBody: "Alle {{count}} Transaktionen über insgesamt {{amount}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", groupedTransactions: "{{count}} gruppierte Transaktionen", confirmPaymentTitle: "Zahlung buchen und abstimmen?", confirmPaymentBody: "Damit wird für {{transaction}} eine Zahlung über {{amount}} eingereicht und auf {{count}} Rechnung(en) verteilt.", onAccountWarning: "{{amount}} bleibt als nicht zugewiesene Zahlung bei dieser Partei bestehen.", confirmJournalTitle: "Buchungssatz erstellen und abstimmen?", confirmJournalBody: "Damit werden {{amount}} für {{transaction}} gegen {{account}} gebucht.", postAndReconcile: "Buchen und abstimmen", undoTitle: "Abstimmung rückgängig machen?", undoCreatedBody: "Der durch diese Abstimmung erstellte Beleg wird storniert, seine Hauptbuchungen werden umgekehrt und Rechnungszuweisungen wiederhergestellt.", undoExistingBody: "Der bestehende Beleg wird nur von der Banktransaktion getrennt. Er bleibt eingereicht und seine Buchungen werden nicht verändert.", undoExistingGroupBody: "Alle {{count}} gruppierten Banktransaktionen ({{transactions}}) werden gemeinsam vom Beleg getrennt. Der bestehende Beleg bleibt eingereicht und seine Buchungen werden nicht verändert.", reconciledNotice: "Banktransaktion wurde abgestimmt.", groupReconciledNotice: "{{count}} Banktransaktionen wurden als Gruppe abgestimmt.", undoneNotice: "Abstimmung wurde rückgängig gemacht." }, nl = { placeholder: "Suchen oder Feld:Wert eingeben…", search: "Suchen", addFilter: "+ Filter", availableFields: "Verfügbare Felder", fieldHelp: "Feld auswählen oder den technischen Namen mit Doppelpunkt eingeben.", field: "Feld", valueFor: "Wert für {{label}}", allFields: "Alle Felder", typeForValues: "Tippen, um Werte in diesem Feld zu finden.", noValues: "Keine passenden Werte gefunden.", noFields: "Keine passenden Felder gefunden.", useValue: "„{{value}}“ verwenden", removeFilter: "Filter {{label}} entfernen", types: { text: "Text", textarea: "Langtext", select: "Auswahl", link: "Verknüpfter Eintrag", date: "Datum", datetime: "Datum und Uhrzeit", number: "Zahl", currency: "Betrag" } }, al = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, rl = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, sl = { dashboard: "Dashboard", setup: "Unternehmenseinrichtung", tutorial: "Erste Schritte", chat: "Chat", reports: "Berichte", "trial-balance": "Rohbilanz", "general-ledger": "Hauptbuch", "stock-balance": "Lagerbestand", "profit-and-loss": "Gewinn- und Verlustrechnung", "balance-sheet": "Bilanz", "ar-aging": "Offene Posten Debitoren", "ap-aging": "Offene Posten Kreditoren", analytics: "Analysen", "chart-of-accounts": "Kontenplan" }, il = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, "bank-account": { one: "Bankkonto", other: "Bankkonten" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, ol = { company: { one: "Unternehmen", other: "Unternehmen" }, customer: { one: "Kunde", other: "Kunden" }, supplier: { one: "Lieferant", other: "Lieferanten" }, item: { one: "Artikel", other: "Artikel" }, warehouse: { one: "Lager", other: "Lager" } }, ll = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen", Rentals: "Vermietung" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", "Bank Account": "Bankkonten", "Bank Statement Import": "Kontoauszug importieren", "Bank Reconciliation": "Bankabstimmung", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan", "Fleet Calendar": "Flottenkalender", "Fleet (Assets)": "Flotte (Geräte)", Reservations: "Reservationen" } }, cl = { taglineFirstRun: "Erstellen Sie Ihr Administratorkonto, um zu beginnen", taglineRegister: "Erstellen Sie Ihr Konto", taglineSignIn: "Melden Sie sich bei Ihrem Konto an", demoBanner: "Der Demomodus ist aktiv. Melden Sie sich mit einem Administratorkonto an, um Einstellungen zu verwalten oder den öffentlichen Zugriff zu deaktivieren.", fullName: "Vollständiger Name", email: "E-Mail", password: "Passwort", confirmPassword: "Passwort bestätigen", createAdmin: "Administratorkonto erstellen", register: "Registrieren", signIn: "Anmelden", browsingTitle: "Nur am Stöbern?", browsingBody: "Starten Sie eine neue Chat-Sitzung und sehen Sie sich die Live-Demo an.", enterDemo: "Live-Demo starten", haveInvite: "Haben Sie eine Einladung?", noAccountPrompt: "Noch kein Konto?", registerLink: "Registrieren", alreadyHaveAccount: "Haben Sie bereits ein Konto?", signInLink: "Anmelden", passwordsNoMatch: "Passwörter stimmen nicht überein", passwordTooShort: "Das Passwort muss mindestens 6 Zeichen lang sein", registrationFailed: "Registrierung fehlgeschlagen", loginFailed: "Anmeldung fehlgeschlagen", orContinueWith: "oder weiter mit", continueWithProvider: "Weiter mit {{provider}}", oauthError: { generic: "Anmeldung fehlgeschlagen. Bitte erneut versuchen.", email_exists: "Ein Konto mit dieser E-Mail existiert bereits. Melden Sie sich an und verknüpfen Sie diesen Anbieter in den Kontoeinstellungen.", email_unverified: "Ihr Anbieter hat keine bestätigte E-Mail übermittelt, daher ist keine Anmeldung möglich.", registration_closed: "Für diese E-Mail besteht noch kein Konto und die Registrierung ist nur per Einladung möglich.", invite_invalid: "Diese Einladung ist ungültig, bereits verwendet oder für eine andere E-Mail ausgestellt.", identity_taken: "Dieses Anbieterkonto ist bereits mit einem anderen Benutzer verknüpft.", account_disabled: "Dieses Konto wurde deaktiviert.", token_exchange_failed: "Anmeldung beim Anbieter fehlgeschlagen. Bitte erneut versuchen." } }, dl = { pdfTitle: "PDF & Druck", pageSize: "Seitengröße", pdfHelp: "A4 ist international Standard (210 x 297 mm). Letter ist Standard in den USA (8,5 x 11 Zoll).", passwordTitle: "Passwort ändern", currentPassword: "Aktuelles Passwort", newPassword: "Neues Passwort", confirmNewPassword: "Neues Passwort bestätigen", changePassword: "Passwort ändern", changingPassword: "Wird geändert...", passwordChanged: "Passwort geändert.", setPasswordTitle: "Passwort festlegen", setPasswordBody: "Ihr Konto meldet sich mit Google an. Legen Sie ein Passwort fest, um sich auch mit E-Mail und Passwort anzumelden — ein praktischer Rückfall, falls Sie den Zugang zu Ihrem Google-Konto verlieren.", setPassword: "Passwort festlegen", passwordSet: "Passwort festgelegt.", linkedAccountsTitle: "Verknüpfte Konten", linkedAccountsBody: "Verknüpfen Sie ein Google- oder Apple-Konto, um sich ohne Passwort anzumelden.", linked: "Verknüpft", linkProvider: "{{provider}} verknüpfen", openingTitle: "Eröffnungsbilanzen", openingBody: "Auf der Seite Eröffnungsbilanzen können Kontensalden, Lagerbestände und offene Rechnungen aus einem früheren System importiert werden.", openingEnabled: "Derzeit aktiviert — erreichbar unter Einführung > Eröffnungsbilanzen.", openingDisabled: "Derzeit deaktiviert — die Seite ist in der Seitenleiste ausgeblendet.", signupTitle: "Öffentliche Registrierung", signupBody: "Erlauben Sie es jedem, ohne Einladung ein eigenes Konto (als Betrachter) zu erstellen. Wenn deaktiviert, können neue Benutzer nur über einen Einladungslink beitreten.", signupEnabled: "Derzeit aktiviert — jeder mit der URL kann sich als Betrachter registrieren.", signupDisabled: "Derzeit deaktiviert — die Registrierung erfolgt nur per Einladung.", chatApiTitle: "Chat-API", apiTitle: "Programmatische API", restApiBody: "Konnektoren und Skripten erlauben, dieses ERP über seine REST-API (Belege, Stammdaten, Berichte) mit denselben Bearer-API-Schlüsseln zu steuern. Standardmäßig deaktiviert.", restApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können /api/documents, /api/masters und die übrige REST-API aufrufen.", restApiDisabled: "Derzeit deaktiviert — die REST-API akzeptiert nur das Sitzungs-Cookie; Schlüssel werden abgewiesen.", restApiDeactivateTitle: "REST-API deaktivieren?", restApiDeactivateBody: "Der Bearer-Schlüssel-Zugriff auf die REST-API wird abgeschaltet — Konnektoren und Skripte werden abgewiesen, bis Sie ihn wieder einschalten. Die Web-App (Sitzungs-Cookie) ist nicht betroffen, und Ihre API-Schlüssel werden NICHT gelöscht: Sie funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat.", version: "Version {{version}}" }, ul = { Draft: "Entwurf", Open: "Offen", Submitted: "Gebucht", "To Deliver and Bill": "Zu liefern und abzurechnen", "To Deliver": "Zu liefern", "To Bill": "Abzurechnen", Completed: "Abgeschlossen", Ordered: "Bestellt", Paid: "Bezahlt", Unpaid: "Unbezahlt", Cancelled: "Storniert", Discarded: "Verworfen", Overdue: "Überfällig", Return: "Retoure", Closed: "Geschlossen" }, ml = { periodRange: "Berichtszeitraum: {{from}} – {{to}}", periodFrom: "Berichtszeitraum ab {{from}}", periodThrough: "Berichtszeitraum bis {{to}}", asOfDate: "Stichtag: {{date}}", balanced: "AUSGEGLICHEN", imbalanced: "NICHT AUSGEGLICHEN", income: "Erträge", expenses: "Aufwendungen", totalIncome: "Summe Erträge", totalExpenses: "Summe Aufwendungen", netProfit: "Gewinn", netLoss: "Verlust", assets: "Aktiva", liabilities: "Verbindlichkeiten", equity: "Eigenkapital", totalAssets: "Summe Aktiva", totalLiabilities: "Summe Verbindlichkeiten", totalEquity: "Summe Eigenkapital", totalLiabilitiesEquity: "Summe Verbindlichkeiten + Eigenkapital", current: "Laufend", noData: "Keine Daten gefunden", noEntries: "Keine Buchungen gefunden", noStockData: "Keine Lagerdaten gefunden", noReceivables: "Keine offenen Forderungen", noPayables: "Keine offenen Verbindlichkeiten", noDocuments: "Keine Dokumente gefunden" }, pl = { required: "Erforderlich: {{fields}}", deleteConfirm: "Diesen Datensatz löschen: {{label}}?", disabledNotice: "Dieser Datensatz ({{label}}) ist deaktiviert. Er verbleibt im System, weil andere Datensätze noch darauf verweisen.", disabledOnDelete: "{{label}} {{name}} wurde deaktiviert statt gelöscht, da er von {{reason}} referenziert wird." }, hl = { "Last modified": "Zuletzt geändert", Created: "Erstellt", Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname", "Item (type)": "Artikel (Typ)", "Asset Tag / Plate": "Kennung / Kennzeichen", "Home Yard": "Heimdepot", "Purchase Value": "Kaufwert", "Meter Reading": "Zählerstand", "Meter Unit": "Zählereinheit", Yard: "Depot", "Asset (specific unit)": "Gerät (bestimmte Einheit)", Allocation: "Zuweisung", From: "Von", To: "Bis", Purpose: "Zweck", "Purchase Date": "Kaufdatum", Notes: "Notizen" }, gl = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, fl = { "Create Sales Order": "Kundenauftrag erstellen", "Create Sales Invoice": "Ausgangsrechnung erstellen", "Create Delivery Note": "Lieferschein erstellen", "Create Purchase Invoice": "Eingangsrechnung erstellen", "Create Purchase Receipt": "Wareneingang erstellen", "Create Credit Note": "Gutschrift erstellen", "Create Debit Note": "Lastschrift erstellen", "Create Return": "Retoure erstellen" }, yl = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, bl = { title: "Lambda ERP Chat", subtitle: "Bitten Sie mich, Dokumente zu erstellen, Daten abzurufen oder Berichte auszuführen.", s1: "Welche Kunden haben wir?", s2: "Zeig mir die Rohbilanz", s3: "Erstelle ein Angebot für 10 Bolt Pack M8", s4: "Liste alle unbezahlten Rechnungen auf", loadOlder: "Ältere Nachrichten laden", uploading: "Wird hochgeladen...", failed: "Fehlgeschlagen", remove: "Entfernen", placeholderDemo: "Live-Demo läuft...", placeholderType: "Nachricht eingeben...", placeholderConnecting: "Verbindung wird hergestellt...", attachTitle: "Datei anhängen (PDF oder Bild, max. 10 MB)", creating: "Chat wird erstellt...", dropToAttach: "Datei zum Anhängen ablegen (Bilder oder PDF, je max. 10 MB)", demoError: "Demo konnte nicht gestartet werden", voiceStart: "Sprachnachricht aufnehmen", voiceStop: "Aufnahme stoppen", voiceTranscribing: "Wird transkribiert...", micDenied: "Zugriff auf das Mikrofon wurde verweigert.", transcribeFailed: "Transkription fehlgeschlagen. Bitte erneut versuchen." }, vl = /* @__PURE__ */ JSON.parse('{"pageTitle":"Erste Schritte mit Lambda ERP","intro":"Lambda ERP ist ein KI-natives ERP-System, bei dem die gesamte Funktionalität – etwa das Erstellen von Aufträgen, das Prüfen von Beständen und das Erfassen von Zahlungen – über eine Chat-Oberfläche zugänglich ist. Es leitet an, denkt mit und prüft alle Ihre täglichen Geschäftsaufgaben.","openChat":"KI-Chat öffnen","tipLabel":"Tipp:","topTip":"Der KI-Chat kann Ihnen auch direkte Links zu Dokumenten und herunterladbaren PDFs geben. Bitten Sie ihn einfach, ein Dokument zu erstellen oder nachzuschlagen, und er fügt anklickbare Links in seine Antwort ein.","manualIntro":"Wenn Sie genau verstehen möchten, wie die Dinge unter der Haube funktionieren, oder Dinge lieber manuell erledigen, finden Sie hier einen vollständigen Geschäftszyklus Schritt für Schritt.","caTitle":"Dynamische Analysen – Chatten Sie sich zu jedem Diagramm","caBadge":"Kernfunktion","caBody":"Brauchen Sie einen Bericht, den die Vorlagen nicht liefern? Beschreiben Sie ihn einfach im Chat. Der Assistent ruft ein Code-Spezialmodell auf, das den Bericht für Sie schreibt, ihn live über Ihre ERP-Daten ausführt und einen teilbaren Link zurückgibt. Das Diagramm oder die Tabelle wird in Sekunden gerendert und als Entwurf unter „Eigene Analysen“ in der Seitenleiste gespeichert – Sie können ihn erneut öffnen, die URL mit Kollegen teilen oder den Assistenten bitten, ihn zu verfeinern.","caTryAsking":"Versuchen Sie zu fragen (zum Vorausfüllen im Chat klicken):","caPrompt1":"Zeig mir die Top 10 Kunden nach Umsatz dieses Jahr als Balkendiagramm","caPrompt2":"Monatlicher Einkaufstrend nach Lieferant über alle Monate, x-Achse mit Lieferantennamen beschriften","caPrompt3":"Bestseller-Artikel nach Menge, mit Tabelle und Diagramm","caPrompt4":"Welche Kunden schulden mir gerade am meisten?","caTryInChat":"Im Chat ausprobieren","caOpenWorkspace":"Analyse-Arbeitsbereich öffnen","flowTitle":"Überblick Dokumentenfluss","salesCycle":"Verkaufszyklus","purchaseCycle":"Einkaufszyklus","returns":"Retouren","flowShortcut":"Abkürzung: Das Angebot kann den Kundenauftrag überspringen und direkt zur Ausgangsrechnung oder zum Lieferschein führen","legendStock":"Lagerwirkung","legendGl":"Buchungswirkung","legendCash":"Geldwirkung","legendReversal":"Stornierung","lifecycleTitle":"Dokumenten-Lebenszyklus","lcDraftLabel":"Entwurf:","lcDraftDesc":"Bearbeitbar. Keine finanzielle oder Bestandswirkung.","lcSubmittedLabel":"Gebucht:","lcSubmittedDesc":"Gesperrt. Buchungen und Lagerbuchungen werden erzeugt.","lcCancelledLabel":"Storniert:","lcCancelledDesc":"Alle Buchungen storniert. Das Dokument wird dauerhaft archiviert.","lcNoDelete":"Es gibt kein Löschen. Um einen Entwurf zu verwerfen: buchen und dann stornieren.","lcCorrect":"Um ein gebuchtes Dokument zu korrigieren: stornieren und ein neues erstellen.","readyTitle":"Sie sind startklar","readyBody1":"Sie verstehen jetzt den vollständigen Zyklus. Ein typisches Praxisszenario sieht so aus: Sie erhalten einen Kundenauftrag (Angebot → Kundenauftrag), prüfen den Bestand, kaufen, was Sie brauchen (Bestellung → Wareneingang → Eingangsrechnung → Zahlung), liefern an den Kunden (Lieferschein), stellen ihm die Rechnung (Ausgangsrechnung) und ziehen die Zahlung ein (Zahlung). Kommt etwas zurück, erstellen Sie eine Gutschrift und eine Lieferschein-Retoure, um Finanzen und Bestand umzukehren. Die Rohbilanz bestätigt, dass alles ausgeglichen ist.","readyBody2":"Sie können all dies auch über den KI-Chat per natürlicher Konversation erledigen – beschreiben Sie einfach, was Sie brauchen, und er erstellt die richtigen Dokumente für Sie.","chips":{"Quotation":"Angebot","Sales Order":"Kundenauftrag","Delivery Note":"Lieferschein","Sales Invoice":"Ausgangsrechnung","Payment Entry":"Zahlung","Purchase Order":"Bestellung","Purchase Receipt":"Wareneingang","Purchase Invoice":"Eingangsrechnung","Credit Note":"Gutschrift","DN Return":"Lieferschein-Retoure","Debit Note":"Lastschrift","Draft":"Entwurf","Submitted":"Gebucht","Cancelled":"Storniert"},"links":{"Go to Setup":"Zur Einrichtung","Customers":"Kunden","Suppliers":"Lieferanten","Items":"Artikel","Warehouses":"Lager","New Quotation":"Neues Angebot","View Quotations":"Angebote anzeigen","Stock Balance":"Lagerbestand","New Purchase Order":"Neue Bestellung","Purchase Receipts":"Wareneingänge","Purchase Invoices":"Eingangsrechnungen","Delivery Notes":"Lieferscheine","Sales Invoices":"Ausgangsrechnungen","New Payment Entry":"Neue Zahlung","New Stock Entry":"Neue Lagerbuchung","New Journal Entry":"Neuer Buchungssatz","Profit & Loss":"Gewinn- und Verlustrechnung","Balance Sheet":"Bilanz","AR Aging":"Offene Posten Debitoren","AP Aging":"Offene Posten Kreditoren","Trial Balance":"Rohbilanz","General Ledger":"Hauptbuch","Open AI Chat":"KI-Chat öffnen"},"steps":{"1":{"title":"Unternehmen einrichten","description":"Erstellen Sie ein Unternehmen mit einer Basiswährung. Dadurch wird Ihr Kontenplan generiert (30 Standardkonten in den Bereichen Aktiva, Verbindlichkeiten, Eigenkapital, Erträge und Aufwendungen) sowie eine Standard-Kostenstelle. Sie können außerdem Demodaten mit Beispielkunden, -lieferanten und -artikeln anlegen, um schnell loszulegen."},"2":{"title":"Stammdaten anlegen","description":"Bevor Sie buchen können, benötigen Sie Stammdaten. Legen Sie mindestens einen Kunden, einen Lieferanten, einen Artikel (mit Standardpreis) und ein Lager an. Wenn Sie in Schritt 1 Demodaten angelegt haben, existieren diese bereits.","tip":"Artikel haben einen Standardpreis, der beim Hinzufügen zu Dokumenten automatisch ausgefüllt wird. Sie können den Preis pro Transaktion jederzeit überschreiben."},"3":{"title":"Angebot erstellen","description":"Ein Angebot ist eine unverbindliche Offerte an einen Kunden. Wählen Sie einen Kunden, fügen Sie Positionen mit Mengen und Preisen hinzu, optional Steuerzeilen, und speichern Sie. Angebote haben keine finanzielle Auswirkung – sie erzeugen keine Buchungs- oder Lagerbewegungen. Legen Sie ein Gültigkeitsdatum fest, damit das Angebot automatisch abläuft."},"4":{"title":"Buchen und in Kundenauftrag umwandeln","description":"Öffnen Sie Ihr gespeichertes Angebot und klicken Sie auf Buchen, um es zu bestätigen. Klicken Sie dann auf „Kundenauftrag erstellen“, um es umzuwandeln. Der Kundenauftrag stellt eine bestätigte Zusage des Kunden dar. Er hat weiterhin keine finanzielle Auswirkung, reserviert aber Bestand für die Planung.","tip":"Nur gebuchte Dokumente können in den nächsten Schritt umgewandelt werden. Entwurf → Buchen → Umwandeln ist der Standardablauf. Für schnelle Geschäfte können Sie den Kundenauftrag überspringen und direkt vom Angebot zur Ausgangsrechnung oder zum Lieferschein gehen."},"5":{"title":"Bestand vor der Erfüllung prüfen","description":"Bevor Sie liefern können, prüfen Sie, ob der Artikel tatsächlich auf Lager ist. Öffnen Sie den Bericht Lagerbestand und suchen Sie den Artikel. Wenn Ihr Lager eine Menge von null aufweist, müssen Sie zunächst Bestand beschaffen – entweder über eine Bestellung (Einkauf bei einem Lieferanten) oder eine Lagerbuchung (manueller Eingang).","tip":"Dies ist ein häufiges Szenario aus der Praxis: Sie verkaufen etwas und stellen dann fest, dass Sie es erst einkaufen müssen. Das ERP unterstützt beide Abläufe."},"6":{"title":"Einkaufszyklus: Bestand bei einem Lieferanten kaufen","description":"Wenn Sie Bestand einkaufen müssen, haben Sie zwei gültige Wege. Der Standardweg ist Bestellung → Wareneingang → Eingangsrechnung: Nutzen Sie ihn, wenn die Ware vor oder getrennt von der Lieferantenrechnung eintrifft. Treffen Rechnung und Wareneingang gleichzeitig ein, können Sie die Eingangsrechnung direkt erstellen und „Lager aktualisieren“ aktivieren, sodass dasselbe Dokument sowohl den Bestand vereinnahmt als auch die Verbindlichkeit erfasst.","tip":"Verwenden Sie zuerst den Wareneingang, wenn Sie Waren getrennt erhalten. Verwenden Sie die Eingangsrechnung mit „Lager aktualisieren“, wenn ein Schritt sowohl den Bestand vereinnahmen als auch die Lieferantenrechnung buchen soll. Setzen Sie in diesem direkten Weg ein Lager in jeder Bestandszeile."},"7":{"title":"Lieferschein erstellen","description":"Nachdem Sie nun Bestand haben, kehren Sie zu Ihrem gebuchten Kundenauftrag zurück und klicken Sie auf „Lieferschein erstellen“. Setzen Sie in jeder Position das Lager (von dem die Ware versendet wird) und buchen Sie. Dadurch wird Bestand aus dem Lager ausgebucht – Ihr Lagerbestand sinkt.","tip":"Der Lieferschein ist das Versanddokument. Er reduziert den Bestand, erzeugt aber keine Rechnung. Sie können Lieferung und Rechnungsstellung getrennt vornehmen."},"8":{"title":"Ausgangsrechnung erstellen und buchen","description":"Erstellen Sie aus dem gebuchten Kundenauftrag eine Ausgangsrechnung. Beim Buchen der Rechnung werden Buchungen erzeugt: Forderungen aus Lieferungen und Leistungen werden im Soll gebucht (der Kunde schuldet Ihnen Geld) und Umsatzerlöse im Haben (erzielter Ertrag). Sind Steuern konfiguriert, wird auch die Steuerverbindlichkeit im Haben gebucht. Der offene Betrag zeigt, was der Kunde noch schuldet."},"9":{"title":"Kundenzahlungen erfassen","description":"Erstellen Sie eine Zahlung, um vom Kunden erhaltenes Geld zu erfassen. Setzen Sie die Zahlungsart auf „Receive“ (Erhalten), wählen Sie den Kunden, geben Sie den Betrag an und ordnen Sie ihn der Ausgangsrechnung zu. Sie können Teilzahlungen vornehmen – der offene Betrag der Rechnung aktualisiert sich entsprechend. Erstellen Sie weitere Zahlungen, bis die Rechnung vollständig beglichen ist.","tip":"Teilzahlungen sind üblich. Eine Rechnung über 10.000 kann jetzt mit 3.000 und später mit 7.000 bezahlt werden. Jede Zahlung reduziert den offenen Betrag."},"10":{"title":"Lagerbuchungen (manuelle Bestandsführung)","description":"Verwenden Sie Lagerbuchungen für Bestandsbewegungen, die nicht mit Ein- oder Verkäufen verbunden sind. „Material Receipt“ fügt Bestand hinzu (Eröffnungsbestände, Korrekturen). „Material Issue“ bucht Bestand aus (Abschreibungen, interner Verbrauch). „Material Transfer“ verschiebt Bestand zwischen Lägern. Jede Buchung aktualisiert das Lagerbuch mit gleitender Durchschnittsbewertung.","tip":"Verwenden Sie für eingekaufte Waren Wareneingänge statt Lagerbuchungen – sie sind mit der Bestellung verknüpft und bieten einen sauberen Prüfpfad."},"11":{"title":"Buchungssätze","description":"Buchungssätze sind manuelle buchhalterische Anpassungen – Aufwandsabgrenzungen, Korrekturen, Umgliederungen, Eröffnungsbestände. Jeder Satz muss ausgeglichene Soll- und Haben-Beträge haben (Summe Soll = Summe Haben). Verwenden Sie sie, wenn kein anderer Dokumenttyp passt."},"12":{"title":"Gehaltszahlungen","description":"Lambda ERP wickelt Gehälter über die vorhandenen Buchhaltungswerkzeuge ab. Grenzen Sie zunächst den Gehaltsaufwand ab: Erstellen Sie einen Buchungssatz, der Gehaltsaufwand im Soll und Gehaltsverbindlichkeiten im Haben für den gesamten Lohnbetrag bucht. Bezahlen Sie dann die Mitarbeiter: Erstellen Sie einen weiteren Buchungssatz (oder eine Zahlung), der Gehaltsverbindlichkeiten im Soll und Ihr Bankkonto im Haben bucht. Dieser zweistufige Prozess hält Ihre Bücher korrekt – der Aufwand wird in der richtigen Periode erfasst und der Geldabfluss separat nachverfolgt.","tip":"Sie können den KI-Assistenten bitten, dies für Sie zu erledigen: „Grenze 15.000 an Gehältern für April ab“ gefolgt von „Zahle die April-Gehälter von der Bank“. Er erstellt die richtigen Buchungssätze automatisch."},"13":{"title":"Retouren und Gutschriften","description":"Wenn ein Kunde Waren zurückgibt oder Sie eine Gutschrift ausstellen müssen, erstellen Sie eine Retoure. Retouren verwenden denselben Dokumenttyp mit negativen Mengen. Öffnen Sie eine gebuchte Ausgangsrechnung und erstellen Sie eine Gutschrift (Ausgangsrechnungs-Retoure) – dies kehrt die Buchungen um und reduziert den offenen Betrag der ursprünglichen Rechnung. Erstellen Sie für den Bestand eine Lieferschein-Retoure, um Waren zurück ins Lager zu nehmen. Auf der Einkaufsseite erstellen Sie eine Lastschrift (Eingangsrechnungs-Retoure), um eine Lieferantenrechnung umzukehren, oder eine Wareneingangs-Retoure, um Waren zurückzusenden.","tip":"Eine Gutschrift ist einfach eine Ausgangsrechnung mit is_return=1 und negativen Mengen. Dieselbe Buchungslogik läuft – negative Beträge wechseln automatisch auf die richtige Soll-/Haben-Seite. Für eine vollständige Verkaufsretoure benötigen Sie sowohl eine Gutschrift (Finanzen) als auch eine Lieferschein-Retoure (Bestand)."},"14":{"title":"Berichte ausführen","description":"Prüfen Sie Ihre Bücher. Die Gewinn- und Verlustrechnung zeigt Erträge gegenüber Aufwendungen und den Periodengewinn. Die Bilanz zeigt Ihre finanzielle Lage (Aktiva = Verbindlichkeiten + Eigenkapital). Die Offenen Posten Debitoren zeigen, wer Ihnen Geld schuldet und wie überfällig es ist. Die Offenen Posten Kreditoren zeigen, was Sie Lieferanten schulden. Die Rohbilanz überprüft die doppelte Buchführung. Das Hauptbuch zeigt jede einzelne Buchung. Der Lagerbestand zeigt den aktuellen Bestand."},"15":{"title":"Arbeiten in Fremdwährungen","description":"Ihre Bücher werden in einer einzigen Basiswährung geführt (bei der Unternehmenseinrichtung gewählt), aber Sie können in jeder Währung buchen. Setzen Sie eine Währung auf einer Rechnung oder einem Beleg – oder geben Sie einem Kunden oder Lieferanten eine Standardwährung – und der Wechselkurs für dieses Datum wird automatisch ermittelt und auf dem Dokument gespeichert. Das Dokument behält seine Beträge in seiner eigenen Währung, während das Hauptbuch stets in Ihrer Basiswährung bucht. Wenn Sie später zu einem anderen Kurs einnehmen oder zahlen, wird der realisierte Währungsgewinn oder -verlust automatisch auf ein Konto Währungsgewinn/-verlust gebucht. Sie können sogar ein Fremdwährungs-Bankguthaben halten und es später zum Kurs Ihrer Bank umrechnen – die Differenz zum Buchwert wird dann realisiert. Zum Monatsende können Sie offene Fremdwährungssalden zum Stichtagskurs neu bewerten (ein unrealisierter Gewinn/Verlust, der in der nächsten Periode storniert wird), und Sie können jeden Jahresabschluss zur Anzeige in eine andere Währung umgerechnet betrachten.","tip":"Am einfachsten geht das über den KI-Chat – probieren Sie „Erstelle eine Ausgangsrechnung für Lumiere Audio in EUR“, „Zeig mir die Bilanz in EUR“ oder „Wie hoch ist unser unrealisiertes Währungsrisiko zum Monatsende?“. Die Demodaten enthalten bereits einen EUR-Kunden (Lumiere Audio SARL), dessen Rechnung zu einem anderen Kurs eingenommen wurde, sowie eine offene EUR-Lieferantenrechnung – öffnen Sie das Hauptbuch, um die realisierten Währungsbuchungen zu sehen."}},"setupTitle":"Richten Sie Ihr Unternehmen ein — KI-geführt","setupBadge":"Hier starten","setupBody":"Sagen Sie dem Assistenten, welche Art von Unternehmen Sie führen, und er erstellt Ihren Kontenplan für Sie — zugeschnitten auf Ihre Branche, mit den passenden Konten und sinnvollen Voreinstellungen. Er erklärt jede Entscheidung und legt erst dann etwas an, wenn Sie zustimmen.","setupSectors":"Zugeschnitten auf Dienstleistungen, Einzelhandel & POS, Gastronomie, Großhandel & Distribution, Import/Export, Fertigung und Bauwesen.","setupGetStarted":"Im Chat loslegen","setupManual":"Lieber ein manuelles Formular? Nutzen Sie die klassische Einrichtung.","setupManualLink":"Klassische Einrichtung","setupPrompt":"Ich möchte mein Unternehmen einrichten. Können Sie mich durch den Prozess führen?"}'), xl = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, kl = { period: "Periode", allTime: "Gesamter Zeitraum", semantics: "Bilanzkonten: Saldo per Periodenende. Erfolgskonten: Bewegung innerhalb der Periode. Konto anklicken für den Kontoauszug.", empty: "Keine Konten gefunden. Zuerst die Firmeneinrichtung abschliessen.", disabled: "deaktiviert", rootType: { Asset: "Aktiven", Liability: "Passiven", Equity: "Eigenkapital", Income: "Ertrag", Expense: "Aufwand" } }, Nl = { fleetCalendar: "Flottenkalender", yard: "Depot", machineType: "Maschinentyp", prev: "Zurück", today: "Heute", next: "Weiter", weeks: "Wochen", newBooking: "Neue Reservation", reserved: "Reserviert", onHire: "Vermietet", machine: "Maschine", loadError: "Flottenkalender konnte nicht geladen werden.", noAssets: "Keine Geräte vorhanden. Maschinen unter Vermietung → Flotte hinzufügen.", pooledNote: "{{count}} Pool-Reservation(en) noch ohne Maschinenzuordnung", unassigned: "Pool — noch nicht zugeordnet", poolWarning: "Die Pool-Kapazität ist reserviert. Eine konkrete Maschine ist noch nicht zugeordnet; vor der Ausgabe eine Maschine auswählen." }, wl = { Unit: "Bestimmte Maschine", Pool: "Pool – Maschine später zuweisen", Available: "Verfügbar", "On Hire": "Vermietet", Out: "Ausgeliefert", Maintenance: "Wartung", Retired: "Ausgemustert", Reserved: "Reserviert", Returned: "Zurückgegeben", Cancelled: "Storniert", Customer: "Kunde", Supplier: "Lieferant" }, Cl = { asset: { item_code: "Der Artikel ist der Maschinen-TYP und trägt den Tarif; ein Gerät ist eine physische Einheit davon. Der Artikel muss is_asset_tracked = 1 haben.", asset_tag: "Kennzeichen oder Seriennummer — muss über alle Geräte eindeutig sein.", status: "Aktueller Zustand der Einheit (kein Zeitraum). Ausgemusterte Einheiten verlassen den Pool.", meter_reading: "Betriebsstunden / km." }, reservation: { item_code: "Pool-Reservation ('ein 1.7t-Bagger'): Artikel + Depot + Menge setzen. Für eine bestimmte Maschine stattdessen Gerät setzen.", asset: "Eine bestimmte Maschine buchen. Eine Einheiten-Buchung belegt auch einen Platz im Artikel+Depot-Pool.", from_datetime: "Genauer Beginn — Datum und Uhrzeit (z. B. 14:27). Ein reines Datum bedeutet 00:00.", to_datetime: "Genaues Ende. Fenster sind halboffen [von, bis): eine Miete, die um 09:00 endet, und die nächste um 09:00 beginnende, kollidieren NICHT." } }, Sl = {
|
|
9161
|
-
proposal: Jo,
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
}, Al = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, _l = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", cancelBooking: "Annuler la réservation", cancelBookingConfirm: "Oui, annuler", keepBooking: "Conserver", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", showDisabled: "Afficher les désactivés", columns: "Colonnes", searchPlaceholder: "Rechercher…", noRecords: "Aucun enregistrement trouvé", active: "Actif", disabled: "Désactivé", sortByColumn: "Trier par cette colonne", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Dl = { today: "Aujourd’hui", thisWeek: "Cette semaine", thisMonth: "Ce mois-ci", thisQuarter: "Ce trimestre", thisYear: "Cette année", lastMonth: "Mois dernier", lastQuarter: "Trimestre dernier", lastYear: "Année dernière", endOfThisMonth: "Fin du mois en cours", endOfLastMonth: "Fin du mois dernier", endOfThisQuarter: "Fin du trimestre en cours", endOfThisYear: "Fin de l’année en cours", endOfLastYear: "Fin de l’année dernière" }, Pl = { title: "Importer un relevé bancaire", subtitle: "Prévisualisez et importez des relevés ISO 20022 CAMT sans écriture comptable automatique.", selectFiles: "Fichiers CAMT", chooseFiles: "Choisir des fichiers XML ou ZIP", dropFiles: "Déposez les fichiers XML ou ZIP ici", unsupportedFiles: "Seuls les fichiers CAMT XML ou ZIP sont acceptés : {{files}}", fileHint: "camt.053.001.04 et camt.053.001.08 · plusieurs fichiers acceptés", preview: "Afficher l’aperçu", noPosting: "L’aperçu et l’importation ne génèrent aucune écriture comptable.", alreadyImported: "Déjà importé", period: "Période", openingBalance: "Solde initial", closingBalance: "Solde final", entries: "Opérations", credits: "Crédits", debits: "Débits", details: "Détails des transactions", batches: "lots", qrReferences: "Références QR", mapping: "Affectation du compte bancaire", selectBankAccount: "Sélectionner un compte bancaire…", noBankAccounts: "Aucun compte bancaire n’a encore été configuré.", createBankAccount: "Configurer un compte bancaire", mappingRequired: "Affectez chaque nouveau relevé à un compte bancaire avant l’importation.", import: "Importer les relevés", importComplete: "Importation terminée", importCounts: "{{imported}} opérations importées, {{duplicates}} doublons ignorés", history: "Importations récentes", importId: "Importation", bankAccount: "Compte bancaire", source: "Fichier source", openReconciliation: "Ouvrir le rapprochement bancaire" }, Tl = { title: "Rapprochement bancaire", subtitle: "Rapprochez les transactions importées avec des écritures, des factures ouvertes ou des comptes comptables.", status: "Statut", unreconciled: "Non rapprochée", reconciled: "Rapprochée", transactions: "Transactions bancaires", empty: "Aucune transaction bancaire dans cette vue.", remittance: "Information de paiement", reference: "Référence", openTransaction: "Ouvrir la transaction bancaire", conversionRate: "Taux de change (1 {{currency}} en {{base}})", conversionRateHint: "Requis si aucun taux de change n’existe à la date de la transaction.", existingVouchers: "Écritures existantes", existingVouchersHint: "Ces pièces validées contiennent un mouvement exact sur ce compte bancaire. Le rapprochement ne les comptabilise pas une seconde fois.", match: "Rapprocher", openInvoices: "Factures ouvertes", openInvoicesHint: "Sélectionnez une ou plusieurs factures du même tiers. La confirmation crée et valide un paiement.", outstanding: "Solde ouvert", allocation: "Affectation", noInvoiceSuggestions: "Aucune facture ouverte plausible n’a été trouvée.", allocated: "{{amount}} affectés sur {{total}}", createPayment: "Créer le paiement et rapprocher", directPosting: "Comptabiliser sur un compte", directPostingHint: "Pour les frais, intérêts et autres mouvements sans facture. Les comptes clients, fournisseurs, bancaires et de caisse sont volontairement exclus.", counterpartyAccount: "Compte de contrepartie", remarks: "Remarque", createJournal: "Créer l’écriture et rapprocher", activeMatch: "Rapprochement actif", undo: "Annuler le rapprochement", confirmExistingTitle: "Rapprocher l’écriture existante ?", confirmExistingBody: "Rapprocher {{transaction}} avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", confirmGroupBody: "Rapprocher les {{count}} transactions, pour un total de {{amount}}, avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", groupedTransactions: "{{count}} transactions groupées", confirmPaymentTitle: "Comptabiliser le paiement et rapprocher ?", confirmPaymentBody: "Cette action valide un paiement de {{amount}} pour {{transaction}} et l’affecte à {{count}} facture(s).", onAccountWarning: "{{amount}} resteront comme paiement non affecté pour ce tiers.", confirmJournalTitle: "Comptabiliser l’écriture et rapprocher ?", confirmJournalBody: "Cette action comptabilise {{amount}} pour {{transaction}} sur {{account}}.", postAndReconcile: "Comptabiliser et rapprocher", undoTitle: "Annuler le rapprochement ?", undoCreatedBody: "La pièce créée par ce rapprochement sera annulée, ses écritures extournées et les affectations aux factures restaurées.", undoExistingBody: "La pièce existante sera uniquement dissociée. Elle restera validée et ses écritures ne seront pas modifiées.", undoExistingGroupBody: "Les {{count}} transactions groupées ({{transactions}}) seront toutes dissociées ensemble. La pièce existante restera validée et ses écritures ne seront pas modifiées.", reconciledNotice: "Transaction bancaire rapprochée.", groupReconciledNotice: "{{count}} transactions bancaires ont été rapprochées en groupe.", undoneNotice: "Rapprochement annulé." }, Rl = { placeholder: "Rechercher ou saisir champ:valeur…", search: "Rechercher", addFilter: "+ Filtre", availableFields: "Champs disponibles", fieldHelp: "Choisissez un champ ou saisissez son nom technique suivi de deux-points.", field: "Champ", valueFor: "Valeur pour {{label}}", allFields: "Tous les champs", typeForValues: "Commencez à saisir pour rechercher des valeurs dans ce champ.", noValues: "Aucune valeur correspondante.", noFields: "Aucun champ correspondant.", useValue: "Utiliser « {{value}} »", removeFilter: "Supprimer le filtre {{label}}", types: { text: "Texte", textarea: "Texte long", select: "Sélection", link: "Enregistrement lié", date: "Date", datetime: "Date et heure", number: "Nombre", currency: "Montant" } }, Bl = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Il = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, El = { dashboard: "Tableau de bord", setup: "Configuration de l'entreprise", tutorial: "Premiers pas", chat: "Chat", reports: "Rapports", "trial-balance": "Balance comptable", "general-ledger": "Grand livre", "stock-balance": "Solde de stock", "profit-and-loss": "Compte de résultat", "balance-sheet": "Bilan", "ar-aging": "Balance âgée clients", "ap-aging": "Balance âgée fournisseurs", analytics: "Analyses", "chart-of-accounts": "Plan comptable" }, Ll = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, "bank-account": { one: "Compte bancaire", other: "Comptes bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, Ol = { company: { one: "Société", other: "Sociétés" }, customer: { one: "Client", other: "Clients" }, supplier: { one: "Fournisseur", other: "Fournisseurs" }, item: { one: "Article", other: "Articles" }, warehouse: { one: "Entrepôt", other: "Entrepôts" } }, Fl = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres", Rentals: "Locations" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", "Bank Account": "Comptes bancaires", "Bank Statement Import": "Importer un relevé bancaire", "Bank Reconciliation": "Rapprochement bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable", "Fleet Calendar": "Calendrier de flotte", "Fleet (Assets)": "Flotte (matériel)", Reservations: "Réservations" } }, Ml = { taglineFirstRun: "Créez votre compte administrateur pour commencer", taglineRegister: "Créez votre compte", taglineSignIn: "Connectez-vous à votre compte", demoBanner: "Le mode démo est actif. Connectez-vous avec un compte administrateur pour gérer les paramètres ou désactiver l'accès public.", fullName: "Nom complet", email: "E-mail", password: "Mot de passe", confirmPassword: "Confirmer le mot de passe", createAdmin: "Créer un compte administrateur", register: "S'inscrire", signIn: "Se connecter", browsingTitle: "Simple visite ?", browsingBody: "Démarrez une nouvelle session de chat et regardez la démo en direct.", enterDemo: "Lancer la démo", haveInvite: "Vous avez une invitation ?", noAccountPrompt: "Besoin d'un compte ?", registerLink: "S'inscrire", alreadyHaveAccount: "Vous avez déjà un compte ?", signInLink: "Se connecter", passwordsNoMatch: "Les mots de passe ne correspondent pas", passwordTooShort: "Le mot de passe doit comporter au moins 6 caractères", registrationFailed: "Échec de l'inscription", loginFailed: "Échec de la connexion", orContinueWith: "ou continuer avec", continueWithProvider: "Continuer avec {{provider}}", oauthError: { generic: "Échec de la connexion. Veuillez réessayer.", email_exists: "Un compte avec cet e-mail existe déjà. Connectez-vous, puis liez ce fournisseur depuis les paramètres du compte.", email_unverified: "Votre fournisseur n'a pas confirmé d'e-mail vérifié, la connexion est donc impossible.", registration_closed: "Cet e-mail n'a pas encore de compte et l'inscription se fait uniquement sur invitation.", invite_invalid: "Cette invitation est invalide, déjà utilisée ou émise pour un autre e-mail.", identity_taken: "Ce compte fournisseur est déjà lié à un autre utilisateur.", account_disabled: "Ce compte a été désactivé.", token_exchange_failed: "Échec de la connexion auprès du fournisseur. Veuillez réessayer." } }, ql = { pdfTitle: "PDF et impression", pageSize: "Format de page", pdfHelp: "A4 est la norme internationale (210 x 297 mm). Letter est la norme aux États-Unis (8,5 x 11 po).", passwordTitle: "Changer le mot de passe", currentPassword: "Mot de passe actuel", newPassword: "Nouveau mot de passe", confirmNewPassword: "Confirmer le nouveau mot de passe", changePassword: "Changer le mot de passe", changingPassword: "Modification...", passwordChanged: "Mot de passe modifié.", setPasswordTitle: "Définir un mot de passe", setPasswordBody: "Votre compte se connecte avec Google. Définissez un mot de passe pour vous connecter aussi avec e-mail et mot de passe — un recours pratique si vous perdez l'accès à votre compte Google.", setPassword: "Définir le mot de passe", passwordSet: "Mot de passe défini.", linkedAccountsTitle: "Comptes liés", linkedAccountsBody: "Liez un compte Google ou Apple pour vous connecter sans mot de passe.", linked: "Lié", linkProvider: "Lier {{provider}}", openingTitle: "Soldes d'ouverture", openingBody: "La page Soldes d'ouverture permet d'importer les soldes des comptes, le stock et les factures impayées d'un système précédent.", openingEnabled: "Actuellement activé — accessible sous Introduction > Soldes d'ouverture.", openingDisabled: "Actuellement désactivé — la page est masquée dans la barre latérale.", signupTitle: "Inscription publique", signupBody: "Permettre à quiconque de créer son propre compte (en tant que lecteur) sans invitation. Lorsque désactivé, les nouveaux utilisateurs ne peuvent rejoindre que via un lien d'invitation.", signupEnabled: "Actuellement activé — toute personne disposant de l'URL peut s'inscrire en tant que lecteur.", signupDisabled: "Actuellement désactivé — l'inscription se fait uniquement sur invitation.", chatApiTitle: "API de chat", apiTitle: "API programmatique", restApiBody: "Permettre à des connecteurs et scripts de piloter cet ERP via son API REST (documents, données de base, rapports) avec les mêmes clés API Bearer. Désactivé par défaut.", restApiEnabled: "Actuellement activé — les clés émises peuvent appeler /api/documents, /api/masters et le reste de l'API REST.", restApiDisabled: "Actuellement désactivé — l'API REST n'accepte que le cookie de session ; les clés sont rejetées.", restApiDeactivateTitle: "Désactiver l'API REST ?", restApiDeactivateBody: "L'accès par clé Bearer à l'API REST sera désactivé — les connecteurs et scripts sont rejetés jusqu'à sa réactivation. L'application web (cookie de session) n'est pas affectée, et vos clés API ne sont PAS supprimées : elles fonctionnent à nouveau dès que vous réactivez l'API.", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat.", version: "Version {{version}}" }, zl = { Draft: "Brouillon", Open: "Ouvert", Submitted: "Validé", "To Deliver and Bill": "À livrer et facturer", "To Deliver": "À livrer", "To Bill": "À facturer", Completed: "Terminé", Ordered: "Commandé", Paid: "Payé", Unpaid: "Impayé", Cancelled: "Annulé", Discarded: "Supprimé", Overdue: "En retard", Return: "Retour", Closed: "Clôturé" }, $l = { periodRange: "Période du rapport : {{from}} – {{to}}", periodFrom: "Période du rapport à partir du {{from}}", periodThrough: "Période du rapport jusqu’au {{to}}", asOfDate: "Date de référence : {{date}}", balanced: "ÉQUILIBRÉ", imbalanced: "DÉSÉQUILIBRÉ", income: "Produits", expenses: "Charges", totalIncome: "Total des produits", totalExpenses: "Total des charges", netProfit: "Bénéfice", netLoss: "Perte", assets: "Actif", liabilities: "Passif", equity: "Capitaux propres", totalAssets: "Total de l'actif", totalLiabilities: "Total du passif", totalEquity: "Total des capitaux propres", totalLiabilitiesEquity: "Total passif + capitaux propres", current: "Non échu", noData: "Aucune donnée trouvée", noEntries: "Aucune écriture trouvée", noStockData: "Aucune donnée de stock trouvée", noReceivables: "Aucune créance en cours", noPayables: "Aucune dette en cours", noDocuments: "Aucun document trouvé" }, Vl = { required: "Requis : {{fields}}", deleteConfirm: "Supprimer ce {{label}} ?", disabledNotice: "Ce {{label}} est désactivé. Il reste dans le système car d'autres enregistrements y font référence.", disabledOnDelete: "{{label}} {{name}} a été désactivé au lieu d'être supprimé car il est référencé par {{reason}}." }, Ul = { "Last modified": "Dernière modification", Created: "Créé", Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société", "Item (type)": "Article (type)", "Asset Tag / Plate": "Étiquette / plaque", "Home Yard": "Dépôt d'attache", "Purchase Value": "Valeur d'achat", "Meter Reading": "Relevé compteur", "Meter Unit": "Unité compteur", Yard: "Dépôt", "Asset (specific unit)": "Équipement (unité spécifique)", Allocation: "Affectation", From: "Du", To: "Au", Purpose: "Objet", "Purchase Date": "Date d'achat", Notes: "Notes" }, Kl = { items: "Lignes", taxes: "Taxes", references: "Références de paiement", accounts: "Écritures de compte", payments: "Paiements", plans: "Articles du plan", monthly_distribution: "Répartition mensuelle" }, jl = { "Create Sales Order": "Créer une commande client", "Create Sales Invoice": "Créer une facture de vente", "Create Delivery Note": "Créer un bon de livraison", "Create Purchase Invoice": "Créer une facture d'achat", "Create Purchase Receipt": "Créer un bon de réception", "Create Credit Note": "Créer un avoir", "Create Debit Note": "Créer une note de débit", "Create Return": "Créer un retour" }, Wl = { totalRevenue: "Chiffre d'affaires total", outstandingReceivable: "Créances en cours", outstandingPayable: "Dettes en cours", totalStockValue: "Valeur totale du stock", recentDocuments: "Documents récents", noRecentDocuments: "Aucun document récent" }, Gl = { title: "Chat Lambda ERP", subtitle: "Demandez-moi de créer des documents, de consulter des données ou d'exécuter des rapports.", s1: "Quels clients avons-nous ?", s2: "Affiche la balance comptable", s3: "Crée un devis pour 10 Bolt Pack M8", s4: "Liste toutes les factures impayées", loadOlder: "Charger les messages plus anciens", uploading: "Téléversement...", failed: "Échec", remove: "Supprimer", placeholderDemo: "Démo en direct en cours...", placeholderType: "Tapez un message...", placeholderConnecting: "Connexion...", attachTitle: "Joindre un fichier (PDF ou image, max 10 Mo)", creating: "Création du chat...", dropToAttach: "Déposez un fichier à joindre (images ou PDF, max 10 Mo chacun)", demoError: "Impossible de démarrer la démo", voiceStart: "Enregistrer un message vocal", voiceStop: "Arrêter l'enregistrement", voiceTranscribing: "Transcription...", micDenied: "L'accès au microphone a été refusé.", transcribeFailed: "Échec de la transcription. Veuillez réessayer." }, Hl = /* @__PURE__ */ JSON.parse(`{"pageTitle":"Premiers pas avec Lambda ERP","intro":"Lambda ERP est un système ERP nativement IA, où toutes les fonctionnalités – comme créer des commandes, vérifier l'inventaire ou enregistrer des paiements – sont accessibles via une interface de chat. Il guide, raisonne et vérifie toutes vos tâches quotidiennes.","openChat":"Ouvrir le chat IA","tipLabel":"Astuce :","topTip":"Le chat IA peut aussi vous donner des liens directs vers des documents et des PDF téléchargeables. Demandez-lui simplement de créer ou de rechercher un document et il inclura des liens cliquables dans sa réponse.","manualIntro":"Si vous souhaitez comprendre pleinement le fonctionnement interne, ou préférez procéder manuellement, voici un cycle commercial complet étape par étape.","caTitle":"Analyses dynamiques – discutez pour obtenir n'importe quel graphique","caBadge":"Fonctionnalité phare","caBody":"Besoin d'un rapport que les modèles prédéfinis ne fournissent pas ? Décrivez-le simplement dans le chat. L'assistant appelle un modèle spécialiste du code qui écrit le rapport pour vous, l'exécute en direct sur vos données ERP et renvoie un lien partageable. Le graphique ou le tableau s'affiche en quelques secondes et est enregistré comme brouillon sous « Analyses personnalisées » dans la barre latérale – vous pouvez le rouvrir, partager l'URL avec vos collègues ou demander à l'assistant de l'affiner.","caTryAsking":"Essayez de demander (cliquez pour préremplir dans le chat) :","caPrompt1":"Montre-moi les 10 meilleurs clients par chiffre d'affaires cette année en diagramme à barres","caPrompt2":"Tendance mensuelle des achats par fournisseur sur tous les mois, étiquette l'axe des x avec le nom du fournisseur","caPrompt3":"Articles les plus vendus par quantité, avec un tableau et un graphique","caPrompt4":"Quels clients me doivent le plus en ce moment ?","caTryInChat":"Essayer dans le chat","caOpenWorkspace":"Ouvrir l'espace d'analyse","flowTitle":"Aperçu du flux des documents","salesCycle":"Cycle de vente","purchaseCycle":"Cycle d'achat","returns":"Retours","flowShortcut":"Raccourci : le devis peut ignorer la commande client et aller directement à la facture de vente ou au bon de livraison","legendStock":"impact stock","legendGl":"impact comptable","legendCash":"impact trésorerie","legendReversal":"annulation","lifecycleTitle":"Cycle de vie du document","lcDraftLabel":"Brouillon :","lcDraftDesc":"Modifiable. Aucun impact financier ni sur le stock.","lcSubmittedLabel":"Validé :","lcSubmittedDesc":"Verrouillé. Les écritures comptables et de stock sont générées.","lcCancelledLabel":"Annulé :","lcCancelledDesc":"Toutes les écritures sont inversées. Le document est archivé définitivement.","lcNoDelete":"Il n'y a pas de suppression. Pour annuler un brouillon : validez-le, puis annulez-le.","lcCorrect":"Pour corriger un document validé : annulez-le et créez-en un nouveau.","readyTitle":"Vous êtes prêt","readyBody1":"Vous comprenez maintenant le cycle complet. Un scénario réel typique ressemble à ceci : vous recevez une commande client (Devis → Commande client), vérifiez le stock, achetez ce dont vous avez besoin (Bon de commande → Bon de réception → Facture d'achat → Paiement), livrez au client (Bon de livraison), facturez-le (Facture de vente) et encaissez le paiement (Paiement). Si quelque chose revient, créez un avoir et un retour de bon de livraison pour inverser les finances et le stock. La Balance comptable confirme que tout est équilibré.","readyBody2":"Vous pouvez aussi tout faire via le chat IA en conversation naturelle – décrivez simplement ce dont vous avez besoin et il créera les bons documents pour vous.","chips":{"Quotation":"Devis","Sales Order":"Commande client","Delivery Note":"Bon de livraison","Sales Invoice":"Facture de vente","Payment Entry":"Paiement","Purchase Order":"Bon de commande","Purchase Receipt":"Bon de réception","Purchase Invoice":"Facture d'achat","Credit Note":"Avoir","DN Return":"Retour BL","Debit Note":"Note de débit","Draft":"Brouillon","Submitted":"Validé","Cancelled":"Annulé"},"links":{"Go to Setup":"Aller à la configuration","Customers":"Clients","Suppliers":"Fournisseurs","Items":"Articles","Warehouses":"Entrepôts","New Quotation":"Nouveau devis","View Quotations":"Voir les devis","Stock Balance":"Solde de stock","New Purchase Order":"Nouveau bon de commande","Purchase Receipts":"Bons de réception","Purchase Invoices":"Factures d'achat","Delivery Notes":"Bons de livraison","Sales Invoices":"Factures de vente","New Payment Entry":"Nouveau paiement","New Stock Entry":"Nouveau mouvement de stock","New Journal Entry":"Nouvelle écriture de journal","Profit & Loss":"Compte de résultat","Balance Sheet":"Bilan","AR Aging":"Balance âgée clients","AP Aging":"Balance âgée fournisseurs","Trial Balance":"Balance comptable","General Ledger":"Grand livre","Open AI Chat":"Ouvrir le chat IA"},"steps":{"1":{"title":"Configurer votre société","description":"Créez une société avec une devise de base. Cela génère votre plan comptable (30 comptes standard répartis entre Actif, Passif, Capitaux propres, Produits et Charges) ainsi qu'un centre de coûts par défaut. Vous pouvez aussi charger des données de démonstration avec des clients, fournisseurs et articles d'exemple pour démarrer rapidement."},"2":{"title":"Créer les données de base","description":"Avant de pouvoir effectuer des transactions, vous avez besoin de fiches de base. Créez au moins un client, un fournisseur, un article (avec un prix standard) et un entrepôt. Si vous avez chargé les données de démonstration à l'étape 1, elles existent déjà.","tip":"Les articles ont un prix standard qui se remplit automatiquement lorsque vous les ajoutez à des documents. Vous pouvez toujours modifier le prix par transaction."},"3":{"title":"Créer un devis","description":"Un devis est une offre non contraignante adressée à un client. Sélectionnez un client, ajoutez des lignes avec quantités et prix, éventuellement des lignes de taxe, puis enregistrez. Les devis n'ont aucun impact financier – ils ne créent ni écritures comptables ni mouvements de stock. Définissez une date de validité pour que l'offre expire automatiquement."},"4":{"title":"Valider et convertir en commande client","description":"Ouvrez votre devis enregistré et cliquez sur Valider pour le confirmer. Cliquez ensuite sur « Créer une commande client » pour le convertir. La commande client représente un engagement confirmé du client. Elle n'a toujours aucun impact financier, mais réserve du stock à des fins de planification.","tip":"Seuls les documents validés peuvent être convertis à l'étape suivante. Brouillon → Valider → Convertir est le flux standard. Pour les affaires rapides, vous pouvez ignorer la commande client et passer directement du devis à la facture de vente ou au bon de livraison."},"5":{"title":"Vérifier le stock avant l'exécution","description":"Avant de pouvoir livrer, vérifiez si vous avez réellement l'article en stock. Ouvrez le rapport Solde de stock et recherchez l'article. Si votre entrepôt affiche une quantité nulle, vous devrez d'abord approvisionner le stock – soit par un bon de commande (achat auprès d'un fournisseur), soit par un mouvement de stock (réception manuelle).","tip":"C'est un scénario courant dans la pratique : vous vendez quelque chose, puis réalisez que vous devez d'abord l'acheter. L'ERP gère les deux flux."},"6":{"title":"Cycle d'achat : acheter du stock à un fournisseur","description":"Si vous devez acheter du stock, vous avez deux chemins valides. Le chemin standard est Bon de commande → Bon de réception → Facture d'achat : utilisez-le lorsque les marchandises arrivent avant ou séparément de la facture du fournisseur. Si la facture et la réception arrivent ensemble, vous pouvez créer directement la facture d'achat et activer « Mettre à jour le stock » afin que le même document réceptionne le stock et enregistre la dette fournisseur.","tip":"Utilisez d'abord le bon de réception lorsque vous recevez les marchandises séparément. Utilisez la facture d'achat avec « Mettre à jour le stock » lorsqu'une seule étape doit à la fois réceptionner le stock et comptabiliser la facture fournisseur. Dans ce chemin direct, indiquez un entrepôt sur chaque ligne d'article en stock."},"7":{"title":"Créer un bon de livraison","description":"Maintenant que vous avez du stock, revenez à votre commande client validée et cliquez sur « Créer un bon de livraison ». Indiquez l'entrepôt sur chaque ligne d'article (d'où partent les marchandises), puis validez. Cela sort le stock de l'entrepôt – votre solde de stock diminue.","tip":"Le bon de livraison est le document d'expédition. Il réduit le stock mais ne crée pas de facture. Vous pouvez livrer et facturer séparément."},"8":{"title":"Créer et valider la facture de vente","description":"À partir de la commande client validée, créez une facture de vente. Lorsque vous validez la facture, des écritures comptables sont générées : les Clients (créances) sont débités (le client vous doit de l'argent) et les Produits des ventes crédités (revenu acquis). Si des taxes sont configurées, la TVA collectée est également créditée. Le montant dû indique ce que le client doit encore."},"9":{"title":"Enregistrer les paiements clients","description":"Créez un paiement pour enregistrer l'argent reçu du client. Définissez le type de paiement sur « Receive » (Recevoir), sélectionnez le client, indiquez le montant et affectez-le à la facture de vente. Vous pouvez effectuer des paiements partiels – le montant dû de la facture se met à jour en conséquence. Créez des paiements supplémentaires jusqu'à ce que la facture soit entièrement réglée.","tip":"Les paiements partiels sont courants. Une facture de 10 000 peut être payée 3 000 maintenant et 7 000 plus tard. Chaque paiement réduit le montant dû."},"10":{"title":"Mouvements de stock (inventaire manuel)","description":"Utilisez les mouvements de stock pour les mouvements d'inventaire non liés aux achats ou aux ventes. « Material Receipt » ajoute du stock (soldes d'ouverture, ajustements). « Material Issue » sort du stock (pertes, consommation interne). « Material Transfer » déplace du stock entre entrepôts. Chaque mouvement met à jour le livre de stock avec une valorisation au coût moyen pondéré.","tip":"Pour les marchandises achetées, utilisez des bons de réception plutôt que des mouvements de stock – ils sont liés au bon de commande et offrent une piste d'audit appropriée."},"11":{"title":"Écritures de journal","description":"Les écritures de journal sont des ajustements comptables manuels – charges à payer, corrections, reclassements, soldes d'ouverture. Chaque écriture doit avoir des débits et crédits équilibrés (total débit = total crédit). Utilisez-les lorsqu'aucun autre type de document ne convient."},"12":{"title":"Paiements des salaires","description":"Lambda ERP gère les salaires à l'aide des outils comptables existants. Comptabilisez d'abord la charge salariale : créez une écriture de journal qui débite la Charge salariale et crédite les Salaires à payer pour le montant total de la paie. Payez ensuite les employés : créez une autre écriture de journal (ou un paiement) qui débite les Salaires à payer et crédite votre compte bancaire. Ce processus en deux étapes garde vos comptes exacts – la charge est enregistrée dans la bonne période et la sortie de trésorerie est suivie séparément.","tip":"Vous pouvez demander à l'assistant IA de le faire pour vous : « Comptabilise 15 000 de salaires pour avril » suivi de « Paie les salaires d'avril depuis la banque ». Il créera automatiquement les bonnes écritures de journal."},"13":{"title":"Retours et avoirs","description":"Lorsqu'un client retourne des marchandises ou que vous devez émettre un avoir, créez un retour. Les retours utilisent le même type de document avec des quantités négatives. Ouvrez une facture de vente validée et créez un avoir (retour de facture de vente) – cela inverse les écritures comptables et réduit le montant dû de la facture d'origine. Pour le stock, créez un retour de bon de livraison pour réintégrer les marchandises en entrepôt. Côté achats, créez une note de débit (retour de facture d'achat) pour inverser une facture fournisseur, ou un retour de bon de réception pour renvoyer des marchandises.","tip":"Un avoir est simplement une facture de vente avec is_return=1 et des quantités négatives. La même logique comptable s'applique – les montants négatifs basculent automatiquement du bon côté débit/crédit. Pour un retour de vente complet, vous avez besoin à la fois d'un avoir (financier) et d'un retour de bon de livraison (stock)."},"14":{"title":"Exécuter les rapports","description":"Vérifiez vos comptes. Le Compte de résultat montre les produits face aux charges et le résultat net d'une période. Le Bilan montre votre situation financière (actif = passif + capitaux propres). La Balance âgée clients montre qui vous doit de l'argent et le retard. La Balance âgée fournisseurs montre ce que vous devez aux fournisseurs. La Balance comptable vérifie l'intégrité de la partie double. Le Grand livre montre chaque écriture individuelle. Le Solde de stock montre l'inventaire actuel."},"15":{"title":"Travailler en devises étrangères","description":"Vos comptes sont tenus dans une seule devise de base (choisie à la configuration de la société), mais vous pouvez effectuer des transactions dans n'importe quelle devise. Définissez une devise sur une facture ou un effet – ou attribuez une devise par défaut à un client ou un fournisseur – et le taux de change de cette date est recherché automatiquement et enregistré sur le document. Le document conserve ses montants dans sa propre devise, tandis que le Grand livre comptabilise toujours dans votre devise de base. Lorsque vous encaissez ou payez ultérieurement à un taux différent, le gain ou la perte de change réalisé est comptabilisé automatiquement sur un compte Gain/Perte de change. Vous pouvez même détenir un solde bancaire en devise étrangère et le convertir plus tard au taux de votre banque – l'écart par rapport à sa valeur comptable est alors réalisé. En fin de mois, vous pouvez réévaluer les soldes en devises ouverts au taux de clôture (un gain/perte latent qui s'inverse à la période suivante), et vous pouvez consulter n'importe quel état financier converti dans une autre devise pour l'affichage.","tip":"Le plus simple est de passer par le chat IA – essayez « Crée une facture de vente pour Lumiere Audio en EUR », « Montre-moi le bilan en EUR » ou « Quelle est notre exposition de change latente en fin de mois ? ». Les données de démonstration incluent déjà un client EUR (Lumiere Audio SARL) dont la facture a été encaissée à un taux différent, ainsi qu'une facture fournisseur EUR ouverte – ouvrez le Grand livre pour voir les écritures de change réalisées."}},"setupTitle":"Configurez votre entreprise — guidé par l'IA","setupBadge":"Commencez ici","setupBody":"Dites à l'assistant quel type d'entreprise vous dirigez, et il construit votre plan comptable pour vous — adapté à votre secteur, avec les bons comptes et des valeurs par défaut cohérentes déjà en place. Il explique chaque décision et ne crée quoi que ce soit qu'après votre approbation.","setupSectors":"Adapté aux services, au commerce de détail & POS, à l'hôtellerie-restauration, au commerce de gros & distribution, à l'import/export, à la fabrication et à la construction.","setupGetStarted":"Commencer dans le chat","setupManual":"Vous préférez un formulaire manuel ? Utilisez la configuration classique.","setupManualLink":"Configuration classique","setupPrompt":"Je souhaite configurer mon entreprise. Pouvez-vous me guider ?"}`), Ql = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, Yl = { period: "Période", allTime: "Toute la période", semantics: "Comptes de bilan : solde à la fin de la période. Comptes de résultat : mouvement de la période. Cliquez sur un compte pour son grand livre.", empty: "Aucun compte trouvé. Terminez d'abord la configuration de l'entreprise.", disabled: "désactivé", rootType: { Asset: "Actifs", Liability: "Passifs", Equity: "Capitaux propres", Income: "Produits", Expense: "Charges" } }, Jl = { fleetCalendar: "Calendrier de flotte", yard: "Dépôt", machineType: "Type de machine", prev: "Préc.", today: "Aujourd'hui", next: "Suiv.", weeks: "semaines", newBooking: "Nouvelle réservation", reserved: "Réservé", onHire: "En location", machine: "Machine", loadError: "Impossible de charger le calendrier de flotte.", noAssets: "Aucun équipement à afficher. Ajoutez des machines sous Locations → Flotte.", pooledNote: "{{count}} réservation(s) en attente d’attribution", unassigned: "Pool — non attribué", poolWarning: "La capacité est réservée. Aucune machine précise n’est encore attribuée ; attribuez une machine avant la sortie." }, Zl = { Unit: "Machine spécifique", Pool: "Pool – machine à affecter", Available: "Disponible", "On Hire": "En location", Out: "Sorti", Maintenance: "Maintenance", Retired: "Retiré", Reserved: "Réservé", Returned: "Retourné", Cancelled: "Annulé", Customer: "Client", Supplier: "Fournisseur" }, Xl = { asset: { item_code: "L'article est le TYPE de machine et porte le tarif ; un équipement en est une unité physique. L'article doit avoir is_asset_tracked = 1.", asset_tag: "Plaque ou numéro de série — doit être unique sur tous les équipements.", status: "État actuel de l'unité (pas une période). Les unités retirées quittent le pool.", meter_reading: "Heures de fonctionnement / km." }, reservation: { item_code: "Réservation de pool ('une pelle de 1,7 t') : renseigner Article + Dépôt + Qté. Pour une machine précise, renseigner Équipement.", asset: "Réserver une machine précise. Une réservation d'unité consomme aussi une place du pool Article+Dépôt.", from_datetime: "Début exact — date et heure (p. ex. 14:27). Une date seule signifie 00:00.", to_datetime: "Fin exacte. Les fenêtres sont semi-ouvertes [de, à) : une location finissant à 09:00 et la suivante commençant à 09:00 ne se chevauchent PAS." } }, ec = {
|
|
9190
|
-
|
|
9191
|
-
common: _l,
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9179
|
+
const wo = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, Co = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", cancelBooking: "Cancel booking", cancelBookingConfirm: "Yes, cancel booking", keepBooking: "Keep booking", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", showDisabled: "Show disabled", columns: "Columns", searchPlaceholder: "Search…", noRecords: "No records found", active: "Active", disabled: "Disabled", sortByColumn: "Sort by this column", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, So = { today: "Today", thisWeek: "This Week", thisMonth: "This Month", thisQuarter: "This Quarter", thisYear: "This Year", lastMonth: "Last Month", lastQuarter: "Last Quarter", lastYear: "Last Year", endOfThisMonth: "End of This Month", endOfLastMonth: "End of Last Month", endOfThisQuarter: "End of This Quarter", endOfThisYear: "End of This Year", endOfLastYear: "End of Last Year" }, Ao = { title: "Bank statement import", subtitle: "Preview and import ISO 20022 CAMT statements without posting to the ledger.", selectFiles: "CAMT files", chooseFiles: "Choose XML or ZIP files", dropFiles: "Drop XML or ZIP files here", unsupportedFiles: "Only CAMT XML or ZIP files are supported: {{files}}", fileHint: "camt.053.001.04 and camt.053.001.08 · multiple files supported", preview: "Show preview", noPosting: "Previewing and importing do not post accounting entries.", alreadyImported: "Already imported", period: "Period", openingBalance: "Opening balance", closingBalance: "Closing balance", entries: "Entries", credits: "Credits", debits: "Debits", details: "Transaction details", batches: "batches", qrReferences: "QR references", mapping: "Bank account mapping", selectBankAccount: "Select a Bank Account…", noBankAccounts: "No Bank Account has been configured yet.", createBankAccount: "Create Bank Account", mappingRequired: "Map every new statement to a Bank Account before importing.", import: "Import bank statements", importComplete: "Import completed", importCounts: "{{imported}} entries imported, {{duplicates}} duplicates skipped", history: "Recent imports", importId: "Import", bankAccount: "Bank account", source: "Source file", openReconciliation: "Open bank reconciliation" }, _o = { title: "Bank reconciliation", subtitle: "Match imported bank transactions to posted vouchers, open invoices, or ledger accounts.", status: "Status", unreconciled: "Unreconciled", reconciled: "Reconciled", transactions: "Bank transactions", empty: "No bank transactions in this view.", remittance: "Remittance information", reference: "Reference", openTransaction: "Open bank transaction", conversionRate: "Exchange rate (1 {{currency}} in {{base}})", conversionRateHint: "Required when no exchange rate exists for the transaction date.", existingVouchers: "Existing accounting entries", existingVouchersHint: "These submitted vouchers contain an exact movement on this bank account. Matching does not post them again.", match: "Match", openInvoices: "Open invoices", openInvoicesHint: "Select one or more invoices belonging to the same party. Confirmation creates and submits a Payment Entry.", outstanding: "Outstanding", allocation: "Allocation", noInvoiceSuggestions: "No plausible open invoice was found.", allocated: "Allocated {{amount}} of {{total}}", createPayment: "Create payment and reconcile", directPosting: "Post to a ledger account", directPostingHint: "For fees, interest and other non-invoice movements. Receivable, payable, bank and cash control accounts are intentionally excluded.", counterpartyAccount: "Counter account", remarks: "Remarks", createJournal: "Create journal entry and reconcile", activeMatch: "Active reconciliation", undo: "Undo reconciliation", confirmExistingTitle: "Match existing entry?", confirmExistingBody: "Match {{transaction}} to {{voucher}}? No new ledger entry will be posted.", confirmGroupBody: "Match all {{count}} transactions totalling {{amount}} to {{voucher}}? No new ledger entry will be posted.", groupedTransactions: "{{count}} grouped transactions", confirmPaymentTitle: "Post payment and reconcile?", confirmPaymentBody: "This submits a payment of {{amount}} for {{transaction}} and allocates it across {{count}} invoice(s).", onAccountWarning: "{{amount}} will remain as an on-account payment for this party.", confirmJournalTitle: "Post journal entry and reconcile?", confirmJournalBody: "This posts {{amount}} for {{transaction}} against {{account}}.", postAndReconcile: "Post and reconcile", undoTitle: "Undo reconciliation?", undoCreatedBody: "The voucher created by this reconciliation will be cancelled, its ledger entries reversed, and invoice allocations restored.", undoExistingBody: "The existing voucher will only be unlinked. It remains submitted and its ledger entries are not changed.", undoExistingGroupBody: "All {{count}} grouped transactions ({{transactions}}) will be unlinked together. The existing voucher remains submitted and its ledger entries are not changed.", reconciledNotice: "Bank transaction reconciled.", groupReconciledNotice: "{{count}} bank transactions reconciled as one group.", undoneNotice: "Reconciliation reversed." }, Do = { placeholder: "Search or enter field:value…", search: "Search", addFilter: "+ Filter", availableFields: "Available fields", fieldHelp: "Choose a field or type its technical name followed by a colon.", field: "Field", valueFor: "Value for {{label}}", allFields: "All fields", typeForValues: "Start typing to find values in this field.", noValues: "No matching values found.", noFields: "No matching fields found.", useValue: "Use “{{value}}”", removeFilter: "Remove {{label}} filter", types: { text: "Text", textarea: "Long text", select: "Selection", link: "Linked record", date: "Date", datetime: "Date and time", number: "Number", currency: "Amount" } }, Po = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, To = { back: "Back", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Ro = { dashboard: "Dashboard", setup: "Company Setup", tutorial: "Getting Started", chat: "Chat", reports: "Reports", "trial-balance": "Trial Balance", "general-ledger": "General Ledger", "stock-balance": "Stock Balance", "profit-and-loss": "Profit & Loss", "balance-sheet": "Balance Sheet", "ar-aging": "Accounts Receivable Aging", "ap-aging": "Accounts Payable Aging", analytics: "Analytics", "chart-of-accounts": "Chart of Accounts" }, Bo = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, "bank-account": { one: "Bank Account", other: "Bank Accounts" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, Io = { company: { one: "Company", other: "Companies" }, customer: { one: "Customer", other: "Customers" }, supplier: { one: "Supplier", other: "Suppliers" }, item: { one: "Item", other: "Items" }, warehouse: { one: "Warehouse", other: "Warehouses" } }, Eo = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings", Rentals: "Rentals" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", "Bank Account": "Bank Accounts", "Bank Statement Import": "Bank Statement Import", "Bank Reconciliation": "Bank Reconciliation", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts", "Fleet Calendar": "Fleet Calendar", "Fleet (Assets)": "Fleet (Assets)", Reservations: "Reservations" } }, Lo = { taglineFirstRun: "Create your admin account to get started", taglineRegister: "Create your account", taglineSignIn: "Sign in to your account", demoBanner: "Demo mode is active. Sign in with an admin account to manage settings or disable public access.", fullName: "Full Name", email: "Email", password: "Password", confirmPassword: "Confirm Password", createAdmin: "Create Admin Account", register: "Register", signIn: "Sign In", browsingTitle: "Just browsing?", browsingBody: "Start a fresh chat session and watch the live demo.", enterDemo: "Enter Live Demo", haveInvite: "Have an invite?", noAccountPrompt: "Need an account?", registerLink: "Register", alreadyHaveAccount: "Already have an account?", signInLink: "Sign in", passwordsNoMatch: "Passwords do not match", passwordTooShort: "Password must be at least 6 characters", registrationFailed: "Registration failed", loginFailed: "Login failed", orContinueWith: "or continue with", continueWithProvider: "Continue with {{provider}}", oauthError: { generic: "Sign-in failed. Please try again.", email_exists: "An account with this email already exists. Sign in, then link this provider from your account settings.", email_unverified: "Your provider did not confirm a verified email, so we can't sign you in.", registration_closed: "This email has no account yet and registration is invite-only.", invite_invalid: "That invite is invalid, already used, or issued for a different email.", identity_taken: "That provider account is already linked to a different user.", account_disabled: "This account has been disabled.", token_exchange_failed: "Sign-in failed while contacting the provider. Please try again." } }, Oo = { pdfTitle: "PDF & Print", pageSize: "Page Size", pdfHelp: "A4 is standard internationally (210 x 297 mm). Letter is standard in the US (8.5 x 11 in).", passwordTitle: "Change Password", currentPassword: "Current password", newPassword: "New password", confirmNewPassword: "Confirm new password", changePassword: "Change password", changingPassword: "Changing...", passwordChanged: "Password changed.", setPasswordTitle: "Set a Password", setPasswordBody: "Your account signs in with Google. Set a password to also sign in with email and password — a handy fallback if you ever lose access to your Google account.", setPassword: "Set password", passwordSet: "Password set.", linkedAccountsTitle: "Linked Accounts", linkedAccountsBody: "Link a Google or Apple account to sign in without a password.", linked: "Linked", linkProvider: "Link {{provider}}", openingTitle: "Opening Balances", openingBody: "The Opening Balances page allows importing account balances, stock, and outstanding invoices from a previous system.", openingEnabled: "Currently enabled — accessible under Introduction > Opening Balances.", openingDisabled: "Currently disabled — the page is hidden from the sidebar.", signupTitle: "Public Signup", signupBody: "Allow anyone to create their own account (as a viewer) without an invite. When off, new users can only join via an invite link.", signupEnabled: "Currently enabled — anyone with the URL can register as a viewer.", signupDisabled: "Currently disabled — registration is invite-only.", chatApiTitle: "Chat API", apiTitle: "Programmatic API", restApiBody: "Let connectors and scripts drive this ERP over its REST API (documents, masters, reports) with the same Bearer API keys. Off by default.", restApiEnabled: "Currently enabled — issued keys can call /api/documents, /api/masters, and the rest of the REST API.", restApiDisabled: "Currently disabled — the REST API only accepts the session cookie; keys are rejected.", restApiDeactivateTitle: "Deactivate the REST API?", restApiDeactivateBody: "Bearer-key access to the REST API will be switched off — connectors and scripts are rejected until you turn it back on. The web app (session cookie) is unaffected, and your API keys are NOT deleted: they start working again the instant you re-enable the API.", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API.", version: "Version {{version}}" }, Fo = { Draft: "Draft", Open: "Open", Submitted: "Submitted", "To Deliver and Bill": "To Deliver and Bill", "To Deliver": "To Deliver", "To Bill": "To Bill", Completed: "Completed", Ordered: "Ordered", Paid: "Paid", Unpaid: "Unpaid", Cancelled: "Cancelled", Discarded: "Discarded", Overdue: "Overdue", Return: "Return", Closed: "Closed" }, Mo = { periodRange: "Reporting period: {{from}} – {{to}}", periodFrom: "Reporting period from {{from}}", periodThrough: "Reporting period through {{to}}", asOfDate: "As of: {{date}}", balanced: "BALANCED", imbalanced: "IMBALANCED", income: "Income", expenses: "Expenses", totalIncome: "Total Income", totalExpenses: "Total Expenses", netProfit: "Net Profit", netLoss: "Net Loss", assets: "Assets", liabilities: "Liabilities", equity: "Equity", totalAssets: "Total Assets", totalLiabilities: "Total Liabilities", totalEquity: "Total Equity", totalLiabilitiesEquity: "Total Liabilities + Equity", current: "Current", noData: "No data found", noEntries: "No entries found", noStockData: "No stock data found", noReceivables: "No outstanding receivables", noPayables: "No outstanding payables", noDocuments: "No documents found" }, qo = { required: "Required: {{fields}}", deleteConfirm: "Delete this {{label}}?", disabledNotice: "This {{label}} is disabled. It remains in the system because other records still reference it.", disabledOnDelete: "{{label}} {{name}} was disabled instead of deleted because it is referenced by {{reason}}." }, zo = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, $o = { title: "Lambda ERP Chat", subtitle: "Ask me to create documents, look up data, or run reports.", s1: "What customers do we have?", s2: "Show me the trial balance", s3: "Create a quotation for 10 Bolt Pack M8", s4: "List all unpaid invoices", loadOlder: "Load older messages", uploading: "Uploading...", failed: "Failed", remove: "Remove", placeholderDemo: "Running live demo...", placeholderType: "Type a message...", placeholderConnecting: "Connecting...", attachTitle: "Attach file (PDF or image, max 10 MB)", creating: "Creating chat...", dropToAttach: "Drop file to attach (images or PDF, max 10 MB each)", demoError: "Could not start demo", voiceStart: "Record voice message", voiceStop: "Stop recording", voiceTranscribing: "Transcribing...", micDenied: "Microphone access was denied.", transcribeFailed: "Transcription failed. Please try again." }, Vo = { "Create Credit Note": "Create Credit Note", "Create Debit Note": "Create Debit Note", "Create Delivery Note": "Create Delivery Note", "Create Purchase Invoice": "Create Purchase Invoice", "Create Purchase Receipt": "Create Purchase Receipt", "Create Return": "Create Return", "Create Sales Invoice": "Create Sales Invoice", "Create Sales Order": "Create Sales Order" }, Uo = { "Last modified": "Last modified", Created: "Created", "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code", "Item (type)": "Item (type)", "Asset Tag / Plate": "Asset Tag / Plate", "Home Yard": "Home Yard", "Purchase Value": "Purchase Value", "Meter Reading": "Meter Reading", "Meter Unit": "Meter Unit", Yard: "Yard", "Asset (specific unit)": "Asset (specific unit)", Allocation: "Allocation", From: "From", To: "To", Purpose: "Purpose", "Purchase Date": "Purchase Date", Notes: "Notes" }, Ko = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, jo = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a report-specialist model that creates a validated declarative report over your ERP data and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), Wo = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, Go = { period: "Period", allTime: "All time", semantics: "Balance-sheet accounts: closing balance at period end. P&L accounts: movement within the period. Click an account for its ledger.", empty: "No accounts found. Complete the company setup first.", disabled: "disabled", rootType: { Asset: "Assets", Liability: "Liabilities", Equity: "Equity", Income: "Income", Expense: "Expenses" } }, Ho = { fleetCalendar: "Fleet Calendar", yard: "Yard", machineType: "Machine type", prev: "Prev", today: "Today", next: "Next", weeks: "weeks", newBooking: "New booking", reserved: "Reserved", onHire: "On Hire", machine: "Machine", loadError: "Could not load the fleet calendar.", noAssets: "No assets to show. Add machines under Rentals → Fleet.", pooledNote: "{{count}} pool booking(s) awaiting assignment", unassigned: "Pool — unassigned", poolWarning: "Pool capacity is reserved. No specific machine has been assigned yet; assign a machine before dispatch." }, Qo = { Unit: "Specific machine", Pool: "Pool – assign machine later", Available: "Available", "On Hire": "On Hire", Out: "Out", Maintenance: "Maintenance", Retired: "Retired", Reserved: "Reserved", Returned: "Returned", Cancelled: "Cancelled", Customer: "Customer", Supplier: "Supplier" }, Yo = { asset: { item_code: "The Item is the machine TYPE and carries the rate; an Asset is one physical unit of it. The Item must have is_asset_tracked = 1.", asset_tag: "Plate or serial — must be unique across assets.", status: "The unit's state today (not a date range). Retired units leave the pool.", meter_reading: "Operating hours / km." }, reservation: { item_code: "Pooled booking ('a 1.7t excavator'): set Item + Yard + Qty. For a specific machine, set Asset instead.", asset: "Book one specific machine. A unit booking also consumes a slot of its Item+Yard pool.", from_datetime: "Exact start — date and time (e.g. 14:27). A bare date means 00:00.", to_datetime: "Exact end. Windows are half-open [from, to): a hire ending 09:00 and the next starting 09:00 do NOT clash." } }, Jo = { label: "Default sales tax", none: "No automatic tax application", hint: "Applied to new quotations, orders and invoices when taxes are not explicitly provided. Existing documents remain unchanged. Use Save to apply.", saveFirst: "Save the company first, then select one of its sales tax templates.", loadError: "Tax templates could not be loaded. The saved selection is preserved.", retry: "Try again", unavailable: "The saved template is not available as a sales tax template for this company. Please check the selection.", empty: "This company has no sales tax templates yet." }, Zo = {
|
|
9180
|
+
proposal: wo,
|
|
9181
|
+
common: Co,
|
|
9182
|
+
datePresets: So,
|
|
9183
|
+
bankStatements: Ao,
|
|
9184
|
+
bankReconciliation: _o,
|
|
9185
|
+
smartSearch: Do,
|
|
9186
|
+
language: Po,
|
|
9187
|
+
header: To,
|
|
9188
|
+
titles: Ro,
|
|
9189
|
+
doctypes: Bo,
|
|
9190
|
+
masters: Io,
|
|
9191
|
+
nav: Eo,
|
|
9192
|
+
login: Lo,
|
|
9193
|
+
settings: Oo,
|
|
9194
|
+
status: Fo,
|
|
9195
|
+
reports: Mo,
|
|
9196
|
+
masterForm: qo,
|
|
9197
|
+
dashboard: zo,
|
|
9198
|
+
chat: $o,
|
|
9199
|
+
conversions: Vo,
|
|
9200
|
+
fields: Uo,
|
|
9201
|
+
tables: Ko,
|
|
9202
|
+
tutorial: jo,
|
|
9203
|
+
notesMarkup: Wo,
|
|
9204
|
+
coa: Go,
|
|
9205
|
+
rentals: Ho,
|
|
9206
|
+
fieldOptions: Qo,
|
|
9207
|
+
hints: Yo,
|
|
9208
|
+
companyTax: Jo
|
|
9209
|
+
}, Xo = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, el = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", cancelBooking: "Buchung stornieren", cancelBookingConfirm: "Ja, stornieren", keepBooking: "Behalten", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", showDisabled: "Deaktivierte anzeigen", columns: "Spalten", searchPlaceholder: "Suchen…", noRecords: "Keine Einträge gefunden", active: "Aktiv", disabled: "Deaktiviert", sortByColumn: "Nach dieser Spalte sortieren", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, tl = { today: "Heute", thisWeek: "Diese Woche", thisMonth: "Dieser Monat", thisQuarter: "Dieses Quartal", thisYear: "Dieses Jahr", lastMonth: "Letzter Monat", lastQuarter: "Letztes Quartal", lastYear: "Letztes Jahr", endOfThisMonth: "Ende dieses Monats", endOfLastMonth: "Ende des letzten Monats", endOfThisQuarter: "Ende dieses Quartals", endOfThisYear: "Ende dieses Jahres", endOfLastYear: "Ende des letzten Jahres" }, nl = { title: "Kontoauszug importieren", subtitle: "ISO-20022-CAMT-Kontoauszüge prüfen und ohne automatische Verbuchung importieren.", selectFiles: "CAMT-Dateien", chooseFiles: "XML- oder ZIP-Dateien auswählen", dropFiles: "XML- oder ZIP-Dateien hier ablegen", unsupportedFiles: "Es werden nur CAMT-XML- oder ZIP-Dateien unterstützt: {{files}}", fileHint: "camt.053.001.04 und camt.053.001.08 · mehrere Dateien möglich", preview: "Vorschau anzeigen", noPosting: "Vorschau und Import erzeugen keine Buchungssätze.", alreadyImported: "Bereits importiert", period: "Zeitraum", openingBalance: "Anfangssaldo", closingBalance: "Endsaldo", entries: "Buchungen", credits: "Gutschriften", debits: "Belastungen", details: "Transaktionsdetails", batches: "Sammelbuchungen", qrReferences: "QR-Referenzen", mapping: "Bankkonto-Zuordnung", selectBankAccount: "Bankkonto auswählen…", noBankAccounts: "Es wurde noch kein Bankkonto eingerichtet.", createBankAccount: "Bankkonto einrichten", mappingRequired: "Ordnen Sie vor dem Import jeden neuen Auszug einem Bankkonto zu.", import: "Kontoauszüge importieren", importComplete: "Import abgeschlossen", importCounts: "{{imported}} Buchungen importiert, {{duplicates}} Duplikate übersprungen", history: "Letzte Importe", importId: "Import", bankAccount: "Bankkonto", source: "Quelldatei", openReconciliation: "Bankabstimmung öffnen" }, al = { title: "Bankabstimmung", subtitle: "Importierte Banktransaktionen mit Buchungen, offenen Rechnungen oder Sachkonten abstimmen.", status: "Status", unreconciled: "Nicht abgestimmt", reconciled: "Abgestimmt", transactions: "Banktransaktionen", empty: "In dieser Ansicht sind keine Banktransaktionen vorhanden.", remittance: "Zahlungsinformation", reference: "Referenz", openTransaction: "Banktransaktion öffnen", conversionRate: "Wechselkurs (1 {{currency}} in {{base}})", conversionRateHint: "Erforderlich, wenn für das Transaktionsdatum kein Wechselkurs hinterlegt ist.", existingVouchers: "Bestehende Buchungen", existingVouchersHint: "Diese eingereichten Belege enthalten eine exakt passende Bewegung auf diesem Bankkonto. Bei der Zuordnung wird nichts erneut gebucht.", match: "Zuordnen", openInvoices: "Offene Rechnungen", openInvoicesHint: "Wähle eine oder mehrere Rechnungen derselben Partei. Nach der Bestätigung wird eine Zahlung erstellt und eingereicht.", outstanding: "Offen", allocation: "Zuweisung", noInvoiceSuggestions: "Es wurde keine plausible offene Rechnung gefunden.", allocated: "{{amount}} von {{total}} zugewiesen", createPayment: "Zahlung erstellen und abstimmen", directPosting: "Auf ein Sachkonto buchen", directPostingHint: "Für Gebühren, Zinsen und andere Bewegungen ohne Rechnung. Debitoren-, Kreditoren-, Bank- und Kassenkonten sind bewusst ausgeschlossen.", counterpartyAccount: "Gegenkonto", remarks: "Bemerkung", createJournal: "Buchungssatz erstellen und abstimmen", activeMatch: "Aktive Abstimmung", undo: "Abstimmung rückgängig machen", confirmExistingTitle: "Bestehende Buchung zuordnen?", confirmExistingBody: "{{transaction}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", confirmGroupBody: "Alle {{count}} Transaktionen über insgesamt {{amount}} mit {{voucher}} abstimmen? Es wird kein neuer Buchungssatz erzeugt.", groupedTransactions: "{{count}} gruppierte Transaktionen", confirmPaymentTitle: "Zahlung buchen und abstimmen?", confirmPaymentBody: "Damit wird für {{transaction}} eine Zahlung über {{amount}} eingereicht und auf {{count}} Rechnung(en) verteilt.", onAccountWarning: "{{amount}} bleibt als nicht zugewiesene Zahlung bei dieser Partei bestehen.", confirmJournalTitle: "Buchungssatz erstellen und abstimmen?", confirmJournalBody: "Damit werden {{amount}} für {{transaction}} gegen {{account}} gebucht.", postAndReconcile: "Buchen und abstimmen", undoTitle: "Abstimmung rückgängig machen?", undoCreatedBody: "Der durch diese Abstimmung erstellte Beleg wird storniert, seine Hauptbuchungen werden umgekehrt und Rechnungszuweisungen wiederhergestellt.", undoExistingBody: "Der bestehende Beleg wird nur von der Banktransaktion getrennt. Er bleibt eingereicht und seine Buchungen werden nicht verändert.", undoExistingGroupBody: "Alle {{count}} gruppierten Banktransaktionen ({{transactions}}) werden gemeinsam vom Beleg getrennt. Der bestehende Beleg bleibt eingereicht und seine Buchungen werden nicht verändert.", reconciledNotice: "Banktransaktion wurde abgestimmt.", groupReconciledNotice: "{{count}} Banktransaktionen wurden als Gruppe abgestimmt.", undoneNotice: "Abstimmung wurde rückgängig gemacht." }, rl = { placeholder: "Suchen oder Feld:Wert eingeben…", search: "Suchen", addFilter: "+ Filter", availableFields: "Verfügbare Felder", fieldHelp: "Feld auswählen oder den technischen Namen mit Doppelpunkt eingeben.", field: "Feld", valueFor: "Wert für {{label}}", allFields: "Alle Felder", typeForValues: "Tippen, um Werte in diesem Feld zu finden.", noValues: "Keine passenden Werte gefunden.", noFields: "Keine passenden Felder gefunden.", useValue: "„{{value}}“ verwenden", removeFilter: "Filter {{label}} entfernen", types: { text: "Text", textarea: "Langtext", select: "Auswahl", link: "Verknüpfter Eintrag", date: "Datum", datetime: "Datum und Uhrzeit", number: "Zahl", currency: "Betrag" } }, sl = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, il = { back: "Zurück", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, ol = { dashboard: "Dashboard", setup: "Unternehmenseinrichtung", tutorial: "Erste Schritte", chat: "Chat", reports: "Berichte", "trial-balance": "Rohbilanz", "general-ledger": "Hauptbuch", "stock-balance": "Lagerbestand", "profit-and-loss": "Gewinn- und Verlustrechnung", "balance-sheet": "Bilanz", "ar-aging": "Offene Posten Debitoren", "ap-aging": "Offene Posten Kreditoren", analytics: "Analysen", "chart-of-accounts": "Kontenplan" }, ll = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, "bank-account": { one: "Bankkonto", other: "Bankkonten" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, cl = { company: { one: "Unternehmen", other: "Unternehmen" }, customer: { one: "Kunde", other: "Kunden" }, supplier: { one: "Lieferant", other: "Lieferanten" }, item: { one: "Artikel", other: "Artikel" }, warehouse: { one: "Lager", other: "Lager" } }, dl = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen", Rentals: "Vermietung" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", "Bank Account": "Bankkonten", "Bank Statement Import": "Kontoauszug importieren", "Bank Reconciliation": "Bankabstimmung", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan", "Fleet Calendar": "Flottenkalender", "Fleet (Assets)": "Flotte (Geräte)", Reservations: "Reservationen" } }, ul = { taglineFirstRun: "Erstellen Sie Ihr Administratorkonto, um zu beginnen", taglineRegister: "Erstellen Sie Ihr Konto", taglineSignIn: "Melden Sie sich bei Ihrem Konto an", demoBanner: "Der Demomodus ist aktiv. Melden Sie sich mit einem Administratorkonto an, um Einstellungen zu verwalten oder den öffentlichen Zugriff zu deaktivieren.", fullName: "Vollständiger Name", email: "E-Mail", password: "Passwort", confirmPassword: "Passwort bestätigen", createAdmin: "Administratorkonto erstellen", register: "Registrieren", signIn: "Anmelden", browsingTitle: "Nur am Stöbern?", browsingBody: "Starten Sie eine neue Chat-Sitzung und sehen Sie sich die Live-Demo an.", enterDemo: "Live-Demo starten", haveInvite: "Haben Sie eine Einladung?", noAccountPrompt: "Noch kein Konto?", registerLink: "Registrieren", alreadyHaveAccount: "Haben Sie bereits ein Konto?", signInLink: "Anmelden", passwordsNoMatch: "Passwörter stimmen nicht überein", passwordTooShort: "Das Passwort muss mindestens 6 Zeichen lang sein", registrationFailed: "Registrierung fehlgeschlagen", loginFailed: "Anmeldung fehlgeschlagen", orContinueWith: "oder weiter mit", continueWithProvider: "Weiter mit {{provider}}", oauthError: { generic: "Anmeldung fehlgeschlagen. Bitte erneut versuchen.", email_exists: "Ein Konto mit dieser E-Mail existiert bereits. Melden Sie sich an und verknüpfen Sie diesen Anbieter in den Kontoeinstellungen.", email_unverified: "Ihr Anbieter hat keine bestätigte E-Mail übermittelt, daher ist keine Anmeldung möglich.", registration_closed: "Für diese E-Mail besteht noch kein Konto und die Registrierung ist nur per Einladung möglich.", invite_invalid: "Diese Einladung ist ungültig, bereits verwendet oder für eine andere E-Mail ausgestellt.", identity_taken: "Dieses Anbieterkonto ist bereits mit einem anderen Benutzer verknüpft.", account_disabled: "Dieses Konto wurde deaktiviert.", token_exchange_failed: "Anmeldung beim Anbieter fehlgeschlagen. Bitte erneut versuchen." } }, ml = { pdfTitle: "PDF & Druck", pageSize: "Seitengröße", pdfHelp: "A4 ist international Standard (210 x 297 mm). Letter ist Standard in den USA (8,5 x 11 Zoll).", passwordTitle: "Passwort ändern", currentPassword: "Aktuelles Passwort", newPassword: "Neues Passwort", confirmNewPassword: "Neues Passwort bestätigen", changePassword: "Passwort ändern", changingPassword: "Wird geändert...", passwordChanged: "Passwort geändert.", setPasswordTitle: "Passwort festlegen", setPasswordBody: "Ihr Konto meldet sich mit Google an. Legen Sie ein Passwort fest, um sich auch mit E-Mail und Passwort anzumelden — ein praktischer Rückfall, falls Sie den Zugang zu Ihrem Google-Konto verlieren.", setPassword: "Passwort festlegen", passwordSet: "Passwort festgelegt.", linkedAccountsTitle: "Verknüpfte Konten", linkedAccountsBody: "Verknüpfen Sie ein Google- oder Apple-Konto, um sich ohne Passwort anzumelden.", linked: "Verknüpft", linkProvider: "{{provider}} verknüpfen", openingTitle: "Eröffnungsbilanzen", openingBody: "Auf der Seite Eröffnungsbilanzen können Kontensalden, Lagerbestände und offene Rechnungen aus einem früheren System importiert werden.", openingEnabled: "Derzeit aktiviert — erreichbar unter Einführung > Eröffnungsbilanzen.", openingDisabled: "Derzeit deaktiviert — die Seite ist in der Seitenleiste ausgeblendet.", signupTitle: "Öffentliche Registrierung", signupBody: "Erlauben Sie es jedem, ohne Einladung ein eigenes Konto (als Betrachter) zu erstellen. Wenn deaktiviert, können neue Benutzer nur über einen Einladungslink beitreten.", signupEnabled: "Derzeit aktiviert — jeder mit der URL kann sich als Betrachter registrieren.", signupDisabled: "Derzeit deaktiviert — die Registrierung erfolgt nur per Einladung.", chatApiTitle: "Chat-API", apiTitle: "Programmatische API", restApiBody: "Konnektoren und Skripten erlauben, dieses ERP über seine REST-API (Belege, Stammdaten, Berichte) mit denselben Bearer-API-Schlüsseln zu steuern. Standardmäßig deaktiviert.", restApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können /api/documents, /api/masters und die übrige REST-API aufrufen.", restApiDisabled: "Derzeit deaktiviert — die REST-API akzeptiert nur das Sitzungs-Cookie; Schlüssel werden abgewiesen.", restApiDeactivateTitle: "REST-API deaktivieren?", restApiDeactivateBody: "Der Bearer-Schlüssel-Zugriff auf die REST-API wird abgeschaltet — Konnektoren und Skripte werden abgewiesen, bis Sie ihn wieder einschalten. Die Web-App (Sitzungs-Cookie) ist nicht betroffen, und Ihre API-Schlüssel werden NICHT gelöscht: Sie funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat.", version: "Version {{version}}" }, pl = { Draft: "Entwurf", Open: "Offen", Submitted: "Gebucht", "To Deliver and Bill": "Zu liefern und abzurechnen", "To Deliver": "Zu liefern", "To Bill": "Abzurechnen", Completed: "Abgeschlossen", Ordered: "Bestellt", Paid: "Bezahlt", Unpaid: "Unbezahlt", Cancelled: "Storniert", Discarded: "Verworfen", Overdue: "Überfällig", Return: "Retoure", Closed: "Geschlossen" }, hl = { periodRange: "Berichtszeitraum: {{from}} – {{to}}", periodFrom: "Berichtszeitraum ab {{from}}", periodThrough: "Berichtszeitraum bis {{to}}", asOfDate: "Stichtag: {{date}}", balanced: "AUSGEGLICHEN", imbalanced: "NICHT AUSGEGLICHEN", income: "Erträge", expenses: "Aufwendungen", totalIncome: "Summe Erträge", totalExpenses: "Summe Aufwendungen", netProfit: "Gewinn", netLoss: "Verlust", assets: "Aktiva", liabilities: "Verbindlichkeiten", equity: "Eigenkapital", totalAssets: "Summe Aktiva", totalLiabilities: "Summe Verbindlichkeiten", totalEquity: "Summe Eigenkapital", totalLiabilitiesEquity: "Summe Verbindlichkeiten + Eigenkapital", current: "Laufend", noData: "Keine Daten gefunden", noEntries: "Keine Buchungen gefunden", noStockData: "Keine Lagerdaten gefunden", noReceivables: "Keine offenen Forderungen", noPayables: "Keine offenen Verbindlichkeiten", noDocuments: "Keine Dokumente gefunden" }, gl = { required: "Erforderlich: {{fields}}", deleteConfirm: "Diesen Datensatz löschen: {{label}}?", disabledNotice: "Dieser Datensatz ({{label}}) ist deaktiviert. Er verbleibt im System, weil andere Datensätze noch darauf verweisen.", disabledOnDelete: "{{label}} {{name}} wurde deaktiviert statt gelöscht, da er von {{reason}} referenziert wird." }, fl = { "Last modified": "Zuletzt geändert", Created: "Erstellt", Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname", "Item (type)": "Artikel (Typ)", "Asset Tag / Plate": "Kennung / Kennzeichen", "Home Yard": "Heimdepot", "Purchase Value": "Kaufwert", "Meter Reading": "Zählerstand", "Meter Unit": "Zählereinheit", Yard: "Depot", "Asset (specific unit)": "Gerät (bestimmte Einheit)", Allocation: "Zuweisung", From: "Von", To: "Bis", Purpose: "Zweck", "Purchase Date": "Kaufdatum", Notes: "Notizen" }, yl = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, bl = { "Create Sales Order": "Kundenauftrag erstellen", "Create Sales Invoice": "Ausgangsrechnung erstellen", "Create Delivery Note": "Lieferschein erstellen", "Create Purchase Invoice": "Eingangsrechnung erstellen", "Create Purchase Receipt": "Wareneingang erstellen", "Create Credit Note": "Gutschrift erstellen", "Create Debit Note": "Lastschrift erstellen", "Create Return": "Retoure erstellen" }, vl = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, xl = { title: "Lambda ERP Chat", subtitle: "Bitten Sie mich, Dokumente zu erstellen, Daten abzurufen oder Berichte auszuführen.", s1: "Welche Kunden haben wir?", s2: "Zeig mir die Rohbilanz", s3: "Erstelle ein Angebot für 10 Bolt Pack M8", s4: "Liste alle unbezahlten Rechnungen auf", loadOlder: "Ältere Nachrichten laden", uploading: "Wird hochgeladen...", failed: "Fehlgeschlagen", remove: "Entfernen", placeholderDemo: "Live-Demo läuft...", placeholderType: "Nachricht eingeben...", placeholderConnecting: "Verbindung wird hergestellt...", attachTitle: "Datei anhängen (PDF oder Bild, max. 10 MB)", creating: "Chat wird erstellt...", dropToAttach: "Datei zum Anhängen ablegen (Bilder oder PDF, je max. 10 MB)", demoError: "Demo konnte nicht gestartet werden", voiceStart: "Sprachnachricht aufnehmen", voiceStop: "Aufnahme stoppen", voiceTranscribing: "Wird transkribiert...", micDenied: "Zugriff auf das Mikrofon wurde verweigert.", transcribeFailed: "Transkription fehlgeschlagen. Bitte erneut versuchen." }, kl = /* @__PURE__ */ JSON.parse('{"pageTitle":"Erste Schritte mit Lambda ERP","intro":"Lambda ERP ist ein KI-natives ERP-System, bei dem die gesamte Funktionalität – etwa das Erstellen von Aufträgen, das Prüfen von Beständen und das Erfassen von Zahlungen – über eine Chat-Oberfläche zugänglich ist. Es leitet an, denkt mit und prüft alle Ihre täglichen Geschäftsaufgaben.","openChat":"KI-Chat öffnen","tipLabel":"Tipp:","topTip":"Der KI-Chat kann Ihnen auch direkte Links zu Dokumenten und herunterladbaren PDFs geben. Bitten Sie ihn einfach, ein Dokument zu erstellen oder nachzuschlagen, und er fügt anklickbare Links in seine Antwort ein.","manualIntro":"Wenn Sie genau verstehen möchten, wie die Dinge unter der Haube funktionieren, oder Dinge lieber manuell erledigen, finden Sie hier einen vollständigen Geschäftszyklus Schritt für Schritt.","caTitle":"Dynamische Analysen – Chatten Sie sich zu jedem Diagramm","caBadge":"Kernfunktion","caBody":"Brauchen Sie einen Bericht, den die Vorlagen nicht liefern? Beschreiben Sie ihn einfach im Chat. Der Assistent ruft ein Code-Spezialmodell auf, das den Bericht für Sie schreibt, ihn live über Ihre ERP-Daten ausführt und einen teilbaren Link zurückgibt. Das Diagramm oder die Tabelle wird in Sekunden gerendert und als Entwurf unter „Eigene Analysen“ in der Seitenleiste gespeichert – Sie können ihn erneut öffnen, die URL mit Kollegen teilen oder den Assistenten bitten, ihn zu verfeinern.","caTryAsking":"Versuchen Sie zu fragen (zum Vorausfüllen im Chat klicken):","caPrompt1":"Zeig mir die Top 10 Kunden nach Umsatz dieses Jahr als Balkendiagramm","caPrompt2":"Monatlicher Einkaufstrend nach Lieferant über alle Monate, x-Achse mit Lieferantennamen beschriften","caPrompt3":"Bestseller-Artikel nach Menge, mit Tabelle und Diagramm","caPrompt4":"Welche Kunden schulden mir gerade am meisten?","caTryInChat":"Im Chat ausprobieren","caOpenWorkspace":"Analyse-Arbeitsbereich öffnen","flowTitle":"Überblick Dokumentenfluss","salesCycle":"Verkaufszyklus","purchaseCycle":"Einkaufszyklus","returns":"Retouren","flowShortcut":"Abkürzung: Das Angebot kann den Kundenauftrag überspringen und direkt zur Ausgangsrechnung oder zum Lieferschein führen","legendStock":"Lagerwirkung","legendGl":"Buchungswirkung","legendCash":"Geldwirkung","legendReversal":"Stornierung","lifecycleTitle":"Dokumenten-Lebenszyklus","lcDraftLabel":"Entwurf:","lcDraftDesc":"Bearbeitbar. Keine finanzielle oder Bestandswirkung.","lcSubmittedLabel":"Gebucht:","lcSubmittedDesc":"Gesperrt. Buchungen und Lagerbuchungen werden erzeugt.","lcCancelledLabel":"Storniert:","lcCancelledDesc":"Alle Buchungen storniert. Das Dokument wird dauerhaft archiviert.","lcNoDelete":"Es gibt kein Löschen. Um einen Entwurf zu verwerfen: buchen und dann stornieren.","lcCorrect":"Um ein gebuchtes Dokument zu korrigieren: stornieren und ein neues erstellen.","readyTitle":"Sie sind startklar","readyBody1":"Sie verstehen jetzt den vollständigen Zyklus. Ein typisches Praxisszenario sieht so aus: Sie erhalten einen Kundenauftrag (Angebot → Kundenauftrag), prüfen den Bestand, kaufen, was Sie brauchen (Bestellung → Wareneingang → Eingangsrechnung → Zahlung), liefern an den Kunden (Lieferschein), stellen ihm die Rechnung (Ausgangsrechnung) und ziehen die Zahlung ein (Zahlung). Kommt etwas zurück, erstellen Sie eine Gutschrift und eine Lieferschein-Retoure, um Finanzen und Bestand umzukehren. Die Rohbilanz bestätigt, dass alles ausgeglichen ist.","readyBody2":"Sie können all dies auch über den KI-Chat per natürlicher Konversation erledigen – beschreiben Sie einfach, was Sie brauchen, und er erstellt die richtigen Dokumente für Sie.","chips":{"Quotation":"Angebot","Sales Order":"Kundenauftrag","Delivery Note":"Lieferschein","Sales Invoice":"Ausgangsrechnung","Payment Entry":"Zahlung","Purchase Order":"Bestellung","Purchase Receipt":"Wareneingang","Purchase Invoice":"Eingangsrechnung","Credit Note":"Gutschrift","DN Return":"Lieferschein-Retoure","Debit Note":"Lastschrift","Draft":"Entwurf","Submitted":"Gebucht","Cancelled":"Storniert"},"links":{"Go to Setup":"Zur Einrichtung","Customers":"Kunden","Suppliers":"Lieferanten","Items":"Artikel","Warehouses":"Lager","New Quotation":"Neues Angebot","View Quotations":"Angebote anzeigen","Stock Balance":"Lagerbestand","New Purchase Order":"Neue Bestellung","Purchase Receipts":"Wareneingänge","Purchase Invoices":"Eingangsrechnungen","Delivery Notes":"Lieferscheine","Sales Invoices":"Ausgangsrechnungen","New Payment Entry":"Neue Zahlung","New Stock Entry":"Neue Lagerbuchung","New Journal Entry":"Neuer Buchungssatz","Profit & Loss":"Gewinn- und Verlustrechnung","Balance Sheet":"Bilanz","AR Aging":"Offene Posten Debitoren","AP Aging":"Offene Posten Kreditoren","Trial Balance":"Rohbilanz","General Ledger":"Hauptbuch","Open AI Chat":"KI-Chat öffnen"},"steps":{"1":{"title":"Unternehmen einrichten","description":"Erstellen Sie ein Unternehmen mit einer Basiswährung. Dadurch wird Ihr Kontenplan generiert (30 Standardkonten in den Bereichen Aktiva, Verbindlichkeiten, Eigenkapital, Erträge und Aufwendungen) sowie eine Standard-Kostenstelle. Sie können außerdem Demodaten mit Beispielkunden, -lieferanten und -artikeln anlegen, um schnell loszulegen."},"2":{"title":"Stammdaten anlegen","description":"Bevor Sie buchen können, benötigen Sie Stammdaten. Legen Sie mindestens einen Kunden, einen Lieferanten, einen Artikel (mit Standardpreis) und ein Lager an. Wenn Sie in Schritt 1 Demodaten angelegt haben, existieren diese bereits.","tip":"Artikel haben einen Standardpreis, der beim Hinzufügen zu Dokumenten automatisch ausgefüllt wird. Sie können den Preis pro Transaktion jederzeit überschreiben."},"3":{"title":"Angebot erstellen","description":"Ein Angebot ist eine unverbindliche Offerte an einen Kunden. Wählen Sie einen Kunden, fügen Sie Positionen mit Mengen und Preisen hinzu, optional Steuerzeilen, und speichern Sie. Angebote haben keine finanzielle Auswirkung – sie erzeugen keine Buchungs- oder Lagerbewegungen. Legen Sie ein Gültigkeitsdatum fest, damit das Angebot automatisch abläuft."},"4":{"title":"Buchen und in Kundenauftrag umwandeln","description":"Öffnen Sie Ihr gespeichertes Angebot und klicken Sie auf Buchen, um es zu bestätigen. Klicken Sie dann auf „Kundenauftrag erstellen“, um es umzuwandeln. Der Kundenauftrag stellt eine bestätigte Zusage des Kunden dar. Er hat weiterhin keine finanzielle Auswirkung, reserviert aber Bestand für die Planung.","tip":"Nur gebuchte Dokumente können in den nächsten Schritt umgewandelt werden. Entwurf → Buchen → Umwandeln ist der Standardablauf. Für schnelle Geschäfte können Sie den Kundenauftrag überspringen und direkt vom Angebot zur Ausgangsrechnung oder zum Lieferschein gehen."},"5":{"title":"Bestand vor der Erfüllung prüfen","description":"Bevor Sie liefern können, prüfen Sie, ob der Artikel tatsächlich auf Lager ist. Öffnen Sie den Bericht Lagerbestand und suchen Sie den Artikel. Wenn Ihr Lager eine Menge von null aufweist, müssen Sie zunächst Bestand beschaffen – entweder über eine Bestellung (Einkauf bei einem Lieferanten) oder eine Lagerbuchung (manueller Eingang).","tip":"Dies ist ein häufiges Szenario aus der Praxis: Sie verkaufen etwas und stellen dann fest, dass Sie es erst einkaufen müssen. Das ERP unterstützt beide Abläufe."},"6":{"title":"Einkaufszyklus: Bestand bei einem Lieferanten kaufen","description":"Wenn Sie Bestand einkaufen müssen, haben Sie zwei gültige Wege. Der Standardweg ist Bestellung → Wareneingang → Eingangsrechnung: Nutzen Sie ihn, wenn die Ware vor oder getrennt von der Lieferantenrechnung eintrifft. Treffen Rechnung und Wareneingang gleichzeitig ein, können Sie die Eingangsrechnung direkt erstellen und „Lager aktualisieren“ aktivieren, sodass dasselbe Dokument sowohl den Bestand vereinnahmt als auch die Verbindlichkeit erfasst.","tip":"Verwenden Sie zuerst den Wareneingang, wenn Sie Waren getrennt erhalten. Verwenden Sie die Eingangsrechnung mit „Lager aktualisieren“, wenn ein Schritt sowohl den Bestand vereinnahmen als auch die Lieferantenrechnung buchen soll. Setzen Sie in diesem direkten Weg ein Lager in jeder Bestandszeile."},"7":{"title":"Lieferschein erstellen","description":"Nachdem Sie nun Bestand haben, kehren Sie zu Ihrem gebuchten Kundenauftrag zurück und klicken Sie auf „Lieferschein erstellen“. Setzen Sie in jeder Position das Lager (von dem die Ware versendet wird) und buchen Sie. Dadurch wird Bestand aus dem Lager ausgebucht – Ihr Lagerbestand sinkt.","tip":"Der Lieferschein ist das Versanddokument. Er reduziert den Bestand, erzeugt aber keine Rechnung. Sie können Lieferung und Rechnungsstellung getrennt vornehmen."},"8":{"title":"Ausgangsrechnung erstellen und buchen","description":"Erstellen Sie aus dem gebuchten Kundenauftrag eine Ausgangsrechnung. Beim Buchen der Rechnung werden Buchungen erzeugt: Forderungen aus Lieferungen und Leistungen werden im Soll gebucht (der Kunde schuldet Ihnen Geld) und Umsatzerlöse im Haben (erzielter Ertrag). Sind Steuern konfiguriert, wird auch die Steuerverbindlichkeit im Haben gebucht. Der offene Betrag zeigt, was der Kunde noch schuldet."},"9":{"title":"Kundenzahlungen erfassen","description":"Erstellen Sie eine Zahlung, um vom Kunden erhaltenes Geld zu erfassen. Setzen Sie die Zahlungsart auf „Receive“ (Erhalten), wählen Sie den Kunden, geben Sie den Betrag an und ordnen Sie ihn der Ausgangsrechnung zu. Sie können Teilzahlungen vornehmen – der offene Betrag der Rechnung aktualisiert sich entsprechend. Erstellen Sie weitere Zahlungen, bis die Rechnung vollständig beglichen ist.","tip":"Teilzahlungen sind üblich. Eine Rechnung über 10.000 kann jetzt mit 3.000 und später mit 7.000 bezahlt werden. Jede Zahlung reduziert den offenen Betrag."},"10":{"title":"Lagerbuchungen (manuelle Bestandsführung)","description":"Verwenden Sie Lagerbuchungen für Bestandsbewegungen, die nicht mit Ein- oder Verkäufen verbunden sind. „Material Receipt“ fügt Bestand hinzu (Eröffnungsbestände, Korrekturen). „Material Issue“ bucht Bestand aus (Abschreibungen, interner Verbrauch). „Material Transfer“ verschiebt Bestand zwischen Lägern. Jede Buchung aktualisiert das Lagerbuch mit gleitender Durchschnittsbewertung.","tip":"Verwenden Sie für eingekaufte Waren Wareneingänge statt Lagerbuchungen – sie sind mit der Bestellung verknüpft und bieten einen sauberen Prüfpfad."},"11":{"title":"Buchungssätze","description":"Buchungssätze sind manuelle buchhalterische Anpassungen – Aufwandsabgrenzungen, Korrekturen, Umgliederungen, Eröffnungsbestände. Jeder Satz muss ausgeglichene Soll- und Haben-Beträge haben (Summe Soll = Summe Haben). Verwenden Sie sie, wenn kein anderer Dokumenttyp passt."},"12":{"title":"Gehaltszahlungen","description":"Lambda ERP wickelt Gehälter über die vorhandenen Buchhaltungswerkzeuge ab. Grenzen Sie zunächst den Gehaltsaufwand ab: Erstellen Sie einen Buchungssatz, der Gehaltsaufwand im Soll und Gehaltsverbindlichkeiten im Haben für den gesamten Lohnbetrag bucht. Bezahlen Sie dann die Mitarbeiter: Erstellen Sie einen weiteren Buchungssatz (oder eine Zahlung), der Gehaltsverbindlichkeiten im Soll und Ihr Bankkonto im Haben bucht. Dieser zweistufige Prozess hält Ihre Bücher korrekt – der Aufwand wird in der richtigen Periode erfasst und der Geldabfluss separat nachverfolgt.","tip":"Sie können den KI-Assistenten bitten, dies für Sie zu erledigen: „Grenze 15.000 an Gehältern für April ab“ gefolgt von „Zahle die April-Gehälter von der Bank“. Er erstellt die richtigen Buchungssätze automatisch."},"13":{"title":"Retouren und Gutschriften","description":"Wenn ein Kunde Waren zurückgibt oder Sie eine Gutschrift ausstellen müssen, erstellen Sie eine Retoure. Retouren verwenden denselben Dokumenttyp mit negativen Mengen. Öffnen Sie eine gebuchte Ausgangsrechnung und erstellen Sie eine Gutschrift (Ausgangsrechnungs-Retoure) – dies kehrt die Buchungen um und reduziert den offenen Betrag der ursprünglichen Rechnung. Erstellen Sie für den Bestand eine Lieferschein-Retoure, um Waren zurück ins Lager zu nehmen. Auf der Einkaufsseite erstellen Sie eine Lastschrift (Eingangsrechnungs-Retoure), um eine Lieferantenrechnung umzukehren, oder eine Wareneingangs-Retoure, um Waren zurückzusenden.","tip":"Eine Gutschrift ist einfach eine Ausgangsrechnung mit is_return=1 und negativen Mengen. Dieselbe Buchungslogik läuft – negative Beträge wechseln automatisch auf die richtige Soll-/Haben-Seite. Für eine vollständige Verkaufsretoure benötigen Sie sowohl eine Gutschrift (Finanzen) als auch eine Lieferschein-Retoure (Bestand)."},"14":{"title":"Berichte ausführen","description":"Prüfen Sie Ihre Bücher. Die Gewinn- und Verlustrechnung zeigt Erträge gegenüber Aufwendungen und den Periodengewinn. Die Bilanz zeigt Ihre finanzielle Lage (Aktiva = Verbindlichkeiten + Eigenkapital). Die Offenen Posten Debitoren zeigen, wer Ihnen Geld schuldet und wie überfällig es ist. Die Offenen Posten Kreditoren zeigen, was Sie Lieferanten schulden. Die Rohbilanz überprüft die doppelte Buchführung. Das Hauptbuch zeigt jede einzelne Buchung. Der Lagerbestand zeigt den aktuellen Bestand."},"15":{"title":"Arbeiten in Fremdwährungen","description":"Ihre Bücher werden in einer einzigen Basiswährung geführt (bei der Unternehmenseinrichtung gewählt), aber Sie können in jeder Währung buchen. Setzen Sie eine Währung auf einer Rechnung oder einem Beleg – oder geben Sie einem Kunden oder Lieferanten eine Standardwährung – und der Wechselkurs für dieses Datum wird automatisch ermittelt und auf dem Dokument gespeichert. Das Dokument behält seine Beträge in seiner eigenen Währung, während das Hauptbuch stets in Ihrer Basiswährung bucht. Wenn Sie später zu einem anderen Kurs einnehmen oder zahlen, wird der realisierte Währungsgewinn oder -verlust automatisch auf ein Konto Währungsgewinn/-verlust gebucht. Sie können sogar ein Fremdwährungs-Bankguthaben halten und es später zum Kurs Ihrer Bank umrechnen – die Differenz zum Buchwert wird dann realisiert. Zum Monatsende können Sie offene Fremdwährungssalden zum Stichtagskurs neu bewerten (ein unrealisierter Gewinn/Verlust, der in der nächsten Periode storniert wird), und Sie können jeden Jahresabschluss zur Anzeige in eine andere Währung umgerechnet betrachten.","tip":"Am einfachsten geht das über den KI-Chat – probieren Sie „Erstelle eine Ausgangsrechnung für Lumiere Audio in EUR“, „Zeig mir die Bilanz in EUR“ oder „Wie hoch ist unser unrealisiertes Währungsrisiko zum Monatsende?“. Die Demodaten enthalten bereits einen EUR-Kunden (Lumiere Audio SARL), dessen Rechnung zu einem anderen Kurs eingenommen wurde, sowie eine offene EUR-Lieferantenrechnung – öffnen Sie das Hauptbuch, um die realisierten Währungsbuchungen zu sehen."}},"setupTitle":"Richten Sie Ihr Unternehmen ein — KI-geführt","setupBadge":"Hier starten","setupBody":"Sagen Sie dem Assistenten, welche Art von Unternehmen Sie führen, und er erstellt Ihren Kontenplan für Sie — zugeschnitten auf Ihre Branche, mit den passenden Konten und sinnvollen Voreinstellungen. Er erklärt jede Entscheidung und legt erst dann etwas an, wenn Sie zustimmen.","setupSectors":"Zugeschnitten auf Dienstleistungen, Einzelhandel & POS, Gastronomie, Großhandel & Distribution, Import/Export, Fertigung und Bauwesen.","setupGetStarted":"Im Chat loslegen","setupManual":"Lieber ein manuelles Formular? Nutzen Sie die klassische Einrichtung.","setupManualLink":"Klassische Einrichtung","setupPrompt":"Ich möchte mein Unternehmen einrichten. Können Sie mich durch den Prozess führen?"}'), Nl = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, wl = { period: "Periode", allTime: "Gesamter Zeitraum", semantics: "Bilanzkonten: Saldo per Periodenende. Erfolgskonten: Bewegung innerhalb der Periode. Konto anklicken für den Kontoauszug.", empty: "Keine Konten gefunden. Zuerst die Firmeneinrichtung abschliessen.", disabled: "deaktiviert", rootType: { Asset: "Aktiven", Liability: "Passiven", Equity: "Eigenkapital", Income: "Ertrag", Expense: "Aufwand" } }, Cl = { fleetCalendar: "Flottenkalender", yard: "Depot", machineType: "Maschinentyp", prev: "Zurück", today: "Heute", next: "Weiter", weeks: "Wochen", newBooking: "Neue Reservation", reserved: "Reserviert", onHire: "Vermietet", machine: "Maschine", loadError: "Flottenkalender konnte nicht geladen werden.", noAssets: "Keine Geräte vorhanden. Maschinen unter Vermietung → Flotte hinzufügen.", pooledNote: "{{count}} Pool-Reservation(en) noch ohne Maschinenzuordnung", unassigned: "Pool — noch nicht zugeordnet", poolWarning: "Die Pool-Kapazität ist reserviert. Eine konkrete Maschine ist noch nicht zugeordnet; vor der Ausgabe eine Maschine auswählen." }, Sl = { Unit: "Bestimmte Maschine", Pool: "Pool – Maschine später zuweisen", Available: "Verfügbar", "On Hire": "Vermietet", Out: "Ausgeliefert", Maintenance: "Wartung", Retired: "Ausgemustert", Reserved: "Reserviert", Returned: "Zurückgegeben", Cancelled: "Storniert", Customer: "Kunde", Supplier: "Lieferant" }, Al = { asset: { item_code: "Der Artikel ist der Maschinen-TYP und trägt den Tarif; ein Gerät ist eine physische Einheit davon. Der Artikel muss is_asset_tracked = 1 haben.", asset_tag: "Kennzeichen oder Seriennummer — muss über alle Geräte eindeutig sein.", status: "Aktueller Zustand der Einheit (kein Zeitraum). Ausgemusterte Einheiten verlassen den Pool.", meter_reading: "Betriebsstunden / km." }, reservation: { item_code: "Pool-Reservation ('ein 1.7t-Bagger'): Artikel + Depot + Menge setzen. Für eine bestimmte Maschine stattdessen Gerät setzen.", asset: "Eine bestimmte Maschine buchen. Eine Einheiten-Buchung belegt auch einen Platz im Artikel+Depot-Pool.", from_datetime: "Genauer Beginn — Datum und Uhrzeit (z. B. 14:27). Ein reines Datum bedeutet 00:00.", to_datetime: "Genaues Ende. Fenster sind halboffen [von, bis): eine Miete, die um 09:00 endet, und die nächste um 09:00 beginnende, kollidieren NICHT." } }, _l = { label: "Standard-Verkaufssteuer", none: "Keine automatische Übernahme", hint: "Wird bei neuen Offerten, Aufträgen und Rechnungen übernommen, sofern keine Steuern ausdrücklich vorgegeben werden. Bestehende Belege bleiben unverändert. Mit „Speichern“ übernehmen.", saveFirst: "Firma zuerst speichern. Anschliessend können Sie eine ihrer Verkaufsteuervorlagen auswählen.", loadError: "Steuervorlagen konnten nicht geladen werden. Die gespeicherte Auswahl bleibt erhalten.", retry: "Erneut versuchen", unavailable: "Die gespeicherte Vorlage ist für diese Firma nicht als Verkaufsteuervorlage verfügbar. Bitte prüfen Sie die Auswahl.", empty: "Für diese Firma sind noch keine Verkaufsteuervorlagen hinterlegt." }, Dl = {
|
|
9210
|
+
proposal: Xo,
|
|
9211
|
+
common: el,
|
|
9212
|
+
datePresets: tl,
|
|
9213
|
+
bankStatements: nl,
|
|
9214
|
+
bankReconciliation: al,
|
|
9215
|
+
smartSearch: rl,
|
|
9216
|
+
language: sl,
|
|
9217
|
+
header: il,
|
|
9218
|
+
titles: ol,
|
|
9219
|
+
doctypes: ll,
|
|
9220
|
+
masters: cl,
|
|
9221
|
+
nav: dl,
|
|
9222
|
+
login: ul,
|
|
9223
|
+
settings: ml,
|
|
9224
|
+
status: pl,
|
|
9225
|
+
reports: hl,
|
|
9226
|
+
masterForm: gl,
|
|
9227
|
+
fields: fl,
|
|
9228
|
+
tables: yl,
|
|
9229
|
+
conversions: bl,
|
|
9230
|
+
dashboard: vl,
|
|
9231
|
+
chat: xl,
|
|
9232
|
+
tutorial: kl,
|
|
9233
|
+
notesMarkup: Nl,
|
|
9234
|
+
coa: wl,
|
|
9235
|
+
rentals: Cl,
|
|
9236
|
+
fieldOptions: Sl,
|
|
9237
|
+
hints: Al,
|
|
9238
|
+
companyTax: _l
|
|
9239
|
+
}, Pl = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, Tl = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", cancelBooking: "Annuler la réservation", cancelBookingConfirm: "Oui, annuler", keepBooking: "Conserver", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", showDisabled: "Afficher les désactivés", columns: "Colonnes", searchPlaceholder: "Rechercher…", noRecords: "Aucun enregistrement trouvé", active: "Actif", disabled: "Désactivé", sortByColumn: "Trier par cette colonne", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Rl = { today: "Aujourd’hui", thisWeek: "Cette semaine", thisMonth: "Ce mois-ci", thisQuarter: "Ce trimestre", thisYear: "Cette année", lastMonth: "Mois dernier", lastQuarter: "Trimestre dernier", lastYear: "Année dernière", endOfThisMonth: "Fin du mois en cours", endOfLastMonth: "Fin du mois dernier", endOfThisQuarter: "Fin du trimestre en cours", endOfThisYear: "Fin de l’année en cours", endOfLastYear: "Fin de l’année dernière" }, Bl = { title: "Importer un relevé bancaire", subtitle: "Prévisualisez et importez des relevés ISO 20022 CAMT sans écriture comptable automatique.", selectFiles: "Fichiers CAMT", chooseFiles: "Choisir des fichiers XML ou ZIP", dropFiles: "Déposez les fichiers XML ou ZIP ici", unsupportedFiles: "Seuls les fichiers CAMT XML ou ZIP sont acceptés : {{files}}", fileHint: "camt.053.001.04 et camt.053.001.08 · plusieurs fichiers acceptés", preview: "Afficher l’aperçu", noPosting: "L’aperçu et l’importation ne génèrent aucune écriture comptable.", alreadyImported: "Déjà importé", period: "Période", openingBalance: "Solde initial", closingBalance: "Solde final", entries: "Opérations", credits: "Crédits", debits: "Débits", details: "Détails des transactions", batches: "lots", qrReferences: "Références QR", mapping: "Affectation du compte bancaire", selectBankAccount: "Sélectionner un compte bancaire…", noBankAccounts: "Aucun compte bancaire n’a encore été configuré.", createBankAccount: "Configurer un compte bancaire", mappingRequired: "Affectez chaque nouveau relevé à un compte bancaire avant l’importation.", import: "Importer les relevés", importComplete: "Importation terminée", importCounts: "{{imported}} opérations importées, {{duplicates}} doublons ignorés", history: "Importations récentes", importId: "Importation", bankAccount: "Compte bancaire", source: "Fichier source", openReconciliation: "Ouvrir le rapprochement bancaire" }, Il = { title: "Rapprochement bancaire", subtitle: "Rapprochez les transactions importées avec des écritures, des factures ouvertes ou des comptes comptables.", status: "Statut", unreconciled: "Non rapprochée", reconciled: "Rapprochée", transactions: "Transactions bancaires", empty: "Aucune transaction bancaire dans cette vue.", remittance: "Information de paiement", reference: "Référence", openTransaction: "Ouvrir la transaction bancaire", conversionRate: "Taux de change (1 {{currency}} en {{base}})", conversionRateHint: "Requis si aucun taux de change n’existe à la date de la transaction.", existingVouchers: "Écritures existantes", existingVouchersHint: "Ces pièces validées contiennent un mouvement exact sur ce compte bancaire. Le rapprochement ne les comptabilise pas une seconde fois.", match: "Rapprocher", openInvoices: "Factures ouvertes", openInvoicesHint: "Sélectionnez une ou plusieurs factures du même tiers. La confirmation crée et valide un paiement.", outstanding: "Solde ouvert", allocation: "Affectation", noInvoiceSuggestions: "Aucune facture ouverte plausible n’a été trouvée.", allocated: "{{amount}} affectés sur {{total}}", createPayment: "Créer le paiement et rapprocher", directPosting: "Comptabiliser sur un compte", directPostingHint: "Pour les frais, intérêts et autres mouvements sans facture. Les comptes clients, fournisseurs, bancaires et de caisse sont volontairement exclus.", counterpartyAccount: "Compte de contrepartie", remarks: "Remarque", createJournal: "Créer l’écriture et rapprocher", activeMatch: "Rapprochement actif", undo: "Annuler le rapprochement", confirmExistingTitle: "Rapprocher l’écriture existante ?", confirmExistingBody: "Rapprocher {{transaction}} avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", confirmGroupBody: "Rapprocher les {{count}} transactions, pour un total de {{amount}}, avec {{voucher}} ? Aucune nouvelle écriture ne sera comptabilisée.", groupedTransactions: "{{count}} transactions groupées", confirmPaymentTitle: "Comptabiliser le paiement et rapprocher ?", confirmPaymentBody: "Cette action valide un paiement de {{amount}} pour {{transaction}} et l’affecte à {{count}} facture(s).", onAccountWarning: "{{amount}} resteront comme paiement non affecté pour ce tiers.", confirmJournalTitle: "Comptabiliser l’écriture et rapprocher ?", confirmJournalBody: "Cette action comptabilise {{amount}} pour {{transaction}} sur {{account}}.", postAndReconcile: "Comptabiliser et rapprocher", undoTitle: "Annuler le rapprochement ?", undoCreatedBody: "La pièce créée par ce rapprochement sera annulée, ses écritures extournées et les affectations aux factures restaurées.", undoExistingBody: "La pièce existante sera uniquement dissociée. Elle restera validée et ses écritures ne seront pas modifiées.", undoExistingGroupBody: "Les {{count}} transactions groupées ({{transactions}}) seront toutes dissociées ensemble. La pièce existante restera validée et ses écritures ne seront pas modifiées.", reconciledNotice: "Transaction bancaire rapprochée.", groupReconciledNotice: "{{count}} transactions bancaires ont été rapprochées en groupe.", undoneNotice: "Rapprochement annulé." }, El = { placeholder: "Rechercher ou saisir champ:valeur…", search: "Rechercher", addFilter: "+ Filtre", availableFields: "Champs disponibles", fieldHelp: "Choisissez un champ ou saisissez son nom technique suivi de deux-points.", field: "Champ", valueFor: "Valeur pour {{label}}", allFields: "Tous les champs", typeForValues: "Commencez à saisir pour rechercher des valeurs dans ce champ.", noValues: "Aucune valeur correspondante.", noFields: "Aucun champ correspondant.", useValue: "Utiliser « {{value}} »", removeFilter: "Supprimer le filtre {{label}}", types: { text: "Texte", textarea: "Texte long", select: "Sélection", link: "Enregistrement lié", date: "Date", datetime: "Date et heure", number: "Nombre", currency: "Montant" } }, Ll = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Ol = { back: "Retour", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Fl = { dashboard: "Tableau de bord", setup: "Configuration de l'entreprise", tutorial: "Premiers pas", chat: "Chat", reports: "Rapports", "trial-balance": "Balance comptable", "general-ledger": "Grand livre", "stock-balance": "Solde de stock", "profit-and-loss": "Compte de résultat", "balance-sheet": "Bilan", "ar-aging": "Balance âgée clients", "ap-aging": "Balance âgée fournisseurs", analytics: "Analyses", "chart-of-accounts": "Plan comptable" }, Ml = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, "bank-account": { one: "Compte bancaire", other: "Comptes bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, ql = { company: { one: "Société", other: "Sociétés" }, customer: { one: "Client", other: "Clients" }, supplier: { one: "Fournisseur", other: "Fournisseurs" }, item: { one: "Article", other: "Articles" }, warehouse: { one: "Entrepôt", other: "Entrepôts" } }, zl = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres", Rentals: "Locations" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", "Bank Account": "Comptes bancaires", "Bank Statement Import": "Importer un relevé bancaire", "Bank Reconciliation": "Rapprochement bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable", "Fleet Calendar": "Calendrier de flotte", "Fleet (Assets)": "Flotte (matériel)", Reservations: "Réservations" } }, $l = { taglineFirstRun: "Créez votre compte administrateur pour commencer", taglineRegister: "Créez votre compte", taglineSignIn: "Connectez-vous à votre compte", demoBanner: "Le mode démo est actif. Connectez-vous avec un compte administrateur pour gérer les paramètres ou désactiver l'accès public.", fullName: "Nom complet", email: "E-mail", password: "Mot de passe", confirmPassword: "Confirmer le mot de passe", createAdmin: "Créer un compte administrateur", register: "S'inscrire", signIn: "Se connecter", browsingTitle: "Simple visite ?", browsingBody: "Démarrez une nouvelle session de chat et regardez la démo en direct.", enterDemo: "Lancer la démo", haveInvite: "Vous avez une invitation ?", noAccountPrompt: "Besoin d'un compte ?", registerLink: "S'inscrire", alreadyHaveAccount: "Vous avez déjà un compte ?", signInLink: "Se connecter", passwordsNoMatch: "Les mots de passe ne correspondent pas", passwordTooShort: "Le mot de passe doit comporter au moins 6 caractères", registrationFailed: "Échec de l'inscription", loginFailed: "Échec de la connexion", orContinueWith: "ou continuer avec", continueWithProvider: "Continuer avec {{provider}}", oauthError: { generic: "Échec de la connexion. Veuillez réessayer.", email_exists: "Un compte avec cet e-mail existe déjà. Connectez-vous, puis liez ce fournisseur depuis les paramètres du compte.", email_unverified: "Votre fournisseur n'a pas confirmé d'e-mail vérifié, la connexion est donc impossible.", registration_closed: "Cet e-mail n'a pas encore de compte et l'inscription se fait uniquement sur invitation.", invite_invalid: "Cette invitation est invalide, déjà utilisée ou émise pour un autre e-mail.", identity_taken: "Ce compte fournisseur est déjà lié à un autre utilisateur.", account_disabled: "Ce compte a été désactivé.", token_exchange_failed: "Échec de la connexion auprès du fournisseur. Veuillez réessayer." } }, Vl = { pdfTitle: "PDF et impression", pageSize: "Format de page", pdfHelp: "A4 est la norme internationale (210 x 297 mm). Letter est la norme aux États-Unis (8,5 x 11 po).", passwordTitle: "Changer le mot de passe", currentPassword: "Mot de passe actuel", newPassword: "Nouveau mot de passe", confirmNewPassword: "Confirmer le nouveau mot de passe", changePassword: "Changer le mot de passe", changingPassword: "Modification...", passwordChanged: "Mot de passe modifié.", setPasswordTitle: "Définir un mot de passe", setPasswordBody: "Votre compte se connecte avec Google. Définissez un mot de passe pour vous connecter aussi avec e-mail et mot de passe — un recours pratique si vous perdez l'accès à votre compte Google.", setPassword: "Définir le mot de passe", passwordSet: "Mot de passe défini.", linkedAccountsTitle: "Comptes liés", linkedAccountsBody: "Liez un compte Google ou Apple pour vous connecter sans mot de passe.", linked: "Lié", linkProvider: "Lier {{provider}}", openingTitle: "Soldes d'ouverture", openingBody: "La page Soldes d'ouverture permet d'importer les soldes des comptes, le stock et les factures impayées d'un système précédent.", openingEnabled: "Actuellement activé — accessible sous Introduction > Soldes d'ouverture.", openingDisabled: "Actuellement désactivé — la page est masquée dans la barre latérale.", signupTitle: "Inscription publique", signupBody: "Permettre à quiconque de créer son propre compte (en tant que lecteur) sans invitation. Lorsque désactivé, les nouveaux utilisateurs ne peuvent rejoindre que via un lien d'invitation.", signupEnabled: "Actuellement activé — toute personne disposant de l'URL peut s'inscrire en tant que lecteur.", signupDisabled: "Actuellement désactivé — l'inscription se fait uniquement sur invitation.", chatApiTitle: "API de chat", apiTitle: "API programmatique", restApiBody: "Permettre à des connecteurs et scripts de piloter cet ERP via son API REST (documents, données de base, rapports) avec les mêmes clés API Bearer. Désactivé par défaut.", restApiEnabled: "Actuellement activé — les clés émises peuvent appeler /api/documents, /api/masters et le reste de l'API REST.", restApiDisabled: "Actuellement désactivé — l'API REST n'accepte que le cookie de session ; les clés sont rejetées.", restApiDeactivateTitle: "Désactiver l'API REST ?", restApiDeactivateBody: "L'accès par clé Bearer à l'API REST sera désactivé — les connecteurs et scripts sont rejetés jusqu'à sa réactivation. L'application web (cookie de session) n'est pas affectée, et vos clés API ne sont PAS supprimées : elles fonctionnent à nouveau dès que vous réactivez l'API.", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat.", version: "Version {{version}}" }, Ul = { Draft: "Brouillon", Open: "Ouvert", Submitted: "Validé", "To Deliver and Bill": "À livrer et facturer", "To Deliver": "À livrer", "To Bill": "À facturer", Completed: "Terminé", Ordered: "Commandé", Paid: "Payé", Unpaid: "Impayé", Cancelled: "Annulé", Discarded: "Supprimé", Overdue: "En retard", Return: "Retour", Closed: "Clôturé" }, Kl = { periodRange: "Période du rapport : {{from}} – {{to}}", periodFrom: "Période du rapport à partir du {{from}}", periodThrough: "Période du rapport jusqu’au {{to}}", asOfDate: "Date de référence : {{date}}", balanced: "ÉQUILIBRÉ", imbalanced: "DÉSÉQUILIBRÉ", income: "Produits", expenses: "Charges", totalIncome: "Total des produits", totalExpenses: "Total des charges", netProfit: "Bénéfice", netLoss: "Perte", assets: "Actif", liabilities: "Passif", equity: "Capitaux propres", totalAssets: "Total de l'actif", totalLiabilities: "Total du passif", totalEquity: "Total des capitaux propres", totalLiabilitiesEquity: "Total passif + capitaux propres", current: "Non échu", noData: "Aucune donnée trouvée", noEntries: "Aucune écriture trouvée", noStockData: "Aucune donnée de stock trouvée", noReceivables: "Aucune créance en cours", noPayables: "Aucune dette en cours", noDocuments: "Aucun document trouvé" }, jl = { required: "Requis : {{fields}}", deleteConfirm: "Supprimer ce {{label}} ?", disabledNotice: "Ce {{label}} est désactivé. Il reste dans le système car d'autres enregistrements y font référence.", disabledOnDelete: "{{label}} {{name}} a été désactivé au lieu d'être supprimé car il est référencé par {{reason}}." }, Wl = { "Last modified": "Dernière modification", Created: "Créé", Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société", "Item (type)": "Article (type)", "Asset Tag / Plate": "Étiquette / plaque", "Home Yard": "Dépôt d'attache", "Purchase Value": "Valeur d'achat", "Meter Reading": "Relevé compteur", "Meter Unit": "Unité compteur", Yard: "Dépôt", "Asset (specific unit)": "Équipement (unité spécifique)", Allocation: "Affectation", From: "Du", To: "Au", Purpose: "Objet", "Purchase Date": "Date d'achat", Notes: "Notes" }, Gl = { items: "Lignes", taxes: "Taxes", references: "Références de paiement", accounts: "Écritures de compte", payments: "Paiements", plans: "Articles du plan", monthly_distribution: "Répartition mensuelle" }, Hl = { "Create Sales Order": "Créer une commande client", "Create Sales Invoice": "Créer une facture de vente", "Create Delivery Note": "Créer un bon de livraison", "Create Purchase Invoice": "Créer une facture d'achat", "Create Purchase Receipt": "Créer un bon de réception", "Create Credit Note": "Créer un avoir", "Create Debit Note": "Créer une note de débit", "Create Return": "Créer un retour" }, Ql = { totalRevenue: "Chiffre d'affaires total", outstandingReceivable: "Créances en cours", outstandingPayable: "Dettes en cours", totalStockValue: "Valeur totale du stock", recentDocuments: "Documents récents", noRecentDocuments: "Aucun document récent" }, Yl = { title: "Chat Lambda ERP", subtitle: "Demandez-moi de créer des documents, de consulter des données ou d'exécuter des rapports.", s1: "Quels clients avons-nous ?", s2: "Affiche la balance comptable", s3: "Crée un devis pour 10 Bolt Pack M8", s4: "Liste toutes les factures impayées", loadOlder: "Charger les messages plus anciens", uploading: "Téléversement...", failed: "Échec", remove: "Supprimer", placeholderDemo: "Démo en direct en cours...", placeholderType: "Tapez un message...", placeholderConnecting: "Connexion...", attachTitle: "Joindre un fichier (PDF ou image, max 10 Mo)", creating: "Création du chat...", dropToAttach: "Déposez un fichier à joindre (images ou PDF, max 10 Mo chacun)", demoError: "Impossible de démarrer la démo", voiceStart: "Enregistrer un message vocal", voiceStop: "Arrêter l'enregistrement", voiceTranscribing: "Transcription...", micDenied: "L'accès au microphone a été refusé.", transcribeFailed: "Échec de la transcription. Veuillez réessayer." }, Jl = /* @__PURE__ */ JSON.parse(`{"pageTitle":"Premiers pas avec Lambda ERP","intro":"Lambda ERP est un système ERP nativement IA, où toutes les fonctionnalités – comme créer des commandes, vérifier l'inventaire ou enregistrer des paiements – sont accessibles via une interface de chat. Il guide, raisonne et vérifie toutes vos tâches quotidiennes.","openChat":"Ouvrir le chat IA","tipLabel":"Astuce :","topTip":"Le chat IA peut aussi vous donner des liens directs vers des documents et des PDF téléchargeables. Demandez-lui simplement de créer ou de rechercher un document et il inclura des liens cliquables dans sa réponse.","manualIntro":"Si vous souhaitez comprendre pleinement le fonctionnement interne, ou préférez procéder manuellement, voici un cycle commercial complet étape par étape.","caTitle":"Analyses dynamiques – discutez pour obtenir n'importe quel graphique","caBadge":"Fonctionnalité phare","caBody":"Besoin d'un rapport que les modèles prédéfinis ne fournissent pas ? Décrivez-le simplement dans le chat. L'assistant appelle un modèle spécialiste du code qui écrit le rapport pour vous, l'exécute en direct sur vos données ERP et renvoie un lien partageable. Le graphique ou le tableau s'affiche en quelques secondes et est enregistré comme brouillon sous « Analyses personnalisées » dans la barre latérale – vous pouvez le rouvrir, partager l'URL avec vos collègues ou demander à l'assistant de l'affiner.","caTryAsking":"Essayez de demander (cliquez pour préremplir dans le chat) :","caPrompt1":"Montre-moi les 10 meilleurs clients par chiffre d'affaires cette année en diagramme à barres","caPrompt2":"Tendance mensuelle des achats par fournisseur sur tous les mois, étiquette l'axe des x avec le nom du fournisseur","caPrompt3":"Articles les plus vendus par quantité, avec un tableau et un graphique","caPrompt4":"Quels clients me doivent le plus en ce moment ?","caTryInChat":"Essayer dans le chat","caOpenWorkspace":"Ouvrir l'espace d'analyse","flowTitle":"Aperçu du flux des documents","salesCycle":"Cycle de vente","purchaseCycle":"Cycle d'achat","returns":"Retours","flowShortcut":"Raccourci : le devis peut ignorer la commande client et aller directement à la facture de vente ou au bon de livraison","legendStock":"impact stock","legendGl":"impact comptable","legendCash":"impact trésorerie","legendReversal":"annulation","lifecycleTitle":"Cycle de vie du document","lcDraftLabel":"Brouillon :","lcDraftDesc":"Modifiable. Aucun impact financier ni sur le stock.","lcSubmittedLabel":"Validé :","lcSubmittedDesc":"Verrouillé. Les écritures comptables et de stock sont générées.","lcCancelledLabel":"Annulé :","lcCancelledDesc":"Toutes les écritures sont inversées. Le document est archivé définitivement.","lcNoDelete":"Il n'y a pas de suppression. Pour annuler un brouillon : validez-le, puis annulez-le.","lcCorrect":"Pour corriger un document validé : annulez-le et créez-en un nouveau.","readyTitle":"Vous êtes prêt","readyBody1":"Vous comprenez maintenant le cycle complet. Un scénario réel typique ressemble à ceci : vous recevez une commande client (Devis → Commande client), vérifiez le stock, achetez ce dont vous avez besoin (Bon de commande → Bon de réception → Facture d'achat → Paiement), livrez au client (Bon de livraison), facturez-le (Facture de vente) et encaissez le paiement (Paiement). Si quelque chose revient, créez un avoir et un retour de bon de livraison pour inverser les finances et le stock. La Balance comptable confirme que tout est équilibré.","readyBody2":"Vous pouvez aussi tout faire via le chat IA en conversation naturelle – décrivez simplement ce dont vous avez besoin et il créera les bons documents pour vous.","chips":{"Quotation":"Devis","Sales Order":"Commande client","Delivery Note":"Bon de livraison","Sales Invoice":"Facture de vente","Payment Entry":"Paiement","Purchase Order":"Bon de commande","Purchase Receipt":"Bon de réception","Purchase Invoice":"Facture d'achat","Credit Note":"Avoir","DN Return":"Retour BL","Debit Note":"Note de débit","Draft":"Brouillon","Submitted":"Validé","Cancelled":"Annulé"},"links":{"Go to Setup":"Aller à la configuration","Customers":"Clients","Suppliers":"Fournisseurs","Items":"Articles","Warehouses":"Entrepôts","New Quotation":"Nouveau devis","View Quotations":"Voir les devis","Stock Balance":"Solde de stock","New Purchase Order":"Nouveau bon de commande","Purchase Receipts":"Bons de réception","Purchase Invoices":"Factures d'achat","Delivery Notes":"Bons de livraison","Sales Invoices":"Factures de vente","New Payment Entry":"Nouveau paiement","New Stock Entry":"Nouveau mouvement de stock","New Journal Entry":"Nouvelle écriture de journal","Profit & Loss":"Compte de résultat","Balance Sheet":"Bilan","AR Aging":"Balance âgée clients","AP Aging":"Balance âgée fournisseurs","Trial Balance":"Balance comptable","General Ledger":"Grand livre","Open AI Chat":"Ouvrir le chat IA"},"steps":{"1":{"title":"Configurer votre société","description":"Créez une société avec une devise de base. Cela génère votre plan comptable (30 comptes standard répartis entre Actif, Passif, Capitaux propres, Produits et Charges) ainsi qu'un centre de coûts par défaut. Vous pouvez aussi charger des données de démonstration avec des clients, fournisseurs et articles d'exemple pour démarrer rapidement."},"2":{"title":"Créer les données de base","description":"Avant de pouvoir effectuer des transactions, vous avez besoin de fiches de base. Créez au moins un client, un fournisseur, un article (avec un prix standard) et un entrepôt. Si vous avez chargé les données de démonstration à l'étape 1, elles existent déjà.","tip":"Les articles ont un prix standard qui se remplit automatiquement lorsque vous les ajoutez à des documents. Vous pouvez toujours modifier le prix par transaction."},"3":{"title":"Créer un devis","description":"Un devis est une offre non contraignante adressée à un client. Sélectionnez un client, ajoutez des lignes avec quantités et prix, éventuellement des lignes de taxe, puis enregistrez. Les devis n'ont aucun impact financier – ils ne créent ni écritures comptables ni mouvements de stock. Définissez une date de validité pour que l'offre expire automatiquement."},"4":{"title":"Valider et convertir en commande client","description":"Ouvrez votre devis enregistré et cliquez sur Valider pour le confirmer. Cliquez ensuite sur « Créer une commande client » pour le convertir. La commande client représente un engagement confirmé du client. Elle n'a toujours aucun impact financier, mais réserve du stock à des fins de planification.","tip":"Seuls les documents validés peuvent être convertis à l'étape suivante. Brouillon → Valider → Convertir est le flux standard. Pour les affaires rapides, vous pouvez ignorer la commande client et passer directement du devis à la facture de vente ou au bon de livraison."},"5":{"title":"Vérifier le stock avant l'exécution","description":"Avant de pouvoir livrer, vérifiez si vous avez réellement l'article en stock. Ouvrez le rapport Solde de stock et recherchez l'article. Si votre entrepôt affiche une quantité nulle, vous devrez d'abord approvisionner le stock – soit par un bon de commande (achat auprès d'un fournisseur), soit par un mouvement de stock (réception manuelle).","tip":"C'est un scénario courant dans la pratique : vous vendez quelque chose, puis réalisez que vous devez d'abord l'acheter. L'ERP gère les deux flux."},"6":{"title":"Cycle d'achat : acheter du stock à un fournisseur","description":"Si vous devez acheter du stock, vous avez deux chemins valides. Le chemin standard est Bon de commande → Bon de réception → Facture d'achat : utilisez-le lorsque les marchandises arrivent avant ou séparément de la facture du fournisseur. Si la facture et la réception arrivent ensemble, vous pouvez créer directement la facture d'achat et activer « Mettre à jour le stock » afin que le même document réceptionne le stock et enregistre la dette fournisseur.","tip":"Utilisez d'abord le bon de réception lorsque vous recevez les marchandises séparément. Utilisez la facture d'achat avec « Mettre à jour le stock » lorsqu'une seule étape doit à la fois réceptionner le stock et comptabiliser la facture fournisseur. Dans ce chemin direct, indiquez un entrepôt sur chaque ligne d'article en stock."},"7":{"title":"Créer un bon de livraison","description":"Maintenant que vous avez du stock, revenez à votre commande client validée et cliquez sur « Créer un bon de livraison ». Indiquez l'entrepôt sur chaque ligne d'article (d'où partent les marchandises), puis validez. Cela sort le stock de l'entrepôt – votre solde de stock diminue.","tip":"Le bon de livraison est le document d'expédition. Il réduit le stock mais ne crée pas de facture. Vous pouvez livrer et facturer séparément."},"8":{"title":"Créer et valider la facture de vente","description":"À partir de la commande client validée, créez une facture de vente. Lorsque vous validez la facture, des écritures comptables sont générées : les Clients (créances) sont débités (le client vous doit de l'argent) et les Produits des ventes crédités (revenu acquis). Si des taxes sont configurées, la TVA collectée est également créditée. Le montant dû indique ce que le client doit encore."},"9":{"title":"Enregistrer les paiements clients","description":"Créez un paiement pour enregistrer l'argent reçu du client. Définissez le type de paiement sur « Receive » (Recevoir), sélectionnez le client, indiquez le montant et affectez-le à la facture de vente. Vous pouvez effectuer des paiements partiels – le montant dû de la facture se met à jour en conséquence. Créez des paiements supplémentaires jusqu'à ce que la facture soit entièrement réglée.","tip":"Les paiements partiels sont courants. Une facture de 10 000 peut être payée 3 000 maintenant et 7 000 plus tard. Chaque paiement réduit le montant dû."},"10":{"title":"Mouvements de stock (inventaire manuel)","description":"Utilisez les mouvements de stock pour les mouvements d'inventaire non liés aux achats ou aux ventes. « Material Receipt » ajoute du stock (soldes d'ouverture, ajustements). « Material Issue » sort du stock (pertes, consommation interne). « Material Transfer » déplace du stock entre entrepôts. Chaque mouvement met à jour le livre de stock avec une valorisation au coût moyen pondéré.","tip":"Pour les marchandises achetées, utilisez des bons de réception plutôt que des mouvements de stock – ils sont liés au bon de commande et offrent une piste d'audit appropriée."},"11":{"title":"Écritures de journal","description":"Les écritures de journal sont des ajustements comptables manuels – charges à payer, corrections, reclassements, soldes d'ouverture. Chaque écriture doit avoir des débits et crédits équilibrés (total débit = total crédit). Utilisez-les lorsqu'aucun autre type de document ne convient."},"12":{"title":"Paiements des salaires","description":"Lambda ERP gère les salaires à l'aide des outils comptables existants. Comptabilisez d'abord la charge salariale : créez une écriture de journal qui débite la Charge salariale et crédite les Salaires à payer pour le montant total de la paie. Payez ensuite les employés : créez une autre écriture de journal (ou un paiement) qui débite les Salaires à payer et crédite votre compte bancaire. Ce processus en deux étapes garde vos comptes exacts – la charge est enregistrée dans la bonne période et la sortie de trésorerie est suivie séparément.","tip":"Vous pouvez demander à l'assistant IA de le faire pour vous : « Comptabilise 15 000 de salaires pour avril » suivi de « Paie les salaires d'avril depuis la banque ». Il créera automatiquement les bonnes écritures de journal."},"13":{"title":"Retours et avoirs","description":"Lorsqu'un client retourne des marchandises ou que vous devez émettre un avoir, créez un retour. Les retours utilisent le même type de document avec des quantités négatives. Ouvrez une facture de vente validée et créez un avoir (retour de facture de vente) – cela inverse les écritures comptables et réduit le montant dû de la facture d'origine. Pour le stock, créez un retour de bon de livraison pour réintégrer les marchandises en entrepôt. Côté achats, créez une note de débit (retour de facture d'achat) pour inverser une facture fournisseur, ou un retour de bon de réception pour renvoyer des marchandises.","tip":"Un avoir est simplement une facture de vente avec is_return=1 et des quantités négatives. La même logique comptable s'applique – les montants négatifs basculent automatiquement du bon côté débit/crédit. Pour un retour de vente complet, vous avez besoin à la fois d'un avoir (financier) et d'un retour de bon de livraison (stock)."},"14":{"title":"Exécuter les rapports","description":"Vérifiez vos comptes. Le Compte de résultat montre les produits face aux charges et le résultat net d'une période. Le Bilan montre votre situation financière (actif = passif + capitaux propres). La Balance âgée clients montre qui vous doit de l'argent et le retard. La Balance âgée fournisseurs montre ce que vous devez aux fournisseurs. La Balance comptable vérifie l'intégrité de la partie double. Le Grand livre montre chaque écriture individuelle. Le Solde de stock montre l'inventaire actuel."},"15":{"title":"Travailler en devises étrangères","description":"Vos comptes sont tenus dans une seule devise de base (choisie à la configuration de la société), mais vous pouvez effectuer des transactions dans n'importe quelle devise. Définissez une devise sur une facture ou un effet – ou attribuez une devise par défaut à un client ou un fournisseur – et le taux de change de cette date est recherché automatiquement et enregistré sur le document. Le document conserve ses montants dans sa propre devise, tandis que le Grand livre comptabilise toujours dans votre devise de base. Lorsque vous encaissez ou payez ultérieurement à un taux différent, le gain ou la perte de change réalisé est comptabilisé automatiquement sur un compte Gain/Perte de change. Vous pouvez même détenir un solde bancaire en devise étrangère et le convertir plus tard au taux de votre banque – l'écart par rapport à sa valeur comptable est alors réalisé. En fin de mois, vous pouvez réévaluer les soldes en devises ouverts au taux de clôture (un gain/perte latent qui s'inverse à la période suivante), et vous pouvez consulter n'importe quel état financier converti dans une autre devise pour l'affichage.","tip":"Le plus simple est de passer par le chat IA – essayez « Crée une facture de vente pour Lumiere Audio en EUR », « Montre-moi le bilan en EUR » ou « Quelle est notre exposition de change latente en fin de mois ? ». Les données de démonstration incluent déjà un client EUR (Lumiere Audio SARL) dont la facture a été encaissée à un taux différent, ainsi qu'une facture fournisseur EUR ouverte – ouvrez le Grand livre pour voir les écritures de change réalisées."}},"setupTitle":"Configurez votre entreprise — guidé par l'IA","setupBadge":"Commencez ici","setupBody":"Dites à l'assistant quel type d'entreprise vous dirigez, et il construit votre plan comptable pour vous — adapté à votre secteur, avec les bons comptes et des valeurs par défaut cohérentes déjà en place. Il explique chaque décision et ne crée quoi que ce soit qu'après votre approbation.","setupSectors":"Adapté aux services, au commerce de détail & POS, à l'hôtellerie-restauration, au commerce de gros & distribution, à l'import/export, à la fabrication et à la construction.","setupGetStarted":"Commencer dans le chat","setupManual":"Vous préférez un formulaire manuel ? Utilisez la configuration classique.","setupManualLink":"Configuration classique","setupPrompt":"Je souhaite configurer mon entreprise. Pouvez-vous me guider ?"}`), Zl = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, Xl = { period: "Période", allTime: "Toute la période", semantics: "Comptes de bilan : solde à la fin de la période. Comptes de résultat : mouvement de la période. Cliquez sur un compte pour son grand livre.", empty: "Aucun compte trouvé. Terminez d'abord la configuration de l'entreprise.", disabled: "désactivé", rootType: { Asset: "Actifs", Liability: "Passifs", Equity: "Capitaux propres", Income: "Produits", Expense: "Charges" } }, ec = { fleetCalendar: "Calendrier de flotte", yard: "Dépôt", machineType: "Type de machine", prev: "Préc.", today: "Aujourd'hui", next: "Suiv.", weeks: "semaines", newBooking: "Nouvelle réservation", reserved: "Réservé", onHire: "En location", machine: "Machine", loadError: "Impossible de charger le calendrier de flotte.", noAssets: "Aucun équipement à afficher. Ajoutez des machines sous Locations → Flotte.", pooledNote: "{{count}} réservation(s) en attente d’attribution", unassigned: "Pool — non attribué", poolWarning: "La capacité est réservée. Aucune machine précise n’est encore attribuée ; attribuez une machine avant la sortie." }, tc = { Unit: "Machine spécifique", Pool: "Pool – machine à affecter", Available: "Disponible", "On Hire": "En location", Out: "Sorti", Maintenance: "Maintenance", Retired: "Retiré", Reserved: "Réservé", Returned: "Retourné", Cancelled: "Annulé", Customer: "Client", Supplier: "Fournisseur" }, nc = { asset: { item_code: "L'article est le TYPE de machine et porte le tarif ; un équipement en est une unité physique. L'article doit avoir is_asset_tracked = 1.", asset_tag: "Plaque ou numéro de série — doit être unique sur tous les équipements.", status: "État actuel de l'unité (pas une période). Les unités retirées quittent le pool.", meter_reading: "Heures de fonctionnement / km." }, reservation: { item_code: "Réservation de pool ('une pelle de 1,7 t') : renseigner Article + Dépôt + Qté. Pour une machine précise, renseigner Équipement.", asset: "Réserver une machine précise. Une réservation d'unité consomme aussi une place du pool Article+Dépôt.", from_datetime: "Début exact — date et heure (p. ex. 14:27). Une date seule signifie 00:00.", to_datetime: "Fin exacte. Les fenêtres sont semi-ouvertes [de, à) : une location finissant à 09:00 et la suivante commençant à 09:00 ne se chevauchent PAS." } }, ac = { label: "Taxe de vente par défaut", none: "Aucune application automatique", hint: "Appliquée aux nouveaux devis, commandes et factures si les taxes ne sont pas explicitement définies. Les documents existants restent inchangés. Cliquez sur Enregistrer pour appliquer.", saveFirst: "Enregistrez d’abord l’entreprise, puis sélectionnez un de ses modèles de taxes de vente.", loadError: "Impossible de charger les modèles de taxes. La sélection enregistrée est conservée.", retry: "Réessayer", unavailable: "Le modèle enregistré n’est pas disponible comme modèle de taxes de vente pour cette entreprise. Vérifiez la sélection.", empty: "Aucun modèle de taxes de vente n’est encore défini pour cette entreprise." }, rc = {
|
|
9240
|
+
proposal: Pl,
|
|
9241
|
+
common: Tl,
|
|
9242
|
+
datePresets: Rl,
|
|
9243
|
+
bankStatements: Bl,
|
|
9244
|
+
bankReconciliation: Il,
|
|
9245
|
+
smartSearch: El,
|
|
9246
|
+
language: Ll,
|
|
9247
|
+
header: Ol,
|
|
9248
|
+
titles: Fl,
|
|
9249
|
+
doctypes: Ml,
|
|
9250
|
+
masters: ql,
|
|
9251
|
+
nav: zl,
|
|
9252
|
+
login: $l,
|
|
9253
|
+
settings: Vl,
|
|
9254
|
+
status: Ul,
|
|
9255
|
+
reports: Kl,
|
|
9256
|
+
masterForm: jl,
|
|
9257
|
+
fields: Wl,
|
|
9258
|
+
tables: Gl,
|
|
9259
|
+
conversions: Hl,
|
|
9260
|
+
dashboard: Ql,
|
|
9261
|
+
chat: Yl,
|
|
9262
|
+
tutorial: Jl,
|
|
9263
|
+
notesMarkup: Zl,
|
|
9264
|
+
coa: Xl,
|
|
9265
|
+
rentals: ec,
|
|
9266
|
+
fieldOptions: tc,
|
|
9267
|
+
hints: nc,
|
|
9268
|
+
companyTax: ac
|
|
9218
9269
|
}, yr = [
|
|
9219
9270
|
{ code: "en", label: "English" },
|
|
9220
9271
|
{ code: "de", label: "Deutsch" },
|
|
9221
9272
|
{ code: "fr", label: "Français" }
|
|
9222
9273
|
], br = "lambda-erp:language";
|
|
9223
|
-
function
|
|
9274
|
+
function sc(e) {
|
|
9224
9275
|
return !!e && yr.some((n) => n.code === e);
|
|
9225
9276
|
}
|
|
9226
|
-
function
|
|
9277
|
+
function ic() {
|
|
9227
9278
|
try {
|
|
9228
9279
|
const e = localStorage.getItem(br);
|
|
9229
|
-
if (
|
|
9280
|
+
if (sc(e)) return e;
|
|
9230
9281
|
} catch {
|
|
9231
9282
|
}
|
|
9232
9283
|
return "en";
|
|
9233
9284
|
}
|
|
9234
|
-
function
|
|
9285
|
+
function oc(e) {
|
|
9235
9286
|
try {
|
|
9236
9287
|
localStorage.setItem(br, e);
|
|
9237
9288
|
} catch {
|
|
@@ -9239,11 +9290,11 @@ function ac(e) {
|
|
|
9239
9290
|
}
|
|
9240
9291
|
Ma.use(Lr).init({
|
|
9241
9292
|
resources: {
|
|
9242
|
-
en: { translation:
|
|
9243
|
-
de: { translation:
|
|
9244
|
-
fr: { translation:
|
|
9293
|
+
en: { translation: Zo },
|
|
9294
|
+
de: { translation: Dl },
|
|
9295
|
+
fr: { translation: rc }
|
|
9245
9296
|
},
|
|
9246
|
-
lng:
|
|
9297
|
+
lng: ic(),
|
|
9247
9298
|
fallbackLng: "en",
|
|
9248
9299
|
// any key missing in de/fr falls back to the English value
|
|
9249
9300
|
interpolation: { escapeValue: !1 },
|
|
@@ -9251,10 +9302,10 @@ Ma.use(Lr).init({
|
|
|
9251
9302
|
react: { useSuspense: !1 }
|
|
9252
9303
|
// resources are bundled synchronously — no Suspense needed
|
|
9253
9304
|
});
|
|
9254
|
-
Ma.on("languageChanged",
|
|
9255
|
-
function
|
|
9305
|
+
Ma.on("languageChanged", oc);
|
|
9306
|
+
function lc({ label: e }) {
|
|
9256
9307
|
var i;
|
|
9257
|
-
const { t: n, i18n: a } =
|
|
9308
|
+
const { t: n, i18n: a } = re(), { setSetting: s } = Zt(), o = ((i = a.language) == null ? void 0 : i.split("-")[0]) ?? "en";
|
|
9258
9309
|
return /* @__PURE__ */ t(
|
|
9259
9310
|
Ge,
|
|
9260
9311
|
{
|
|
@@ -9279,9 +9330,9 @@ const wa = [
|
|
|
9279
9330
|
function at(e) {
|
|
9280
9331
|
return e === 0 ? "$0.00" : e < 0.01 ? `$${e.toFixed(4)}` : `$${e.toFixed(2)}`;
|
|
9281
9332
|
}
|
|
9282
|
-
function
|
|
9333
|
+
function cc({ demoActive: e }) {
|
|
9283
9334
|
var S, x;
|
|
9284
|
-
const { t: n } =
|
|
9335
|
+
const { t: n } = re(), [a, s] = w("1h"), { data: o, isLoading: i, isFetching: l, error: c, refetch: h, dataUpdatedAt: d } = ve({
|
|
9285
9336
|
queryKey: ["demo-spend"],
|
|
9286
9337
|
queryFn: () => F.getDemoSpend(),
|
|
9287
9338
|
// Refresh once a minute — demo spend changes slowly; no need to poll harder.
|
|
@@ -9463,8 +9514,8 @@ function Tt({ label: e, value: n }) {
|
|
|
9463
9514
|
/* @__PURE__ */ t("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-gray-900", children: n })
|
|
9464
9515
|
] });
|
|
9465
9516
|
}
|
|
9466
|
-
function
|
|
9467
|
-
const { t: e } =
|
|
9517
|
+
function dc() {
|
|
9518
|
+
const { t: e } = re(), { user: n } = Ze(), [a, s] = w(""), [o, i] = w(""), [l, c] = w(""), [h, d] = w(""), [g, m] = w(!1), b = ke({
|
|
9468
9519
|
mutationFn: () => F.authChangePassword(a, o),
|
|
9469
9520
|
onSuccess: () => {
|
|
9470
9521
|
m(!0), d(""), s(""), i(""), c(""), setTimeout(() => m(!1), 4e3);
|
|
@@ -9540,8 +9591,8 @@ function ic() {
|
|
|
9540
9591
|
/* @__PURE__ */ t(Y, { type: "submit", disabled: b.isPending || !a || !o || !l, children: b.isPending ? e("settings.changingPassword") : e("settings.changePassword") })
|
|
9541
9592
|
] }) });
|
|
9542
9593
|
}
|
|
9543
|
-
function
|
|
9544
|
-
const { t: e } =
|
|
9594
|
+
function uc() {
|
|
9595
|
+
const { t: e } = re(), { user: n, refreshUser: a } = Ze(), [s, o] = w(""), [i, l] = w(""), [c, h] = w(""), [d, g] = w(!1), m = ke({
|
|
9545
9596
|
mutationFn: () => F.authSetPassword(s),
|
|
9546
9597
|
onSuccess: async () => {
|
|
9547
9598
|
g(!0), h(""), o(""), l(""), await a();
|
|
@@ -9606,8 +9657,8 @@ function oc() {
|
|
|
9606
9657
|
] })
|
|
9607
9658
|
] });
|
|
9608
9659
|
}
|
|
9609
|
-
function
|
|
9610
|
-
const { t: e } =
|
|
9660
|
+
function mc() {
|
|
9661
|
+
const { t: e } = re(), { data: n } = ve({
|
|
9611
9662
|
queryKey: ["auth-setup-status"],
|
|
9612
9663
|
queryFn: () => F.authSetupStatus()
|
|
9613
9664
|
}), { data: a } = ve({
|
|
@@ -9642,8 +9693,8 @@ function lc() {
|
|
|
9642
9693
|
}
|
|
9643
9694
|
const fn = { viewer: 1, manager: 2, admin: 3 };
|
|
9644
9695
|
function vr({ ownRole: e }) {
|
|
9645
|
-
const { t: n } =
|
|
9646
|
-
(
|
|
9696
|
+
const { t: n } = re(), { user: a } = Ze(), s = et(), [o, i] = w(""), [l, c] = w(e in fn ? e : "viewer"), [h, d] = w(null), [g, m] = w(null), b = ["viewer", "manager", "admin"].filter(
|
|
9697
|
+
(L) => fn[L] <= (fn[e] ?? 1)
|
|
9647
9698
|
), v = `${window.location.origin}/api/mcp`, k = h ? `claude mcp add --transport http --scope user lambda-erp ${v} \\
|
|
9648
9699
|
--header "Authorization: Bearer ${h}"` : "", y = h ? `# ~/.codex/config.toml
|
|
9649
9700
|
[mcp_servers.lambda-erp]
|
|
@@ -9653,33 +9704,33 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9653
9704
|
queryFn: () => F.getApiKeys()
|
|
9654
9705
|
}), S = ke({
|
|
9655
9706
|
mutationFn: () => F.createApiKey(o.trim(), l),
|
|
9656
|
-
onSuccess: (
|
|
9657
|
-
d(
|
|
9707
|
+
onSuccess: (L) => {
|
|
9708
|
+
d(L.token), i(""), s.invalidateQueries({ queryKey: ["api-keys"] });
|
|
9658
9709
|
}
|
|
9659
9710
|
}), x = ke({
|
|
9660
|
-
mutationFn: (
|
|
9711
|
+
mutationFn: (L) => F.revokeApiKey(L),
|
|
9661
9712
|
onSuccess: () => s.invalidateQueries({ queryKey: ["api-keys"] })
|
|
9662
9713
|
}), p = ke({
|
|
9663
|
-
mutationFn: (
|
|
9714
|
+
mutationFn: (L) => F.deleteApiKey(L),
|
|
9664
9715
|
onSuccess: () => s.invalidateQueries({ queryKey: ["api-keys"] })
|
|
9665
|
-
}), f = (
|
|
9666
|
-
const
|
|
9716
|
+
}), f = (L) => L.is_mine ?? L.user === (a == null ? void 0 : a.name), B = (L) => L.owner_full_name || L.owner_email || L.user || n("settings.chatApiUnknownUser"), E = fe(() => {
|
|
9717
|
+
const L = /* @__PURE__ */ new Map();
|
|
9667
9718
|
for (const q of A ?? []) {
|
|
9668
9719
|
const Q = q.is_mine ?? q.user === (a == null ? void 0 : a.name), N = Q ? "__me__" : q.user ?? "__unknown__";
|
|
9669
|
-
|
|
9720
|
+
L.has(N) || L.set(N, {
|
|
9670
9721
|
label: Q ? n("settings.chatApiYourKeys") : q.owner_full_name || q.owner_email || q.user || n("settings.chatApiUnknownUser"),
|
|
9671
9722
|
sublabel: Q ? void 0 : q.owner_email ?? void 0,
|
|
9672
9723
|
isMine: Q,
|
|
9673
9724
|
keys: []
|
|
9674
|
-
}),
|
|
9725
|
+
}), L.get(N).keys.push(q);
|
|
9675
9726
|
}
|
|
9676
|
-
return Array.from(
|
|
9727
|
+
return Array.from(L.values()).sort(
|
|
9677
9728
|
(q, Q) => q.isMine ? -1 : Q.isMine ? 1 : q.label.localeCompare(Q.label)
|
|
9678
9729
|
);
|
|
9679
|
-
}, [A, a, n]), J = (
|
|
9680
|
-
q === "revoke" ? x.mutate(
|
|
9681
|
-
}, Z = (
|
|
9682
|
-
f(
|
|
9730
|
+
}, [A, a, n]), J = (L, q) => {
|
|
9731
|
+
q === "revoke" ? x.mutate(L) : p.mutate(L);
|
|
9732
|
+
}, Z = (L, q) => {
|
|
9733
|
+
f(L) ? J(L.id, q) : m({ id: L.id, action: q, owner: B(L), keyName: L.name });
|
|
9683
9734
|
};
|
|
9684
9735
|
return /* @__PURE__ */ r("div", { children: [
|
|
9685
9736
|
h && /* @__PURE__ */ r("div", { className: "mb-3 rounded-lg bg-amber-50 p-3 ring-1 ring-inset ring-amber-200", children: [
|
|
@@ -9690,8 +9741,8 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9690
9741
|
{
|
|
9691
9742
|
className: "mt-2 text-xs font-medium text-brand hover:underline",
|
|
9692
9743
|
onClick: () => {
|
|
9693
|
-
var
|
|
9694
|
-
return (
|
|
9744
|
+
var L;
|
|
9745
|
+
return (L = navigator.clipboard) == null ? void 0 : L.writeText(h);
|
|
9695
9746
|
},
|
|
9696
9747
|
children: n("settings.chatApiCopy")
|
|
9697
9748
|
}
|
|
@@ -9720,12 +9771,12 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9720
9771
|
] })
|
|
9721
9772
|
] }),
|
|
9722
9773
|
e === "admin" && /* @__PURE__ */ t("p", { className: "mb-3 text-xs text-fg-muted", children: n("settings.chatApiAdminAllNote") }),
|
|
9723
|
-
E.length > 0 ? /* @__PURE__ */ t("div", { className: "mb-4 space-y-4", children: E.map((
|
|
9774
|
+
E.length > 0 ? /* @__PURE__ */ t("div", { className: "mb-4 space-y-4", children: E.map((L) => /* @__PURE__ */ r("div", { children: [
|
|
9724
9775
|
/* @__PURE__ */ r("div", { className: "mb-1.5 flex items-baseline gap-2", children: [
|
|
9725
|
-
/* @__PURE__ */ t("span", { className: "text-xs font-semibold text-fg", children:
|
|
9726
|
-
|
|
9776
|
+
/* @__PURE__ */ t("span", { className: "text-xs font-semibold text-fg", children: L.label }),
|
|
9777
|
+
L.isMine ? /* @__PURE__ */ t(Ut, { variant: "default", children: n("settings.chatApiYouBadge") }) : L.sublabel && /* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: L.sublabel })
|
|
9727
9778
|
] }),
|
|
9728
|
-
/* @__PURE__ */ t("ul", { className: "divide-y divide-line rounded-lg ring-1 ring-line", children:
|
|
9779
|
+
/* @__PURE__ */ t("ul", { className: "divide-y divide-line rounded-lg ring-1 ring-line", children: L.keys.map((q) => /* @__PURE__ */ r(
|
|
9729
9780
|
"li",
|
|
9730
9781
|
{
|
|
9731
9782
|
className: "flex items-center justify-between gap-3 px-3 py-2 text-sm",
|
|
@@ -9754,14 +9805,14 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9754
9805
|
},
|
|
9755
9806
|
q.id
|
|
9756
9807
|
)) })
|
|
9757
|
-
] },
|
|
9808
|
+
] }, L.label)) }) : /* @__PURE__ */ t("p", { className: "mb-4 text-xs text-fg-muted", children: n("settings.chatApiNoKeys") }),
|
|
9758
9809
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
9759
9810
|
/* @__PURE__ */ t("div", { className: "w-48", children: /* @__PURE__ */ t(
|
|
9760
9811
|
me,
|
|
9761
9812
|
{
|
|
9762
9813
|
label: n("settings.chatApiName"),
|
|
9763
9814
|
value: o,
|
|
9764
|
-
onChange: (
|
|
9815
|
+
onChange: (L) => i(L.target.value),
|
|
9765
9816
|
placeholder: "lambda-web"
|
|
9766
9817
|
}
|
|
9767
9818
|
) }),
|
|
@@ -9771,7 +9822,7 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9771
9822
|
label: n("settings.chatApiRole"),
|
|
9772
9823
|
options: b,
|
|
9773
9824
|
value: l,
|
|
9774
|
-
onChange: (
|
|
9825
|
+
onChange: (L) => c(L.target.value)
|
|
9775
9826
|
}
|
|
9776
9827
|
),
|
|
9777
9828
|
/* @__PURE__ */ t(Y, { onClick: () => S.mutate(), disabled: !o.trim() || S.isPending, children: n("settings.chatApiCreate") })
|
|
@@ -9788,7 +9839,7 @@ http_headers = { Authorization = "Bearer ${h}" }` : "", { data: A } = ve({
|
|
|
9788
9839
|
className: "w-full max-w-sm rounded-xl border border-line bg-surface p-5 shadow-xl",
|
|
9789
9840
|
role: "dialog",
|
|
9790
9841
|
"aria-modal": "true",
|
|
9791
|
-
onClick: (
|
|
9842
|
+
onClick: (L) => L.stopPropagation(),
|
|
9792
9843
|
children: [
|
|
9793
9844
|
/* @__PURE__ */ t("h3", { className: "text-sm font-semibold text-fg", children: n("settings.chatApiConfirmTitle") }),
|
|
9794
9845
|
/* @__PURE__ */ t("p", { className: "mt-2 text-xs text-fg-muted", children: n(
|
|
@@ -9823,7 +9874,7 @@ function Ca({
|
|
|
9823
9874
|
statusOn: s,
|
|
9824
9875
|
statusOff: o
|
|
9825
9876
|
}) {
|
|
9826
|
-
const { t: i } =
|
|
9877
|
+
const { t: i } = re();
|
|
9827
9878
|
return /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
|
|
9828
9879
|
/* @__PURE__ */ r("div", { children: [
|
|
9829
9880
|
/* @__PURE__ */ t("p", { className: "text-sm text-gray-700", children: a }),
|
|
@@ -9839,14 +9890,14 @@ function Ca({
|
|
|
9839
9890
|
)
|
|
9840
9891
|
] });
|
|
9841
9892
|
}
|
|
9842
|
-
function
|
|
9893
|
+
function pc({
|
|
9843
9894
|
chatEnabled: e,
|
|
9844
9895
|
restEnabled: n,
|
|
9845
9896
|
onToggleChat: a,
|
|
9846
9897
|
onToggleRest: s,
|
|
9847
9898
|
ownRole: o
|
|
9848
9899
|
}) {
|
|
9849
|
-
const { t: i } =
|
|
9900
|
+
const { t: i } = re(), [l, c] = w(null);
|
|
9850
9901
|
return /* @__PURE__ */ r(H, { title: i("settings.apiTitle"), children: [
|
|
9851
9902
|
/* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
9852
9903
|
/* @__PURE__ */ t(
|
|
@@ -9911,8 +9962,8 @@ function cc({
|
|
|
9911
9962
|
)
|
|
9912
9963
|
] });
|
|
9913
9964
|
}
|
|
9914
|
-
function
|
|
9915
|
-
const { user: e } = Ze(), { t: n } =
|
|
9965
|
+
function hc() {
|
|
9966
|
+
const { user: e } = Ze(), { t: n } = re(), a = et(), s = (e == null ? void 0 : e.role) === "admin", { data: o, isLoading: i } = ve({
|
|
9916
9967
|
queryKey: ["settings"],
|
|
9917
9968
|
queryFn: () => F.getSettings()
|
|
9918
9969
|
}), l = ke({
|
|
@@ -9937,11 +9988,11 @@ function dc() {
|
|
|
9937
9988
|
});
|
|
9938
9989
|
return i ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: n("common.loading") }) : /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
9939
9990
|
/* @__PURE__ */ r(H, { title: n("language.title"), children: [
|
|
9940
|
-
/* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ t("div", { className: "w-64", children: /* @__PURE__ */ t(
|
|
9991
|
+
/* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ t("div", { className: "w-64", children: /* @__PURE__ */ t(lc, {}) }) }),
|
|
9941
9992
|
/* @__PURE__ */ t("p", { className: "mt-2 text-xs text-gray-400", children: n("language.help") })
|
|
9942
9993
|
] }),
|
|
9943
|
-
(e == null ? void 0 : e.role) !== "public_manager" && ((e == null ? void 0 : e.has_password) === !1 ? /* @__PURE__ */ t(
|
|
9944
|
-
(e == null ? void 0 : e.role) !== "public_manager" && /* @__PURE__ */ t(
|
|
9994
|
+
(e == null ? void 0 : e.role) !== "public_manager" && ((e == null ? void 0 : e.has_password) === !1 ? /* @__PURE__ */ t(uc, {}) : /* @__PURE__ */ t(dc, {})),
|
|
9995
|
+
(e == null ? void 0 : e.role) !== "public_manager" && /* @__PURE__ */ t(mc, {}),
|
|
9945
9996
|
/* @__PURE__ */ r(H, { title: n("settings.pdfTitle"), children: [
|
|
9946
9997
|
/* @__PURE__ */ t("div", { className: "flex flex-wrap items-end gap-4", children: s ? /* @__PURE__ */ t(
|
|
9947
9998
|
Ge,
|
|
@@ -9990,7 +10041,7 @@ function dc() {
|
|
|
9990
10041
|
)
|
|
9991
10042
|
] }) }),
|
|
9992
10043
|
s && /* @__PURE__ */ t(
|
|
9993
|
-
|
|
10044
|
+
pc,
|
|
9994
10045
|
{
|
|
9995
10046
|
chatEnabled: (o == null ? void 0 : o.chat_api_enabled) === "1",
|
|
9996
10047
|
restEnabled: (o == null ? void 0 : o.rest_api_enabled) === "1",
|
|
@@ -10007,7 +10058,7 @@ function dc() {
|
|
|
10007
10058
|
/* @__PURE__ */ t("p", { className: "mb-3 text-sm text-gray-700", children: n("settings.chatApiPersonal") }),
|
|
10008
10059
|
/* @__PURE__ */ t(vr, { ownRole: (e == null ? void 0 : e.role) ?? "viewer" })
|
|
10009
10060
|
] }),
|
|
10010
|
-
s && /* @__PURE__ */ t(
|
|
10061
|
+
s && /* @__PURE__ */ t(cc, { demoActive: !!(c != null && c.active) }),
|
|
10011
10062
|
s && /* @__PURE__ */ t(H, { title: n("settings.publicTitle"), children: c != null && c.active ? /* @__PURE__ */ r("div", { children: [
|
|
10012
10063
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
|
|
10013
10064
|
/* @__PURE__ */ t("span", { className: "inline-block h-2 w-2 rounded-full bg-green-500" }),
|
|
@@ -10060,26 +10111,26 @@ function dc() {
|
|
|
10060
10111
|
] });
|
|
10061
10112
|
}
|
|
10062
10113
|
const xr = {};
|
|
10063
|
-
function
|
|
10114
|
+
function Kc(e, n) {
|
|
10064
10115
|
xr[e] = n;
|
|
10065
10116
|
}
|
|
10066
|
-
function
|
|
10117
|
+
function gc(e, n) {
|
|
10067
10118
|
return xr[e] ?? n;
|
|
10068
10119
|
}
|
|
10069
|
-
function
|
|
10070
|
-
const e =
|
|
10120
|
+
function fc() {
|
|
10121
|
+
const e = gc("Dashboard", Ls);
|
|
10071
10122
|
return /* @__PURE__ */ t(e, {});
|
|
10072
10123
|
}
|
|
10073
|
-
const
|
|
10074
|
-
{ path: "/login", element: /* @__PURE__ */ t(
|
|
10075
|
-
{ path: "/demo", element: /* @__PURE__ */ t(
|
|
10076
|
-
],
|
|
10077
|
-
{ index: !0, element: /* @__PURE__ */ t(
|
|
10078
|
-
{ path: "setup", element: /* @__PURE__ */ t(
|
|
10079
|
-
{ path: "setup/opening-balances", element: /* @__PURE__ */ t(Ts, { children: /* @__PURE__ */ t(
|
|
10080
|
-
{ path: "accounting/bank-statements", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(
|
|
10081
|
-
{ path: "accounting/bank-reconciliation", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(
|
|
10082
|
-
{ path: "tutorial", element: /* @__PURE__ */ t(
|
|
10124
|
+
const yc = [
|
|
10125
|
+
{ path: "/login", element: /* @__PURE__ */ t(ho, {}) },
|
|
10126
|
+
{ path: "/demo", element: /* @__PURE__ */ t(yo, {}) }
|
|
10127
|
+
], bc = [
|
|
10128
|
+
{ index: !0, element: /* @__PURE__ */ t(fc, {}) },
|
|
10129
|
+
{ path: "setup", element: /* @__PURE__ */ t(Hi, {}) },
|
|
10130
|
+
{ path: "setup/opening-balances", element: /* @__PURE__ */ t(Ts, { children: /* @__PURE__ */ t(bo, {}) }) },
|
|
10131
|
+
{ path: "accounting/bank-statements", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(xo, {}) }) },
|
|
10132
|
+
{ path: "accounting/bank-reconciliation", element: /* @__PURE__ */ t(Xn, { children: /* @__PURE__ */ t(ko, {}) }) },
|
|
10133
|
+
{ path: "tutorial", element: /* @__PURE__ */ t(to, {}) },
|
|
10083
10134
|
{ path: "chat", element: /* @__PURE__ */ t(va, {}) },
|
|
10084
10135
|
{ path: "chat/:sessionId", element: /* @__PURE__ */ t(va, {}) },
|
|
10085
10136
|
// Proposal (Sammelofferte) — a custom builder; the list reuses the generic
|
|
@@ -10096,22 +10147,22 @@ const pc = [
|
|
|
10096
10147
|
{ path: "masters/:type/new", element: /* @__PURE__ */ t(ma, {}) },
|
|
10097
10148
|
{ path: "masters/:type/:name", element: /* @__PURE__ */ t(ma, {}) },
|
|
10098
10149
|
// Reports
|
|
10099
|
-
{ path: "reports/chart-of-accounts", element: /* @__PURE__ */ t(
|
|
10100
|
-
{ path: "reports/trial-balance", element: /* @__PURE__ */ t(
|
|
10101
|
-
{ path: "reports/general-ledger", element: /* @__PURE__ */ t(
|
|
10102
|
-
{ path: "reports/stock-balance", element: /* @__PURE__ */ t(
|
|
10103
|
-
{ path: "reports/profit-and-loss", element: /* @__PURE__ */ t(
|
|
10104
|
-
{ path: "reports/balance-sheet", element: /* @__PURE__ */ t(
|
|
10105
|
-
{ path: "reports/ar-aging", element: /* @__PURE__ */ t(
|
|
10106
|
-
{ path: "reports/ap-aging", element: /* @__PURE__ */ t(
|
|
10107
|
-
{ path: "reports/analytics", element: /* @__PURE__ */ t(
|
|
10150
|
+
{ path: "reports/chart-of-accounts", element: /* @__PURE__ */ t(bi, {}) },
|
|
10151
|
+
{ path: "reports/trial-balance", element: /* @__PURE__ */ t(fi, {}) },
|
|
10152
|
+
{ path: "reports/general-ledger", element: /* @__PURE__ */ t(ki, {}) },
|
|
10153
|
+
{ path: "reports/stock-balance", element: /* @__PURE__ */ t(Ni, {}) },
|
|
10154
|
+
{ path: "reports/profit-and-loss", element: /* @__PURE__ */ t(wi, {}) },
|
|
10155
|
+
{ path: "reports/balance-sheet", element: /* @__PURE__ */ t(Ci, {}) },
|
|
10156
|
+
{ path: "reports/ar-aging", element: /* @__PURE__ */ t(Si, {}) },
|
|
10157
|
+
{ path: "reports/ap-aging", element: /* @__PURE__ */ t(Ai, {}) },
|
|
10158
|
+
{ path: "reports/analytics", element: /* @__PURE__ */ t(Ii, {}) },
|
|
10108
10159
|
// Rentals
|
|
10109
|
-
{ path: "rentals/calendar", element: /* @__PURE__ */ t(
|
|
10160
|
+
{ path: "rentals/calendar", element: /* @__PURE__ */ t(Wi, {}) },
|
|
10110
10161
|
// Admin
|
|
10111
|
-
{ path: "admin/users", element: /* @__PURE__ */ t(
|
|
10112
|
-
{ path: "admin/settings", element: /* @__PURE__ */ t(
|
|
10162
|
+
{ path: "admin/users", element: /* @__PURE__ */ t(No, {}) },
|
|
10163
|
+
{ path: "admin/settings", element: /* @__PURE__ */ t(hc, {}) }
|
|
10113
10164
|
], kr = [], Nr = [];
|
|
10114
|
-
function
|
|
10165
|
+
function vc(e, n) {
|
|
10115
10166
|
(n == null ? void 0 : n.area) === "top" ? kr.push(e) : Nr.push(e);
|
|
10116
10167
|
}
|
|
10117
10168
|
const Sa = (e) => e.index ? "__index__" : e.path ?? "";
|
|
@@ -10123,17 +10174,17 @@ function Aa(e, n) {
|
|
|
10123
10174
|
}
|
|
10124
10175
|
return a;
|
|
10125
10176
|
}
|
|
10126
|
-
function
|
|
10177
|
+
function xc() {
|
|
10127
10178
|
return [
|
|
10128
|
-
...Aa(
|
|
10179
|
+
...Aa(yc, kr),
|
|
10129
10180
|
{
|
|
10130
10181
|
path: "/",
|
|
10131
10182
|
element: /* @__PURE__ */ t(Ps, { children: /* @__PURE__ */ t(_s, {}) }),
|
|
10132
|
-
children: Aa(
|
|
10183
|
+
children: Aa(bc, Nr)
|
|
10133
10184
|
}
|
|
10134
10185
|
];
|
|
10135
10186
|
}
|
|
10136
|
-
function
|
|
10187
|
+
function kc({ slug: e, parentSlug: n, linkField: a }) {
|
|
10137
10188
|
const { name: s = "" } = bt(), o = Ke();
|
|
10138
10189
|
return ce(() => {
|
|
10139
10190
|
let i = !0;
|
|
@@ -10148,7 +10199,7 @@ function yc({ slug: e, parentSlug: n, linkField: a }) {
|
|
|
10148
10199
|
};
|
|
10149
10200
|
}, [e, s, n, a, o]), /* @__PURE__ */ t("div", { className: "p-6 text-sm text-fg-muted", children: "…" });
|
|
10150
10201
|
}
|
|
10151
|
-
async function
|
|
10202
|
+
async function Nc() {
|
|
10152
10203
|
try {
|
|
10153
10204
|
const e = await z(
|
|
10154
10205
|
"/chat-doctypes",
|
|
@@ -10156,33 +10207,33 @@ async function bc() {
|
|
|
10156
10207
|
);
|
|
10157
10208
|
for (const n of e.doctypes || []) {
|
|
10158
10209
|
const a = n.page;
|
|
10159
|
-
a && a.kind === "via" &&
|
|
10210
|
+
a && a.kind === "via" && vc({
|
|
10160
10211
|
path: `app/${n.slug}/:name`,
|
|
10161
|
-
element: /* @__PURE__ */ t(
|
|
10212
|
+
element: /* @__PURE__ */ t(kc, { slug: n.slug, parentSlug: a.parent_slug, linkField: a.link_field })
|
|
10162
10213
|
});
|
|
10163
10214
|
}
|
|
10164
10215
|
} catch {
|
|
10165
10216
|
}
|
|
10166
10217
|
}
|
|
10167
|
-
function
|
|
10218
|
+
function wc() {
|
|
10168
10219
|
return new Rr({
|
|
10169
10220
|
defaultOptions: {
|
|
10170
10221
|
queries: { retry: 1, refetchOnWindowFocus: !1 }
|
|
10171
10222
|
}
|
|
10172
10223
|
});
|
|
10173
10224
|
}
|
|
10174
|
-
async function
|
|
10225
|
+
async function jc(e = {}) {
|
|
10175
10226
|
const n = e.rootElement ?? document.getElementById("root");
|
|
10176
10227
|
if (!n)
|
|
10177
10228
|
throw new Error('bootstrap: no mount element (pass rootElement or add <div id="root">)');
|
|
10178
|
-
const a = e.queryClient ??
|
|
10179
|
-
await
|
|
10180
|
-
const s = Ir(
|
|
10229
|
+
const a = e.queryClient ?? wc();
|
|
10230
|
+
await Nc();
|
|
10231
|
+
const s = Ir(xc());
|
|
10181
10232
|
Pr(n).render(
|
|
10182
10233
|
/* @__PURE__ */ t(Dr, { children: /* @__PURE__ */ t(Tr, { client: a, children: /* @__PURE__ */ t(us, { children: /* @__PURE__ */ t(Er, { router: s }) }) }) })
|
|
10183
10234
|
);
|
|
10184
10235
|
}
|
|
10185
|
-
function
|
|
10236
|
+
function Wc({
|
|
10186
10237
|
onConfirm: e,
|
|
10187
10238
|
children: n,
|
|
10188
10239
|
confirmLabel: a,
|
|
@@ -10195,7 +10246,7 @@ function Vc({
|
|
|
10195
10246
|
size: d = "sm",
|
|
10196
10247
|
cancelSide: g = "left"
|
|
10197
10248
|
}) {
|
|
10198
|
-
const { t: m } =
|
|
10249
|
+
const { t: m } = re(), [b, v] = w(!1), k = pe(void 0);
|
|
10199
10250
|
if (ce(() => {
|
|
10200
10251
|
if (b)
|
|
10201
10252
|
return k.current = setTimeout(() => v(!1), h), () => clearTimeout(k.current);
|
|
@@ -10252,36 +10303,36 @@ export {
|
|
|
10252
10303
|
We as ApiError,
|
|
10253
10304
|
_s as AppShell,
|
|
10254
10305
|
us as AuthProvider,
|
|
10255
|
-
|
|
10306
|
+
Wc as ConfirmButton,
|
|
10256
10307
|
ys as DialogProvider,
|
|
10257
10308
|
nr as DocPager,
|
|
10258
10309
|
yr as SUPPORTED_LANGUAGES,
|
|
10259
10310
|
F as api,
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10311
|
+
jc as bootstrap,
|
|
10312
|
+
xc as buildRoutes,
|
|
10313
|
+
Lc as configureApiBase,
|
|
10314
|
+
qc as configureBranding,
|
|
10315
|
+
wc as createAppQueryClient,
|
|
10265
10316
|
rt as formatDate,
|
|
10266
10317
|
De as formatLocalDate,
|
|
10267
|
-
|
|
10268
|
-
|
|
10318
|
+
$c as getAllDoctypeConfigs,
|
|
10319
|
+
Uc as getAllMasterConfigs,
|
|
10269
10320
|
Qa as getBranding,
|
|
10270
|
-
|
|
10321
|
+
gc as getComponent,
|
|
10271
10322
|
er as getDoctypeConfig,
|
|
10272
10323
|
kn as getListContext,
|
|
10273
10324
|
lr as getMasterConfig,
|
|
10274
10325
|
vs as getNavGroups,
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10326
|
+
ic as getStoredLanguage,
|
|
10327
|
+
Qc as i18n,
|
|
10328
|
+
Kc as registerComponent,
|
|
10329
|
+
zc as registerDoctype,
|
|
10330
|
+
Vc as registerMaster,
|
|
10331
|
+
Fc as registerNavGroup,
|
|
10332
|
+
Mc as registerNavItem,
|
|
10333
|
+
vc as registerRoute,
|
|
10283
10334
|
z as request,
|
|
10284
|
-
|
|
10335
|
+
Oc as setDateLocale,
|
|
10285
10336
|
Xa as setListContext,
|
|
10286
10337
|
Ze as useAuth,
|
|
10287
10338
|
Tn as useConfirm,
|