@lambda-development/erp-core 1.4.12 → 1.4.13
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/i18n/locales/de.json.d.ts +4 -0
- package/dist/i18n/locales/en.json.d.ts +4 -0
- package/dist/i18n/locales/fr.json.d.ts +4 -0
- package/dist/index.js +333 -263
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as t, jsxs as r, Fragment as Ne } from "react/jsx-runtime";
|
|
2
2
|
import { useState as C, useEffect as ie, useCallback as ze, useContext as Gn, createContext as Hn, useRef as me, useMemo as ye, useId as Qn, useLayoutEffect as ma, StrictMode as _s } from "react";
|
|
3
3
|
import { createRoot as Ds } from "react-dom/client";
|
|
4
|
-
import { useQueryClient as
|
|
5
|
-
import { NavLink as yn, useLocation as ut, useNavigate as
|
|
4
|
+
import { useQueryClient as We, useQuery as he, useMutation as xe, QueryClientProvider as Ps, QueryClient as As } from "@tanstack/react-query";
|
|
5
|
+
import { NavLink as yn, useLocation as ut, useNavigate as Ke, Outlet as Ts, Navigate as Ut, Link as Ce, useSearchParams as St, useBlocker as Rs, useParams as vt, createBrowserRouter as Bs, RouterProvider as Ls } from "react-router-dom";
|
|
6
6
|
import { useTranslation as ee, initReactI18next as Is } from "react-i18next";
|
|
7
|
-
import { BookOpen as Es, ShoppingCart as dr, CreditCard as Fs, FileText as bn, Package as ur, BarChart3 as Os, CalendarRange as qs, Database as zs, Settings as Ms, MessageCircle as mr, ChevronDown as Ct, ChevronRight as Tt, Plus as Yn, Trash2 as Jn, LineChart as $s, X as Zn, Bell as Vs, RotateCcw as Us, Check as vn, ArrowLeft as pr, TrendingUp as
|
|
7
|
+
import { BookOpen as Es, ShoppingCart as dr, CreditCard as Fs, FileText as bn, Package as ur, BarChart3 as Os, CalendarRange as qs, Database as zs, Settings as Ms, MessageCircle as mr, ChevronDown as Ct, ChevronRight as Tt, Plus as Yn, Trash2 as Jn, LineChart as $s, X as Zn, Bell as Vs, RotateCcw as Us, Check as vn, ArrowLeft as pr, TrendingUp as Ws, ArrowDownRight as Ks, ArrowUpRight as js, Wallet as Gs, Receipt as pa, ChevronLeft as Hs, Loader2 as ln, Info as Qs, Lock as hr, MessageSquare as Ys, Printer as Js, Search as ha, Filter as Zs, SlidersHorizontal as gr, ChevronUp as fr, ChevronsUpDown as yr, Plug as br, ShieldCheck as vr, FileUp as Xs, CheckCircle2 as zn, AlertTriangle as ei, RefreshCw as xr, Undo2 as ti, Monitor as ni, Terminal as ai, Code2 as ri, Copy as kr, GripVertical as si, EyeOff as ii, Eye as oi, Upload as li } from "lucide-react";
|
|
8
8
|
import { createColumnHelper as Nr, useReactTable as wr, getCoreRowModel as Sr, flexRender as cn } from "@tanstack/react-table";
|
|
9
9
|
import { createPortal as Cr } from "react-dom";
|
|
10
10
|
import { ResponsiveContainer as ci, LineChart as di, CartesianGrid as ga, XAxis as fa, YAxis as ya, Tooltip as Sn, Legend as ba, Line as ui, PieChart as mi, Pie as pi, Cell as hi, BarChart as gi, Bar as fi } from "recharts";
|
|
@@ -473,7 +473,7 @@ function ht(e) {
|
|
|
473
473
|
return Number.isNaN(a) ? 0 : a;
|
|
474
474
|
}
|
|
475
475
|
function ki({ children: e }) {
|
|
476
|
-
const n =
|
|
476
|
+
const n = We(), [a, s] = C([]), [o, i] = C({}), [l, c] = C({}), [h, u] = C({}), [g, d] = C({}), [v, k] = C({}), [x, p] = C({}), [w, b] = C({}), [y, m] = C(null), [f, D] = C("connecting"), [N, A] = C(0), T = me(null), _ = me(null), V = me(/* @__PURE__ */ new Map()), K = me(null), I = me({}), F = me({}), G = me(null);
|
|
477
477
|
function O(B) {
|
|
478
478
|
for (const M of V.current.values())
|
|
479
479
|
M.reject(new Error(B));
|
|
@@ -797,12 +797,12 @@ function ki({ children: e }) {
|
|
|
797
797
|
};
|
|
798
798
|
}, []);
|
|
799
799
|
async function be() {
|
|
800
|
-
if (
|
|
801
|
-
return
|
|
800
|
+
if (K.current)
|
|
801
|
+
return K.current;
|
|
802
802
|
const B = Z("create_session", {}, "session_created").then((M) => M.session).finally(() => {
|
|
803
|
-
|
|
803
|
+
K.current === B && (K.current = null);
|
|
804
804
|
});
|
|
805
|
-
return
|
|
805
|
+
return K.current = B, B;
|
|
806
806
|
}
|
|
807
807
|
async function we(B) {
|
|
808
808
|
S(B, "running"), L(B, null);
|
|
@@ -937,7 +937,7 @@ function Xe(e, n = 2) {
|
|
|
937
937
|
}).format(e ?? 0);
|
|
938
938
|
}
|
|
939
939
|
let ta;
|
|
940
|
-
function
|
|
940
|
+
function Wu(e) {
|
|
941
941
|
ta = e;
|
|
942
942
|
}
|
|
943
943
|
function Ee(e = /* @__PURE__ */ new Date()) {
|
|
@@ -981,7 +981,7 @@ const Ni = {
|
|
|
981
981
|
md: "h-10 px-4 text-sm",
|
|
982
982
|
lg: "h-11 px-5 text-sm"
|
|
983
983
|
};
|
|
984
|
-
function
|
|
984
|
+
function W({
|
|
985
985
|
variant: e = "primary",
|
|
986
986
|
size: n = "md",
|
|
987
987
|
disabled: a,
|
|
@@ -1102,8 +1102,8 @@ function Si({ children: e }) {
|
|
|
1102
1102
|
}
|
|
1103
1103
|
),
|
|
1104
1104
|
/* @__PURE__ */ r("div", { className: "mt-5 flex justify-end gap-2", children: [
|
|
1105
|
-
/* @__PURE__ */ t(
|
|
1106
|
-
/* @__PURE__ */ t(
|
|
1105
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: d, children: a.opts.cancelLabel ?? n("common.cancel", { defaultValue: "Cancel" }) }),
|
|
1106
|
+
/* @__PURE__ */ t(W, { variant: a.opts.danger ? "danger" : "primary", onClick: g, children: a.opts.confirmLabel ?? n("common.ok", { defaultValue: "OK" }) })
|
|
1107
1107
|
] })
|
|
1108
1108
|
] })
|
|
1109
1109
|
]
|
|
@@ -1215,7 +1215,8 @@ const Nt = [
|
|
|
1215
1215
|
{ label: "Item", path: "/masters/item" },
|
|
1216
1216
|
{ label: "Warehouse", path: "/masters/warehouse" },
|
|
1217
1217
|
{ label: "Storage Location", path: "/masters/storage-location" },
|
|
1218
|
-
{ label: "Batch", path: "/masters/batch" }
|
|
1218
|
+
{ label: "Batch", path: "/masters/batch" },
|
|
1219
|
+
{ label: "Serial Number", path: "/masters/serial-no" }
|
|
1219
1220
|
]
|
|
1220
1221
|
},
|
|
1221
1222
|
{
|
|
@@ -1237,7 +1238,7 @@ const Nt = [
|
|
|
1237
1238
|
function Ci() {
|
|
1238
1239
|
return Nt;
|
|
1239
1240
|
}
|
|
1240
|
-
function
|
|
1241
|
+
function Ku(e, n) {
|
|
1241
1242
|
const a = Nt.findIndex((s) => s.label === e.label);
|
|
1242
1243
|
if (a >= 0) {
|
|
1243
1244
|
Nt[a] = e;
|
|
@@ -1291,7 +1292,7 @@ function Ai(e) {
|
|
|
1291
1292
|
}
|
|
1292
1293
|
const Ht = ["my-settings"];
|
|
1293
1294
|
function Bt() {
|
|
1294
|
-
const e =
|
|
1295
|
+
const e = We(), { user: n } = Ye(), { data: a } = he({
|
|
1295
1296
|
queryKey: Ht,
|
|
1296
1297
|
queryFn: () => q.getMySettings(),
|
|
1297
1298
|
enabled: !!n,
|
|
@@ -1355,7 +1356,7 @@ const sa = {
|
|
|
1355
1356
|
"Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
|
|
1356
1357
|
};
|
|
1357
1358
|
function Ti() {
|
|
1358
|
-
const [e, n] = ra("chats"), a = ut(), s =
|
|
1359
|
+
const [e, n] = ra("chats"), a = ut(), s = Ke(), { t: o } = ee(), { sessions: i, createSession: l, deleteSession: c } = _t(), h = async () => {
|
|
1359
1360
|
try {
|
|
1360
1361
|
const g = await l();
|
|
1361
1362
|
s(`/chat/${g.id}`);
|
|
@@ -1433,7 +1434,7 @@ function ia() {
|
|
|
1433
1434
|
);
|
|
1434
1435
|
}
|
|
1435
1436
|
function Ri() {
|
|
1436
|
-
const [e, n, a] = ra("custom-analytics"), s = ut(), o =
|
|
1437
|
+
const [e, n, a] = ra("custom-analytics"), s = ut(), o = Ke(), i = We(), { t: l } = ee(), { navigationFlash: c, sessions: h, createSession: u } = _t(), g = (c == null ? void 0 : c.group) === "Custom Analytics", d = sa["Custom Analytics"], { data: v } = he({
|
|
1437
1438
|
queryKey: ["runtime-drafts"],
|
|
1438
1439
|
queryFn: () => q.listRuntimeDrafts(),
|
|
1439
1440
|
staleTime: 3e4
|
|
@@ -1785,7 +1786,7 @@ function Un({ value: e, recipients: n, onChange: a, placeholder: s, className: o
|
|
|
1785
1786
|
}
|
|
1786
1787
|
function Vr({ identity: e, action: n = $t, onOpenRecord: a } = {}) {
|
|
1787
1788
|
var f, D, N, A, T;
|
|
1788
|
-
const { user: s } = Ye(), o = e ?? s, { t: i } = ee(), l =
|
|
1789
|
+
const { user: s } = Ye(), o = e ?? s, { t: i } = ee(), l = Ke(), c = We(), h = me(null), u = Qn(), [g, d] = C(!1), [v, k] = C("open"), [x, p] = C(0), w = !!o && o.role !== "public_manager", b = he({
|
|
1789
1790
|
queryKey: ["mentions", o == null ? void 0 : o.name, v, x],
|
|
1790
1791
|
queryFn: () => n("list_my_mentions", { view: v, offset: x, limit: 25 }),
|
|
1791
1792
|
enabled: w,
|
|
@@ -1795,8 +1796,8 @@ function Vr({ identity: e, action: n = $t, onOpenRecord: a } = {}) {
|
|
|
1795
1796
|
onSuccess: () => c.invalidateQueries({ queryKey: ["mentions", o == null ? void 0 : o.name] })
|
|
1796
1797
|
});
|
|
1797
1798
|
ie(() => {
|
|
1798
|
-
var _, V,
|
|
1799
|
-
g && !((_ = h.current) != null && _.open) && ((V = h.current) == null || V.showModal()), !g && ((
|
|
1799
|
+
var _, V, K, I;
|
|
1800
|
+
g && !((_ = h.current) != null && _.open) && ((V = h.current) == null || V.showModal()), !g && ((K = h.current) != null && K.open) && ((I = h.current) == null || I.close());
|
|
1800
1801
|
}, [g]);
|
|
1801
1802
|
const m = async (_) => {
|
|
1802
1803
|
try {
|
|
@@ -1940,7 +1941,7 @@ function qi() {
|
|
|
1940
1941
|
return /* @__PURE__ */ t(Si, { children: /* @__PURE__ */ t(ki, { children: /* @__PURE__ */ t(zi, {}) }) });
|
|
1941
1942
|
}
|
|
1942
1943
|
function zi() {
|
|
1943
|
-
const e = ut(), { pathname: n } = e, a =
|
|
1944
|
+
const e = ut(), { pathname: n } = e, a = Ke(), { user: s, logout: o } = Ye(), { navigationFlash: i } = _t(), { t: l, i18n: c } = ee(), { settings: h } = Bt();
|
|
1944
1945
|
ie(() => {
|
|
1945
1946
|
const b = h.language;
|
|
1946
1947
|
b && b !== (c.language || "").split("-")[0] && c.changeLanguage(b);
|
|
@@ -2133,15 +2134,15 @@ function Yt() {
|
|
|
2133
2134
|
/* @__PURE__ */ t("div", { className: "h-9 w-9 shrink-0 animate-pulse rounded-lg bg-surface-subtle" })
|
|
2134
2135
|
] }) });
|
|
2135
2136
|
}
|
|
2136
|
-
const
|
|
2137
|
+
const Wi = {
|
|
2137
2138
|
"Sales Invoice": pa,
|
|
2138
2139
|
"Purchase Invoice": pa,
|
|
2139
2140
|
"Payment Entry": Gs,
|
|
2140
2141
|
"Sales Order": dr,
|
|
2141
2142
|
Quotation: bn
|
|
2142
2143
|
};
|
|
2143
|
-
function
|
|
2144
|
-
const { t: n } = ee(), a = e.doctype ?? e.type ?? "Document", s = e.creation ?? e.date, o =
|
|
2144
|
+
function Ki({ doc: e }) {
|
|
2145
|
+
const { t: n } = ee(), a = e.doctype ?? e.type ?? "Document", s = e.creation ?? e.date, o = Wi[a] ?? bn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(e.name)}`;
|
|
2145
2146
|
return /* @__PURE__ */ r(
|
|
2146
2147
|
Ce,
|
|
2147
2148
|
{
|
|
@@ -2189,7 +2190,7 @@ function ji() {
|
|
|
2189
2190
|
{
|
|
2190
2191
|
title: e("dashboard.totalRevenue"),
|
|
2191
2192
|
value: n == null ? void 0 : n.total_revenue,
|
|
2192
|
-
icon:
|
|
2193
|
+
icon: Ws,
|
|
2193
2194
|
tone: "text-emerald-600 bg-emerald-500/10"
|
|
2194
2195
|
}
|
|
2195
2196
|
),
|
|
@@ -2198,7 +2199,7 @@ function ji() {
|
|
|
2198
2199
|
{
|
|
2199
2200
|
title: e("dashboard.outstandingReceivable"),
|
|
2200
2201
|
value: n == null ? void 0 : n.outstanding_receivable,
|
|
2201
|
-
icon:
|
|
2202
|
+
icon: Ks,
|
|
2202
2203
|
tone: "text-sky-600 bg-sky-500/10"
|
|
2203
2204
|
}
|
|
2204
2205
|
),
|
|
@@ -2227,7 +2228,7 @@ function ji() {
|
|
|
2227
2228
|
/* @__PURE__ */ t(Et, {}),
|
|
2228
2229
|
/* @__PURE__ */ t(Et, {}),
|
|
2229
2230
|
/* @__PURE__ */ t(Et, {})
|
|
2230
|
-
] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ t(
|
|
2231
|
+
] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, o) => /* @__PURE__ */ t(Ki, { doc: s }, `${s.name}-${o}`)) : /* @__PURE__ */ t("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: e("dashboard.noRecentDocuments") }) }) })
|
|
2231
2232
|
] });
|
|
2232
2233
|
}
|
|
2233
2234
|
function Gi(e, n) {
|
|
@@ -2489,6 +2490,12 @@ const yt = [
|
|
|
2489
2490
|
...yt,
|
|
2490
2491
|
{ name: "income_account", label: "Income Account", type: "link", linkDoctype: "account" },
|
|
2491
2492
|
{ name: "location", label: "Storage Location", type: "text", suggest: "location", hint: "Only when this invoice also moves stock (Update Stock) and the warehouse uses storage locations." },
|
|
2493
|
+
{
|
|
2494
|
+
name: "serial_no",
|
|
2495
|
+
label: "Serial Numbers",
|
|
2496
|
+
type: "text",
|
|
2497
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
2498
|
+
},
|
|
2492
2499
|
{ name: "batch_no", label: "Batch", type: "text", suggest: "batch", hint: "Only when this invoice also moves stock (Update Stock) and the item is batch-tracked." },
|
|
2493
2500
|
{ name: "shelf_life_exception", label: "Shelf Life Exception", type: "text", hint: "Only when the batch has less shelf life left than the item requires: the approved reason for shipping it anyway." }
|
|
2494
2501
|
], lineDeductions: !0 },
|
|
@@ -2608,6 +2615,12 @@ const yt = [
|
|
|
2608
2615
|
suggest: "location",
|
|
2609
2616
|
hint: "Required when the warehouse uses storage locations: the place the goods are taken from or put."
|
|
2610
2617
|
},
|
|
2618
|
+
{
|
|
2619
|
+
name: "serial_no",
|
|
2620
|
+
label: "Serial Numbers",
|
|
2621
|
+
type: "text",
|
|
2622
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
2623
|
+
},
|
|
2611
2624
|
{
|
|
2612
2625
|
name: "batch_no",
|
|
2613
2626
|
label: "Batch",
|
|
@@ -2768,9 +2781,9 @@ const yt = [
|
|
|
2768
2781
|
name: "stock_entry_type",
|
|
2769
2782
|
label: "Type",
|
|
2770
2783
|
type: "select",
|
|
2771
|
-
options: ["Material Receipt", "Material Issue", "Material Transfer", "Opening Stock", "Batch Assignment"],
|
|
2784
|
+
options: ["Material Receipt", "Material Issue", "Material Transfer", "Opening Stock", "Batch Assignment", "Serial Assignment"],
|
|
2772
2785
|
required: !0,
|
|
2773
|
-
hint: "Opening Stock is for one-time initial inventory (contra: Opening Balance Equity). Material Receipt/Issue are for adjustments and write-offs (contra: Stock Adjustment). Batch Assignment gives stock without a batch its batch, in place. A Material Transfer with the same warehouse on both sides moves stock between storage locations."
|
|
2786
|
+
hint: "Opening Stock is for one-time initial inventory (contra: Opening Balance Equity). Material Receipt/Issue are for adjustments and write-offs (contra: Stock Adjustment). Batch Assignment gives stock without a batch its batch, in place. Serial Assignment gives units without a serial number theirs, in place. A Material Transfer with the same warehouse on both sides moves stock between storage locations."
|
|
2774
2787
|
},
|
|
2775
2788
|
{ name: "posting_date", label: "Posting Date", type: "date", required: !0 },
|
|
2776
2789
|
{ name: "company", label: "Company", type: "link", linkDoctype: "company", required: !0 },
|
|
@@ -2805,6 +2818,12 @@ const yt = [
|
|
|
2805
2818
|
suggestWarehouse: ["t_warehouse"],
|
|
2806
2819
|
hint: "The storage location the goods are put into (warehouses with storage locations)."
|
|
2807
2820
|
},
|
|
2821
|
+
{
|
|
2822
|
+
name: "serial_no",
|
|
2823
|
+
label: "Serial Numbers",
|
|
2824
|
+
type: "text",
|
|
2825
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
2826
|
+
},
|
|
2808
2827
|
{
|
|
2809
2828
|
name: "batch_no",
|
|
2810
2829
|
label: "Batch",
|
|
@@ -2874,6 +2893,12 @@ const yt = [
|
|
|
2874
2893
|
suggest: "location",
|
|
2875
2894
|
hint: "Required when the warehouse uses storage locations: the place the goods are taken from or put."
|
|
2876
2895
|
},
|
|
2896
|
+
{
|
|
2897
|
+
name: "serial_no",
|
|
2898
|
+
label: "Serial Numbers",
|
|
2899
|
+
type: "text",
|
|
2900
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
2901
|
+
},
|
|
2877
2902
|
{
|
|
2878
2903
|
name: "batch_no",
|
|
2879
2904
|
label: "Batch",
|
|
@@ -2931,6 +2956,12 @@ const yt = [
|
|
|
2931
2956
|
suggest: "location",
|
|
2932
2957
|
hint: "Required when the warehouse uses storage locations: the place the goods are taken from or put."
|
|
2933
2958
|
},
|
|
2959
|
+
{
|
|
2960
|
+
name: "serial_no",
|
|
2961
|
+
label: "Serial Numbers",
|
|
2962
|
+
type: "text",
|
|
2963
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
2964
|
+
},
|
|
2934
2965
|
{
|
|
2935
2966
|
name: "batch_no",
|
|
2936
2967
|
label: "Batch",
|
|
@@ -3002,6 +3033,12 @@ const yt = [
|
|
|
3002
3033
|
suggest: "location",
|
|
3003
3034
|
hint: "Required when the warehouse uses storage locations: the place the goods are taken from or put."
|
|
3004
3035
|
},
|
|
3036
|
+
{
|
|
3037
|
+
name: "serial_no",
|
|
3038
|
+
label: "Serial Numbers",
|
|
3039
|
+
type: "text",
|
|
3040
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
3041
|
+
},
|
|
3005
3042
|
{
|
|
3006
3043
|
name: "batch_no",
|
|
3007
3044
|
label: "Batch",
|
|
@@ -3302,6 +3339,12 @@ const yt = [
|
|
|
3302
3339
|
{ name: "location", label: "Storage Location", type: "text", suggest: "location" },
|
|
3303
3340
|
{ name: "item_code", label: "Item", type: "link", linkDoctype: "item", required: !0 },
|
|
3304
3341
|
{ name: "item_name", label: "Item Name", type: "text", readOnly: !0 },
|
|
3342
|
+
{
|
|
3343
|
+
name: "serial_no",
|
|
3344
|
+
label: "Serial Numbers",
|
|
3345
|
+
type: "text",
|
|
3346
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
3347
|
+
},
|
|
3305
3348
|
{ name: "batch_no", label: "Batch", type: "text", suggest: "batch" },
|
|
3306
3349
|
{ name: "expiry_date", label: "Expiry Date", type: "date", hint: "Needed for a batch the system does not know yet." },
|
|
3307
3350
|
{ name: "system_qty", label: "System Qty", type: "number", readOnly: !0 },
|
|
@@ -3376,6 +3419,12 @@ const yt = [
|
|
|
3376
3419
|
{ name: "item_code", label: "Item", type: "link", linkDoctype: "item", required: !0 },
|
|
3377
3420
|
{ name: "item_name", label: "Item Name", type: "text", readOnly: !0 },
|
|
3378
3421
|
{ name: "qty", label: "Qty", type: "number", required: !0 },
|
|
3422
|
+
{
|
|
3423
|
+
name: "serial_no",
|
|
3424
|
+
label: "Serial Numbers",
|
|
3425
|
+
type: "text",
|
|
3426
|
+
hint: "For serial-tracked items: one number per unit, as many as the quantity, separated by commas."
|
|
3427
|
+
},
|
|
3379
3428
|
{ name: "batch_no", label: "Batch", type: "text", suggest: "batch", hint: "The batch the customer reported. It must lie in this consignment warehouse." },
|
|
3380
3429
|
{ name: "location", label: "Storage Location", type: "text", suggest: "location" },
|
|
3381
3430
|
{ name: "rate", label: "Rate", type: "currency", default: null, hint: "Leave blank to bill the customer's price." }
|
|
@@ -3562,7 +3611,7 @@ function Hu(e) {
|
|
|
3562
3611
|
function Qu() {
|
|
3563
3612
|
return Object.values(la);
|
|
3564
3613
|
}
|
|
3565
|
-
function
|
|
3614
|
+
function Wr({ doctype: e, name: n }) {
|
|
3566
3615
|
var u;
|
|
3567
3616
|
const { t: a } = ee(), [s, o] = C(null), [i, l] = C(!1), { data: c } = he({
|
|
3568
3617
|
queryKey: ["document-fields", e],
|
|
@@ -3583,7 +3632,7 @@ function Kr({ doctype: e, name: n }) {
|
|
|
3583
3632
|
}
|
|
3584
3633
|
}
|
|
3585
3634
|
return /* @__PURE__ */ r(Ne, { children: [
|
|
3586
|
-
/* @__PURE__ */ t(
|
|
3635
|
+
/* @__PURE__ */ t(W, { variant: "secondary", disabled: i, onClick: h, children: a(i ? "common.loading" : "common.pdf") }),
|
|
3587
3636
|
s && /* @__PURE__ */ t("span", { role: "alert", className: "text-sm text-red-600", children: s })
|
|
3588
3637
|
] });
|
|
3589
3638
|
}
|
|
@@ -3646,8 +3695,8 @@ function Qi({
|
|
|
3646
3695
|
g.length > 0 && /* @__PURE__ */ t("datalist", { id: c, children: g.map((d) => /* @__PURE__ */ t("option", { value: d.value, label: d.label, children: d.label }, d.value)) })
|
|
3647
3696
|
] });
|
|
3648
3697
|
}
|
|
3649
|
-
function
|
|
3650
|
-
const o =
|
|
3698
|
+
function Kr({ slug: e, name: n, onSave: a, kind: s = "document" }) {
|
|
3699
|
+
const o = Ke(), i = s === "master", l = Vn(i ? `master:${e}` : e), c = i ? `/masters/${e}` : `/app/${e}`, h = ut(), u = Ar(h.state), g = (p) => o(`${c}/${p}`, { state: u }), { data: d } = he({
|
|
3651
3700
|
queryKey: ["adjacent", s, e, n, (l == null ? void 0 : l.filters) ?? null],
|
|
3652
3701
|
queryFn: () => i ? q.adjacentMaster(e, n, l == null ? void 0 : l.filters) : q.adjacentDocument(e, n, l == null ? void 0 : l.filters)
|
|
3653
3702
|
}), v = (d == null ? void 0 : d.prev) ?? null, k = (d == null ? void 0 : d.next) ?? null;
|
|
@@ -3688,7 +3737,7 @@ function Wr({ slug: e, name: n, onSave: a, kind: s = "document" }) {
|
|
|
3688
3737
|
)
|
|
3689
3738
|
] });
|
|
3690
3739
|
}
|
|
3691
|
-
function
|
|
3740
|
+
function Kt({
|
|
3692
3741
|
dirty: e,
|
|
3693
3742
|
saving: n,
|
|
3694
3743
|
isNew: a = !1,
|
|
@@ -3696,7 +3745,7 @@ function Wt({
|
|
|
3696
3745
|
onClick: o
|
|
3697
3746
|
}) {
|
|
3698
3747
|
const { t: i } = ee();
|
|
3699
|
-
return n ? /* @__PURE__ */ r(
|
|
3748
|
+
return n ? /* @__PURE__ */ r(W, { disabled: !0, children: [
|
|
3700
3749
|
/* @__PURE__ */ t(ln, { className: "h-4 w-4 animate-spin" }),
|
|
3701
3750
|
i("common.saving")
|
|
3702
3751
|
] }) : !a && !e ? /* @__PURE__ */ r(
|
|
@@ -3709,7 +3758,7 @@ function Wt({
|
|
|
3709
3758
|
i("common.saved")
|
|
3710
3759
|
]
|
|
3711
3760
|
}
|
|
3712
|
-
) : /* @__PURE__ */ t(
|
|
3761
|
+
) : /* @__PURE__ */ t(W, { onClick: o, disabled: s, children: i("common.save") });
|
|
3713
3762
|
}
|
|
3714
3763
|
function jt() {
|
|
3715
3764
|
const { t: e } = ee(), n = Rt(), [a, s] = C(!1), o = me(!1), i = ze(() => {
|
|
@@ -3951,7 +4000,7 @@ function eo({ text: e }) {
|
|
|
3951
4000
|
}
|
|
3952
4001
|
function Qr({ recordType: e, recordId: n }) {
|
|
3953
4002
|
var N, A, T;
|
|
3954
|
-
const { t: a } = ee(), { enabled: s, canWrite: o } = jr(), i =
|
|
4003
|
+
const { t: a } = ee(), { enabled: s, canWrite: o } = jr(), i = We(), { hash: l } = ut(), [c, h] = C(sn), [u, g] = C(!1), [d, v] = C({ body: "", recipients: [], requestId: crypto.randomUUID() }), [k, x] = C(null), p = Gr(e, n, c), w = () => i.invalidateQueries({ queryKey: ["record-notes", e, n] }), b = xe({
|
|
3955
4004
|
mutationFn: () => $t("add_record_note", {
|
|
3956
4005
|
doctype: e,
|
|
3957
4006
|
record_id: n,
|
|
@@ -3988,7 +4037,7 @@ function Qr({ recordType: e, recordId: n }) {
|
|
|
3988
4037
|
a("recordNotes.private")
|
|
3989
4038
|
] })
|
|
3990
4039
|
] }),
|
|
3991
|
-
o && !u && /* @__PURE__ */ t(
|
|
4040
|
+
o && !u && /* @__PURE__ */ t(W, { variant: "secondary", size: "sm", onClick: () => g(!0), children: a("recordNotes.add") })
|
|
3992
4041
|
] }),
|
|
3993
4042
|
D && /* @__PURE__ */ t("p", { role: "alert", className: "mb-3 rounded-lg bg-rose-50 p-3 text-sm text-rose-700 ring-1 ring-rose-200", children: D.message }),
|
|
3994
4043
|
u && /* @__PURE__ */ r("div", { className: "mb-5 space-y-2", children: [
|
|
@@ -4000,13 +4049,13 @@ function Qr({ recordType: e, recordId: n }) {
|
|
|
4000
4049
|
className: _a,
|
|
4001
4050
|
placeholder: a("recordNotes.placeholder"),
|
|
4002
4051
|
disabled: b.isPending,
|
|
4003
|
-
onChange: (_, V) => v((
|
|
4052
|
+
onChange: (_, V) => v((K) => ({ ...K, body: _, recipients: V }))
|
|
4004
4053
|
}
|
|
4005
4054
|
),
|
|
4006
4055
|
/* @__PURE__ */ r("div", { className: "flex gap-2", children: [
|
|
4007
|
-
/* @__PURE__ */ t(
|
|
4056
|
+
/* @__PURE__ */ t(W, { size: "sm", disabled: !d.body.trim() || b.isPending, onClick: () => b.mutate(), children: a("recordNotes.save") }),
|
|
4008
4057
|
/* @__PURE__ */ t(
|
|
4009
|
-
|
|
4058
|
+
W,
|
|
4010
4059
|
{
|
|
4011
4060
|
size: "sm",
|
|
4012
4061
|
variant: "ghost",
|
|
@@ -4068,12 +4117,12 @@ function Qr({ recordType: e, recordId: n }) {
|
|
|
4068
4117
|
recipients: k.recipients,
|
|
4069
4118
|
className: _a,
|
|
4070
4119
|
disabled: y.isPending,
|
|
4071
|
-
onChange: (V,
|
|
4120
|
+
onChange: (V, K) => x({ ...k, body: V, recipients: K })
|
|
4072
4121
|
}
|
|
4073
4122
|
),
|
|
4074
4123
|
/* @__PURE__ */ r("div", { className: "flex gap-2", children: [
|
|
4075
4124
|
/* @__PURE__ */ t(
|
|
4076
|
-
|
|
4125
|
+
W,
|
|
4077
4126
|
{
|
|
4078
4127
|
size: "sm",
|
|
4079
4128
|
disabled: !k.body.trim() || y.isPending,
|
|
@@ -4081,14 +4130,14 @@ function Qr({ recordType: e, recordId: n }) {
|
|
|
4081
4130
|
children: a("recordNotes.save")
|
|
4082
4131
|
}
|
|
4083
4132
|
),
|
|
4084
|
-
/* @__PURE__ */ t(
|
|
4133
|
+
/* @__PURE__ */ t(W, { size: "sm", variant: "ghost", disabled: y.isPending, onClick: () => x(null), children: a("common.cancel") })
|
|
4085
4134
|
] })
|
|
4086
4135
|
] }) : /* @__PURE__ */ t(eo, { text: _.body })
|
|
4087
4136
|
]
|
|
4088
4137
|
},
|
|
4089
4138
|
_.id
|
|
4090
4139
|
)) }),
|
|
4091
|
-
((T = p.data) == null ? void 0 : T.has_more) && /* @__PURE__ */ t(
|
|
4140
|
+
((T = p.data) == null ? void 0 : T.has_more) && /* @__PURE__ */ t(W, { variant: "ghost", size: "sm", className: "mt-3", onClick: () => h((_) => _ + sn), children: a("recordNotes.older") })
|
|
4092
4141
|
] });
|
|
4093
4142
|
}
|
|
4094
4143
|
function to(e, n = !0) {
|
|
@@ -4100,7 +4149,7 @@ function to(e, n = !0) {
|
|
|
4100
4149
|
});
|
|
4101
4150
|
return (a == null ? void 0 : a.currencies) ?? [];
|
|
4102
4151
|
}
|
|
4103
|
-
const
|
|
4152
|
+
const Wt = [
|
|
4104
4153
|
{ slug: "quotation", doctype: "Quotation", texts: !0 },
|
|
4105
4154
|
{ slug: "sales-order", doctype: "Sales Order", texts: !0 },
|
|
4106
4155
|
{ slug: "sales-invoice", doctype: "Sales Invoice", texts: !0 },
|
|
@@ -4110,7 +4159,7 @@ const Kt = [
|
|
|
4110
4159
|
{ slug: "reservation", doctype: "Reservation", texts: !1 }
|
|
4111
4160
|
];
|
|
4112
4161
|
function un(e) {
|
|
4113
|
-
return
|
|
4162
|
+
return Wt.find((n) => n.slug === e || n.doctype === e);
|
|
4114
4163
|
}
|
|
4115
4164
|
const wt = ["pdf-templates"];
|
|
4116
4165
|
function mn(e = !1, n = !0, a) {
|
|
@@ -4148,7 +4197,7 @@ const ao = /* @__PURE__ */ new Set([
|
|
|
4148
4197
|
"item",
|
|
4149
4198
|
"warehouse"
|
|
4150
4199
|
]);
|
|
4151
|
-
function
|
|
4200
|
+
function Wn(e, n) {
|
|
4152
4201
|
return !e || !n ? null : ao.has(e) ? `/masters/${e}/${encodeURIComponent(n)}` : e === "price-list" ? `/app/price-list/${encodeURIComponent(n)}` : e === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
|
|
4153
4202
|
}
|
|
4154
4203
|
function Da() {
|
|
@@ -4255,14 +4304,14 @@ function Vt({
|
|
|
4255
4304
|
};
|
|
4256
4305
|
if (g) {
|
|
4257
4306
|
if (e.type === "link" && n) {
|
|
4258
|
-
const V = e.linkDoctypeField && o ? String(o[e.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : e.linkDoctype,
|
|
4259
|
-
if (
|
|
4307
|
+
const V = e.linkDoctypeField && o ? String(o[e.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : e.linkDoctype, K = Wn(V, String(n));
|
|
4308
|
+
if (K)
|
|
4260
4309
|
return /* @__PURE__ */ r("div", { children: [
|
|
4261
4310
|
/* @__PURE__ */ t(d, {}),
|
|
4262
4311
|
/* @__PURE__ */ t("p", { className: i ? "text-sm" : "py-2 text-sm", children: /* @__PURE__ */ t(
|
|
4263
4312
|
Ce,
|
|
4264
4313
|
{
|
|
4265
|
-
to:
|
|
4314
|
+
to: K,
|
|
4266
4315
|
className: "text-sky-600 hover:text-sky-800 hover:underline",
|
|
4267
4316
|
children: n
|
|
4268
4317
|
}
|
|
@@ -4301,7 +4350,7 @@ function Vt({
|
|
|
4301
4350
|
if (x) {
|
|
4302
4351
|
const T = ((N = un(c)) == null ? void 0 : N.doctype) ?? Ra(c), _ = ((A = p == null ? void 0 : p.defaults) == null ? void 0 : A[T]) ?? "standard", V = [
|
|
4303
4352
|
{ value: "", label: u("pdfTemplates.defaultOption", { name: b(_) }) },
|
|
4304
|
-
...w.filter((
|
|
4353
|
+
...w.filter((K) => K.standard || K.doctype === T).filter((K) => K.published && (!K.archived || K.template === n)).map((K) => ({ value: K.template, label: K.standard ? u("pdfTemplates.standard") : K.title }))
|
|
4305
4354
|
];
|
|
4306
4355
|
return /* @__PURE__ */ r("div", { children: [
|
|
4307
4356
|
/* @__PURE__ */ t(d, {}),
|
|
@@ -4311,7 +4360,7 @@ function Vt({
|
|
|
4311
4360
|
options: V,
|
|
4312
4361
|
value: n ?? "",
|
|
4313
4362
|
placeholder: !1,
|
|
4314
|
-
onChange: (
|
|
4363
|
+
onChange: (K) => a(K.target.value || null)
|
|
4315
4364
|
}
|
|
4316
4365
|
)
|
|
4317
4366
|
] });
|
|
@@ -4321,8 +4370,8 @@ function Vt({
|
|
|
4321
4370
|
// Translate the visible label but keep the stored value (e.g. status
|
|
4322
4371
|
// "Available" -> "Verfügbar"): t(`fieldOptions.<value>`), English fallback.
|
|
4323
4372
|
e.options.map((_) => {
|
|
4324
|
-
const V = typeof _ == "string" ? _ : _.value,
|
|
4325
|
-
return { value: V, label: u(`fieldOptions.${V}`, { defaultValue:
|
|
4373
|
+
const V = typeof _ == "string" ? _ : _.value, K = typeof _ == "string" ? _ : _.label;
|
|
4374
|
+
return { value: V, label: u(`fieldOptions.${V}`, { defaultValue: K }) };
|
|
4326
4375
|
})
|
|
4327
4376
|
);
|
|
4328
4377
|
return /* @__PURE__ */ r("div", { children: [
|
|
@@ -4471,7 +4520,7 @@ function so({
|
|
|
4471
4520
|
}),
|
|
4472
4521
|
!s && /* @__PURE__ */ t("td", { className: "px-2 py-1", children: /* @__PURE__ */ r("div", { className: "flex flex-col items-start", children: [
|
|
4473
4522
|
/* @__PURE__ */ t(
|
|
4474
|
-
|
|
4523
|
+
W,
|
|
4475
4524
|
{
|
|
4476
4525
|
variant: "ghost",
|
|
4477
4526
|
size: "sm",
|
|
@@ -4479,7 +4528,7 @@ function so({
|
|
|
4479
4528
|
children: "Remove"
|
|
4480
4529
|
}
|
|
4481
4530
|
),
|
|
4482
|
-
g && y >= 0 && !d(m) && /* @__PURE__ */ t(
|
|
4531
|
+
g && y >= 0 && !d(m) && /* @__PURE__ */ t(W, { variant: "ghost", size: "sm", onClick: () => x(f), children: l("deductions.add") })
|
|
4483
4532
|
] }) })
|
|
4484
4533
|
] }, f),
|
|
4485
4534
|
d(m) && y >= 0 && /* @__PURE__ */ r("tr", { className: "!border-t-0", children: [
|
|
@@ -4518,11 +4567,11 @@ function so({
|
|
|
4518
4567
|
children: l("deductions.perUnit")
|
|
4519
4568
|
}
|
|
4520
4569
|
),
|
|
4521
|
-
!s && /* @__PURE__ */ t("td", { className: "px-2 pb-2 align-top", children: /* @__PURE__ */ t(
|
|
4570
|
+
!s && /* @__PURE__ */ t("td", { className: "px-2 pb-2 align-top", children: /* @__PURE__ */ t(W, { variant: "ghost", size: "sm", onClick: () => p(f), children: l("deductions.remove") }) })
|
|
4522
4571
|
] }, `${f}-deduction`)
|
|
4523
4572
|
]) })
|
|
4524
4573
|
] }) }),
|
|
4525
|
-
!s && /* @__PURE__ */ t("div", { className: "mt-2", children: /* @__PURE__ */ t(
|
|
4574
|
+
!s && /* @__PURE__ */ t("div", { className: "mt-2", children: /* @__PURE__ */ t(W, { variant: "secondary", size: "sm", onClick: h, children: l("common.addRow") }) })
|
|
4526
4575
|
] });
|
|
4527
4576
|
}
|
|
4528
4577
|
function io({
|
|
@@ -4547,13 +4596,13 @@ function io({
|
|
|
4547
4596
|
if (!c) return null;
|
|
4548
4597
|
const A = !e && c.canCancel && s === 1;
|
|
4549
4598
|
return /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
4550
|
-
!e && n && a && /* @__PURE__ */ t(
|
|
4551
|
-
s < 1 && !o && !p && /* @__PURE__ */ t(
|
|
4552
|
-
!e && c.canSubmit && s === 0 && !o && /* @__PURE__ */ t(
|
|
4599
|
+
!e && n && a && /* @__PURE__ */ t(Wr, { doctype: n, name: a }),
|
|
4600
|
+
s < 1 && !o && !p && /* @__PURE__ */ t(Kt, { dirty: l, saving: i, isNew: e, onClick: h }),
|
|
4601
|
+
!e && c.canSubmit && s === 0 && !o && /* @__PURE__ */ t(W, { variant: "secondary", onClick: u, children: w("common.submit") }),
|
|
4553
4602
|
!e && c.canSubmit && s === 0 && !o && (m ? /* @__PURE__ */ r(Ne, { children: [
|
|
4554
|
-
/* @__PURE__ */ t(
|
|
4603
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => f(!1), children: w("common.keepDraft") }),
|
|
4555
4604
|
/* @__PURE__ */ t(
|
|
4556
|
-
|
|
4605
|
+
W,
|
|
4557
4606
|
{
|
|
4558
4607
|
variant: "danger",
|
|
4559
4608
|
onClick: () => {
|
|
@@ -4562,11 +4611,11 @@ function io({
|
|
|
4562
4611
|
children: w("common.discardDraftConfirm")
|
|
4563
4612
|
}
|
|
4564
4613
|
)
|
|
4565
|
-
] }) : /* @__PURE__ */ t(
|
|
4614
|
+
] }) : /* @__PURE__ */ t(W, { variant: "ghost", onClick: () => f(!0), children: w("common.discardDraft") })),
|
|
4566
4615
|
c.softCancel && !e && !o && !x && (D ? /* @__PURE__ */ r(Ne, { children: [
|
|
4567
|
-
/* @__PURE__ */ t(
|
|
4616
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => N(!1), children: w("common.keepBooking") }),
|
|
4568
4617
|
/* @__PURE__ */ t(
|
|
4569
|
-
|
|
4618
|
+
W,
|
|
4570
4619
|
{
|
|
4571
4620
|
variant: "danger",
|
|
4572
4621
|
onClick: () => {
|
|
@@ -4575,10 +4624,10 @@ function io({
|
|
|
4575
4624
|
children: w("common.cancelBookingConfirm")
|
|
4576
4625
|
}
|
|
4577
4626
|
)
|
|
4578
|
-
] }) : /* @__PURE__ */ t(
|
|
4579
|
-
A && (b ? /* @__PURE__ */ t(
|
|
4627
|
+
] }) : /* @__PURE__ */ t(W, { variant: "ghost", onClick: () => N(!0), children: w("common.cancelBooking") })),
|
|
4628
|
+
A && (b ? /* @__PURE__ */ t(W, { variant: "secondary", onClick: () => y(!1), children: w("common.cancelDocAbort") }) : /* @__PURE__ */ t(W, { variant: "danger", onClick: () => y(!0), children: w("common.cancelDoc") })),
|
|
4580
4629
|
!e && s === 1 && !b && c.conversions.map((T) => /* @__PURE__ */ t(
|
|
4581
|
-
|
|
4630
|
+
W,
|
|
4582
4631
|
{
|
|
4583
4632
|
variant: "secondary",
|
|
4584
4633
|
onClick: () => d(T.targetDoctype),
|
|
@@ -4587,7 +4636,7 @@ function io({
|
|
|
4587
4636
|
T.targetDoctype
|
|
4588
4637
|
)),
|
|
4589
4638
|
A && b && /* @__PURE__ */ t(
|
|
4590
|
-
|
|
4639
|
+
W,
|
|
4591
4640
|
{
|
|
4592
4641
|
variant: "danger",
|
|
4593
4642
|
className: "ml-auto",
|
|
@@ -4624,7 +4673,7 @@ function Aa(e, n) {
|
|
|
4624
4673
|
}
|
|
4625
4674
|
function Ta() {
|
|
4626
4675
|
var Qe, Je;
|
|
4627
|
-
const { doctype: e, name: n } = vt(), a =
|
|
4676
|
+
const { doctype: e, name: n } = vt(), a = Ke(), s = We(), { t: o } = ee(), i = Ur(e ?? ""), l = !n;
|
|
4628
4677
|
Fe(l ? (i == null ? void 0 : i.label) ?? null : n ?? (i == null ? void 0 : i.label) ?? null);
|
|
4629
4678
|
const [c, h] = C({}), { dirty: u, markDirty: g, markClean: d } = jt(), [v, k] = C(!1), { data: x, isLoading: p } = he({
|
|
4630
4679
|
queryKey: ["document", e, n],
|
|
@@ -4666,7 +4715,7 @@ function Ta() {
|
|
|
4666
4715
|
}), Y.docstatus = 0, h(Y), d();
|
|
4667
4716
|
} else x && (h(x), d());
|
|
4668
4717
|
}, [l, x, i, d]);
|
|
4669
|
-
const D =
|
|
4718
|
+
const D = Wt.find((Y) => Y.slug === (i == null ? void 0 : i.slug) && Y.texts), N = Yr(l && !!D, D == null ? void 0 : D.doctype), A = me(!1);
|
|
4670
4719
|
ie(() => {
|
|
4671
4720
|
if (!l || A.current || !N.data || c.docstatus !== 0) return;
|
|
4672
4721
|
A.current = !0;
|
|
@@ -4692,7 +4741,7 @@ function Ta() {
|
|
|
4692
4741
|
onSuccess: (Y) => {
|
|
4693
4742
|
h(Y), d(), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
|
|
4694
4743
|
}
|
|
4695
|
-
}),
|
|
4744
|
+
}), K = xe({
|
|
4696
4745
|
mutationFn: () => q.cancelDocument(e, n),
|
|
4697
4746
|
onSuccess: (Y) => {
|
|
4698
4747
|
h(Y), d(), s.invalidateQueries({ queryKey: ["document", e, n] }), s.invalidateQueries({ queryKey: ["documents", e] }), (e === "reservation" || e === "asset") && (s.invalidateQueries({ queryKey: ["fleet-calendar"] }), s.invalidateQueries({ queryKey: ["availability"] }));
|
|
@@ -4729,7 +4778,7 @@ function Ta() {
|
|
|
4729
4778
|
}, z = () => {
|
|
4730
4779
|
V.mutate();
|
|
4731
4780
|
}, S = () => {
|
|
4732
|
-
|
|
4781
|
+
K.mutate();
|
|
4733
4782
|
}, L = (Y) => {
|
|
4734
4783
|
F.mutate(Y);
|
|
4735
4784
|
}, j = () => {
|
|
@@ -4748,7 +4797,7 @@ function Ta() {
|
|
|
4748
4797
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
4749
4798
|
/* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
4750
4799
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
|
|
4751
|
-
!l && /* @__PURE__ */ t(
|
|
4800
|
+
!l && /* @__PURE__ */ t(Kr, { slug: i.slug, name: n, onSave: R }),
|
|
4752
4801
|
!l && c.status && /* @__PURE__ */ t(oa, { status: c.status }),
|
|
4753
4802
|
!l && c.currency && /* @__PURE__ */ r(
|
|
4754
4803
|
"span",
|
|
@@ -4788,7 +4837,7 @@ function Ta() {
|
|
|
4788
4837
|
}
|
|
4789
4838
|
)
|
|
4790
4839
|
] }),
|
|
4791
|
-
(T.error || _.error || V.error ||
|
|
4840
|
+
(T.error || _.error || V.error || K.error) && /* @__PURE__ */ t("div", { className: "rounded-lg bg-rose-50 p-4 text-sm text-rose-700 ring-1 ring-rose-200", children: ((Qe = T.error ?? _.error ?? V.error ?? K.error) == null ? void 0 : Qe.message) ?? o("common.errorOccurred") }),
|
|
4792
4841
|
(((Je = c._validation) == null ? void 0 : Je.warnings) ?? []).map((Y) => /* @__PURE__ */ t("div", { className: "rounded-lg bg-amber-50 p-4 text-sm text-amber-900", role: "status", children: Y.code === "asset_unassigned" ? o("rentals.poolWarning") : o(`documentWarnings.${Y.code}`, { defaultValue: Y.message, template: Y.template }) }, Y.code)),
|
|
4793
4842
|
/* @__PURE__ */ r(X, { children: [
|
|
4794
4843
|
/* @__PURE__ */ t("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Se.map((Y) => /* @__PURE__ */ t(
|
|
@@ -5007,7 +5056,7 @@ function Xr({
|
|
|
5007
5056
|
}), 200);
|
|
5008
5057
|
return () => clearTimeout(S);
|
|
5009
5058
|
}, [m == null ? void 0 : m.field.name, m == null ? void 0 : m.value]);
|
|
5010
|
-
const _ = !!m && b.field === m.field.name && A.length === 0 && (!!b.value || !!m.field.suggestOnEmpty), { data: V = [], isFetching:
|
|
5059
|
+
const _ = !!m && b.field === m.field.name && A.length === 0 && (!!b.value || !!m.field.suggestOnEmpty), { data: V = [], isFetching: K } = he({
|
|
5011
5060
|
queryKey: ["smart-list-values", e, m == null ? void 0 : m.field.name, b.value],
|
|
5012
5061
|
queryFn: () => c(m.field.name, b.value),
|
|
5013
5062
|
enabled: _,
|
|
@@ -5081,11 +5130,11 @@ function Xr({
|
|
|
5081
5130
|
}
|
|
5082
5131
|
)
|
|
5083
5132
|
] }),
|
|
5084
|
-
/* @__PURE__ */ r(
|
|
5133
|
+
/* @__PURE__ */ r(W, { size: "sm", onClick: R, children: [
|
|
5085
5134
|
/* @__PURE__ */ t(ha, { className: "h-4 w-4" }),
|
|
5086
5135
|
g("smartSearch.search")
|
|
5087
5136
|
] }),
|
|
5088
|
-
/* @__PURE__ */ r(
|
|
5137
|
+
/* @__PURE__ */ r(W, { size: "sm", variant: "secondary", onClick: O, children: [
|
|
5089
5138
|
/* @__PURE__ */ t(Zs, { className: "h-4 w-4" }),
|
|
5090
5139
|
g("smartSearch.addFilter")
|
|
5091
5140
|
] }),
|
|
@@ -5135,8 +5184,8 @@ function Xr({
|
|
|
5135
5184
|
)
|
|
5136
5185
|
] }),
|
|
5137
5186
|
!m.value && !m.field.suggestOnEmpty && A.length === 0 && /* @__PURE__ */ t("div", { className: "px-3 py-4 text-sm text-fg-muted", children: g("smartSearch.typeForValues") }),
|
|
5138
|
-
|
|
5139
|
-
!
|
|
5187
|
+
K && /* @__PURE__ */ t("div", { className: "px-3 py-3 text-sm text-fg-muted", children: g("common.loading") }),
|
|
5188
|
+
!K && I.map((S) => /* @__PURE__ */ r(
|
|
5140
5189
|
"button",
|
|
5141
5190
|
{
|
|
5142
5191
|
type: "button",
|
|
@@ -5150,7 +5199,7 @@ function Xr({
|
|
|
5150
5199
|
},
|
|
5151
5200
|
Jt(S)
|
|
5152
5201
|
)),
|
|
5153
|
-
!
|
|
5202
|
+
!K && _ && I.length === 0 && /* @__PURE__ */ t("div", { className: "px-3 py-4 text-sm text-fg-muted", children: g("smartSearch.noValues") }),
|
|
5154
5203
|
!!m.value && /* @__PURE__ */ t(
|
|
5155
5204
|
"button",
|
|
5156
5205
|
{
|
|
@@ -5208,12 +5257,12 @@ function La(e) {
|
|
|
5208
5257
|
function hn(e) {
|
|
5209
5258
|
return new Date(e.getFullYear(), e.getMonth() + 1, 0);
|
|
5210
5259
|
}
|
|
5211
|
-
function
|
|
5260
|
+
function Kn(e) {
|
|
5212
5261
|
const n = Math.floor(e.getMonth() / 3);
|
|
5213
5262
|
return new Date(e.getFullYear(), n * 3, 1);
|
|
5214
5263
|
}
|
|
5215
5264
|
function jn(e) {
|
|
5216
|
-
const n =
|
|
5265
|
+
const n = Kn(e);
|
|
5217
5266
|
return new Date(n.getFullYear(), n.getMonth() + 3, 0);
|
|
5218
5267
|
}
|
|
5219
5268
|
function Ia(e) {
|
|
@@ -5244,7 +5293,7 @@ const po = [
|
|
|
5244
5293
|
{
|
|
5245
5294
|
id: "thisQuarter",
|
|
5246
5295
|
labelKey: "datePresets.thisQuarter",
|
|
5247
|
-
range: (e) => [Ee(
|
|
5296
|
+
range: (e) => [Ee(Kn(e)), Ee(jn(e))]
|
|
5248
5297
|
},
|
|
5249
5298
|
{
|
|
5250
5299
|
id: "thisYear",
|
|
@@ -5264,7 +5313,7 @@ const po = [
|
|
|
5264
5313
|
labelKey: "datePresets.lastQuarter",
|
|
5265
5314
|
range: (e) => {
|
|
5266
5315
|
const n = new Date(e.getFullYear(), e.getMonth() - 3, 1);
|
|
5267
|
-
return [Ee(
|
|
5316
|
+
return [Ee(Kn(n)), Ee(jn(n))];
|
|
5268
5317
|
}
|
|
5269
5318
|
},
|
|
5270
5319
|
{
|
|
@@ -5356,8 +5405,8 @@ function yo() {
|
|
|
5356
5405
|
const E = {};
|
|
5357
5406
|
for (const Q of i) E[Q] = l[Q] ?? "";
|
|
5358
5407
|
return E;
|
|
5359
|
-
}, [i, l]), [h] = de("status", "All"), [u] = de("from", ""), [g] = de("to", ""), [d] = de("discarded", ""), [v] = de("per_page", 50), k = (s == null ? void 0 : s.searchFields) ?? [], [x] = de("q", ""), [p, w] = C(x), [b] = de("page", 1), y = b - 1, m = nt(), { settings: f, setSetting: D } = Bt(), [N] = de("order_by", ""), [A] = de("order", ""), [T, _] = (f[`sort.${a}`] || "").split(":"), V = N || T || "",
|
|
5360
|
-
const Q = V === E ?
|
|
5408
|
+
}, [i, l]), [h] = de("status", "All"), [u] = de("from", ""), [g] = de("to", ""), [d] = de("discarded", ""), [v] = de("per_page", 50), k = (s == null ? void 0 : s.searchFields) ?? [], [x] = de("q", ""), [p, w] = C(x), [b] = de("page", 1), y = b - 1, m = nt(), { settings: f, setSetting: D } = Bt(), [N] = de("order_by", ""), [A] = de("order", ""), [T, _] = (f[`sort.${a}`] || "").split(":"), V = N || T || "", K = (N ? A : _) || "desc", I = (E) => {
|
|
5409
|
+
const Q = V === E ? K === "desc" ? "asc" : "desc" : Fa(E) ? "desc" : "asc";
|
|
5361
5410
|
m({ order_by: E, order: Q, page: null }), D(`sort.${a}`, `${E}:${Q}`);
|
|
5362
5411
|
}, [F, G] = C(!1), O = me(null), R = ye(
|
|
5363
5412
|
() => (f[`columns.${a}`] || "").split(",").map((E) => E.trim()).filter(Boolean),
|
|
@@ -5393,8 +5442,8 @@ function yo() {
|
|
|
5393
5442
|
c[Q] && (E[Q] = c[Q]);
|
|
5394
5443
|
for (const [Q, B] of Object.entries(l))
|
|
5395
5444
|
E[Q] = B;
|
|
5396
|
-
return k.length > 0 && x && (E.search = x, E.search_fields = k.join(",")), d && (E.include_discarded = "true"), V && (E.order_by = V, E.order =
|
|
5397
|
-
}, [h, u, g, d, v, y, s == null ? void 0 : s.dateField, i, c, l, k, x, V,
|
|
5445
|
+
return k.length > 0 && x && (E.search = x, E.search_fields = k.join(",")), d && (E.include_discarded = "true"), V && (E.order_by = V, E.order = K), S && (E.fields = S), E.limit = v, E.offset = y * v, E;
|
|
5446
|
+
}, [h, u, g, d, v, y, s == null ? void 0 : s.dateField, i, c, l, k, x, V, K, S]), { data: we, isLoading: Se, refetch: je } = Gi(a ?? "", be), Me = (we == null ? void 0 : we.rows) ?? [], Qe = (we == null ? void 0 : we.total) ?? 0, Je = ye(() => new Set((we == null ? void 0 : we.text_fields) ?? []), [we == null ? void 0 : we.text_fields]), Y = ye(() => {
|
|
5398
5447
|
if (!s) return [];
|
|
5399
5448
|
const E = new Map(s.fields.map((B) => [B.name, B]));
|
|
5400
5449
|
return [.../* @__PURE__ */ new Set([
|
|
@@ -5462,7 +5511,7 @@ function yo() {
|
|
|
5462
5511
|
cell: (M) => {
|
|
5463
5512
|
const te = M.getValue();
|
|
5464
5513
|
if (!te) return "-";
|
|
5465
|
-
const ge = fo(M.row.original.party_type), Pe = ge ?
|
|
5514
|
+
const ge = fo(M.row.original.party_type), Pe = ge ? Wn(ge, String(te)) : null;
|
|
5466
5515
|
return Pe ? /* @__PURE__ */ t(
|
|
5467
5516
|
Ce,
|
|
5468
5517
|
{
|
|
@@ -5481,7 +5530,7 @@ function yo() {
|
|
|
5481
5530
|
cell: (te) => {
|
|
5482
5531
|
const ge = te.getValue();
|
|
5483
5532
|
if (!ge) return "-";
|
|
5484
|
-
const Pe =
|
|
5533
|
+
const Pe = Wn(M, String(ge));
|
|
5485
5534
|
return Pe ? /* @__PURE__ */ t(
|
|
5486
5535
|
Ce,
|
|
5487
5536
|
{
|
|
@@ -5512,7 +5561,7 @@ function yo() {
|
|
|
5512
5561
|
return s ? /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
5513
5562
|
/* @__PURE__ */ r("div", { className: "flex items-center justify-end gap-2", children: [
|
|
5514
5563
|
/* @__PURE__ */ r("div", { className: "relative", ref: O, children: [
|
|
5515
|
-
/* @__PURE__ */ t(
|
|
5564
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => G((E) => !E), children: /* @__PURE__ */ r("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
5516
5565
|
/* @__PURE__ */ t(gr, { className: "h-4 w-4" }),
|
|
5517
5566
|
e("common.columns", { defaultValue: "Columns" })
|
|
5518
5567
|
] }) }),
|
|
@@ -5543,7 +5592,7 @@ function yo() {
|
|
|
5543
5592
|
})
|
|
5544
5593
|
] })
|
|
5545
5594
|
] }),
|
|
5546
|
-
/* @__PURE__ */ t(Ce, { to: `/app/${s.slug}/new`, children: /* @__PURE__ */ t(
|
|
5595
|
+
/* @__PURE__ */ t(Ce, { to: `/app/${s.slug}/new`, children: /* @__PURE__ */ t(W, { children: e("common.new") }) })
|
|
5547
5596
|
] }),
|
|
5548
5597
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
5549
5598
|
k.length > 0 && /* @__PURE__ */ t(
|
|
@@ -5652,7 +5701,7 @@ function yo() {
|
|
|
5652
5701
|
className: "group inline-flex items-center gap-1 uppercase tracking-wide transition-colors hover:text-fg",
|
|
5653
5702
|
children: [
|
|
5654
5703
|
cn(Q.column.columnDef.header, Q.getContext()),
|
|
5655
|
-
V === Q.column.id ?
|
|
5704
|
+
V === Q.column.id ? K === "asc" ? /* @__PURE__ */ t(fr, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ t(Ct, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ t(yr, { className: "h-3.5 w-3.5 opacity-0 transition-opacity group-hover:opacity-40" })
|
|
5656
5705
|
]
|
|
5657
5706
|
}
|
|
5658
5707
|
)
|
|
@@ -5738,8 +5787,8 @@ function Te({
|
|
|
5738
5787
|
return ie(() => {
|
|
5739
5788
|
const _ = (V) => {
|
|
5740
5789
|
var I, F;
|
|
5741
|
-
const
|
|
5742
|
-
(I = w.current) != null && I.contains(
|
|
5790
|
+
const K = V.target;
|
|
5791
|
+
(I = w.current) != null && I.contains(K) || (F = b.current) != null && F.contains(K) || g(!1);
|
|
5743
5792
|
};
|
|
5744
5793
|
return document.addEventListener("mousedown", _), () => document.removeEventListener("mousedown", _);
|
|
5745
5794
|
}, []), o ? /* @__PURE__ */ r("div", { children: [
|
|
@@ -5767,7 +5816,7 @@ function Te({
|
|
|
5767
5816
|
),
|
|
5768
5817
|
u && c.length > 0 && Cr(
|
|
5769
5818
|
/* @__PURE__ */ t("div", { ref: b, style: k, className: "max-h-48 overflow-y-auto rounded-lg bg-surface ring-1 ring-line shadow-card-hover", children: c.map((_, V) => {
|
|
5770
|
-
const
|
|
5819
|
+
const K = _.name ?? _.id ?? String(_);
|
|
5771
5820
|
return /* @__PURE__ */ t(
|
|
5772
5821
|
"button",
|
|
5773
5822
|
{
|
|
@@ -5777,7 +5826,7 @@ function Te({
|
|
|
5777
5826
|
},
|
|
5778
5827
|
onClick: () => A(_),
|
|
5779
5828
|
className: "block w-full px-3 py-1.5 text-left text-sm text-fg transition-colors hover:bg-surface-subtle",
|
|
5780
|
-
children:
|
|
5829
|
+
children: K
|
|
5781
5830
|
},
|
|
5782
5831
|
V
|
|
5783
5832
|
);
|
|
@@ -5814,7 +5863,7 @@ const Zt = () => ({
|
|
|
5814
5863
|
}), vo = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
5815
5864
|
function qa() {
|
|
5816
5865
|
var S;
|
|
5817
|
-
const { name: e } = vt(), n = !e, a =
|
|
5866
|
+
const { name: e } = vt(), n = !e, a = Ke(), s = We(), { t: o } = ee();
|
|
5818
5867
|
Fe(o("titles.proposal"));
|
|
5819
5868
|
const i = (L, j) => o(L, { defaultValue: j }), l = Rt(), [c, h] = C({
|
|
5820
5869
|
title: "Offerte",
|
|
@@ -5873,9 +5922,9 @@ function qa() {
|
|
|
5873
5922
|
f(), s.invalidateQueries({ queryKey: ["documents", "proposal"] }), a("/app/proposal");
|
|
5874
5923
|
},
|
|
5875
5924
|
onError: (L) => w((L == null ? void 0 : L.message) ?? "Discard failed")
|
|
5876
|
-
}),
|
|
5925
|
+
}), K = (L) => {
|
|
5877
5926
|
m(), g(L);
|
|
5878
|
-
}, I = (L, j) =>
|
|
5927
|
+
}, I = (L, j) => K((ne) => ne.map((ue, H) => H === L ? { ...ue, ...j } : ue)), F = () => K((L) => [...L, Zt()]), G = (L) => K((j) => j.length > 1 ? j.filter((ne, ue) => ue !== L) : j), O = (L, j) => K((ne) => {
|
|
5879
5928
|
const ue = L + j;
|
|
5880
5929
|
if (ue < 0 || ue >= ne.length) return ne;
|
|
5881
5930
|
const H = [...ne];
|
|
@@ -5914,7 +5963,7 @@ function qa() {
|
|
|
5914
5963
|
] }),
|
|
5915
5964
|
/* @__PURE__ */ r("div", { className: "flex gap-2", children: [
|
|
5916
5965
|
!n && /* @__PURE__ */ t(
|
|
5917
|
-
|
|
5966
|
+
W,
|
|
5918
5967
|
{
|
|
5919
5968
|
variant: "danger",
|
|
5920
5969
|
disabled: V.isPending,
|
|
@@ -5928,8 +5977,8 @@ function qa() {
|
|
|
5928
5977
|
children: V.isPending ? i("common.discarding", "Discarding…") : i("common.discard", "Discard")
|
|
5929
5978
|
}
|
|
5930
5979
|
),
|
|
5931
|
-
!n && /* @__PURE__ */ t(
|
|
5932
|
-
/* @__PURE__ */ t(
|
|
5980
|
+
!n && /* @__PURE__ */ t(Wr, { doctype: "proposal", name: e }),
|
|
5981
|
+
/* @__PURE__ */ t(Kt, { dirty: y, saving: _.isPending, isNew: n, onClick: () => _.mutate() })
|
|
5933
5982
|
] })
|
|
5934
5983
|
] }),
|
|
5935
5984
|
p && /* @__PURE__ */ t("div", { className: "rounded-lg bg-red-50 px-4 py-2 text-sm text-red-700 ring-1 ring-red-200", children: p }),
|
|
@@ -5971,7 +6020,7 @@ function qa() {
|
|
|
5971
6020
|
/* @__PURE__ */ r(X, { className: "space-y-4 p-5", children: [
|
|
5972
6021
|
/* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
|
|
5973
6022
|
/* @__PURE__ */ t("h2", { className: "font-semibold text-fg", children: i("proposal.offers", "Offers") }),
|
|
5974
|
-
/* @__PURE__ */ t(
|
|
6023
|
+
/* @__PURE__ */ t(W, { size: "sm", variant: "secondary", onClick: F, children: i("proposal.addOffer", "Add offer") })
|
|
5975
6024
|
] }),
|
|
5976
6025
|
u.map((L, j) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
|
|
5977
6026
|
/* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
|
|
@@ -6001,7 +6050,7 @@ function qa() {
|
|
|
6001
6050
|
/* @__PURE__ */ t("button", { type: "button", onClick: z, disabled: k, className: "text-red-500 hover:underline", children: i("common.remove", "Remove") })
|
|
6002
6051
|
] }) : /* @__PURE__ */ r("div", { children: [
|
|
6003
6052
|
/* @__PURE__ */ t("input", { ref: b, type: "file", accept: "application/pdf", onChange: R, className: "hidden" }),
|
|
6004
|
-
/* @__PURE__ */ t(
|
|
6053
|
+
/* @__PURE__ */ t(W, { size: "sm", variant: "secondary", disabled: k, onClick: () => {
|
|
6005
6054
|
var L;
|
|
6006
6055
|
return (L = b.current) == null ? void 0 : L.click();
|
|
6007
6056
|
}, children: k ? i("common.uploading", "Uploading…") : i("proposal.uploadAppendix", "Upload appendix PDF") }),
|
|
@@ -6076,6 +6125,14 @@ const as = {
|
|
|
6076
6125
|
default: "0",
|
|
6077
6126
|
hint: "If Yes, every batch of this item needs an expiry date. Requires batch tracking."
|
|
6078
6127
|
},
|
|
6128
|
+
{
|
|
6129
|
+
name: "has_serial_no",
|
|
6130
|
+
label: "Serial-tracked",
|
|
6131
|
+
type: "select",
|
|
6132
|
+
options: [{ value: "0", label: "No" }, { value: "1", label: "Yes" }],
|
|
6133
|
+
default: "0",
|
|
6134
|
+
hint: "If Yes, every stock movement of this item lists one serial number per unit. Units already in stock stay without a number until a Serial Assignment."
|
|
6135
|
+
},
|
|
6079
6136
|
{
|
|
6080
6137
|
name: "min_shelf_life_days",
|
|
6081
6138
|
label: "Min. Shelf Life (days)",
|
|
@@ -6137,6 +6194,16 @@ const as = {
|
|
|
6137
6194
|
{ name: "zip_code", label: "Zip Code", type: "text" },
|
|
6138
6195
|
{ name: "country", label: "Country", type: "text" }
|
|
6139
6196
|
],
|
|
6197
|
+
"serial-no": [
|
|
6198
|
+
{ name: "item_code", label: "Item", type: "link", linkDoctype: "item", readOnly: !0 },
|
|
6199
|
+
{ name: "serial_no", label: "Serial Number", type: "text", readOnly: !0 },
|
|
6200
|
+
{ name: "status", label: "Status", type: "text", readOnly: !0 },
|
|
6201
|
+
{ name: "warehouse", label: "Warehouse", type: "text", readOnly: !0 },
|
|
6202
|
+
{ name: "location", label: "Storage Location", type: "text", readOnly: !0 },
|
|
6203
|
+
{ name: "batch_no", label: "Batch", type: "text", readOnly: !0 },
|
|
6204
|
+
{ name: "customer", label: "Customer", type: "text", readOnly: !0 },
|
|
6205
|
+
{ name: "description", label: "Description", type: "textarea" }
|
|
6206
|
+
],
|
|
6140
6207
|
"storage-location": [
|
|
6141
6208
|
{ name: "warehouse", label: "Warehouse", type: "link", linkDoctype: "warehouse", required: !0 },
|
|
6142
6209
|
{
|
|
@@ -6178,7 +6245,8 @@ const as = {
|
|
|
6178
6245
|
warehouse: "Warehouse",
|
|
6179
6246
|
company: "Company",
|
|
6180
6247
|
batch: "Batch",
|
|
6181
|
-
"storage-location": "Storage Location"
|
|
6248
|
+
"storage-location": "Storage Location",
|
|
6249
|
+
"serial-no": "Serial Number"
|
|
6182
6250
|
}, Ft = (e) => e.split("_").map((n) => n.charAt(0).toUpperCase() + n.slice(1)).join(" "), za = (e) => e === "modified" || e === "creation" || e.endsWith("_date") || e.endsWith("_at") || e.endsWith("_datetime"), ko = {
|
|
6183
6251
|
customer: [{ field: "customer_group", label: "Customer Group" }, { field: "territory", label: "Territory" }],
|
|
6184
6252
|
supplier: [{ field: "supplier_group", label: "Supplier Group" }],
|
|
@@ -6186,11 +6254,12 @@ const as = {
|
|
|
6186
6254
|
warehouse: [{ field: "parent_warehouse", label: "Parent Warehouse" }],
|
|
6187
6255
|
batch: [{ field: "item_code", label: "Item" }],
|
|
6188
6256
|
"storage-location": [{ field: "warehouse", label: "Warehouse" }],
|
|
6257
|
+
"serial-no": [{ field: "item_code", label: "Item" }, { field: "warehouse", label: "Warehouse" }, { field: "status", label: "Status" }],
|
|
6189
6258
|
account: [{ field: "root_type", label: "Root Type" }, { field: "account_type", label: "Account Type" }]
|
|
6190
6259
|
};
|
|
6191
6260
|
function No() {
|
|
6192
6261
|
var De;
|
|
6193
|
-
const { type: e } = vt(), n =
|
|
6262
|
+
const { type: e } = vt(), n = Ke(), a = ut(), s = ns(e ?? ""), o = (s == null ? void 0 : s.label) ?? xo[e ?? ""] ?? e ?? "";
|
|
6194
6263
|
Fe(o || null);
|
|
6195
6264
|
const { t: i } = ee(), l = (De = a.state) == null ? void 0 : De.notice, [c] = de("per_page", 50), [h] = de("page", 1), [u] = de("include_disabled", ""), g = h - 1, d = nt(), v = (J) => d({ page: J === 0 ? null : J + 1 }), k = (J) => d({ per_page: J, page: null }), x = (J) => d({ include_disabled: J ? "1" : null, page: null }), { settings: p, setSetting: w } = Bt(), [b] = de("order_by", ""), [y] = de("order", ""), [m, f] = (p[`sort.master:${e}`] || "").split(":"), D = b || m || "", N = (b ? y : f) || "asc", A = (J) => {
|
|
6196
6265
|
const ce = D === J ? N === "desc" ? "asc" : "desc" : za(J) ? "desc" : "asc";
|
|
@@ -6199,7 +6268,7 @@ function No() {
|
|
|
6199
6268
|
ie(() => {
|
|
6200
6269
|
V(T);
|
|
6201
6270
|
}, [T]);
|
|
6202
|
-
const
|
|
6271
|
+
const K = (s == null ? void 0 : s.listFilters) ?? ko[e ?? ""] ?? [], I = ye(() => {
|
|
6203
6272
|
const J = new URLSearchParams(a.search), ce = {}, Ie = /* @__PURE__ */ new Set(["q", "page", "per_page", "include_disabled", "order_by", "order"]);
|
|
6204
6273
|
for (const [E, Q] of J.entries())
|
|
6205
6274
|
!Ie.has(E) && Q && (ce[E] = Q);
|
|
@@ -6231,7 +6300,7 @@ function No() {
|
|
|
6231
6300
|
return [.../* @__PURE__ */ new Set([
|
|
6232
6301
|
...le,
|
|
6233
6302
|
...J.map((E) => E.name),
|
|
6234
|
-
...
|
|
6303
|
+
...K.map((E) => E.field)
|
|
6235
6304
|
])].map((E) => {
|
|
6236
6305
|
var te;
|
|
6237
6306
|
const Q = ce.get(E), B = (Q == null ? void 0 : Q.label) ?? Ft(E), M = (te = Q == null ? void 0 : Q.options) == null ? void 0 : te.map(
|
|
@@ -6243,10 +6312,10 @@ function No() {
|
|
|
6243
6312
|
type: (Q == null ? void 0 : Q.type) ?? (za(E) ? "date" : "text"),
|
|
6244
6313
|
options: M,
|
|
6245
6314
|
contains: L.has(E),
|
|
6246
|
-
suggestOnEmpty: !!(M != null && M.length) ||
|
|
6315
|
+
suggestOnEmpty: !!(M != null && M.length) || K.some((ge) => ge.field === E)
|
|
6247
6316
|
};
|
|
6248
6317
|
});
|
|
6249
|
-
}, [le, s,
|
|
6318
|
+
}, [le, s, K, i, L, e]), be = ye(
|
|
6250
6319
|
() => (p[`columns.master:${e}`] || "").split(",").map((J) => J.trim()).filter(Boolean),
|
|
6251
6320
|
[p, e]
|
|
6252
6321
|
).filter((J) => le.includes(J)), we = ((s == null ? void 0 : s.listColumns) ?? []).filter((J) => le.includes(J)), Se = be.length ? be : we.length ? we : le, je = (J) => {
|
|
@@ -6340,7 +6409,7 @@ function No() {
|
|
|
6340
6409
|
] }),
|
|
6341
6410
|
/* @__PURE__ */ r("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
6342
6411
|
le.length > 0 && /* @__PURE__ */ r("div", { className: "relative", ref: Je, children: [
|
|
6343
|
-
/* @__PURE__ */ t(
|
|
6412
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => Qe((J) => !J), children: /* @__PURE__ */ r("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
6344
6413
|
/* @__PURE__ */ t(gr, { className: "h-4 w-4" }),
|
|
6345
6414
|
i("common.columns", { defaultValue: "Columns" })
|
|
6346
6415
|
] }) }),
|
|
@@ -6374,7 +6443,7 @@ function No() {
|
|
|
6374
6443
|
})
|
|
6375
6444
|
] })
|
|
6376
6445
|
] }),
|
|
6377
|
-
(s == null ? void 0 : s.allowCreate) !== !1 && /* @__PURE__ */ t(Ce, { to: `/masters/${e}/new`, children: /* @__PURE__ */ t(
|
|
6446
|
+
(s == null ? void 0 : s.allowCreate) !== !1 && /* @__PURE__ */ t(Ce, { to: `/masters/${e}/new`, children: /* @__PURE__ */ t(W, { children: i("common.new") }) })
|
|
6378
6447
|
] })
|
|
6379
6448
|
] }),
|
|
6380
6449
|
O ? /* @__PURE__ */ t("p", { className: "text-fg-muted", children: i("common.loading") }) : z.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-fg-muted", children: i("common.noRecords", { defaultValue: "No records found" }) }) : /* @__PURE__ */ r(Ne, { children: [
|
|
@@ -6485,11 +6554,12 @@ const So = {
|
|
|
6485
6554
|
warehouse: "Warehouse",
|
|
6486
6555
|
company: "Company",
|
|
6487
6556
|
batch: "Batch",
|
|
6488
|
-
"storage-location": "Storage Location"
|
|
6557
|
+
"storage-location": "Storage Location",
|
|
6558
|
+
"serial-no": "Serial Number"
|
|
6489
6559
|
}, Ma = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
|
|
6490
6560
|
function $a() {
|
|
6491
6561
|
var O, R, z;
|
|
6492
|
-
const { type: e, name: n } = vt(), a =
|
|
6562
|
+
const { type: e, name: n } = vt(), a = Ke(), s = We(), { t: o } = ee(), i = !n || n === "new", l = ns(e ?? ""), c = (l == null ? void 0 : l.label) ?? So[e ?? ""] ?? e ?? "", h = o(`masters.${e}.one`, { defaultValue: c }), u = (l == null ? void 0 : l.fields) ?? as[e ?? ""] ?? [], g = (S) => o(`fields.${S.label}`, { defaultValue: S.label }), [d, v] = C({}), { dirty: k, markDirty: x, markClean: p } = jt(), { data: w, isLoading: b } = he({
|
|
6493
6563
|
queryKey: ["master", e, n],
|
|
6494
6564
|
queryFn: () => q.getMaster(e, n),
|
|
6495
6565
|
enabled: !!e && !!n && !i
|
|
@@ -6555,7 +6625,7 @@ function $a() {
|
|
|
6555
6625
|
if (G.length > 0) return;
|
|
6556
6626
|
const S = e === "company" && !d.name ? { ...d, name: d.company_name } : d;
|
|
6557
6627
|
i ? D.mutate(S) : N.mutate(S);
|
|
6558
|
-
}, V = Rt(),
|
|
6628
|
+
}, V = Rt(), K = async () => {
|
|
6559
6629
|
await V({
|
|
6560
6630
|
title: o("masterForm.deleteConfirm", { label: h }),
|
|
6561
6631
|
confirmLabel: o("common.delete", { defaultValue: "Delete" }),
|
|
@@ -6574,12 +6644,12 @@ function $a() {
|
|
|
6574
6644
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
6575
6645
|
/* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
|
|
6576
6646
|
i ? /* @__PURE__ */ t("div", {}) : /* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
|
|
6577
|
-
/* @__PURE__ */ t(
|
|
6647
|
+
/* @__PURE__ */ t(Kr, { kind: "master", slug: e, name: n, onSave: _ }),
|
|
6578
6648
|
/* @__PURE__ */ t(Hr, { recordType: e, recordId: n })
|
|
6579
6649
|
] }),
|
|
6580
6650
|
/* @__PURE__ */ r("div", { className: "flex gap-2", children: [
|
|
6581
6651
|
/* @__PURE__ */ t(
|
|
6582
|
-
|
|
6652
|
+
Kt,
|
|
6583
6653
|
{
|
|
6584
6654
|
dirty: k,
|
|
6585
6655
|
saving: F,
|
|
@@ -6589,7 +6659,7 @@ function $a() {
|
|
|
6589
6659
|
}
|
|
6590
6660
|
),
|
|
6591
6661
|
!i && ((R = l == null ? void 0 : l.actions) == null ? void 0 : R.filter((S) => !S.visibleWhen || S.visibleWhen(d)).map((S) => /* @__PURE__ */ t(
|
|
6592
|
-
|
|
6662
|
+
W,
|
|
6593
6663
|
{
|
|
6594
6664
|
variant: "secondary",
|
|
6595
6665
|
disabled: T.isPending,
|
|
@@ -6605,10 +6675,10 @@ function $a() {
|
|
|
6605
6675
|
S.action
|
|
6606
6676
|
))),
|
|
6607
6677
|
!i && /* @__PURE__ */ t(
|
|
6608
|
-
|
|
6678
|
+
W,
|
|
6609
6679
|
{
|
|
6610
6680
|
variant: "danger",
|
|
6611
|
-
onClick:
|
|
6681
|
+
onClick: K,
|
|
6612
6682
|
disabled: A.isPending,
|
|
6613
6683
|
children: o("common.delete")
|
|
6614
6684
|
}
|
|
@@ -6856,7 +6926,7 @@ function Mo() {
|
|
|
6856
6926
|
onChange: (m) => g(m.target.value)
|
|
6857
6927
|
}
|
|
6858
6928
|
),
|
|
6859
|
-
/* @__PURE__ */ t(
|
|
6929
|
+
/* @__PURE__ */ t(W, { onClick: b, children: e("common.apply") })
|
|
6860
6930
|
] }),
|
|
6861
6931
|
/* @__PURE__ */ t(xn, { onSelect: (m, f) => {
|
|
6862
6932
|
h(m), g(f), o({ from: m, to: f });
|
|
@@ -6984,14 +7054,14 @@ function Vo() {
|
|
|
6984
7054
|
function Uo(e) {
|
|
6985
7055
|
return e.toLowerCase().replace(/\s+/g, "-");
|
|
6986
7056
|
}
|
|
6987
|
-
const
|
|
6988
|
-
function
|
|
7057
|
+
const Wo = ["25", "50", "100", "200"];
|
|
7058
|
+
function Ko() {
|
|
6989
7059
|
const { t: e } = ee();
|
|
6990
7060
|
Fe(e("titles.general-ledger"));
|
|
6991
7061
|
const [n] = de("account", ""), [a] = de("party", ""), [s] = de("from", ""), [o] = de("to", ""), [i] = de("per_page", 50), [l] = de("page", 1), c = l - 1, h = nt(), u = (O) => h({ page: O === 0 ? null : O + 1 }), g = (O) => h({ per_page: O, page: null }), [d, v] = C(n), [k, x] = C(a), [p, w] = C(s), [b, y] = C(o), m = tt(), f = (O) => et(O, m), D = ye(() => {
|
|
6992
7062
|
const O = {};
|
|
6993
7063
|
return n && (O.account = n), a && (O.party = a), s && (O.from_date = s), o && (O.to_date = o), O.limit = String(i), O.offset = String(c * i), O;
|
|
6994
|
-
}, [n, a, s, o, i, c]), { data: N, isLoading: A, refetch: T } = Do(D), _ = (N == null ? void 0 : N.rows) ?? [], V = (N == null ? void 0 : N.total) ?? 0,
|
|
7064
|
+
}, [n, a, s, o, i, c]), { data: N, isLoading: A, refetch: T } = Do(D), _ = (N == null ? void 0 : N.rows) ?? [], V = (N == null ? void 0 : N.total) ?? 0, K = Math.max(1, Math.ceil(V / i)), I = V === 0 ? 0 : c * i + 1, F = Math.min(V, (c + 1) * i), G = () => {
|
|
6995
7065
|
h({
|
|
6996
7066
|
account: d || null,
|
|
6997
7067
|
party: k || null,
|
|
@@ -7040,7 +7110,7 @@ function Wo() {
|
|
|
7040
7110
|
onChange: (O) => y(O.target.value)
|
|
7041
7111
|
}
|
|
7042
7112
|
),
|
|
7043
|
-
/* @__PURE__ */ t(
|
|
7113
|
+
/* @__PURE__ */ t(W, { onClick: G, children: e("common.apply") })
|
|
7044
7114
|
] }),
|
|
7045
7115
|
/* @__PURE__ */ t(xn, { onSelect: (O, R) => {
|
|
7046
7116
|
w(O), y(R), h({ from: O, to: R, page: null });
|
|
@@ -7099,7 +7169,7 @@ function Wo() {
|
|
|
7099
7169
|
value: i,
|
|
7100
7170
|
onChange: (O) => g(Number(O.target.value)),
|
|
7101
7171
|
className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
|
|
7102
|
-
children:
|
|
7172
|
+
children: Wo.map((O) => /* @__PURE__ */ t("option", { value: O, children: O }, O))
|
|
7103
7173
|
}
|
|
7104
7174
|
)
|
|
7105
7175
|
] }),
|
|
@@ -7119,13 +7189,13 @@ function Wo() {
|
|
|
7119
7189
|
" ",
|
|
7120
7190
|
e("common.of"),
|
|
7121
7191
|
" ",
|
|
7122
|
-
/* @__PURE__ */ t("span", { className: "font-medium text-gray-900", children:
|
|
7192
|
+
/* @__PURE__ */ t("span", { className: "font-medium text-gray-900", children: K })
|
|
7123
7193
|
] }),
|
|
7124
7194
|
/* @__PURE__ */ t(
|
|
7125
7195
|
"button",
|
|
7126
7196
|
{
|
|
7127
|
-
onClick: () => u(Math.min(
|
|
7128
|
-
disabled: c >=
|
|
7197
|
+
onClick: () => u(Math.min(K - 1, c + 1)),
|
|
7198
|
+
disabled: c >= K - 1,
|
|
7129
7199
|
className: "rounded border border-gray-300 bg-white px-3 py-1 text-sm text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-40",
|
|
7130
7200
|
children: e("common.next")
|
|
7131
7201
|
}
|
|
@@ -7169,7 +7239,7 @@ function jo() {
|
|
|
7169
7239
|
readOnly: !1
|
|
7170
7240
|
}
|
|
7171
7241
|
),
|
|
7172
|
-
/* @__PURE__ */ t(
|
|
7242
|
+
/* @__PURE__ */ t(W, { onClick: x, children: e("common.apply") })
|
|
7173
7243
|
] }),
|
|
7174
7244
|
v ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : !d || !d.rows || d.rows.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noStockData") }) : /* @__PURE__ */ t(X, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
7175
7245
|
/* @__PURE__ */ t("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
|
|
@@ -7199,7 +7269,7 @@ function Va() {
|
|
|
7199
7269
|
const [n] = de("item_code", ""), [a] = de("warehouse", ""), [s] = de("batch_no", ""), [o] = de("item_prefix", ""), [i] = de("expiring_before", ""), [l] = de("location", ""), [c] = de("consignment_customer", ""), h = nt(), [u, g] = C(n), [d, v] = C(a), [k, x] = C(s), [p, w] = C(o), [b, y] = C(i), [m, f] = C(l), [D, N] = C(c), [A, T] = C(null), _ = ye(() => {
|
|
7200
7270
|
const P = {};
|
|
7201
7271
|
return n && (P.item_code = n), a && (P.warehouse = a), s && (P.batch_no = s), o && (P.item_prefix = o), i && (P.expiring_before = i), l && (P.location = l), c && (P.consignment_customer = c), P;
|
|
7202
|
-
}, [n, a, s, o, i, l, c]), { data: V, isLoading:
|
|
7272
|
+
}, [n, a, s, o, i, l, c]), { data: V, isLoading: K, refetch: I } = Bo(_), F = Lo(A), G = Io(A), O = Eo(A), R = () => {
|
|
7203
7273
|
h({
|
|
7204
7274
|
item_code: u || null,
|
|
7205
7275
|
warehouse: d || null,
|
|
@@ -7278,9 +7348,9 @@ function Va() {
|
|
|
7278
7348
|
onChange: (P) => y(P.target.value)
|
|
7279
7349
|
}
|
|
7280
7350
|
),
|
|
7281
|
-
/* @__PURE__ */ t(
|
|
7351
|
+
/* @__PURE__ */ t(W, { onClick: R, children: e("common.apply") })
|
|
7282
7352
|
] }),
|
|
7283
|
-
|
|
7353
|
+
K ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : !V || !V.rows || V.rows.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noStockData", { defaultValue: "No stock data found" }) }) : /* @__PURE__ */ t(X, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
7284
7354
|
/* @__PURE__ */ t("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
|
|
7285
7355
|
/* @__PURE__ */ t("th", { className: z, children: e("fields.Item Code", { defaultValue: "Item Code" }) }),
|
|
7286
7356
|
/* @__PURE__ */ t("th", { className: z, children: e("fields.Item Name", { defaultValue: "Item Name" }) }),
|
|
@@ -7440,7 +7510,7 @@ function Qo() {
|
|
|
7440
7510
|
readOnly: !1
|
|
7441
7511
|
}
|
|
7442
7512
|
),
|
|
7443
|
-
/* @__PURE__ */ t(
|
|
7513
|
+
/* @__PURE__ */ t(W, { onClick: p, children: e("common.apply") })
|
|
7444
7514
|
] }),
|
|
7445
7515
|
k ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : !v || !v.rows || v.rows.length === 0 ? /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noStockData") }) : /* @__PURE__ */ t(X, { children: /* @__PURE__ */ t("div", { className: "overflow-x-auto", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
7446
7516
|
/* @__PURE__ */ t("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
|
|
@@ -7509,7 +7579,7 @@ function Yo() {
|
|
|
7509
7579
|
/* @__PURE__ */ t("input", { type: "checkbox", checked: u, onChange: (y) => g(y.target.checked) }),
|
|
7510
7580
|
e("reports.onlyDeliverable", { defaultValue: "Only what can be delivered now" })
|
|
7511
7581
|
] }),
|
|
7512
|
-
/* @__PURE__ */ t(
|
|
7582
|
+
/* @__PURE__ */ t(W, { onClick: p, children: e("common.apply") })
|
|
7513
7583
|
] }),
|
|
7514
7584
|
k ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : (b = v == null ? void 0 : v.rows) != null && b.length ? /* @__PURE__ */ t(rs, { rows: v.rows, columns: w }) : /* @__PURE__ */ t("p", { className: "py-8 text-center text-gray-400", children: e("reports.noBacklog", { defaultValue: "Nothing open" }) })
|
|
7515
7585
|
] });
|
|
@@ -7555,7 +7625,7 @@ function Jo() {
|
|
|
7555
7625
|
/* @__PURE__ */ t("input", { type: "checkbox", checked: u, onChange: (y) => g(y.target.checked) }),
|
|
7556
7626
|
e("reports.onlyOverdue", { defaultValue: "Only overdue" })
|
|
7557
7627
|
] }),
|
|
7558
|
-
/* @__PURE__ */ t(
|
|
7628
|
+
/* @__PURE__ */ t(W, { onClick: p, children: e("common.apply") })
|
|
7559
7629
|
] }),
|
|
7560
7630
|
k ? /* @__PURE__ */ t("p", { className: "text-gray-500", children: e("common.loading") }) : (b = v == null ? void 0 : v.rows) != null && b.length ? /* @__PURE__ */ r(Ne, { children: [
|
|
7561
7631
|
/* @__PURE__ */ t(rs, { rows: v.rows, columns: w }),
|
|
@@ -7581,7 +7651,7 @@ function Zo() {
|
|
|
7581
7651
|
/* @__PURE__ */ t(Te, { label: e("fields.Company", { defaultValue: "Company" }), value: i, onChange: l, linkDoctype: "company", readOnly: !1 }),
|
|
7582
7652
|
/* @__PURE__ */ t(pe, { label: e("fields.From Date", { defaultValue: "From Date" }), type: "date", value: u, onChange: (m) => g(m.target.value) }),
|
|
7583
7653
|
/* @__PURE__ */ t(pe, { label: e("fields.To Date", { defaultValue: "To Date" }), type: "date", value: d, onChange: (m) => v(m.target.value) }),
|
|
7584
|
-
/* @__PURE__ */ t(
|
|
7654
|
+
/* @__PURE__ */ t(W, { onClick: b, children: e("common.apply") })
|
|
7585
7655
|
] }),
|
|
7586
7656
|
/* @__PURE__ */ t(xn, { onSelect: (m, f) => {
|
|
7587
7657
|
g(m), v(f), o({ from: m, to: f });
|
|
@@ -7664,7 +7734,7 @@ function Xo() {
|
|
|
7664
7734
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
7665
7735
|
/* @__PURE__ */ t(Te, { label: e("fields.Company", { defaultValue: "Company" }), value: o, onChange: i, linkDoctype: "company", readOnly: !1 }),
|
|
7666
7736
|
/* @__PURE__ */ t(pe, { label: e("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (f) => c(f.target.value) }),
|
|
7667
|
-
/* @__PURE__ */ t(
|
|
7737
|
+
/* @__PURE__ */ t(W, { onClick: x, children: e("common.apply") })
|
|
7668
7738
|
] }),
|
|
7669
7739
|
/* @__PURE__ */ t(ca, { onSelect: (f) => {
|
|
7670
7740
|
c(f), s({ as_of_date: f });
|
|
@@ -7705,7 +7775,7 @@ function el() {
|
|
|
7705
7775
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
7706
7776
|
/* @__PURE__ */ t(Te, { label: e("fields.Company", { defaultValue: "Company" }), value: o, onChange: i, linkDoctype: "company", readOnly: !1 }),
|
|
7707
7777
|
/* @__PURE__ */ t(pe, { label: e("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (p) => c(p.target.value) }),
|
|
7708
|
-
/* @__PURE__ */ t(
|
|
7778
|
+
/* @__PURE__ */ t(W, { onClick: x, children: e("common.apply") })
|
|
7709
7779
|
] }),
|
|
7710
7780
|
/* @__PURE__ */ t(ca, { onSelect: (p) => {
|
|
7711
7781
|
c(p), s({ as_of_date: p });
|
|
@@ -7765,7 +7835,7 @@ function tl() {
|
|
|
7765
7835
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
7766
7836
|
/* @__PURE__ */ t(Te, { label: e("fields.Company", { defaultValue: "Company" }), value: o, onChange: i, linkDoctype: "company", readOnly: !1 }),
|
|
7767
7837
|
/* @__PURE__ */ t(pe, { label: e("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (p) => c(p.target.value) }),
|
|
7768
|
-
/* @__PURE__ */ t(
|
|
7838
|
+
/* @__PURE__ */ t(W, { onClick: x, children: e("common.apply") })
|
|
7769
7839
|
] }),
|
|
7770
7840
|
/* @__PURE__ */ t(ca, { onSelect: (p) => {
|
|
7771
7841
|
c(p), s({ as_of_date: p });
|
|
@@ -7968,13 +8038,13 @@ function ol() {
|
|
|
7968
8038
|
const os = ol();
|
|
7969
8039
|
function ll() {
|
|
7970
8040
|
Fe("Analytics");
|
|
7971
|
-
const e =
|
|
8041
|
+
const e = Ke(), { sessions: n, createSession: a } = _t(), [s] = de("report_id", ""), [o] = de("metric", ""), [i] = de("group_by", ""), [l] = de("from", ""), [c] = de("to", ""), [h] = de("company", ""), [u, g] = C(os), [d, v] = C([]), [k, x] = C(null), [p, w] = C(""), [b, y] = C(!1), [m, f] = C(!1), [D, N] = C(""), A = me(""), T = me(""), _ = me(0), V = ye(() => !o || !i ? "" : JSON.stringify(ml({
|
|
7972
8042
|
metric: o,
|
|
7973
8043
|
groupBy: i,
|
|
7974
8044
|
fromDate: l || void 0,
|
|
7975
8045
|
toDate: c || void 0,
|
|
7976
8046
|
company: h || void 0
|
|
7977
|
-
}), null, 2), [o, i, l, c, h]),
|
|
8047
|
+
}), null, 2), [o, i, l, c, h]), K = async (O) => {
|
|
7978
8048
|
const R = ++_.current, z = () => _.current === R;
|
|
7979
8049
|
w(""), y(!0);
|
|
7980
8050
|
try {
|
|
@@ -7996,14 +8066,14 @@ function ll() {
|
|
|
7996
8066
|
return s ? A.current === s ? void 0 : (f(!0), w(""), q.getRuntimeDraft(s).then((R) => {
|
|
7997
8067
|
if (O) return;
|
|
7998
8068
|
const z = JSON.stringify(R.definition, null, 2);
|
|
7999
|
-
return A.current = s, T.current = z, N(R.source_chat_session_id || ""), g(z),
|
|
8069
|
+
return A.current = s, T.current = z, N(R.source_chat_session_id || ""), g(z), K(z);
|
|
8000
8070
|
}).catch((R) => {
|
|
8001
8071
|
O || (x(null), w(R instanceof Error ? R.message : String(R)));
|
|
8002
8072
|
}).finally(() => {
|
|
8003
8073
|
O || f(!1);
|
|
8004
8074
|
}), () => {
|
|
8005
8075
|
O = !0;
|
|
8006
|
-
}) : (A.current = "", T.current = "", N(""), V && (T.current = V, g(V),
|
|
8076
|
+
}) : (A.current = "", T.current = "", N(""), V && (T.current = V, g(V), K(V)), () => {
|
|
8007
8077
|
O = !0;
|
|
8008
8078
|
});
|
|
8009
8079
|
}, [s, V]);
|
|
@@ -8055,8 +8125,8 @@ function ll() {
|
|
|
8055
8125
|
"Loaded draft: ",
|
|
8056
8126
|
s
|
|
8057
8127
|
] }) : I ? /* @__PURE__ */ t("div", { className: "text-xs text-gray-500", children: "Loaded runtime report from legacy URL filters." }) : null,
|
|
8058
|
-
s ? /* @__PURE__ */ t(
|
|
8059
|
-
/* @__PURE__ */ t(
|
|
8128
|
+
s ? /* @__PURE__ */ t(W, { variant: "secondary", onClick: () => void G(), children: "Fix In Chat" }) : null,
|
|
8129
|
+
/* @__PURE__ */ t(W, { onClick: () => void K(), disabled: b, children: b ? "Running..." : "Run Report" })
|
|
8060
8130
|
] })
|
|
8061
8131
|
] }) }),
|
|
8062
8132
|
m ? /* @__PURE__ */ t(X, { children: /* @__PURE__ */ t("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : p ? /* @__PURE__ */ t(X, { children: /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: p }) }) : k ? /* @__PURE__ */ t(cl, { output: k }) : /* @__PURE__ */ t(X, { 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." }) }),
|
|
@@ -8150,7 +8220,7 @@ function cl({ output: e }) {
|
|
|
8150
8220
|
))
|
|
8151
8221
|
] }) : l.type === "pie" ? /* @__PURE__ */ r(mi, { children: [
|
|
8152
8222
|
/* @__PURE__ */ t(Sn, { formatter: x }),
|
|
8153
|
-
/* @__PURE__ */ t(pi, { data: u, dataKey: (w = k[0]) == null ? void 0 : w.key, nameKey: l.x, outerRadius: 110, children: u.map((b, y) => /* @__PURE__ */ t(hi, { fill:
|
|
8223
|
+
/* @__PURE__ */ t(pi, { data: u, dataKey: (w = k[0]) == null ? void 0 : w.key, nameKey: l.x, outerRadius: 110, children: u.map((b, y) => /* @__PURE__ */ t(hi, { fill: Wa[y % Wa.length] }, y)) })
|
|
8154
8224
|
] }) : /* @__PURE__ */ r(gi, { data: u, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
|
|
8155
8225
|
/* @__PURE__ */ t(ga, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
|
|
8156
8226
|
/* @__PURE__ */ t(
|
|
@@ -8390,7 +8460,7 @@ function Ua(e) {
|
|
|
8390
8460
|
const n = Math.abs(e);
|
|
8391
8461
|
return n >= 1e6 ? `${(e / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(e / 1e3).toFixed(0)}k` : String(e);
|
|
8392
8462
|
}
|
|
8393
|
-
const zt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"],
|
|
8463
|
+
const zt = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], Wa = zt, gl = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
8394
8464
|
let Rn = null;
|
|
8395
8465
|
function fl(e, n = gl) {
|
|
8396
8466
|
if (typeof document > "u") return e.length * 7;
|
|
@@ -8417,7 +8487,7 @@ function Xt(e) {
|
|
|
8417
8487
|
const n = `${e.getMonth() + 1}`.padStart(2, "0"), a = `${e.getDate()}`.padStart(2, "0");
|
|
8418
8488
|
return `${e.getFullYear()}-${n}-${a}`;
|
|
8419
8489
|
}
|
|
8420
|
-
function
|
|
8490
|
+
function Ka() {
|
|
8421
8491
|
const e = /* @__PURE__ */ new Date();
|
|
8422
8492
|
return e.setHours(0, 0, 0, 0), e;
|
|
8423
8493
|
}
|
|
@@ -8441,7 +8511,7 @@ const vl = {
|
|
|
8441
8511
|
function kl() {
|
|
8442
8512
|
const { t: e } = ee();
|
|
8443
8513
|
Fe(e("rentals.fleetCalendar", { defaultValue: "Fleet Calendar" }));
|
|
8444
|
-
const n =
|
|
8514
|
+
const n = Ke(), [a, s] = C(28), [o, i] = C(Ka()), [l, c] = C(""), [h, u] = C(""), [g, d] = C(""), [v, k] = C(""), x = ye(() => In(o, a), [o, a]), p = o.getTime(), w = a * cs, b = ye(
|
|
8445
8515
|
() => Array.from({ length: a }, (O, R) => In(o, R)),
|
|
8446
8516
|
[o, a]
|
|
8447
8517
|
), { data: y, isLoading: m, error: f, refetch: D } = bl({
|
|
@@ -8464,7 +8534,7 @@ function kl() {
|
|
|
8464
8534
|
status: "Pool",
|
|
8465
8535
|
meter_reading: null
|
|
8466
8536
|
}))];
|
|
8467
|
-
function
|
|
8537
|
+
function K(O) {
|
|
8468
8538
|
const R = ja(O.from_datetime), z = ja(O.to_datetime), S = Math.max(0, R - p), L = Math.min(w, z - p), j = S / w * 100, ne = Math.max(0.6, (L - S) / w * 100);
|
|
8469
8539
|
return { left: j, width: ne };
|
|
8470
8540
|
}
|
|
@@ -8475,14 +8545,14 @@ function kl() {
|
|
|
8475
8545
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
8476
8546
|
/* @__PURE__ */ t(Te, { label: e("rentals.yard", { defaultValue: "Yard" }), value: l, onChange: c, linkDoctype: "warehouse", readOnly: !1 }),
|
|
8477
8547
|
/* @__PURE__ */ t(Te, { label: e("rentals.machineType", { defaultValue: "Machine type" }), value: h, onChange: u, linkDoctype: "item", readOnly: !1 }),
|
|
8478
|
-
/* @__PURE__ */ t(
|
|
8548
|
+
/* @__PURE__ */ t(W, { onClick: I, children: e("common.apply", { defaultValue: "Apply" }) }),
|
|
8479
8549
|
/* @__PURE__ */ r("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
8480
|
-
/* @__PURE__ */ r(
|
|
8550
|
+
/* @__PURE__ */ r(W, { variant: "secondary", onClick: () => F(-a), children: [
|
|
8481
8551
|
"‹ ",
|
|
8482
8552
|
e("rentals.prev", { defaultValue: "Prev" })
|
|
8483
8553
|
] }),
|
|
8484
|
-
/* @__PURE__ */ t(
|
|
8485
|
-
/* @__PURE__ */ r(
|
|
8554
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => i(Ka()), children: e("rentals.today", { defaultValue: "Today" }) }),
|
|
8555
|
+
/* @__PURE__ */ r(W, { variant: "secondary", onClick: () => F(a), children: [
|
|
8486
8556
|
e("rentals.next", { defaultValue: "Next" }),
|
|
8487
8557
|
" ›"
|
|
8488
8558
|
] }),
|
|
@@ -8508,7 +8578,7 @@ function kl() {
|
|
|
8508
8578
|
]
|
|
8509
8579
|
}
|
|
8510
8580
|
),
|
|
8511
|
-
/* @__PURE__ */ t(
|
|
8581
|
+
/* @__PURE__ */ t(W, { onClick: () => n("/app/reservation/new"), children: e("rentals.newBooking", { defaultValue: "New booking" }) })
|
|
8512
8582
|
] })
|
|
8513
8583
|
] }),
|
|
8514
8584
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap gap-4 text-xs text-gray-500", children: [
|
|
@@ -8555,7 +8625,7 @@ function kl() {
|
|
|
8555
8625
|
/* @__PURE__ */ r("div", { className: "relative", style: { width: G, height: 44 }, children: [
|
|
8556
8626
|
/* @__PURE__ */ t("div", { className: "absolute inset-0 flex", children: b.map((z) => /* @__PURE__ */ t("div", { className: "shrink-0 border-l", style: { width: Bn } }, z.getTime())) }),
|
|
8557
8627
|
R.map((z) => {
|
|
8558
|
-
const { left: S, width: L } =
|
|
8628
|
+
const { left: S, width: L } = K(z), j = vl[z.status ?? ""] ?? "bg-slate-400 text-white";
|
|
8559
8629
|
return /* @__PURE__ */ t(
|
|
8560
8630
|
"button",
|
|
8561
8631
|
{
|
|
@@ -8577,7 +8647,7 @@ function kl() {
|
|
|
8577
8647
|
const Nl = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
|
|
8578
8648
|
function wl() {
|
|
8579
8649
|
Fe("Company Setup");
|
|
8580
|
-
const e =
|
|
8650
|
+
const e = We(), { data: n, isLoading: a } = he({
|
|
8581
8651
|
queryKey: ["setup-status"],
|
|
8582
8652
|
queryFn: () => q.setupStatus()
|
|
8583
8653
|
}), [s, o] = C(""), [i, l] = C("USD"), [c, h] = C({
|
|
@@ -8623,7 +8693,7 @@ function wl() {
|
|
|
8623
8693
|
/* @__PURE__ */ t("span", { className: "font-mono text-gray-900", children: A.toLocaleString() })
|
|
8624
8694
|
] }, N)) })
|
|
8625
8695
|
] }),
|
|
8626
|
-
/* @__PURE__ */ t("div", { className: "mt-6", children: /* @__PURE__ */ t(Ce, { to: "/", children: /* @__PURE__ */ t(
|
|
8696
|
+
/* @__PURE__ */ t("div", { className: "mt-6", children: /* @__PURE__ */ t(Ce, { to: "/", children: /* @__PURE__ */ t(W, { children: "Go to Dashboard" }) }) })
|
|
8627
8697
|
] }) }) });
|
|
8628
8698
|
const f = w.isPending || b.isPending || y.isPending, D = w.error ?? b.error ?? y.error;
|
|
8629
8699
|
return /* @__PURE__ */ r("div", { className: "mx-auto max-w-lg space-y-6", children: [
|
|
@@ -8729,7 +8799,7 @@ function wl() {
|
|
|
8729
8799
|
] })
|
|
8730
8800
|
] }),
|
|
8731
8801
|
/* @__PURE__ */ t("div", { className: "pt-2", children: /* @__PURE__ */ t(
|
|
8732
|
-
|
|
8802
|
+
W,
|
|
8733
8803
|
{
|
|
8734
8804
|
onClick: m,
|
|
8735
8805
|
disabled: f || !s.trim(),
|
|
@@ -8918,7 +8988,7 @@ const Cl = [
|
|
|
8918
8988
|
}
|
|
8919
8989
|
];
|
|
8920
8990
|
function ds() {
|
|
8921
|
-
const e =
|
|
8991
|
+
const e = Ke(), { sessions: n, createSession: a } = _t();
|
|
8922
8992
|
return async (s) => {
|
|
8923
8993
|
var i;
|
|
8924
8994
|
let o = ((i = n[0]) == null ? void 0 : i.id) || "";
|
|
@@ -9322,14 +9392,14 @@ function Ha(e) {
|
|
|
9322
9392
|
}
|
|
9323
9393
|
function Qa() {
|
|
9324
9394
|
var ua;
|
|
9325
|
-
const { t: e } = ee(), { sessionId: n } = vt(), a =
|
|
9395
|
+
const { t: e } = ee(), { sessionId: n } = vt(), a = Ke(), s = ut(), [o] = St(), i = o.get("demo") === "1", [l, c] = C(""), [h, u] = C(""), [g, d] = C([]), [v, k] = C(""), [x, p] = C(!1), [w, b] = C("idle"), y = me(null), m = me(null), f = me([]), {
|
|
9326
9396
|
sessions: D,
|
|
9327
9397
|
connectionStatus: N,
|
|
9328
9398
|
connectionVersion: A,
|
|
9329
9399
|
createSession: T,
|
|
9330
9400
|
startDemo: _,
|
|
9331
9401
|
completeDemoTyping: V,
|
|
9332
|
-
loadHistory:
|
|
9402
|
+
loadHistory: K,
|
|
9333
9403
|
loadMoreHistory: I,
|
|
9334
9404
|
sendMessage: F,
|
|
9335
9405
|
transcribeAudio: G,
|
|
@@ -9406,10 +9476,10 @@ function Qa() {
|
|
|
9406
9476
|
$ = !0;
|
|
9407
9477
|
};
|
|
9408
9478
|
}, [n, De, a]);
|
|
9409
|
-
const ae = me(
|
|
9479
|
+
const ae = me(K);
|
|
9410
9480
|
ie(() => {
|
|
9411
|
-
ae.current =
|
|
9412
|
-
}, [
|
|
9481
|
+
ae.current = K;
|
|
9482
|
+
}, [K]), ie(() => {
|
|
9413
9483
|
!n || !De || i || ce === "running" || ae.current(n).catch(() => {
|
|
9414
9484
|
});
|
|
9415
9485
|
}, [n, De, A, i, ce]), ie(() => {
|
|
@@ -10003,10 +10073,10 @@ function Vl(e, n) {
|
|
|
10003
10073
|
}
|
|
10004
10074
|
return s < e.length && a.push(e.slice(s)), a.length > 0 ? a : [e];
|
|
10005
10075
|
}
|
|
10006
|
-
const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, Kl = { save: "Save", saving: "Saving...", saved: "Saved", unsavedTitle: "Leave without saving?", unsavedBody: "Your changes on this page have not been saved and will be lost.", unsavedLeave: "Discard changes", unsavedStay: "Keep editing", 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" }, Wl = { 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" }, jl = { 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" }, Gl = { 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." }, Hl = { 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" } }, Ql = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Yl = { back: "Back", backToChat: "Back to chat", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Jl = { 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", "batch-stock": "Batch Stock", "stock-detail": "Stock by Location & Batch", "stock-availability": "Stock Availability", "sales-backlog": "Sales Backlog", "purchase-backlog": "Purchase Backlog" }, Zl = { 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" }, reservation: { one: "Reservation", other: "Reservations" } }, Xl = { 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" } }, ec = { 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", Menu: "Menu", "PDF Templates": "PDF Templates", Batch: "Batch", "Batch Stock": "Batch Stock", "Storage Location": "Storage Location", "Stock by Location & Batch": "Stock by Location & Batch", "Stock Reservation": "Stock Reservation", "Stock Availability": "Stock Availability", "Sales Backlog": "Sales Backlog", "Purchase Backlog": "Purchase Backlog", "Consignment Withdrawal": "Consignment Withdrawal", "Stock Count": "Stock Count" } }, tc = { 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." } }, nc = { 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: "Allow apps and scripts to access this ERP through REST or MCP, using API keys or OAuth account linking. Disabled 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: "Apps and API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No connections 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 connections", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "As an administrator, you can manage everyone’s connections. Your own connections appear first.", chatApiConfirmTitle: "This connection belongs to another user", chatApiConfirmRevokeBody: "“{{key}}” belongs to {{name}}. Revoking it will immediately disconnect their app. Continue?", chatApiConfirmDeleteBody: "“{{key}}” belongs to {{name}}. Permanently remove this revoked connection?", chatApiPersonal: "Connect apps using your ERP account. Access never exceeds your current permissions.", version: "Version {{version}}" }, ac = { 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" }, rc = { 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", noBatchStock: "No batch stock found", batchMovements: "Movements of batch {{batch}} ({{item}})", withoutBatch: "without batch", showMovements: "Movements", expired: "expired", onlyDeliverable: "Only what can be delivered now", onlyOverdue: "Only overdue", noBacklog: "Nothing open", unconfirmedNote: "* not confirmed by the supplier: the order's schedule date", batchRecipients: "Who received batch {{batch}}", batchChanges: "Changes to batch {{batch}}" }, sc = { 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}}." }, ic = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, oc = { 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." }, lc = { "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" }, cc = { "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", Website: "Website", "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", "Amount only": "Amount only", "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", "Printed notes / terms": "Printed notes / terms", "PDF Layout": "PDF Layout", "Intro text": "Intro text", "Closing text / terms": "Closing text / terms", Batch: "Batch", "Expiry Date": "Expiry Date", "Manufacturing Date": "Manufacturing Date", "Batch-tracked": "Batch-tracked", "Has Expiry Date": "Has Expiry Date", "Item starts with": "Item starts with", "Expiring before": "Expiring before", Document: "Document", "Storage Location": "Storage Location", "Storage Locations": "Storage Locations", "Source Location": "Source Location", "Target Location": "Target Location", "Reserve Stock": "Reserve Stock", "Shelf Life Exception": "Shelf Life Exception", "Reserved Qty": "Reserved Qty", "Sales Order Line": "Sales Order Line", "Reserved By": "Reserved By", "Min. Shelf Life (days)": "Min. Shelf Life (days)", Blocked: "Blocked", "Blocked Reason": "Blocked Reason", "In Stock": "In Stock", Reserved: "Reserved", Available: "Available", "Open Sales Orders": "Open Sales Orders", "On Purchase Order": "On Purchase Order", "Price Source": "Price Source", "Apply On Value": "Apply On Value", "Applicable For Value": "Applicable For Value", "Confirmed Date": "Confirmed Date", "Confirmation Ref.": "Confirmation Ref.", Ordered: "Ordered", Delivered: "Delivered", Open: "Open", "Deliverable Now": "Deliverable Now", Expected: "Expected", Received: "Received", "Days Overdue": "Days Overdue", "Consignment Customer": "Consignment Customer", "Replenished From": "Replenished From", "Consignment Warehouse": "Consignment Warehouse", "Report Source": "Report Source", "Report Number": "Report Number", Replenish: "Replenish", "Replenish From": "Replenish From", "Replacement Transfer": "Replacement Transfer", Replenishment: "Replenishment", Reason: "Reason", "Counted Lines": "Counted Lines", "Lines With Difference": "Lines With Difference", "System Qty": "System Qty", "Counted Qty": "Counted Qty", Difference: "Difference", Returned: "Returned", "Still With Them": "Still With Them", "Last Delivery": "Last Delivery" }, dc = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, uc = /* @__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?"}`), mc = { title: "Formatting help", intro: "The printed 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." }, pc = { 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" } }, hc = { 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." }, gc = { 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" }, fc = { 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.", pdf_template: "How the reservation confirmation looks." }, quotation: { pdf_template: "How the offer's PDF looks. Fixed when the offer is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New offers start with the default from Settings → PDF Templates.", remarks: "Printed after the totals (where exactly is up to the PDF layout). New offers start with the default from Settings → PDF Templates." }, "sales-order": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "sales-invoice": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "purchase-order": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "delivery-note": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." } }, yc = { 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." }, bc = { title: "Connect an app", subtitle: "Choose where you want to use Lambda ERP. We’ll show only the setup you need.", other: "Something else", customName: "Custom integration", signIn: "Sign in", apiKey: "API key", access: "Access", role_viewer: "View data", role_manager: "Create and edit", role_admin: "Full administrative access", roleHelp: "Access is always limited by your own ERP permissions. Choose only what this app needs.", copied: "Copied", copyFailed: "Could not copy automatically. Select the text and copy it manually.", retry: "Try again", interface: "Connection type", chatDisabled: "Chat API access is disabled. Ask an administrator to enable it in the API settings above.", restDisabled: "REST API / MCP access is disabled. An administrator must enable it in the API settings before this app can connect.", chatgptStep: "Open chatgpt.com in your browser. Select Plugins in the left sidebar, click Add (+) at the top right, then choose Create MCP App. Give it a name, such as Lambda ERP, and a short description.", chatgptDeveloperMode: "If Create MCP App is unavailable, check that Developer mode is enabled under Settings → Security and login. If it is already enabled, go straight to Plugins. Workspace permissions may also apply.", claudeStep: "In Claude Desktop, open Settings → Connectors and choose Add custom connector.", urlStep: "Paste this server URL. Use OAuth sign-in; leave optional client ID and client secret fields empty.", approveStep: "Connect, sign in to Lambda ERP, and approve the access you want to grant.", noKeyNeeded: "No API key or custom header is needed. Access is chosen on the approval screen.", officialGuide: "Open the app’s setup guide", copyUrl: "Copy server URL", keyReady: "Your connection key is ready", copySetup: "Copy setup", copyHeader: "Copy authorization header", cliStep: "Run this command in your terminal, then open /mcp in Claude Code to check the connection.", codexStep: "Add this entry to your Codex configuration, then restart Codex and check /mcp.", done: "Done — hide secret", existing: "Existing connections", refresh: "Refresh", lastUsed: "Last used", notUsed: "Not used yet", consentTitle: "Connect to Lambda ERP", expired: "This connection request is missing or expired. Start again in your app.", loginFirst: "Sign in to your ERP account to review this app’s request.", consentBody: "“{{app}}” is requesting access to your ERP. Choose the access you want to allow.", returnTo: "After approval, you will return to", revokeHelp: "You can revoke this connection at any time in Settings → API access.", deny: "Cancel", allow: "Allow connection", explain_viewer: "The app can read ERP records and reports and generate document PDFs. It cannot edit business records.", explain_manager: "The app can also create, edit, submit and cancel business documents and update master data.", explain_admin: "The app can use all available ERP tools, including administrative actions and deleting master data." }, vc = { title: "Mentions", note: "Internal note", placeholder: "Write a note… use @ to mention a colleague", colleagues: "Colleagues", loading: "Loading…", noUsers: "No matching colleagues", hint: "Write @Name or choose a colleague. People mentioned in the text are notified when you save.", remove: "Remove mention of {{name}}", close: "Close", open: "Open", unread: "Unread", done: "Done", retry: "Retry", empty: "No mentions here.", mentionedYou: "mentioned you", reopen: "Reopen", markDone: "Done", markUnread: "Mark unread", markRead: "Mark read", previous: "Previous", next: "Next" }, xc = { title: "Internal notes", private: "Private to your team · never printed", add: "Add note", placeholder: "Write an internal note… type @ to notify a colleague", save: "Save note", empty: "No internal notes yet.", edited: "edited", older: "Show older notes", printedBadge: "Printed on the PDF", count_one: "{{count}} internal note", count_other: "{{count}} internal notes" }, kc = { title: "Your menu", intro: "Drag groups and items into the order you want and hide the ones you don't use, then save. This only changes your own menu: other people keep theirs, and hidden pages stay reachable by link.", chatHint: 'You can also ask the chat, e.g. "hide the rentals section" or "move CRM to the top".', reset: "Reset to default", hide: "Hide {{name}}", show: "Show {{name}}", locked: "Always shown: this page edits the menu", drag: "Drag to reorder {{name}} (or focus it and use the arrow keys)", discard: "Discard changes", unsaved: "Unsaved changes" }, Nc = { title: "PDF templates", intro: "The layouts documents print with: offers, sales orders, invoices, purchase orders, delivery notes, proposals and reservation confirmations, each type with its own templates and default. Edit a template as often as you like: saving only changes its working copy, and publishing makes it the layout documents print with. A submitted document keeps the layout and the PDF it was issued with.", chatHint: 'You can also ask the chat, e.g. "put our logo top right and use a larger font in the item table".', new: "New template", newTitle: "New PDF template", newBody: "Starts as a copy of {{name}}.", copyOf: "Copy of {{name}}", create: "Create", standard: "Standard", standardDescription: "The built-in layout. Read-only: duplicate it to change the look.", default: "Default", builtIn: "Built-in", notPublished: "Not published", unpublishedChanges: "Unpublished changes", archived: "Archived", usedBy_one: "Used by {{count}} offer", usedBy_other: "Used by {{count}} offers", makeDefault: "Make default", duplicate: "Duplicate", archive: "Archive", restore: "Restore", deleteTitle: "Delete {{name}}?", deleteBody: "No offer has used this template, so nothing depends on it.", showArchived: "Show archived templates", name: "Name", editHint: "Save as often as you like: only the working copy changes. Publish when the preview looks right; documents print with the published layout.", publish: "Publish", revert: "Discard unpublished changes", revertTitle: "Discard unpublished changes?", revertBody: "The working copy goes back to the published layout.", publishedNotice: "Published. Checked against {{document}}.", source: "HTML and CSS", lines_one: "{{count}} line", lines_other: "{{count}} lines", preview: "Preview", previewWith: "Preview with document", refresh: "Refresh", show_draft: "Working copy", show_live: "Published", previewShowsSaved: "The preview shows the last saved version.", blocked: "Not loaded (only uploaded assets are allowed): {{urls}}", assets_one: "Images and fonts ({{count}})", assets_other: "Images and fonts ({{count}})", assetsHint: 'Reference an uploaded file by its name, e.g. <img src="logo.png">. Links to other websites are blocked.', upload: "Upload file", versions_one: "Issued versions ({{count}})", versions_other: "Issued versions ({{count}})", versionsHint: "A version is recorded when a document is submitted with a layout. Documents keep the version they were issued with.", noVersions: "No offer has been issued with this template yet.", firstUsed: "first used {{date}}", reference: "Available fields", standardEditHint: "To change this layout, duplicate it on the", defaultOption: "Default ({{name}})", textDefaults: "Default texts for offers", textDefaultsIntro: "New offers start with these texts; they can be changed on each offer. Changing a default doesn’t change existing offers.", textDefaultsPlaceholders: "Placeholders, filled in when the PDF prints: {{placeholders}}", saveTexts: "Save texts", textsSaved: "Saved.", publishWarnings: "Note: {{warnings}}", uploading: "Uploading…", dropHint: "or drag images and fonts here (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Default texts for {{type}}", textDefaultsIntroFor: "New {{type}} start with these texts; they can be changed on each document. Changing them here doesn’t change existing documents.", newTitleFor: "New PDF template ({{type}})", newFor: "New template: {{type}}", fromOtherType: "Start from another type’s template…", usedByIssued_one: "Used by {{count}} issued document", usedByIssued_other: "Used by {{count}} issued documents" }, wc = { pdf_intro_text_not_printed: "The PDF layout “{{template}}” doesn’t print the intro text; the PDF shows it without.", pdf_remarks_not_printed: "The PDF layout “{{template}}” doesn’t print the closing text / terms; the PDF shows it without.", pdf_line_deduction_not_printed: "The PDF layout “{{template}}” doesn’t print line deductions; those lines show only their net amount.", pdf_variable_not_printed: "The PDF layout “{{template}}” doesn’t print the {{label}}; the PDF shows it without." }, Sc = { defaultLabel: "Deduction", add: "+ Deduction", remove: "Remove deduction", label: "Deduction text", labelPlaceholder: "e.g. Less already invoiced (invoice SINV-0003)", perUnit: "Deduction per unit, printed under the line; the line counts the rest." }, Cc = {
|
|
10076
|
+
const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and at least one Quotation." }, Wl = { save: "Save", saving: "Saving...", saved: "Saved", unsavedTitle: "Leave without saving?", unsavedBody: "Your changes on this page have not been saved and will be lost.", unsavedLeave: "Discard changes", unsavedStay: "Keep editing", 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" }, Kl = { 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" }, jl = { 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" }, Gl = { 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." }, Hl = { 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" } }, Ql = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Yl = { back: "Back", backToChat: "Back to chat", logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Jl = { 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", "batch-stock": "Batch Stock", "stock-detail": "Stock by Location & Batch", "stock-availability": "Stock Availability", "sales-backlog": "Sales Backlog", "purchase-backlog": "Purchase Backlog" }, Zl = { 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" }, reservation: { one: "Reservation", other: "Reservations" } }, Xl = { 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" } }, ec = { 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", Menu: "Menu", "PDF Templates": "PDF Templates", Batch: "Batch", "Batch Stock": "Batch Stock", "Storage Location": "Storage Location", "Serial Number": "Serial Number", "Stock by Location & Batch": "Stock by Location & Batch", "Stock Reservation": "Stock Reservation", "Stock Availability": "Stock Availability", "Sales Backlog": "Sales Backlog", "Purchase Backlog": "Purchase Backlog", "Consignment Withdrawal": "Consignment Withdrawal", "Stock Count": "Stock Count" } }, tc = { 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." } }, nc = { 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: "Allow apps and scripts to access this ERP through REST or MCP, using API keys or OAuth account linking. Disabled 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: "Apps and API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No connections 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 connections", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "As an administrator, you can manage everyone’s connections. Your own connections appear first.", chatApiConfirmTitle: "This connection belongs to another user", chatApiConfirmRevokeBody: "“{{key}}” belongs to {{name}}. Revoking it will immediately disconnect their app. Continue?", chatApiConfirmDeleteBody: "“{{key}}” belongs to {{name}}. Permanently remove this revoked connection?", chatApiPersonal: "Connect apps using your ERP account. Access never exceeds your current permissions.", version: "Version {{version}}" }, ac = { 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" }, rc = { 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", noBatchStock: "No batch stock found", batchMovements: "Movements of batch {{batch}} ({{item}})", withoutBatch: "without batch", showMovements: "Movements", expired: "expired", onlyDeliverable: "Only what can be delivered now", onlyOverdue: "Only overdue", noBacklog: "Nothing open", unconfirmedNote: "* not confirmed by the supplier: the order's schedule date", batchRecipients: "Who received batch {{batch}}", batchChanges: "Changes to batch {{batch}}" }, sc = { 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}}." }, ic = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, oc = { 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." }, lc = { "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" }, cc = { "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", Website: "Website", "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", "Amount only": "Amount only", "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", "Printed notes / terms": "Printed notes / terms", "PDF Layout": "PDF Layout", "Intro text": "Intro text", "Closing text / terms": "Closing text / terms", Batch: "Batch", "Expiry Date": "Expiry Date", "Manufacturing Date": "Manufacturing Date", "Batch-tracked": "Batch-tracked", "Has Expiry Date": "Has Expiry Date", "Item starts with": "Item starts with", "Expiring before": "Expiring before", Document: "Document", "Storage Location": "Storage Location", "Serial Number": "Serial Number", "Serial Numbers": "Serial Numbers", "Serial-tracked": "Serial-tracked", "Storage Locations": "Storage Locations", "Source Location": "Source Location", "Target Location": "Target Location", "Reserve Stock": "Reserve Stock", "Shelf Life Exception": "Shelf Life Exception", "Reserved Qty": "Reserved Qty", "Sales Order Line": "Sales Order Line", "Reserved By": "Reserved By", "Min. Shelf Life (days)": "Min. Shelf Life (days)", Blocked: "Blocked", "Blocked Reason": "Blocked Reason", "In Stock": "In Stock", Reserved: "Reserved", Available: "Available", "Open Sales Orders": "Open Sales Orders", "On Purchase Order": "On Purchase Order", "Price Source": "Price Source", "Apply On Value": "Apply On Value", "Applicable For Value": "Applicable For Value", "Confirmed Date": "Confirmed Date", "Confirmation Ref.": "Confirmation Ref.", Ordered: "Ordered", Delivered: "Delivered", Open: "Open", "Deliverable Now": "Deliverable Now", Expected: "Expected", Received: "Received", "Days Overdue": "Days Overdue", "Consignment Customer": "Consignment Customer", "Replenished From": "Replenished From", "Consignment Warehouse": "Consignment Warehouse", "Report Source": "Report Source", "Report Number": "Report Number", Replenish: "Replenish", "Replenish From": "Replenish From", "Replacement Transfer": "Replacement Transfer", Replenishment: "Replenishment", Reason: "Reason", "Counted Lines": "Counted Lines", "Lines With Difference": "Lines With Difference", "System Qty": "System Qty", "Counted Qty": "Counted Qty", Difference: "Difference", Returned: "Returned", "Still With Them": "Still With Them", "Last Delivery": "Last Delivery" }, dc = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, uc = /* @__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?"}`), mc = { title: "Formatting help", intro: "The printed 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." }, pc = { 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" } }, hc = { 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." }, gc = { 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" }, fc = { 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.", pdf_template: "How the reservation confirmation looks." }, quotation: { pdf_template: "How the offer's PDF looks. Fixed when the offer is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New offers start with the default from Settings → PDF Templates.", remarks: "Printed after the totals (where exactly is up to the PDF layout). New offers start with the default from Settings → PDF Templates." }, "sales-order": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "sales-invoice": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "purchase-order": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." }, "delivery-note": { pdf_template: "How the PDF looks. Fixed when the document is submitted.", intro_text: "Printed above the line items (where exactly is up to the PDF layout). New documents start with the default from Settings → PDF Templates." } }, yc = { 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." }, bc = { title: "Connect an app", subtitle: "Choose where you want to use Lambda ERP. We’ll show only the setup you need.", other: "Something else", customName: "Custom integration", signIn: "Sign in", apiKey: "API key", access: "Access", role_viewer: "View data", role_manager: "Create and edit", role_admin: "Full administrative access", roleHelp: "Access is always limited by your own ERP permissions. Choose only what this app needs.", copied: "Copied", copyFailed: "Could not copy automatically. Select the text and copy it manually.", retry: "Try again", interface: "Connection type", chatDisabled: "Chat API access is disabled. Ask an administrator to enable it in the API settings above.", restDisabled: "REST API / MCP access is disabled. An administrator must enable it in the API settings before this app can connect.", chatgptStep: "Open chatgpt.com in your browser. Select Plugins in the left sidebar, click Add (+) at the top right, then choose Create MCP App. Give it a name, such as Lambda ERP, and a short description.", chatgptDeveloperMode: "If Create MCP App is unavailable, check that Developer mode is enabled under Settings → Security and login. If it is already enabled, go straight to Plugins. Workspace permissions may also apply.", claudeStep: "In Claude Desktop, open Settings → Connectors and choose Add custom connector.", urlStep: "Paste this server URL. Use OAuth sign-in; leave optional client ID and client secret fields empty.", approveStep: "Connect, sign in to Lambda ERP, and approve the access you want to grant.", noKeyNeeded: "No API key or custom header is needed. Access is chosen on the approval screen.", officialGuide: "Open the app’s setup guide", copyUrl: "Copy server URL", keyReady: "Your connection key is ready", copySetup: "Copy setup", copyHeader: "Copy authorization header", cliStep: "Run this command in your terminal, then open /mcp in Claude Code to check the connection.", codexStep: "Add this entry to your Codex configuration, then restart Codex and check /mcp.", done: "Done — hide secret", existing: "Existing connections", refresh: "Refresh", lastUsed: "Last used", notUsed: "Not used yet", consentTitle: "Connect to Lambda ERP", expired: "This connection request is missing or expired. Start again in your app.", loginFirst: "Sign in to your ERP account to review this app’s request.", consentBody: "“{{app}}” is requesting access to your ERP. Choose the access you want to allow.", returnTo: "After approval, you will return to", revokeHelp: "You can revoke this connection at any time in Settings → API access.", deny: "Cancel", allow: "Allow connection", explain_viewer: "The app can read ERP records and reports and generate document PDFs. It cannot edit business records.", explain_manager: "The app can also create, edit, submit and cancel business documents and update master data.", explain_admin: "The app can use all available ERP tools, including administrative actions and deleting master data." }, vc = { title: "Mentions", note: "Internal note", placeholder: "Write a note… use @ to mention a colleague", colleagues: "Colleagues", loading: "Loading…", noUsers: "No matching colleagues", hint: "Write @Name or choose a colleague. People mentioned in the text are notified when you save.", remove: "Remove mention of {{name}}", close: "Close", open: "Open", unread: "Unread", done: "Done", retry: "Retry", empty: "No mentions here.", mentionedYou: "mentioned you", reopen: "Reopen", markDone: "Done", markUnread: "Mark unread", markRead: "Mark read", previous: "Previous", next: "Next" }, xc = { title: "Internal notes", private: "Private to your team · never printed", add: "Add note", placeholder: "Write an internal note… type @ to notify a colleague", save: "Save note", empty: "No internal notes yet.", edited: "edited", older: "Show older notes", printedBadge: "Printed on the PDF", count_one: "{{count}} internal note", count_other: "{{count}} internal notes" }, kc = { title: "Your menu", intro: "Drag groups and items into the order you want and hide the ones you don't use, then save. This only changes your own menu: other people keep theirs, and hidden pages stay reachable by link.", chatHint: 'You can also ask the chat, e.g. "hide the rentals section" or "move CRM to the top".', reset: "Reset to default", hide: "Hide {{name}}", show: "Show {{name}}", locked: "Always shown: this page edits the menu", drag: "Drag to reorder {{name}} (or focus it and use the arrow keys)", discard: "Discard changes", unsaved: "Unsaved changes" }, Nc = { title: "PDF templates", intro: "The layouts documents print with: offers, sales orders, invoices, purchase orders, delivery notes, proposals and reservation confirmations, each type with its own templates and default. Edit a template as often as you like: saving only changes its working copy, and publishing makes it the layout documents print with. A submitted document keeps the layout and the PDF it was issued with.", chatHint: 'You can also ask the chat, e.g. "put our logo top right and use a larger font in the item table".', new: "New template", newTitle: "New PDF template", newBody: "Starts as a copy of {{name}}.", copyOf: "Copy of {{name}}", create: "Create", standard: "Standard", standardDescription: "The built-in layout. Read-only: duplicate it to change the look.", default: "Default", builtIn: "Built-in", notPublished: "Not published", unpublishedChanges: "Unpublished changes", archived: "Archived", usedBy_one: "Used by {{count}} offer", usedBy_other: "Used by {{count}} offers", makeDefault: "Make default", duplicate: "Duplicate", archive: "Archive", restore: "Restore", deleteTitle: "Delete {{name}}?", deleteBody: "No offer has used this template, so nothing depends on it.", showArchived: "Show archived templates", name: "Name", editHint: "Save as often as you like: only the working copy changes. Publish when the preview looks right; documents print with the published layout.", publish: "Publish", revert: "Discard unpublished changes", revertTitle: "Discard unpublished changes?", revertBody: "The working copy goes back to the published layout.", publishedNotice: "Published. Checked against {{document}}.", source: "HTML and CSS", lines_one: "{{count}} line", lines_other: "{{count}} lines", preview: "Preview", previewWith: "Preview with document", refresh: "Refresh", show_draft: "Working copy", show_live: "Published", previewShowsSaved: "The preview shows the last saved version.", blocked: "Not loaded (only uploaded assets are allowed): {{urls}}", assets_one: "Images and fonts ({{count}})", assets_other: "Images and fonts ({{count}})", assetsHint: 'Reference an uploaded file by its name, e.g. <img src="logo.png">. Links to other websites are blocked.', upload: "Upload file", versions_one: "Issued versions ({{count}})", versions_other: "Issued versions ({{count}})", versionsHint: "A version is recorded when a document is submitted with a layout. Documents keep the version they were issued with.", noVersions: "No offer has been issued with this template yet.", firstUsed: "first used {{date}}", reference: "Available fields", standardEditHint: "To change this layout, duplicate it on the", defaultOption: "Default ({{name}})", textDefaults: "Default texts for offers", textDefaultsIntro: "New offers start with these texts; they can be changed on each offer. Changing a default doesn’t change existing offers.", textDefaultsPlaceholders: "Placeholders, filled in when the PDF prints: {{placeholders}}", saveTexts: "Save texts", textsSaved: "Saved.", publishWarnings: "Note: {{warnings}}", uploading: "Uploading…", dropHint: "or drag images and fonts here (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Default texts for {{type}}", textDefaultsIntroFor: "New {{type}} start with these texts; they can be changed on each document. Changing them here doesn’t change existing documents.", newTitleFor: "New PDF template ({{type}})", newFor: "New template: {{type}}", fromOtherType: "Start from another type’s template…", usedByIssued_one: "Used by {{count}} issued document", usedByIssued_other: "Used by {{count}} issued documents" }, wc = { pdf_intro_text_not_printed: "The PDF layout “{{template}}” doesn’t print the intro text; the PDF shows it without.", pdf_remarks_not_printed: "The PDF layout “{{template}}” doesn’t print the closing text / terms; the PDF shows it without.", pdf_line_deduction_not_printed: "The PDF layout “{{template}}” doesn’t print line deductions; those lines show only their net amount.", pdf_variable_not_printed: "The PDF layout “{{template}}” doesn’t print the {{label}}; the PDF shows it without." }, Sc = { defaultLabel: "Deduction", add: "+ Deduction", remove: "Remove deduction", label: "Deduction text", labelPlaceholder: "e.g. Less already invoiced (invoice SINV-0003)", perUnit: "Deduction per unit, printed under the line; the line counts the rest." }, Cc = {
|
|
10007
10077
|
proposal: Ul,
|
|
10008
|
-
common:
|
|
10009
|
-
datePresets:
|
|
10078
|
+
common: Wl,
|
|
10079
|
+
datePresets: Kl,
|
|
10010
10080
|
bankStatements: jl,
|
|
10011
10081
|
bankReconciliation: Gl,
|
|
10012
10082
|
smartSearch: Hl,
|
|
@@ -10040,7 +10110,7 @@ const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and
|
|
|
10040
10110
|
pdfTemplates: Nc,
|
|
10041
10111
|
documentWarnings: wc,
|
|
10042
10112
|
deductions: Sc
|
|
10043
|
-
}, _c = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, Dc = { save: "Speichern", saving: "Speichern...", saved: "Gespeichert", unsavedTitle: "Ohne Speichern verlassen?", unsavedBody: "Ihre Änderungen auf dieser Seite sind nicht gespeichert und gehen verloren.", unsavedLeave: "Änderungen verwerfen", unsavedStay: "Weiter bearbeiten", 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" }, Pc = { 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" }, Ac = { 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" }, Tc = { 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." }, Rc = { 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" } }, Bc = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, Lc = { back: "Zurück", backToChat: "Zurück zum Chat", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, Ic = { 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", "batch-stock": "Chargenbestand", "stock-detail": "Bestand nach Lagerplatz & Charge", "stock-availability": "Verfügbarkeit", "sales-backlog": "Auftragsrückstand", "purchase-backlog": "Bestellrückstand" }, Ec = { 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" }, reservation: { one: "Reservation", other: "Reservationen" } }, Fc = { 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" } }, Oc = { 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", Menu: "Menü", "PDF Templates": "PDF-Vorlagen", Batch: "Charge", "Batch Stock": "Chargenbestand", "Storage Location": "Lagerplatz", "Stock by Location & Batch": "Bestand nach Lagerplatz & Charge", "Stock Reservation": "Bestandsreservierung", "Stock Availability": "Verfügbarkeit", "Sales Backlog": "Auftragsrückstand", "Purchase Backlog": "Bestellrückstand", "Consignment Withdrawal": "Konsignationsentnahme", "Stock Count": "Inventur" } }, qc = { 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." } }, zc = { 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: "Apps und Skripten den Zugriff auf dieses ERP über REST oder MCP erlauben — mit API-Schlüsseln oder OAuth-Anmeldung. Standardmässig 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: "Apps und 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 Verbindungen.", 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 Verbindungen", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator können Sie die Verbindungen aller Benutzer verwalten. Ihre eigenen Verbindungen stehen zuerst.", chatApiConfirmTitle: "Diese Verbindung gehört einem anderen Benutzer", chatApiConfirmRevokeBody: "«{{key}}» gehört {{name}}. Ein Widerruf trennt die App sofort. Fortfahren?", chatApiConfirmDeleteBody: "«{{key}}» gehört {{name}}. Diese widerrufene Verbindung endgültig entfernen?", chatApiPersonal: "Verbinden Sie Apps mit Ihrem ERP-Konto. Der Zugriff überschreitet niemals Ihre aktuellen Berechtigungen.", version: "Version {{version}}" }, Mc = { 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" }, $c = { 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", noBatchStock: "Kein Chargenbestand gefunden", batchMovements: "Bewegungen der Charge {{batch}} ({{item}})", withoutBatch: "ohne Charge", showMovements: "Bewegungen", expired: "abgelaufen", onlyDeliverable: "Nur jetzt Lieferbares", onlyOverdue: "Nur Überfälliges", noBacklog: "Nichts offen", unconfirmedNote: "* vom Lieferanten nicht bestätigt: Wunschtermin der Bestellung", batchRecipients: "Empfänger der Charge {{batch}}", batchChanges: "Änderungen an Charge {{batch}}" }, Vc = { 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." }, Uc = { "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", "Amount only": "Nur Betrag", "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", Website: "Webseite", "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", "Printed notes / terms": "Gedruckte Notizen / Konditionen", "PDF Layout": "PDF-Layout", "Intro text": "Einleitungstext", "Closing text / terms": "Schlusstext / Konditionen", Batch: "Charge", "Expiry Date": "Ablaufdatum", "Manufacturing Date": "Herstelldatum", "Batch-tracked": "Chargenpflichtig", "Has Expiry Date": "Mit Ablaufdatum", "Item starts with": "Artikel beginnt mit", "Expiring before": "Ablauf vor", Document: "Beleg", "Storage Location": "Lagerplatz", "Storage Locations": "Lagerplätze", "Source Location": "Von Lagerplatz", "Target Location": "Nach Lagerplatz", "Reserve Stock": "Bestand reservieren", "Shelf Life Exception": "Ausnahme Restlaufzeit", "Reserved Qty": "Reservierte Menge", "Sales Order Line": "Auftragsposition", "Reserved By": "Reserviert von", "Min. Shelf Life (days)": "Mindestrestlaufzeit (Tage)", Blocked: "Gesperrt", "Blocked Reason": "Sperrgrund", "In Stock": "Am Lager", Reserved: "Reserviert", Available: "Verfügbar", "Open Sales Orders": "Offene Aufträge", "On Purchase Order": "In Bestellung", "Price Source": "Preisquelle", "Apply On Value": "Wert zu „Anwenden auf“", "Applicable For Value": "Wert zu „Gilt für“", "Confirmed Date": "Bestätigter Termin", "Confirmation Ref.": "Bestätigungsnr.", Ordered: "Bestellt", Delivered: "Geliefert", Open: "Offen", "Deliverable Now": "Jetzt lieferbar", Expected: "Erwartet", Received: "Erhalten", "Days Overdue": "Tage überfällig", "Consignment Customer": "Konsignationskunde", "Replenished From": "Beschickung aus", "Consignment Warehouse": "Konsignationslager", "Report Source": "Quelle der Meldung", "Report Number": "Meldungsnummer", Replenish: "Nachbeschicken", "Replenish From": "Nachbeschickung aus", "Replacement Transfer": "Ersatzbeschickung", Replenishment: "Nachbeschickung", Reason: "Grund", "Counted Lines": "Gezählte Positionen", "Lines With Difference": "Positionen mit Differenz", "System Qty": "Menge laut System", "Counted Qty": "Gezählte Menge", Difference: "Differenz", Returned: "Retourniert", "Still With Them": "Noch beim Kunden", "Last Delivery": "Letzte Lieferung" }, Kc = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Wc = { "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" }, jc = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Gc = { 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." }, Hc = /* @__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?"}'), Qc = { title: "Formatierungshilfe", intro: "Der Text unter Gedruckte 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." }, Yc = { 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" } }, Jc = { 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." }, Zc = { 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" }, Xc = { 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.", pdf_template: "Wie die Reservationsbestätigung aussieht." }, quotation: { pdf_template: "Wie das PDF der Offerte aussieht. Wird beim Buchen der Offerte festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Offerten starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen.", remarks: "Wird nach den Summen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Offerten starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "sales-order": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "sales-invoice": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "purchase-order": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "delivery-note": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." } }, ed = { 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." }, td = { title: "App verbinden", subtitle: "Wählen Sie, wo Sie Lambda ERP nutzen möchten. Wir zeigen Ihnen die passende Einrichtung.", other: "Etwas anderes", customName: "Eigene Integration", signIn: "Anmelden", apiKey: "API-Schlüssel", access: "Zugriff", role_viewer: "Daten ansehen", role_manager: "Erstellen und bearbeiten", role_admin: "Voller administrativer Zugriff", roleHelp: "Der Zugriff ist immer durch Ihre eigenen ERP-Berechtigungen begrenzt. Wählen Sie nur, was diese App benötigt.", copied: "Kopiert", copyFailed: "Automatisches Kopieren fehlgeschlagen. Markieren und kopieren Sie den Text manuell.", retry: "Erneut versuchen", interface: "Verbindungsart", chatDisabled: "Der Chat-API-Zugriff ist deaktiviert. Ein Administrator kann ihn oben in den API-Einstellungen aktivieren.", restDisabled: "Der REST-API-/MCP-Zugriff ist deaktiviert. Ein Administrator muss ihn in den API-Einstellungen aktivieren, bevor sich diese App verbinden kann.", chatgptStep: "Öffnen Sie chatgpt.com im Browser. Wählen Sie «Plugins» in der linken Seitenleiste, klicken Sie oben rechts auf «Add» (+) und wählen Sie «Create MCP App». Geben Sie einen Namen, etwa Lambda ERP, und eine kurze Beschreibung ein.", chatgptDeveloperMode: "Falls «Create MCP App» nicht verfügbar ist, prüfen Sie unter «Settings» → «Security and login», ob «Developer mode» aktiviert ist. Ist er bereits aktiviert, gehen Sie direkt zu «Plugins». Zusätzlich können Workspace-Berechtigungen erforderlich sein.", claudeStep: "Öffnen Sie in Claude Desktop «Settings» → «Connectors» und wählen Sie «Add custom connector».", urlStep: "Fügen Sie diese Server-URL ein. Verwenden Sie die OAuth-Anmeldung; lassen Sie optionale Felder für Client-ID und Client-Secret leer.", approveStep: "Verbinden Sie die App, melden Sie sich bei Lambda ERP an und bestätigen Sie den gewünschten Zugriff.", noKeyNeeded: "Sie benötigen weder API-Schlüssel noch eigene Header. Den Zugriff wählen Sie auf der Bestätigungsseite.", officialGuide: "Einrichtungsanleitung der App öffnen", copyUrl: "Server-URL kopieren", keyReady: "Ihr Verbindungsschlüssel ist bereit", copySetup: "Einrichtung kopieren", copyHeader: "Autorisierungsheader kopieren", cliStep: "Führen Sie diesen Befehl im Terminal aus. Prüfen Sie die Verbindung anschliessend mit /mcp in Claude Code.", codexStep: "Fügen Sie diesen Eintrag Ihrer Codex-Konfiguration hinzu. Starten Sie Codex neu und prüfen Sie /mcp.", done: "Fertig — Schlüssel ausblenden", existing: "Bestehende Verbindungen", refresh: "Aktualisieren", lastUsed: "Zuletzt verwendet", notUsed: "Noch nicht verwendet", consentTitle: "Mit Lambda ERP verbinden", expired: "Diese Verbindungsanfrage fehlt oder ist abgelaufen. Starten Sie erneut in Ihrer App.", loginFirst: "Melden Sie sich bei Ihrem ERP-Konto an, um die Anfrage dieser App zu prüfen.", consentBody: "«{{app}}» möchte auf Ihr ERP zugreifen. Wählen Sie den Zugriff, den Sie erlauben möchten.", returnTo: "Nach der Bestätigung kehren Sie hierhin zurück", revokeHelp: "Sie können diese Verbindung jederzeit unter Einstellungen → API-Zugriff widerrufen.", deny: "Abbrechen", allow: "Verbindung erlauben", explain_viewer: "Die App kann ERP-Datensätze und Berichte lesen sowie Beleg-PDFs erstellen. Sie kann keine Geschäftsdaten bearbeiten.", explain_manager: "Die App kann zusätzlich Belege erstellen, bearbeiten, buchen und stornieren sowie Stammdaten aktualisieren.", explain_admin: "Die App kann alle verfügbaren ERP-Werkzeuge nutzen, einschliesslich administrativer Aktionen und dem Löschen von Stammdaten." }, nd = { title: "Erwähnungen", note: "Interne Notiz", placeholder: "Notiz schreiben… mit @ jemanden erwähnen", colleagues: "Kolleginnen und Kollegen", loading: "Laden…", noUsers: "Keine passenden Personen", hint: "Schreibe @Name oder wähle eine Person. Im Text erwähnte Personen werden beim Speichern benachrichtigt.", remove: "Erwähnung von {{name}} entfernen", close: "Schliessen", open: "Offen", unread: "Ungelesen", done: "Erledigt", retry: "Erneut versuchen", empty: "Hier gibt es keine Erwähnungen.", mentionedYou: "hat dich erwähnt", reopen: "Wieder öffnen", markDone: "Erledigt", markUnread: "Als ungelesen markieren", markRead: "Als gelesen markieren", previous: "Zurück", next: "Weiter" }, ad = { title: "Interne Notizen", private: "Nur für Ihr Team · wird nie gedruckt", add: "Notiz hinzufügen", placeholder: "Interne Notiz schreiben … mit @ jemanden aus dem Team benachrichtigen", save: "Notiz speichern", empty: "Noch keine internen Notizen.", edited: "bearbeitet", older: "Ältere Notizen anzeigen", printedBadge: "Erscheint auf dem PDF", count_one: "{{count}} interne Notiz", count_other: "{{count}} interne Notizen" }, rd = { title: "Ihr Menü", intro: "Ziehen Sie Gruppen und Einträge in die gewünschte Reihenfolge, blenden Sie aus, was Sie nicht brauchen, und speichern Sie. Das ändert nur Ihr eigenes Menü: andere behalten ihres, und ausgeblendete Seiten bleiben per Link erreichbar.", chatHint: "Das geht auch im Chat, z. B. „Blende die Vermietung aus“ oder „Schiebe CRM nach oben“.", reset: "Auf Standard zurücksetzen", hide: "{{name}} ausblenden", show: "{{name}} einblenden", locked: "Immer sichtbar: Hier wird das Menü bearbeitet", drag: "{{name}} ziehen, um die Reihenfolge zu ändern (oder auswählen und Pfeiltasten nutzen)", discard: "Änderungen verwerfen", unsaved: "Nicht gespeicherte Änderungen" }, sd = { title: "PDF-Vorlagen", intro: "Die Layouts, mit denen Belege gedruckt werden: Offerten, Aufträge, Rechnungen, Bestellungen, Lieferscheine, Sammelofferten und Reservationsbestätigungen, jeder Typ mit eigenen Vorlagen und eigenem Standard. Bearbeite eine Vorlage so oft du willst: Speichern ändert nur den Entwurf, Veröffentlichen macht ihn zum Layout der Belege. Ein gebuchter Beleg behält das Layout und das PDF, mit dem er ausgestellt wurde.", chatHint: "Du kannst auch den Chat fragen, z. B. „setz unser Logo oben rechts und nimm eine grössere Schrift in der Positionstabelle“.", new: "Neue Vorlage", newTitle: "Neue PDF-Vorlage", newBody: "Startet als Kopie von {{name}}.", copyOf: "Kopie von {{name}}", create: "Erstellen", standard: "Standard", standardDescription: "Das eingebaute Layout. Nur lesbar: dupliziere es, um das Aussehen zu ändern.", default: "Standardvorlage", builtIn: "Eingebaut", notPublished: "Nicht veröffentlicht", unpublishedChanges: "Unveröffentlichte Änderungen", archived: "Archiviert", usedBy_one: "Von {{count}} Offerte verwendet", usedBy_other: "Von {{count}} Offerten verwendet", makeDefault: "Als Standard setzen", duplicate: "Duplizieren", archive: "Archivieren", restore: "Wiederherstellen", deleteTitle: "{{name}} löschen?", deleteBody: "Keine Offerte hat diese Vorlage verwendet, es hängt also nichts davon ab.", showArchived: "Archivierte Vorlagen anzeigen", name: "Name", editHint: "Speichere so oft du willst: Es ändert sich nur der Entwurf. Veröffentliche, wenn die Vorschau stimmt; Belege drucken mit dem veröffentlichten Layout.", publish: "Veröffentlichen", revert: "Unveröffentlichte Änderungen verwerfen", revertTitle: "Unveröffentlichte Änderungen verwerfen?", revertBody: "Der Entwurf wird auf das veröffentlichte Layout zurückgesetzt.", publishedNotice: "Veröffentlicht. Geprüft mit {{document}}.", source: "HTML und CSS", lines_one: "{{count}} Zeile", lines_other: "{{count}} Zeilen", preview: "Vorschau", previewWith: "Vorschau mit Beleg", refresh: "Aktualisieren", show_draft: "Entwurf", show_live: "Veröffentlicht", previewShowsSaved: "Die Vorschau zeigt den zuletzt gespeicherten Stand.", blocked: "Nicht geladen (nur hochgeladene Dateien sind erlaubt): {{urls}}", assets_one: "Bilder und Schriften ({{count}})", assets_other: "Bilder und Schriften ({{count}})", assetsHint: 'Verweise auf eine hochgeladene Datei mit ihrem Namen, z. B. <img src="logo.png">. Links auf andere Websites werden blockiert.', upload: "Datei hochladen", versions_one: "Ausgestellte Versionen ({{count}})", versions_other: "Ausgestellte Versionen ({{count}})", versionsHint: "Eine Version entsteht, wenn ein Beleg mit einem Layout gebucht wird. Belege behalten die Version, mit der sie ausgestellt wurden.", noVersions: "Mit dieser Vorlage wurde noch keine Offerte ausgestellt.", firstUsed: "zuerst verwendet am {{date}}", reference: "Verfügbare Felder", standardEditHint: "Um dieses Layout zu ändern, dupliziere es auf der Seite", defaultOption: "Standard ({{name}})", textDefaults: "Standardtexte für Offerten", textDefaultsIntro: "Neue Offerten starten mit diesen Texten; sie lassen sich pro Offerte ändern. Eine Änderung hier ändert bestehende Offerten nicht.", textDefaultsPlaceholders: "Platzhalter, beim Drucken ersetzt: {{placeholders}}", saveTexts: "Texte speichern", textsSaved: "Gespeichert.", publishWarnings: "Hinweis: {{warnings}}", uploading: "Wird hochgeladen…", dropHint: "oder Bilder und Schriften hierher ziehen (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Standardtexte für {{type}}", textDefaultsIntroFor: "Neue {{type}} starten mit diesen Texten; sie lassen sich pro Beleg ändern. Eine Änderung hier ändert bestehende Belege nicht.", newTitleFor: "Neue PDF-Vorlage ({{type}})", newFor: "Neue Vorlage: {{type}}", fromOtherType: "Aus Vorlage eines anderen Typs…", usedByIssued_one: "Von {{count}} gebuchten Beleg verwendet", usedByIssued_other: "Von {{count}} gebuchten Belegen verwendet" }, id = { pdf_intro_text_not_printed: "Das PDF-Layout «{{template}}» druckt den Einleitungstext nicht; das PDF erscheint ohne ihn.", pdf_remarks_not_printed: "Das PDF-Layout «{{template}}» druckt den Schlusstext / die Konditionen nicht; das PDF erscheint ohne sie.", pdf_line_deduction_not_printed: "Das PDF-Layout «{{template}}» druckt keine Abzüge auf Positionen; diese Positionen erscheinen nur mit dem Nettobetrag.", pdf_variable_not_printed: "Das PDF-Layout «{{template}}» druckt {{label}} nicht; das PDF erscheint ohne." }, od = { defaultLabel: "Abzug", add: "+ Abzug", remove: "Abzug entfernen", label: "Text des Abzugs", labelPlaceholder: "z. B. Abzüglich bereits verrechnet (Rechnung SINV-0003)", perUnit: "Abzug pro Einheit, wird unter der Position gedruckt; die Position zählt den Rest." }, ld = {
|
|
10113
|
+
}, _c = { incomplete: "Entwurf gespeichert. Für das PDF werden Kunde, Unternehmen und mindestens ein Angebot benötigt." }, Dc = { save: "Speichern", saving: "Speichern...", saved: "Gespeichert", unsavedTitle: "Ohne Speichern verlassen?", unsavedBody: "Ihre Änderungen auf dieser Seite sind nicht gespeichert und gehen verloren.", unsavedLeave: "Änderungen verwerfen", unsavedStay: "Weiter bearbeiten", 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" }, Pc = { 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" }, Ac = { 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" }, Tc = { 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." }, Rc = { 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" } }, Bc = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, Lc = { back: "Zurück", backToChat: "Zurück zum Chat", logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, Ic = { 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", "batch-stock": "Chargenbestand", "stock-detail": "Bestand nach Lagerplatz & Charge", "stock-availability": "Verfügbarkeit", "sales-backlog": "Auftragsrückstand", "purchase-backlog": "Bestellrückstand" }, Ec = { 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" }, reservation: { one: "Reservation", other: "Reservationen" } }, Fc = { 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" } }, Oc = { 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", Menu: "Menü", "PDF Templates": "PDF-Vorlagen", Batch: "Charge", "Batch Stock": "Chargenbestand", "Storage Location": "Lagerplatz", "Serial Number": "Seriennummer", "Stock by Location & Batch": "Bestand nach Lagerplatz & Charge", "Stock Reservation": "Bestandsreservierung", "Stock Availability": "Verfügbarkeit", "Sales Backlog": "Auftragsrückstand", "Purchase Backlog": "Bestellrückstand", "Consignment Withdrawal": "Konsignationsentnahme", "Stock Count": "Inventur" } }, qc = { 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." } }, zc = { 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: "Apps und Skripten den Zugriff auf dieses ERP über REST oder MCP erlauben — mit API-Schlüsseln oder OAuth-Anmeldung. Standardmässig 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: "Apps und 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 Verbindungen.", 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 Verbindungen", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator können Sie die Verbindungen aller Benutzer verwalten. Ihre eigenen Verbindungen stehen zuerst.", chatApiConfirmTitle: "Diese Verbindung gehört einem anderen Benutzer", chatApiConfirmRevokeBody: "«{{key}}» gehört {{name}}. Ein Widerruf trennt die App sofort. Fortfahren?", chatApiConfirmDeleteBody: "«{{key}}» gehört {{name}}. Diese widerrufene Verbindung endgültig entfernen?", chatApiPersonal: "Verbinden Sie Apps mit Ihrem ERP-Konto. Der Zugriff überschreitet niemals Ihre aktuellen Berechtigungen.", version: "Version {{version}}" }, Mc = { 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" }, $c = { 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", noBatchStock: "Kein Chargenbestand gefunden", batchMovements: "Bewegungen der Charge {{batch}} ({{item}})", withoutBatch: "ohne Charge", showMovements: "Bewegungen", expired: "abgelaufen", onlyDeliverable: "Nur jetzt Lieferbares", onlyOverdue: "Nur Überfälliges", noBacklog: "Nichts offen", unconfirmedNote: "* vom Lieferanten nicht bestätigt: Wunschtermin der Bestellung", batchRecipients: "Empfänger der Charge {{batch}}", batchChanges: "Änderungen an Charge {{batch}}" }, Vc = { 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." }, Uc = { "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", "Amount only": "Nur Betrag", "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", Website: "Webseite", "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", "Printed notes / terms": "Gedruckte Notizen / Konditionen", "PDF Layout": "PDF-Layout", "Intro text": "Einleitungstext", "Closing text / terms": "Schlusstext / Konditionen", Batch: "Charge", "Expiry Date": "Ablaufdatum", "Manufacturing Date": "Herstelldatum", "Batch-tracked": "Chargenpflichtig", "Has Expiry Date": "Mit Ablaufdatum", "Item starts with": "Artikel beginnt mit", "Expiring before": "Ablauf vor", Document: "Beleg", "Storage Location": "Lagerplatz", "Serial Number": "Seriennummer", "Serial Numbers": "Seriennummern", "Serial-tracked": "Seriennummernpflichtig", "Storage Locations": "Lagerplätze", "Source Location": "Von Lagerplatz", "Target Location": "Nach Lagerplatz", "Reserve Stock": "Bestand reservieren", "Shelf Life Exception": "Ausnahme Restlaufzeit", "Reserved Qty": "Reservierte Menge", "Sales Order Line": "Auftragsposition", "Reserved By": "Reserviert von", "Min. Shelf Life (days)": "Mindestrestlaufzeit (Tage)", Blocked: "Gesperrt", "Blocked Reason": "Sperrgrund", "In Stock": "Am Lager", Reserved: "Reserviert", Available: "Verfügbar", "Open Sales Orders": "Offene Aufträge", "On Purchase Order": "In Bestellung", "Price Source": "Preisquelle", "Apply On Value": "Wert zu „Anwenden auf“", "Applicable For Value": "Wert zu „Gilt für“", "Confirmed Date": "Bestätigter Termin", "Confirmation Ref.": "Bestätigungsnr.", Ordered: "Bestellt", Delivered: "Geliefert", Open: "Offen", "Deliverable Now": "Jetzt lieferbar", Expected: "Erwartet", Received: "Erhalten", "Days Overdue": "Tage überfällig", "Consignment Customer": "Konsignationskunde", "Replenished From": "Beschickung aus", "Consignment Warehouse": "Konsignationslager", "Report Source": "Quelle der Meldung", "Report Number": "Meldungsnummer", Replenish: "Nachbeschicken", "Replenish From": "Nachbeschickung aus", "Replacement Transfer": "Ersatzbeschickung", Replenishment: "Nachbeschickung", Reason: "Grund", "Counted Lines": "Gezählte Positionen", "Lines With Difference": "Positionen mit Differenz", "System Qty": "Menge laut System", "Counted Qty": "Gezählte Menge", Difference: "Differenz", Returned: "Retourniert", "Still With Them": "Noch beim Kunden", "Last Delivery": "Letzte Lieferung" }, Wc = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Kc = { "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" }, jc = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Gc = { 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." }, Hc = /* @__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?"}'), Qc = { title: "Formatierungshilfe", intro: "Der Text unter Gedruckte 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." }, Yc = { 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" } }, Jc = { 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." }, Zc = { 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" }, Xc = { 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.", pdf_template: "Wie die Reservationsbestätigung aussieht." }, quotation: { pdf_template: "Wie das PDF der Offerte aussieht. Wird beim Buchen der Offerte festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Offerten starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen.", remarks: "Wird nach den Summen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Offerten starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "sales-order": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "sales-invoice": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "purchase-order": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." }, "delivery-note": { pdf_template: "Wie das PDF aussieht. Wird beim Buchen festgehalten.", intro_text: "Wird über den Positionen gedruckt (wo genau, bestimmt das PDF-Layout). Neue Belege starten mit dem Standardtext aus Einstellungen → PDF-Vorlagen." } }, ed = { 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." }, td = { title: "App verbinden", subtitle: "Wählen Sie, wo Sie Lambda ERP nutzen möchten. Wir zeigen Ihnen die passende Einrichtung.", other: "Etwas anderes", customName: "Eigene Integration", signIn: "Anmelden", apiKey: "API-Schlüssel", access: "Zugriff", role_viewer: "Daten ansehen", role_manager: "Erstellen und bearbeiten", role_admin: "Voller administrativer Zugriff", roleHelp: "Der Zugriff ist immer durch Ihre eigenen ERP-Berechtigungen begrenzt. Wählen Sie nur, was diese App benötigt.", copied: "Kopiert", copyFailed: "Automatisches Kopieren fehlgeschlagen. Markieren und kopieren Sie den Text manuell.", retry: "Erneut versuchen", interface: "Verbindungsart", chatDisabled: "Der Chat-API-Zugriff ist deaktiviert. Ein Administrator kann ihn oben in den API-Einstellungen aktivieren.", restDisabled: "Der REST-API-/MCP-Zugriff ist deaktiviert. Ein Administrator muss ihn in den API-Einstellungen aktivieren, bevor sich diese App verbinden kann.", chatgptStep: "Öffnen Sie chatgpt.com im Browser. Wählen Sie «Plugins» in der linken Seitenleiste, klicken Sie oben rechts auf «Add» (+) und wählen Sie «Create MCP App». Geben Sie einen Namen, etwa Lambda ERP, und eine kurze Beschreibung ein.", chatgptDeveloperMode: "Falls «Create MCP App» nicht verfügbar ist, prüfen Sie unter «Settings» → «Security and login», ob «Developer mode» aktiviert ist. Ist er bereits aktiviert, gehen Sie direkt zu «Plugins». Zusätzlich können Workspace-Berechtigungen erforderlich sein.", claudeStep: "Öffnen Sie in Claude Desktop «Settings» → «Connectors» und wählen Sie «Add custom connector».", urlStep: "Fügen Sie diese Server-URL ein. Verwenden Sie die OAuth-Anmeldung; lassen Sie optionale Felder für Client-ID und Client-Secret leer.", approveStep: "Verbinden Sie die App, melden Sie sich bei Lambda ERP an und bestätigen Sie den gewünschten Zugriff.", noKeyNeeded: "Sie benötigen weder API-Schlüssel noch eigene Header. Den Zugriff wählen Sie auf der Bestätigungsseite.", officialGuide: "Einrichtungsanleitung der App öffnen", copyUrl: "Server-URL kopieren", keyReady: "Ihr Verbindungsschlüssel ist bereit", copySetup: "Einrichtung kopieren", copyHeader: "Autorisierungsheader kopieren", cliStep: "Führen Sie diesen Befehl im Terminal aus. Prüfen Sie die Verbindung anschliessend mit /mcp in Claude Code.", codexStep: "Fügen Sie diesen Eintrag Ihrer Codex-Konfiguration hinzu. Starten Sie Codex neu und prüfen Sie /mcp.", done: "Fertig — Schlüssel ausblenden", existing: "Bestehende Verbindungen", refresh: "Aktualisieren", lastUsed: "Zuletzt verwendet", notUsed: "Noch nicht verwendet", consentTitle: "Mit Lambda ERP verbinden", expired: "Diese Verbindungsanfrage fehlt oder ist abgelaufen. Starten Sie erneut in Ihrer App.", loginFirst: "Melden Sie sich bei Ihrem ERP-Konto an, um die Anfrage dieser App zu prüfen.", consentBody: "«{{app}}» möchte auf Ihr ERP zugreifen. Wählen Sie den Zugriff, den Sie erlauben möchten.", returnTo: "Nach der Bestätigung kehren Sie hierhin zurück", revokeHelp: "Sie können diese Verbindung jederzeit unter Einstellungen → API-Zugriff widerrufen.", deny: "Abbrechen", allow: "Verbindung erlauben", explain_viewer: "Die App kann ERP-Datensätze und Berichte lesen sowie Beleg-PDFs erstellen. Sie kann keine Geschäftsdaten bearbeiten.", explain_manager: "Die App kann zusätzlich Belege erstellen, bearbeiten, buchen und stornieren sowie Stammdaten aktualisieren.", explain_admin: "Die App kann alle verfügbaren ERP-Werkzeuge nutzen, einschliesslich administrativer Aktionen und dem Löschen von Stammdaten." }, nd = { title: "Erwähnungen", note: "Interne Notiz", placeholder: "Notiz schreiben… mit @ jemanden erwähnen", colleagues: "Kolleginnen und Kollegen", loading: "Laden…", noUsers: "Keine passenden Personen", hint: "Schreibe @Name oder wähle eine Person. Im Text erwähnte Personen werden beim Speichern benachrichtigt.", remove: "Erwähnung von {{name}} entfernen", close: "Schliessen", open: "Offen", unread: "Ungelesen", done: "Erledigt", retry: "Erneut versuchen", empty: "Hier gibt es keine Erwähnungen.", mentionedYou: "hat dich erwähnt", reopen: "Wieder öffnen", markDone: "Erledigt", markUnread: "Als ungelesen markieren", markRead: "Als gelesen markieren", previous: "Zurück", next: "Weiter" }, ad = { title: "Interne Notizen", private: "Nur für Ihr Team · wird nie gedruckt", add: "Notiz hinzufügen", placeholder: "Interne Notiz schreiben … mit @ jemanden aus dem Team benachrichtigen", save: "Notiz speichern", empty: "Noch keine internen Notizen.", edited: "bearbeitet", older: "Ältere Notizen anzeigen", printedBadge: "Erscheint auf dem PDF", count_one: "{{count}} interne Notiz", count_other: "{{count}} interne Notizen" }, rd = { title: "Ihr Menü", intro: "Ziehen Sie Gruppen und Einträge in die gewünschte Reihenfolge, blenden Sie aus, was Sie nicht brauchen, und speichern Sie. Das ändert nur Ihr eigenes Menü: andere behalten ihres, und ausgeblendete Seiten bleiben per Link erreichbar.", chatHint: "Das geht auch im Chat, z. B. „Blende die Vermietung aus“ oder „Schiebe CRM nach oben“.", reset: "Auf Standard zurücksetzen", hide: "{{name}} ausblenden", show: "{{name}} einblenden", locked: "Immer sichtbar: Hier wird das Menü bearbeitet", drag: "{{name}} ziehen, um die Reihenfolge zu ändern (oder auswählen und Pfeiltasten nutzen)", discard: "Änderungen verwerfen", unsaved: "Nicht gespeicherte Änderungen" }, sd = { title: "PDF-Vorlagen", intro: "Die Layouts, mit denen Belege gedruckt werden: Offerten, Aufträge, Rechnungen, Bestellungen, Lieferscheine, Sammelofferten und Reservationsbestätigungen, jeder Typ mit eigenen Vorlagen und eigenem Standard. Bearbeite eine Vorlage so oft du willst: Speichern ändert nur den Entwurf, Veröffentlichen macht ihn zum Layout der Belege. Ein gebuchter Beleg behält das Layout und das PDF, mit dem er ausgestellt wurde.", chatHint: "Du kannst auch den Chat fragen, z. B. „setz unser Logo oben rechts und nimm eine grössere Schrift in der Positionstabelle“.", new: "Neue Vorlage", newTitle: "Neue PDF-Vorlage", newBody: "Startet als Kopie von {{name}}.", copyOf: "Kopie von {{name}}", create: "Erstellen", standard: "Standard", standardDescription: "Das eingebaute Layout. Nur lesbar: dupliziere es, um das Aussehen zu ändern.", default: "Standardvorlage", builtIn: "Eingebaut", notPublished: "Nicht veröffentlicht", unpublishedChanges: "Unveröffentlichte Änderungen", archived: "Archiviert", usedBy_one: "Von {{count}} Offerte verwendet", usedBy_other: "Von {{count}} Offerten verwendet", makeDefault: "Als Standard setzen", duplicate: "Duplizieren", archive: "Archivieren", restore: "Wiederherstellen", deleteTitle: "{{name}} löschen?", deleteBody: "Keine Offerte hat diese Vorlage verwendet, es hängt also nichts davon ab.", showArchived: "Archivierte Vorlagen anzeigen", name: "Name", editHint: "Speichere so oft du willst: Es ändert sich nur der Entwurf. Veröffentliche, wenn die Vorschau stimmt; Belege drucken mit dem veröffentlichten Layout.", publish: "Veröffentlichen", revert: "Unveröffentlichte Änderungen verwerfen", revertTitle: "Unveröffentlichte Änderungen verwerfen?", revertBody: "Der Entwurf wird auf das veröffentlichte Layout zurückgesetzt.", publishedNotice: "Veröffentlicht. Geprüft mit {{document}}.", source: "HTML und CSS", lines_one: "{{count}} Zeile", lines_other: "{{count}} Zeilen", preview: "Vorschau", previewWith: "Vorschau mit Beleg", refresh: "Aktualisieren", show_draft: "Entwurf", show_live: "Veröffentlicht", previewShowsSaved: "Die Vorschau zeigt den zuletzt gespeicherten Stand.", blocked: "Nicht geladen (nur hochgeladene Dateien sind erlaubt): {{urls}}", assets_one: "Bilder und Schriften ({{count}})", assets_other: "Bilder und Schriften ({{count}})", assetsHint: 'Verweise auf eine hochgeladene Datei mit ihrem Namen, z. B. <img src="logo.png">. Links auf andere Websites werden blockiert.', upload: "Datei hochladen", versions_one: "Ausgestellte Versionen ({{count}})", versions_other: "Ausgestellte Versionen ({{count}})", versionsHint: "Eine Version entsteht, wenn ein Beleg mit einem Layout gebucht wird. Belege behalten die Version, mit der sie ausgestellt wurden.", noVersions: "Mit dieser Vorlage wurde noch keine Offerte ausgestellt.", firstUsed: "zuerst verwendet am {{date}}", reference: "Verfügbare Felder", standardEditHint: "Um dieses Layout zu ändern, dupliziere es auf der Seite", defaultOption: "Standard ({{name}})", textDefaults: "Standardtexte für Offerten", textDefaultsIntro: "Neue Offerten starten mit diesen Texten; sie lassen sich pro Offerte ändern. Eine Änderung hier ändert bestehende Offerten nicht.", textDefaultsPlaceholders: "Platzhalter, beim Drucken ersetzt: {{placeholders}}", saveTexts: "Texte speichern", textsSaved: "Gespeichert.", publishWarnings: "Hinweis: {{warnings}}", uploading: "Wird hochgeladen…", dropHint: "oder Bilder und Schriften hierher ziehen (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Standardtexte für {{type}}", textDefaultsIntroFor: "Neue {{type}} starten mit diesen Texten; sie lassen sich pro Beleg ändern. Eine Änderung hier ändert bestehende Belege nicht.", newTitleFor: "Neue PDF-Vorlage ({{type}})", newFor: "Neue Vorlage: {{type}}", fromOtherType: "Aus Vorlage eines anderen Typs…", usedByIssued_one: "Von {{count}} gebuchten Beleg verwendet", usedByIssued_other: "Von {{count}} gebuchten Belegen verwendet" }, id = { pdf_intro_text_not_printed: "Das PDF-Layout «{{template}}» druckt den Einleitungstext nicht; das PDF erscheint ohne ihn.", pdf_remarks_not_printed: "Das PDF-Layout «{{template}}» druckt den Schlusstext / die Konditionen nicht; das PDF erscheint ohne sie.", pdf_line_deduction_not_printed: "Das PDF-Layout «{{template}}» druckt keine Abzüge auf Positionen; diese Positionen erscheinen nur mit dem Nettobetrag.", pdf_variable_not_printed: "Das PDF-Layout «{{template}}» druckt {{label}} nicht; das PDF erscheint ohne." }, od = { defaultLabel: "Abzug", add: "+ Abzug", remove: "Abzug entfernen", label: "Text des Abzugs", labelPlaceholder: "z. B. Abzüglich bereits verrechnet (Rechnung SINV-0003)", perUnit: "Abzug pro Einheit, wird unter der Position gedruckt; die Position zählt den Rest." }, ld = {
|
|
10044
10114
|
proposal: _c,
|
|
10045
10115
|
common: Dc,
|
|
10046
10116
|
datePresets: Pc,
|
|
@@ -10059,8 +10129,8 @@ const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and
|
|
|
10059
10129
|
reports: $c,
|
|
10060
10130
|
masterForm: Vc,
|
|
10061
10131
|
fields: Uc,
|
|
10062
|
-
tables:
|
|
10063
|
-
conversions:
|
|
10132
|
+
tables: Wc,
|
|
10133
|
+
conversions: Kc,
|
|
10064
10134
|
dashboard: jc,
|
|
10065
10135
|
chat: Gc,
|
|
10066
10136
|
tutorial: Hc,
|
|
@@ -10077,7 +10147,7 @@ const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and
|
|
|
10077
10147
|
pdfTemplates: sd,
|
|
10078
10148
|
documentWarnings: id,
|
|
10079
10149
|
deductions: od
|
|
10080
|
-
}, cd = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, dd = { save: "Enregistrer", saving: "Enregistrement...", saved: "Enregistré", unsavedTitle: "Quitter sans enregistrer ?", unsavedBody: "Vos modifications sur cette page ne sont pas enregistrées et seront perdues.", unsavedLeave: "Abandonner les modifications", unsavedStay: "Continuer la modification", 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" }, ud = { 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" }, md = { 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" }, pd = { 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é." }, hd = { 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" } }, gd = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, fd = { back: "Retour", backToChat: "Retour au chat", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, yd = { 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", "batch-stock": "Stock par lot", "stock-detail": "Stock par emplacement et lot", "stock-availability": "Disponibilité du stock", "sales-backlog": "Commandes en attente", "purchase-backlog": "Achats en attente" }, bd = { 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" }, reservation: { one: "Réservation", other: "Réservations" } }, vd = { 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" } }, xd = { 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", Menu: "Menu", "PDF Templates": "Modèles PDF", Batch: "Lot", "Batch Stock": "Stock par lot", "Storage Location": "Emplacement", "Stock by Location & Batch": "Stock par emplacement et lot", "Stock Reservation": "Réservation de stock", "Stock Availability": "Disponibilité du stock", "Sales Backlog": "Commandes en attente", "Purchase Backlog": "Achats en attente", "Consignment Withdrawal": "Prélèvement en consignation", "Stock Count": "Inventaire" } }, kd = { 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." } }, Nd = { 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: "Autoriser les applications et scripts à accéder à cet ERP via REST ou MCP, avec des clés API ou une connexion OAuth. 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: "Applications et 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 connexion pour le moment.", 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 connexions", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu’administrateur, vous pouvez gérer les connexions de tous les utilisateurs. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette connexion appartient à un autre utilisateur", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révocation déconnectera immédiatement son application. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. Supprimer définitivement cette connexion révoquée ?", chatApiPersonal: "Connectez des applications à votre compte ERP. L’accès ne dépasse jamais vos droits actuels.", version: "Version {{version}}" }, wd = { 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é" }, Sd = { 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é", noBatchStock: "Aucun stock par lot trouvé", batchMovements: "Mouvements du lot {{batch}} ({{item}})", withoutBatch: "sans lot", showMovements: "Mouvements", expired: "périmé", onlyDeliverable: "Seulement ce qui est livrable", onlyOverdue: "Seulement en retard", noBacklog: "Rien en attente", unconfirmedNote: "* non confirmé par le fournisseur : date prévue de la commande", batchRecipients: "Destinataires du lot {{batch}}", batchChanges: "Modifications du lot {{batch}}" }, Cd = { 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}}." }, _d = { "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", "Amount only": "Montant seul", "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", Website: "Site web", "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", "Printed notes / terms": "Notes / conditions imprimées", "PDF Layout": "Mise en page PDF", "Intro text": "Texte d'introduction", "Closing text / terms": "Texte final / conditions", Batch: "Lot", "Expiry Date": "Date de péremption", "Manufacturing Date": "Date de fabrication", "Batch-tracked": "Géré par lot", "Has Expiry Date": "Avec date de péremption", "Item starts with": "Article commençant par", "Expiring before": "Péremption avant", Document: "Document", "Storage Location": "Emplacement", "Storage Locations": "Emplacements", "Source Location": "Emplacement d'origine", "Target Location": "Emplacement de destination", "Reserve Stock": "Réserver le stock", "Shelf Life Exception": "Exception de durée de vie", "Reserved Qty": "Quantité réservée", "Sales Order Line": "Ligne de commande", "Reserved By": "Réservé par", "Min. Shelf Life (days)": "Durée de vie min. (jours)", Blocked: "Bloqué", "Blocked Reason": "Motif du blocage", "In Stock": "En stock", Reserved: "Réservé", Available: "Disponible", "Open Sales Orders": "Commandes ouvertes", "On Purchase Order": "En commande", "Price Source": "Origine du prix", "Apply On Value": "Valeur de « Appliquer à »", "Applicable For Value": "Valeur de « Valable pour »", "Confirmed Date": "Date confirmée", "Confirmation Ref.": "N° de confirmation", Ordered: "Commandé", Delivered: "Livré", Open: "Ouvert", "Deliverable Now": "Livrable maintenant", Expected: "Attendu", Received: "Reçu", "Days Overdue": "Jours de retard", "Consignment Customer": "Client en consignation", "Replenished From": "Approvisionné depuis", "Consignment Warehouse": "Dépôt en consignation", "Report Source": "Source de la déclaration", "Report Number": "Numéro de déclaration", Replenish: "Réapprovisionner", "Replenish From": "Réapprovisionner depuis", "Replacement Transfer": "Transfert de remplacement", Replenishment: "Réapprovisionnement", Reason: "Motif", "Counted Lines": "Lignes comptées", "Lines With Difference": "Lignes avec écart", "System Qty": "Quantité système", "Counted Qty": "Quantité comptée", Difference: "Écart", Returned: "Retourné", "Still With Them": "Encore chez le client", "Last Delivery": "Dernière livraison" }, Dd = { 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" }, Pd = { "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" }, Ad = { 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" }, Td = { 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." }, Rd = /* @__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 ?"}`), Bd = { title: "Aide au formatage", intro: "Le texte des notes / conditions imprimées 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." }, Ld = { 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" } }, Id = { 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." }, Ed = { 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" }, Fd = { 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.", pdf_template: "L’aspect de la confirmation de réservation." }, quotation: { pdf_template: "L'apparence du PDF de l'offre. Figée lorsque l'offre est validée.", intro_text: "Imprimé au-dessus des positions (l'emplacement exact dépend de la mise en page PDF). Les nouvelles offres reprennent le texte par défaut de Paramètres → Modèles PDF.", remarks: "Imprimé après les totaux (l'emplacement exact dépend de la mise en page PDF). Les nouvelles offres reprennent le texte par défaut de Paramètres → Modèles PDF." }, "sales-order": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "sales-invoice": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "purchase-order": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "delivery-note": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." } }, Od = { 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." }, qd = { title: "Connecter une application", subtitle: "Choisissez où utiliser Lambda ERP. Nous afficherons la configuration adaptée.", other: "Autre application", customName: "Intégration personnalisée", signIn: "Se connecter", apiKey: "Clé API", access: "Accès", role_viewer: "Consulter les données", role_manager: "Créer et modifier", role_admin: "Accès administratif complet", roleHelp: "L’accès est toujours limité par vos propres droits ERP. Accordez uniquement ce dont cette application a besoin.", copied: "Copié", copyFailed: "La copie automatique a échoué. Sélectionnez le texte et copiez-le manuellement.", retry: "Réessayer", interface: "Type de connexion", chatDisabled: "L’accès à l’API de chat est désactivé. Demandez à un administrateur de l’activer dans les paramètres API ci-dessus.", restDisabled: "L’accès REST API / MCP est désactivé. Un administrateur doit l’activer dans les paramètres API avant de connecter cette application.", chatgptStep: "Ouvrez chatgpt.com dans votre navigateur. Sélectionnez « Plugins » dans la barre latérale gauche, cliquez sur « Add » (+) en haut à droite, puis choisissez « Create MCP App ». Saisissez un nom, par exemple Lambda ERP, et une courte description.", chatgptDeveloperMode: "Si « Create MCP App » n’est pas disponible, vérifiez que « Developer mode » est activé dans « Settings » → « Security and login ». S’il est déjà activé, allez directement dans « Plugins ». Des autorisations de l’espace de travail peuvent aussi être nécessaires.", claudeStep: "Dans Claude Desktop, ouvrez « Settings » → « Connectors » puis choisissez « Add custom connector ».", urlStep: "Collez cette URL de serveur. Utilisez la connexion OAuth ; laissez les champs facultatifs Client ID et Client Secret vides.", approveStep: "Connectez l’application, identifiez-vous dans Lambda ERP et approuvez l’accès souhaité.", noKeyNeeded: "Aucune clé API ni en-tête personnalisé n’est nécessaire. Choisissez l’accès sur l’écran d’autorisation.", officialGuide: "Ouvrir le guide de configuration", copyUrl: "Copier l’URL du serveur", keyReady: "Votre clé de connexion est prête", copySetup: "Copier la configuration", copyHeader: "Copier l’en-tête d’autorisation", cliStep: "Exécutez cette commande dans votre terminal, puis vérifiez la connexion avec /mcp dans Claude Code.", codexStep: "Ajoutez cette entrée à votre configuration Codex, puis redémarrez Codex et vérifiez /mcp.", done: "Terminé — masquer la clé", existing: "Connexions existantes", refresh: "Actualiser", lastUsed: "Dernière utilisation", notUsed: "Pas encore utilisée", consentTitle: "Se connecter à Lambda ERP", expired: "Cette demande de connexion est absente ou expirée. Recommencez depuis votre application.", loginFirst: "Connectez-vous à votre compte ERP pour examiner la demande de cette application.", consentBody: "« {{app}} » demande l’accès à votre ERP. Choisissez l’accès que vous souhaitez autoriser.", returnTo: "Après autorisation, vous retournerez vers", revokeHelp: "Vous pouvez révoquer cette connexion à tout moment dans Paramètres → Accès API.", deny: "Annuler", allow: "Autoriser la connexion", explain_viewer: "L’application peut lire les données et rapports ERP et générer des PDF. Elle ne peut pas modifier les données métier.", explain_manager: "L’application peut aussi créer, modifier, valider et annuler des documents et mettre à jour les données de base.", explain_admin: "L’application peut utiliser tous les outils ERP disponibles, y compris les actions administratives et la suppression de données de base." }, zd = { title: "Mentions", note: "Note interne", placeholder: "Écrire une note… utiliser @ pour mentionner un collègue", colleagues: "Collègues", loading: "Chargement…", noUsers: "Aucun collègue correspondant", hint: "Écrivez @Nom ou choisissez une personne. Les personnes mentionnées dans le texte seront averties à l’enregistrement.", remove: "Retirer la mention de {{name}}", close: "Fermer", open: "À traiter", unread: "Non lues", done: "Terminées", retry: "Réessayer", empty: "Aucune mention ici.", mentionedYou: "vous a mentionné", reopen: "Rouvrir", markDone: "Terminer", markUnread: "Marquer comme non lue", markRead: "Marquer comme lue", previous: "Précédent", next: "Suivant" }, Md = { title: "Notes internes", private: "Réservées à votre équipe · jamais imprimées", add: "Ajouter une note", placeholder: "Écrire une note interne… tapez @ pour prévenir un collègue", save: "Enregistrer la note", empty: "Aucune note interne pour l’instant.", edited: "modifiée", older: "Afficher les notes plus anciennes", printedBadge: "Imprimé sur le PDF", count_one: "{{count}} note interne", count_other: "{{count}} notes internes" }, $d = { title: "Votre menu", intro: "Glissez les groupes et les entrées dans l'ordre voulu et masquez ceux dont vous ne vous servez pas, puis enregistrez. Seul votre menu change : les autres gardent le leur, et les pages masquées restent accessibles par lien.", chatHint: "Vous pouvez aussi le demander au chat, p. ex. « masque les Locations » ou « mets le CRM en haut ».", reset: "Rétablir par défaut", hide: "Masquer {{name}}", show: "Afficher {{name}}", locked: "Toujours affiché : cette page modifie le menu", drag: "Glisser pour déplacer {{name}} (ou le sélectionner et utiliser les flèches)", discard: "Annuler les modifications", unsaved: "Modifications non enregistrées" }, Vd = { title: "Modèles PDF", intro: "Les mises en page utilisées pour imprimer les documents : offres, commandes, factures, commandes fournisseur, bons de livraison, propositions et confirmations de réservation, chaque type avec ses modèles et son modèle par défaut. Modifiez un modèle autant que vous voulez : enregistrer ne change que le brouillon, publier en fait la mise en page des documents. Un document validé conserve la mise en page et le PDF avec lesquels il a été émis.", chatHint: "Vous pouvez aussi demander au chat, p. ex. « mets notre logo en haut à droite et agrandis la police du tableau des articles ».", new: "Nouveau modèle", newTitle: "Nouveau modèle PDF", newBody: "Commence comme copie de {{name}}.", copyOf: "Copie de {{name}}", create: "Créer", standard: "Standard", standardDescription: "La mise en page intégrée. Lecture seule : dupliquez-la pour changer l'apparence.", default: "Par défaut", builtIn: "Intégré", notPublished: "Non publié", unpublishedChanges: "Modifications non publiées", archived: "Archivé", usedBy_one: "Utilisé par {{count}} offre", usedBy_other: "Utilisé par {{count}} offres", makeDefault: "Définir par défaut", duplicate: "Dupliquer", archive: "Archiver", restore: "Restaurer", deleteTitle: "Supprimer {{name}} ?", deleteBody: "Aucune offre n'a utilisé ce modèle, rien n'en dépend.", showArchived: "Afficher les modèles archivés", name: "Nom", editHint: "Enregistrez autant que vous voulez : seul le brouillon change. Publiez quand l’aperçu convient ; les documents s’impriment avec la mise en page publiée.", publish: "Publier", revert: "Annuler les modifications non publiées", revertTitle: "Annuler les modifications non publiées ?", revertBody: "Le brouillon revient à la mise en page publiée.", publishedNotice: "Publié. Vérifié avec {{document}}.", source: "HTML et CSS", lines_one: "{{count}} ligne", lines_other: "{{count}} lignes", preview: "Aperçu", previewWith: "Aperçu avec le document", refresh: "Actualiser", show_draft: "Brouillon", show_live: "Publié", previewShowsSaved: "L'aperçu montre la dernière version enregistrée.", blocked: "Non chargé (seuls les fichiers téléversés sont autorisés) : {{urls}}", assets_one: "Images et polices ({{count}})", assets_other: "Images et polices ({{count}})", assetsHint: `Référencez un fichier téléversé par son nom, p. ex. <img src="logo.png">. Les liens vers d'autres sites sont bloqués.`, upload: "Téléverser un fichier", versions_one: "Versions émises ({{count}})", versions_other: "Versions émises ({{count}})", versionsHint: "Une version est enregistrée lorsqu’un document est validé avec une mise en page. Les documents conservent la version avec laquelle ils ont été émis.", noVersions: "Aucune offre n'a encore été émise avec ce modèle.", firstUsed: "utilisé pour la première fois le {{date}}", reference: "Champs disponibles", standardEditHint: "Pour modifier cette mise en page, dupliquez-la sur la page", defaultOption: "Par défaut ({{name}})", textDefaults: "Textes par défaut des offres", textDefaultsIntro: "Les nouvelles offres commencent avec ces textes, modifiables sur chaque offre. Les modifier ne change pas les offres existantes.", textDefaultsPlaceholders: "Variables, remplacées à l'impression : {{placeholders}}", saveTexts: "Enregistrer les textes", textsSaved: "Enregistré.", publishWarnings: "Remarque : {{warnings}}", uploading: "Envoi…", dropHint: "ou glissez des images et des polices ici (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Textes par défaut : {{type}}", textDefaultsIntroFor: "Les nouveaux documents ({{type}}) commencent avec ces textes ; ils peuvent être modifiés sur chaque document. Les modifier ici ne change pas les documents existants.", newTitleFor: "Nouveau modèle PDF ({{type}})", newFor: "Nouveau modèle : {{type}}", fromOtherType: "Partir d’un modèle d’un autre type…", usedByIssued_one: "Utilisé par {{count}} document émis", usedByIssued_other: "Utilisé par {{count}} documents émis" }, Ud = { pdf_intro_text_not_printed: "La mise en page PDF « {{template}} » n'imprime pas le texte d'introduction ; le PDF s'affiche sans.", pdf_remarks_not_printed: "La mise en page PDF « {{template}} » n'imprime pas le texte final / les conditions ; le PDF s'affiche sans.", pdf_line_deduction_not_printed: "La mise en page PDF « {{template}} » n'imprime pas les déductions de ligne ; ces lignes n'affichent que leur montant net.", pdf_variable_not_printed: "La mise en page PDF « {{template}} » n’imprime pas : {{label}} ; le PDF s’affiche sans." }, Kd = { defaultLabel: "Déduction", add: "+ Déduction", remove: "Retirer la déduction", label: "Texte de la déduction", labelPlaceholder: "p. ex. Moins déjà facturé (facture SINV-0003)", perUnit: "Déduction par unité, imprimée sous la ligne ; la ligne compte le reste." }, Wd = {
|
|
10150
|
+
}, cd = { incomplete: "Brouillon enregistré. Le PDF nécessite un client, une entreprise et au moins une offre." }, dd = { save: "Enregistrer", saving: "Enregistrement...", saved: "Enregistré", unsavedTitle: "Quitter sans enregistrer ?", unsavedBody: "Vos modifications sur cette page ne sont pas enregistrées et seront perdues.", unsavedLeave: "Abandonner les modifications", unsavedStay: "Continuer la modification", 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" }, ud = { 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" }, md = { 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" }, pd = { 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é." }, hd = { 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" } }, gd = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, fd = { back: "Retour", backToChat: "Retour au chat", logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, yd = { 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", "batch-stock": "Stock par lot", "stock-detail": "Stock par emplacement et lot", "stock-availability": "Disponibilité du stock", "sales-backlog": "Commandes en attente", "purchase-backlog": "Achats en attente" }, bd = { 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" }, reservation: { one: "Réservation", other: "Réservations" } }, vd = { 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" } }, xd = { 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", Menu: "Menu", "PDF Templates": "Modèles PDF", Batch: "Lot", "Batch Stock": "Stock par lot", "Storage Location": "Emplacement", "Serial Number": "Numéro de série", "Stock by Location & Batch": "Stock par emplacement et lot", "Stock Reservation": "Réservation de stock", "Stock Availability": "Disponibilité du stock", "Sales Backlog": "Commandes en attente", "Purchase Backlog": "Achats en attente", "Consignment Withdrawal": "Prélèvement en consignation", "Stock Count": "Inventaire" } }, kd = { 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." } }, Nd = { 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: "Autoriser les applications et scripts à accéder à cet ERP via REST ou MCP, avec des clés API ou une connexion OAuth. 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: "Applications et 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 connexion pour le moment.", 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 connexions", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu’administrateur, vous pouvez gérer les connexions de tous les utilisateurs. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette connexion appartient à un autre utilisateur", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révocation déconnectera immédiatement son application. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. Supprimer définitivement cette connexion révoquée ?", chatApiPersonal: "Connectez des applications à votre compte ERP. L’accès ne dépasse jamais vos droits actuels.", version: "Version {{version}}" }, wd = { 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é" }, Sd = { 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é", noBatchStock: "Aucun stock par lot trouvé", batchMovements: "Mouvements du lot {{batch}} ({{item}})", withoutBatch: "sans lot", showMovements: "Mouvements", expired: "périmé", onlyDeliverable: "Seulement ce qui est livrable", onlyOverdue: "Seulement en retard", noBacklog: "Rien en attente", unconfirmedNote: "* non confirmé par le fournisseur : date prévue de la commande", batchRecipients: "Destinataires du lot {{batch}}", batchChanges: "Modifications du lot {{batch}}" }, Cd = { 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}}." }, _d = { "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", "Amount only": "Montant seul", "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", Website: "Site web", "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", "Printed notes / terms": "Notes / conditions imprimées", "PDF Layout": "Mise en page PDF", "Intro text": "Texte d'introduction", "Closing text / terms": "Texte final / conditions", Batch: "Lot", "Expiry Date": "Date de péremption", "Manufacturing Date": "Date de fabrication", "Batch-tracked": "Géré par lot", "Has Expiry Date": "Avec date de péremption", "Item starts with": "Article commençant par", "Expiring before": "Péremption avant", Document: "Document", "Storage Location": "Emplacement", "Serial Number": "Numéro de série", "Serial Numbers": "Numéros de série", "Serial-tracked": "Suivi par numéro de série", "Storage Locations": "Emplacements", "Source Location": "Emplacement d'origine", "Target Location": "Emplacement de destination", "Reserve Stock": "Réserver le stock", "Shelf Life Exception": "Exception de durée de vie", "Reserved Qty": "Quantité réservée", "Sales Order Line": "Ligne de commande", "Reserved By": "Réservé par", "Min. Shelf Life (days)": "Durée de vie min. (jours)", Blocked: "Bloqué", "Blocked Reason": "Motif du blocage", "In Stock": "En stock", Reserved: "Réservé", Available: "Disponible", "Open Sales Orders": "Commandes ouvertes", "On Purchase Order": "En commande", "Price Source": "Origine du prix", "Apply On Value": "Valeur de « Appliquer à »", "Applicable For Value": "Valeur de « Valable pour »", "Confirmed Date": "Date confirmée", "Confirmation Ref.": "N° de confirmation", Ordered: "Commandé", Delivered: "Livré", Open: "Ouvert", "Deliverable Now": "Livrable maintenant", Expected: "Attendu", Received: "Reçu", "Days Overdue": "Jours de retard", "Consignment Customer": "Client en consignation", "Replenished From": "Approvisionné depuis", "Consignment Warehouse": "Dépôt en consignation", "Report Source": "Source de la déclaration", "Report Number": "Numéro de déclaration", Replenish: "Réapprovisionner", "Replenish From": "Réapprovisionner depuis", "Replacement Transfer": "Transfert de remplacement", Replenishment: "Réapprovisionnement", Reason: "Motif", "Counted Lines": "Lignes comptées", "Lines With Difference": "Lignes avec écart", "System Qty": "Quantité système", "Counted Qty": "Quantité comptée", Difference: "Écart", Returned: "Retourné", "Still With Them": "Encore chez le client", "Last Delivery": "Dernière livraison" }, Dd = { 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" }, Pd = { "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" }, Ad = { 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" }, Td = { 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." }, Rd = /* @__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 ?"}`), Bd = { title: "Aide au formatage", intro: "Le texte des notes / conditions imprimées 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." }, Ld = { 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" } }, Id = { 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." }, Ed = { 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" }, Fd = { 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.", pdf_template: "L’aspect de la confirmation de réservation." }, quotation: { pdf_template: "L'apparence du PDF de l'offre. Figée lorsque l'offre est validée.", intro_text: "Imprimé au-dessus des positions (l'emplacement exact dépend de la mise en page PDF). Les nouvelles offres reprennent le texte par défaut de Paramètres → Modèles PDF.", remarks: "Imprimé après les totaux (l'emplacement exact dépend de la mise en page PDF). Les nouvelles offres reprennent le texte par défaut de Paramètres → Modèles PDF." }, "sales-order": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "sales-invoice": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "purchase-order": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." }, "delivery-note": { pdf_template: "L’aspect du PDF. Fixé lors de la validation du document.", intro_text: "Imprimé au-dessus des lignes (l’endroit exact dépend de la mise en page PDF). Les nouveaux documents commencent avec le texte par défaut des Paramètres → Modèles PDF." } }, Od = { 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." }, qd = { title: "Connecter une application", subtitle: "Choisissez où utiliser Lambda ERP. Nous afficherons la configuration adaptée.", other: "Autre application", customName: "Intégration personnalisée", signIn: "Se connecter", apiKey: "Clé API", access: "Accès", role_viewer: "Consulter les données", role_manager: "Créer et modifier", role_admin: "Accès administratif complet", roleHelp: "L’accès est toujours limité par vos propres droits ERP. Accordez uniquement ce dont cette application a besoin.", copied: "Copié", copyFailed: "La copie automatique a échoué. Sélectionnez le texte et copiez-le manuellement.", retry: "Réessayer", interface: "Type de connexion", chatDisabled: "L’accès à l’API de chat est désactivé. Demandez à un administrateur de l’activer dans les paramètres API ci-dessus.", restDisabled: "L’accès REST API / MCP est désactivé. Un administrateur doit l’activer dans les paramètres API avant de connecter cette application.", chatgptStep: "Ouvrez chatgpt.com dans votre navigateur. Sélectionnez « Plugins » dans la barre latérale gauche, cliquez sur « Add » (+) en haut à droite, puis choisissez « Create MCP App ». Saisissez un nom, par exemple Lambda ERP, et une courte description.", chatgptDeveloperMode: "Si « Create MCP App » n’est pas disponible, vérifiez que « Developer mode » est activé dans « Settings » → « Security and login ». S’il est déjà activé, allez directement dans « Plugins ». Des autorisations de l’espace de travail peuvent aussi être nécessaires.", claudeStep: "Dans Claude Desktop, ouvrez « Settings » → « Connectors » puis choisissez « Add custom connector ».", urlStep: "Collez cette URL de serveur. Utilisez la connexion OAuth ; laissez les champs facultatifs Client ID et Client Secret vides.", approveStep: "Connectez l’application, identifiez-vous dans Lambda ERP et approuvez l’accès souhaité.", noKeyNeeded: "Aucune clé API ni en-tête personnalisé n’est nécessaire. Choisissez l’accès sur l’écran d’autorisation.", officialGuide: "Ouvrir le guide de configuration", copyUrl: "Copier l’URL du serveur", keyReady: "Votre clé de connexion est prête", copySetup: "Copier la configuration", copyHeader: "Copier l’en-tête d’autorisation", cliStep: "Exécutez cette commande dans votre terminal, puis vérifiez la connexion avec /mcp dans Claude Code.", codexStep: "Ajoutez cette entrée à votre configuration Codex, puis redémarrez Codex et vérifiez /mcp.", done: "Terminé — masquer la clé", existing: "Connexions existantes", refresh: "Actualiser", lastUsed: "Dernière utilisation", notUsed: "Pas encore utilisée", consentTitle: "Se connecter à Lambda ERP", expired: "Cette demande de connexion est absente ou expirée. Recommencez depuis votre application.", loginFirst: "Connectez-vous à votre compte ERP pour examiner la demande de cette application.", consentBody: "« {{app}} » demande l’accès à votre ERP. Choisissez l’accès que vous souhaitez autoriser.", returnTo: "Après autorisation, vous retournerez vers", revokeHelp: "Vous pouvez révoquer cette connexion à tout moment dans Paramètres → Accès API.", deny: "Annuler", allow: "Autoriser la connexion", explain_viewer: "L’application peut lire les données et rapports ERP et générer des PDF. Elle ne peut pas modifier les données métier.", explain_manager: "L’application peut aussi créer, modifier, valider et annuler des documents et mettre à jour les données de base.", explain_admin: "L’application peut utiliser tous les outils ERP disponibles, y compris les actions administratives et la suppression de données de base." }, zd = { title: "Mentions", note: "Note interne", placeholder: "Écrire une note… utiliser @ pour mentionner un collègue", colleagues: "Collègues", loading: "Chargement…", noUsers: "Aucun collègue correspondant", hint: "Écrivez @Nom ou choisissez une personne. Les personnes mentionnées dans le texte seront averties à l’enregistrement.", remove: "Retirer la mention de {{name}}", close: "Fermer", open: "À traiter", unread: "Non lues", done: "Terminées", retry: "Réessayer", empty: "Aucune mention ici.", mentionedYou: "vous a mentionné", reopen: "Rouvrir", markDone: "Terminer", markUnread: "Marquer comme non lue", markRead: "Marquer comme lue", previous: "Précédent", next: "Suivant" }, Md = { title: "Notes internes", private: "Réservées à votre équipe · jamais imprimées", add: "Ajouter une note", placeholder: "Écrire une note interne… tapez @ pour prévenir un collègue", save: "Enregistrer la note", empty: "Aucune note interne pour l’instant.", edited: "modifiée", older: "Afficher les notes plus anciennes", printedBadge: "Imprimé sur le PDF", count_one: "{{count}} note interne", count_other: "{{count}} notes internes" }, $d = { title: "Votre menu", intro: "Glissez les groupes et les entrées dans l'ordre voulu et masquez ceux dont vous ne vous servez pas, puis enregistrez. Seul votre menu change : les autres gardent le leur, et les pages masquées restent accessibles par lien.", chatHint: "Vous pouvez aussi le demander au chat, p. ex. « masque les Locations » ou « mets le CRM en haut ».", reset: "Rétablir par défaut", hide: "Masquer {{name}}", show: "Afficher {{name}}", locked: "Toujours affiché : cette page modifie le menu", drag: "Glisser pour déplacer {{name}} (ou le sélectionner et utiliser les flèches)", discard: "Annuler les modifications", unsaved: "Modifications non enregistrées" }, Vd = { title: "Modèles PDF", intro: "Les mises en page utilisées pour imprimer les documents : offres, commandes, factures, commandes fournisseur, bons de livraison, propositions et confirmations de réservation, chaque type avec ses modèles et son modèle par défaut. Modifiez un modèle autant que vous voulez : enregistrer ne change que le brouillon, publier en fait la mise en page des documents. Un document validé conserve la mise en page et le PDF avec lesquels il a été émis.", chatHint: "Vous pouvez aussi demander au chat, p. ex. « mets notre logo en haut à droite et agrandis la police du tableau des articles ».", new: "Nouveau modèle", newTitle: "Nouveau modèle PDF", newBody: "Commence comme copie de {{name}}.", copyOf: "Copie de {{name}}", create: "Créer", standard: "Standard", standardDescription: "La mise en page intégrée. Lecture seule : dupliquez-la pour changer l'apparence.", default: "Par défaut", builtIn: "Intégré", notPublished: "Non publié", unpublishedChanges: "Modifications non publiées", archived: "Archivé", usedBy_one: "Utilisé par {{count}} offre", usedBy_other: "Utilisé par {{count}} offres", makeDefault: "Définir par défaut", duplicate: "Dupliquer", archive: "Archiver", restore: "Restaurer", deleteTitle: "Supprimer {{name}} ?", deleteBody: "Aucune offre n'a utilisé ce modèle, rien n'en dépend.", showArchived: "Afficher les modèles archivés", name: "Nom", editHint: "Enregistrez autant que vous voulez : seul le brouillon change. Publiez quand l’aperçu convient ; les documents s’impriment avec la mise en page publiée.", publish: "Publier", revert: "Annuler les modifications non publiées", revertTitle: "Annuler les modifications non publiées ?", revertBody: "Le brouillon revient à la mise en page publiée.", publishedNotice: "Publié. Vérifié avec {{document}}.", source: "HTML et CSS", lines_one: "{{count}} ligne", lines_other: "{{count}} lignes", preview: "Aperçu", previewWith: "Aperçu avec le document", refresh: "Actualiser", show_draft: "Brouillon", show_live: "Publié", previewShowsSaved: "L'aperçu montre la dernière version enregistrée.", blocked: "Non chargé (seuls les fichiers téléversés sont autorisés) : {{urls}}", assets_one: "Images et polices ({{count}})", assets_other: "Images et polices ({{count}})", assetsHint: `Référencez un fichier téléversé par son nom, p. ex. <img src="logo.png">. Les liens vers d'autres sites sont bloqués.`, upload: "Téléverser un fichier", versions_one: "Versions émises ({{count}})", versions_other: "Versions émises ({{count}})", versionsHint: "Une version est enregistrée lorsqu’un document est validé avec une mise en page. Les documents conservent la version avec laquelle ils ont été émis.", noVersions: "Aucune offre n'a encore été émise avec ce modèle.", firstUsed: "utilisé pour la première fois le {{date}}", reference: "Champs disponibles", standardEditHint: "Pour modifier cette mise en page, dupliquez-la sur la page", defaultOption: "Par défaut ({{name}})", textDefaults: "Textes par défaut des offres", textDefaultsIntro: "Les nouvelles offres commencent avec ces textes, modifiables sur chaque offre. Les modifier ne change pas les offres existantes.", textDefaultsPlaceholders: "Variables, remplacées à l'impression : {{placeholders}}", saveTexts: "Enregistrer les textes", textsSaved: "Enregistré.", publishWarnings: "Remarque : {{warnings}}", uploading: "Envoi…", dropHint: "ou glissez des images et des polices ici (PNG, JPG, SVG, WebP, GIF, TTF, OTF, WOFF, WOFF2)", textDefaultsFor: "Textes par défaut : {{type}}", textDefaultsIntroFor: "Les nouveaux documents ({{type}}) commencent avec ces textes ; ils peuvent être modifiés sur chaque document. Les modifier ici ne change pas les documents existants.", newTitleFor: "Nouveau modèle PDF ({{type}})", newFor: "Nouveau modèle : {{type}}", fromOtherType: "Partir d’un modèle d’un autre type…", usedByIssued_one: "Utilisé par {{count}} document émis", usedByIssued_other: "Utilisé par {{count}} documents émis" }, Ud = { pdf_intro_text_not_printed: "La mise en page PDF « {{template}} » n'imprime pas le texte d'introduction ; le PDF s'affiche sans.", pdf_remarks_not_printed: "La mise en page PDF « {{template}} » n'imprime pas le texte final / les conditions ; le PDF s'affiche sans.", pdf_line_deduction_not_printed: "La mise en page PDF « {{template}} » n'imprime pas les déductions de ligne ; ces lignes n'affichent que leur montant net.", pdf_variable_not_printed: "La mise en page PDF « {{template}} » n’imprime pas : {{label}} ; le PDF s’affiche sans." }, Wd = { defaultLabel: "Déduction", add: "+ Déduction", remove: "Retirer la déduction", label: "Texte de la déduction", labelPlaceholder: "p. ex. Moins déjà facturé (facture SINV-0003)", perUnit: "Déduction par unité, imprimée sous la ligne ; la ligne compte le reste." }, Kd = {
|
|
10081
10151
|
proposal: cd,
|
|
10082
10152
|
common: dd,
|
|
10083
10153
|
datePresets: ud,
|
|
@@ -10113,7 +10183,7 @@ const Ul = { incomplete: "Draft saved; PDF output requires Customer, Company and
|
|
|
10113
10183
|
menuLayout: $d,
|
|
10114
10184
|
pdfTemplates: Vd,
|
|
10115
10185
|
documentWarnings: Ud,
|
|
10116
|
-
deductions:
|
|
10186
|
+
deductions: Wd
|
|
10117
10187
|
}, ps = [
|
|
10118
10188
|
{ code: "en", label: "English" },
|
|
10119
10189
|
{ code: "de", label: "Deutsch" },
|
|
@@ -10140,7 +10210,7 @@ _r.use(Is).init({
|
|
|
10140
10210
|
resources: {
|
|
10141
10211
|
en: { translation: Cc },
|
|
10142
10212
|
de: { translation: ld },
|
|
10143
|
-
fr: { translation:
|
|
10213
|
+
fr: { translation: Kd }
|
|
10144
10214
|
},
|
|
10145
10215
|
lng: Gd(),
|
|
10146
10216
|
fallbackLng: "en",
|
|
@@ -10212,8 +10282,8 @@ function Qd() {
|
|
|
10212
10282
|
] }),
|
|
10213
10283
|
u.isError && /* @__PURE__ */ t("p", { role: "alert", className: "text-sm text-red-600", children: u.error.message }),
|
|
10214
10284
|
/* @__PURE__ */ r("div", { className: "flex justify-end gap-2", children: [
|
|
10215
|
-
/* @__PURE__ */ t(
|
|
10216
|
-
/* @__PURE__ */ t(
|
|
10285
|
+
/* @__PURE__ */ t(W, { variant: "secondary", disabled: u.isPending, onClick: () => u.mutate(!1), children: e("connections.deny") }),
|
|
10286
|
+
/* @__PURE__ */ t(W, { disabled: u.isPending || !i, onClick: () => u.mutate(!0), children: e("connections.allow") })
|
|
10217
10287
|
] })
|
|
10218
10288
|
] })
|
|
10219
10289
|
] }) : /* @__PURE__ */ r(Ne, { children: [
|
|
@@ -10223,7 +10293,7 @@ function Qd() {
|
|
|
10223
10293
|
] }) });
|
|
10224
10294
|
}
|
|
10225
10295
|
function Yd() {
|
|
10226
|
-
const e =
|
|
10296
|
+
const e = Ke(), [n] = St(), { user: a, login: s, register: o } = Ye(), { t: i } = ee(), l = n.get("next") ?? "", c = /^\/connect\/authorize\?request=[a-f0-9]{64}$/.test(l) ? l : "/", h = n.get("invite") || "", [u, g] = C(h ? "register" : "login"), [d, v] = C(!1), [k, x] = C(!1), [p, w] = C([]), [b, y] = C(!0), [m, f] = C(""), [D, N] = C(""), [A, T] = C(""), [_, V] = C(""), [K, I] = C("");
|
|
10227
10297
|
ie(() => {
|
|
10228
10298
|
a && a.role !== "public_manager" && e(c, { replace: !0 });
|
|
10229
10299
|
}, [a, e, c]), ie(() => {
|
|
@@ -10237,7 +10307,7 @@ function Yd() {
|
|
|
10237
10307
|
}, [n, i]);
|
|
10238
10308
|
const F = async (G) => {
|
|
10239
10309
|
if (G.preventDefault(), f(""), u === "register") {
|
|
10240
|
-
if (_ !==
|
|
10310
|
+
if (_ !== K) {
|
|
10241
10311
|
f(i("login.passwordsNoMatch"));
|
|
10242
10312
|
return;
|
|
10243
10313
|
}
|
|
@@ -10300,12 +10370,12 @@ function Yd() {
|
|
|
10300
10370
|
{
|
|
10301
10371
|
label: i("login.confirmPassword"),
|
|
10302
10372
|
type: "password",
|
|
10303
|
-
value:
|
|
10373
|
+
value: K,
|
|
10304
10374
|
onChange: (G) => I(G.target.value),
|
|
10305
10375
|
required: !0
|
|
10306
10376
|
}
|
|
10307
10377
|
),
|
|
10308
|
-
/* @__PURE__ */ t(
|
|
10378
|
+
/* @__PURE__ */ t(W, { type: "submit", className: "w-full", children: i(u === "register" ? k ? "login.createAdmin" : "login.register" : "login.signIn") })
|
|
10309
10379
|
] }),
|
|
10310
10380
|
p.length > 0 && /* @__PURE__ */ r("div", { className: "mt-4 space-y-3", children: [
|
|
10311
10381
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
|
|
@@ -10336,7 +10406,7 @@ function Yd() {
|
|
|
10336
10406
|
/* @__PURE__ */ t("p", { className: "mt-1 text-sm text-fg-muted", children: i("login.browsingBody") })
|
|
10337
10407
|
] }),
|
|
10338
10408
|
/* @__PURE__ */ t(
|
|
10339
|
-
|
|
10409
|
+
W,
|
|
10340
10410
|
{
|
|
10341
10411
|
type: "button",
|
|
10342
10412
|
className: "w-full",
|
|
@@ -10368,7 +10438,7 @@ function Zd({ provider: e }) {
|
|
|
10368
10438
|
] }) : 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;
|
|
10369
10439
|
}
|
|
10370
10440
|
function Xd() {
|
|
10371
|
-
const e =
|
|
10441
|
+
const e = Ke(), n = me(!1), [a, s] = C("");
|
|
10372
10442
|
return ie(() => {
|
|
10373
10443
|
n.current || (n.current = !0, q.createChatSession().then((o) => {
|
|
10374
10444
|
e(`/chat/${o.id}?demo=1`, { replace: !0 });
|
|
@@ -10397,7 +10467,7 @@ const Mt = [
|
|
|
10397
10467
|
users: Mt.filter((n) => `${n.full_name} ${n.email}`.toLowerCase().includes(e.toLowerCase()))
|
|
10398
10468
|
});
|
|
10399
10469
|
function tu() {
|
|
10400
|
-
const e =
|
|
10470
|
+
const e = We(), [n] = C(() => `mentions-preview-${crypto.randomUUID()}`), [a, s] = C(Mt[0]), [o, i] = C(""), [l, c] = C([]), [h, u] = C(""), [g, d] = C(!1), [v, k] = C([
|
|
10401
10471
|
{ id: "welcome", body: "@Alex Morgan Please review the customer's delivery requirements.", author: "Sam Keller" }
|
|
10402
10472
|
]), x = me([{
|
|
10403
10473
|
id: "welcome",
|
|
@@ -10554,7 +10624,7 @@ function Za() {
|
|
|
10554
10624
|
return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
|
|
10555
10625
|
}
|
|
10556
10626
|
function nu() {
|
|
10557
|
-
const e =
|
|
10627
|
+
const e = Ke(), n = We(), [a, s] = C(""), [o, i] = C(Ee()), [l, c] = C(""), [h, u] = C([Ya()]), [g, d] = C([Ja()]), [v, k] = C([Za()]), [x, p] = C({}), w = xe({
|
|
10558
10628
|
mutationFn: () => q.importAccountBalances({
|
|
10559
10629
|
company: a,
|
|
10560
10630
|
posting_date: o,
|
|
@@ -10627,7 +10697,7 @@ function nu() {
|
|
|
10627
10697
|
] }) }),
|
|
10628
10698
|
/* @__PURE__ */ t("div", { className: "mt-2 flex gap-2", children: /* @__PURE__ */ t("button", { onClick: () => u([...h, Ya()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
|
|
10629
10699
|
/* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
|
|
10630
|
-
/* @__PURE__ */ t(
|
|
10700
|
+
/* @__PURE__ */ t(W, { onClick: () => w.mutate(), disabled: !a || w.isPending, children: w.isPending ? "Importing..." : "Import Account Balances" }),
|
|
10631
10701
|
w.error && /* @__PURE__ */ t("span", { className: "text-xs text-red-600", children: w.error.message }),
|
|
10632
10702
|
x.accounts && /* @__PURE__ */ r("span", { className: "text-xs text-green-600", children: [
|
|
10633
10703
|
"Created ",
|
|
@@ -10652,7 +10722,7 @@ function nu() {
|
|
|
10652
10722
|
] }) }),
|
|
10653
10723
|
/* @__PURE__ */ t("div", { className: "mt-2", children: /* @__PURE__ */ t("button", { onClick: () => d([...g, Ja()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
|
|
10654
10724
|
/* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
|
|
10655
|
-
/* @__PURE__ */ t(
|
|
10725
|
+
/* @__PURE__ */ t(W, { onClick: () => b.mutate(), disabled: !a || !l || b.isPending, children: b.isPending ? "Importing..." : "Import Stock Balances" }),
|
|
10656
10726
|
b.error && /* @__PURE__ */ t("span", { className: "text-xs text-red-600", children: b.error.message }),
|
|
10657
10727
|
x.stock && /* @__PURE__ */ r("span", { className: "text-xs text-green-600", children: [
|
|
10658
10728
|
"Created ",
|
|
@@ -10695,7 +10765,7 @@ function nu() {
|
|
|
10695
10765
|
] }) }),
|
|
10696
10766
|
/* @__PURE__ */ t("div", { className: "mt-2", children: /* @__PURE__ */ t("button", { onClick: () => k([...v, Za()]), className: "text-xs text-blue-600 hover:text-blue-800", children: "+ Add Row" }) }),
|
|
10697
10767
|
/* @__PURE__ */ r("div", { className: "mt-3 flex items-center gap-3", children: [
|
|
10698
|
-
/* @__PURE__ */ t(
|
|
10768
|
+
/* @__PURE__ */ t(W, { onClick: () => y.mutate(), disabled: !a || y.isPending, children: y.isPending ? "Importing..." : "Import Outstanding Invoices" }),
|
|
10699
10769
|
y.error && /* @__PURE__ */ t("span", { className: "text-xs text-red-600", children: y.error.message }),
|
|
10700
10770
|
x.invoices && /* @__PURE__ */ r("span", { className: "text-xs text-green-600", children: [
|
|
10701
10771
|
"Created ",
|
|
@@ -10770,7 +10840,7 @@ function ru() {
|
|
|
10770
10840
|
p(null);
|
|
10771
10841
|
}
|
|
10772
10842
|
}
|
|
10773
|
-
},
|
|
10843
|
+
}, K = async () => {
|
|
10774
10844
|
p("import"), b("");
|
|
10775
10845
|
try {
|
|
10776
10846
|
const I = await q.importBankStatements(a, h);
|
|
@@ -10827,7 +10897,7 @@ function ru() {
|
|
|
10827
10897
|
}
|
|
10828
10898
|
),
|
|
10829
10899
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
10830
|
-
/* @__PURE__ */ r(
|
|
10900
|
+
/* @__PURE__ */ r(W, { disabled: !a.length || x !== null, onClick: V, children: [
|
|
10831
10901
|
x === "preview" && /* @__PURE__ */ t(ln, { className: "h-4 w-4 animate-spin" }),
|
|
10832
10902
|
e("bankStatements.preview")
|
|
10833
10903
|
] }),
|
|
@@ -10934,7 +11004,7 @@ function ru() {
|
|
|
10934
11004
|
] })
|
|
10935
11005
|
] }, I.statement_key)),
|
|
10936
11006
|
o.length > 0 && /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
10937
|
-
/* @__PURE__ */ r(
|
|
11007
|
+
/* @__PURE__ */ r(W, { disabled: !A || x !== null, onClick: K, children: [
|
|
10938
11008
|
x === "import" && /* @__PURE__ */ t(ln, { className: "h-4 w-4 animate-spin" }),
|
|
10939
11009
|
e("bankStatements.import")
|
|
10940
11010
|
] }),
|
|
@@ -10987,7 +11057,7 @@ function su() {
|
|
|
10987
11057
|
var le;
|
|
10988
11058
|
const { t: e, i18n: n } = ee(), a = Rt();
|
|
10989
11059
|
Fe(e("bankReconciliation.title"));
|
|
10990
|
-
const [s, o] = C("Unreconciled"), [i, l] = C([]), [c, h] = C(null), [u, g] = C(null), [d, v] = C([]), [k, x] = C({}), [p, w] = C(""), [b, y] = C(""), [m, f] = C(""), [D, N] = C(!1), [A, T] = C(""), [_, V] = C(""),
|
|
11060
|
+
const [s, o] = C("Unreconciled"), [i, l] = C([]), [c, h] = C(null), [u, g] = C(null), [d, v] = C([]), [k, x] = C({}), [p, w] = C(""), [b, y] = C(""), [m, f] = C(""), [D, N] = C(!1), [A, T] = C(""), [_, V] = C(""), K = (P, Z) => {
|
|
10991
11061
|
try {
|
|
10992
11062
|
return new Intl.NumberFormat(n.language, { style: "currency", currency: Z }).format(P);
|
|
10993
11063
|
} catch {
|
|
@@ -11029,14 +11099,14 @@ function su() {
|
|
|
11029
11099
|
body: be ? /* @__PURE__ */ r("div", { className: "space-y-2", children: [
|
|
11030
11100
|
/* @__PURE__ */ t("p", { children: e("bankReconciliation.confirmGroupBody", {
|
|
11031
11101
|
count: Z.length,
|
|
11032
|
-
amount:
|
|
11102
|
+
amount: K(P.amount, P.currency),
|
|
11033
11103
|
voucher: `${P.voucher_type} ${P.voucher_no}`
|
|
11034
11104
|
}) }),
|
|
11035
11105
|
/* @__PURE__ */ t("ul", { className: "list-disc space-y-1 pl-5 text-sm", children: Z.map((Se) => /* @__PURE__ */ r("li", { children: [
|
|
11036
11106
|
Se.name,
|
|
11037
11107
|
" · ",
|
|
11038
11108
|
Se.deposit ? "+" : "−",
|
|
11039
|
-
|
|
11109
|
+
K(Se.amount, P.currency)
|
|
11040
11110
|
] }, Se.name)) })
|
|
11041
11111
|
] }) : e("bankReconciliation.confirmExistingBody", {
|
|
11042
11112
|
transaction: F.name,
|
|
@@ -11067,10 +11137,10 @@ function su() {
|
|
|
11067
11137
|
body: /* @__PURE__ */ r("div", { className: "space-y-2", children: [
|
|
11068
11138
|
/* @__PURE__ */ t("p", { children: e("bankReconciliation.confirmPaymentBody", {
|
|
11069
11139
|
transaction: F.name,
|
|
11070
|
-
amount:
|
|
11140
|
+
amount: K(F.amount, F.currency),
|
|
11071
11141
|
count: G.length
|
|
11072
11142
|
}) }),
|
|
11073
|
-
P > 9e-3 && /* @__PURE__ */ t("p", { className: "font-medium text-amber-700", children: e("bankReconciliation.onAccountWarning", { amount:
|
|
11143
|
+
P > 9e-3 && /* @__PURE__ */ t("p", { className: "font-medium text-amber-700", children: e("bankReconciliation.onAccountWarning", { amount: K(P, F.currency) }) })
|
|
11074
11144
|
] }),
|
|
11075
11145
|
confirmLabel: e("bankReconciliation.postAndReconcile")
|
|
11076
11146
|
})) {
|
|
@@ -11097,7 +11167,7 @@ function su() {
|
|
|
11097
11167
|
title: e("bankReconciliation.confirmJournalTitle"),
|
|
11098
11168
|
body: e("bankReconciliation.confirmJournalBody", {
|
|
11099
11169
|
transaction: F.name,
|
|
11100
|
-
amount:
|
|
11170
|
+
amount: K(F.amount, F.currency),
|
|
11101
11171
|
account: p
|
|
11102
11172
|
}),
|
|
11103
11173
|
confirmLabel: e("bankReconciliation.postAndReconcile")
|
|
@@ -11159,7 +11229,7 @@ function su() {
|
|
|
11159
11229
|
onChange: (P) => o(P.target.value)
|
|
11160
11230
|
}
|
|
11161
11231
|
),
|
|
11162
|
-
/* @__PURE__ */ t(
|
|
11232
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => I(c), disabled: D, children: /* @__PURE__ */ t(xr, { className: "h-4 w-4" }) })
|
|
11163
11233
|
] })
|
|
11164
11234
|
] }),
|
|
11165
11235
|
A && /* @__PURE__ */ t("div", { className: "rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700", children: A }),
|
|
@@ -11185,7 +11255,7 @@ function su() {
|
|
|
11185
11255
|
/* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: P.posting_date }),
|
|
11186
11256
|
/* @__PURE__ */ r("span", { className: Re("text-sm font-semibold tabular-nums", P.deposit ? "text-emerald-700" : "text-fg"), children: [
|
|
11187
11257
|
P.deposit ? "+" : "−",
|
|
11188
|
-
|
|
11258
|
+
K(P.amount, P.currency)
|
|
11189
11259
|
] })
|
|
11190
11260
|
] }),
|
|
11191
11261
|
/* @__PURE__ */ t("p", { className: "mt-1 truncate text-sm font-medium text-fg", children: P.counterparty_name || P.description || P.name }),
|
|
@@ -11210,7 +11280,7 @@ function su() {
|
|
|
11210
11280
|
] }),
|
|
11211
11281
|
F && /* @__PURE__ */ r("span", { className: "text-lg font-semibold tabular-nums", children: [
|
|
11212
11282
|
F.deposit ? "+" : "−",
|
|
11213
|
-
|
|
11283
|
+
K(F.amount, F.currency)
|
|
11214
11284
|
] })
|
|
11215
11285
|
] }),
|
|
11216
11286
|
/* @__PURE__ */ r("dl", { className: "mt-4 grid gap-3 text-sm sm:grid-cols-2", children: [
|
|
@@ -11249,7 +11319,7 @@ function su() {
|
|
|
11249
11319
|
" ",
|
|
11250
11320
|
u.active_reconciliation.voucher_no
|
|
11251
11321
|
] }),
|
|
11252
|
-
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(
|
|
11322
|
+
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ r(W, { variant: "danger", disabled: D, onClick: H, children: [
|
|
11253
11323
|
/* @__PURE__ */ t(ti, { className: "h-4 w-4" }),
|
|
11254
11324
|
e("bankReconciliation.undo")
|
|
11255
11325
|
] }) })
|
|
@@ -11267,12 +11337,12 @@ function su() {
|
|
|
11267
11337
|
/* @__PURE__ */ r("p", { className: "text-xs text-fg-muted", children: [
|
|
11268
11338
|
P.posting_date,
|
|
11269
11339
|
" · ",
|
|
11270
|
-
|
|
11340
|
+
K(P.amount, P.currency),
|
|
11271
11341
|
P.kind === "existing_voucher_group" && ` · ${e("bankReconciliation.groupedTransactions", { count: P.bank_transactions.length })}`
|
|
11272
11342
|
] }),
|
|
11273
11343
|
P.kind === "existing_voucher_group" && /* @__PURE__ */ t("p", { className: "mt-1 text-xs text-fg-muted", children: P.bank_transactions.map((Z) => Z.name).join(" + ") })
|
|
11274
11344
|
] }),
|
|
11275
|
-
/* @__PURE__ */ t(
|
|
11345
|
+
/* @__PURE__ */ t(W, { variant: "secondary", disabled: D, onClick: () => j(P), children: e("bankReconciliation.match") })
|
|
11276
11346
|
] }, `${P.voucher_type}:${P.voucher_no}`)) })
|
|
11277
11347
|
] }),
|
|
11278
11348
|
/* @__PURE__ */ r(X, { children: [
|
|
@@ -11307,7 +11377,7 @@ function su() {
|
|
|
11307
11377
|
" · ",
|
|
11308
11378
|
e("bankReconciliation.outstanding"),
|
|
11309
11379
|
": ",
|
|
11310
|
-
|
|
11380
|
+
K(P.outstanding_amount, P.currency)
|
|
11311
11381
|
] })
|
|
11312
11382
|
] }),
|
|
11313
11383
|
/* @__PURE__ */ t(
|
|
@@ -11327,8 +11397,8 @@ function su() {
|
|
|
11327
11397
|
!u.invoices.length && /* @__PURE__ */ t("p", { className: "py-4 text-sm text-fg-muted", children: e("bankReconciliation.noInvoiceSuggestions") })
|
|
11328
11398
|
] }),
|
|
11329
11399
|
G.length > 0 && F && /* @__PURE__ */ r("div", { className: "mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-line pt-4", children: [
|
|
11330
|
-
/* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("bankReconciliation.allocated", { amount:
|
|
11331
|
-
/* @__PURE__ */ t(
|
|
11400
|
+
/* @__PURE__ */ t("p", { className: "text-sm text-fg-muted", children: e("bankReconciliation.allocated", { amount: K(O, F.currency), total: K(F.amount, F.currency) }) }),
|
|
11401
|
+
/* @__PURE__ */ t(W, { disabled: D || O <= 0 || O > F.amount + 0.01, onClick: ne, children: e("bankReconciliation.createPayment") })
|
|
11332
11402
|
] })
|
|
11333
11403
|
] }),
|
|
11334
11404
|
/* @__PURE__ */ r(X, { children: [
|
|
@@ -11346,7 +11416,7 @@ function su() {
|
|
|
11346
11416
|
),
|
|
11347
11417
|
/* @__PURE__ */ t(pe, { label: e("bankReconciliation.remarks"), value: b, onChange: (P) => y(P.target.value) })
|
|
11348
11418
|
] }),
|
|
11349
|
-
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ t(
|
|
11419
|
+
/* @__PURE__ */ t("div", { className: "mt-4", children: /* @__PURE__ */ t(W, { disabled: D || !p || !!(F && F.currency !== F.base_currency && !m), onClick: ue, children: e("bankReconciliation.createJournal") }) })
|
|
11350
11420
|
] })
|
|
11351
11421
|
] })
|
|
11352
11422
|
] }) : /* @__PURE__ */ t(X, { className: "flex min-h-48 items-center justify-center", children: /* @__PURE__ */ t(ln, { className: "h-5 w-5 animate-spin text-brand" }) }) : null
|
|
@@ -11355,7 +11425,7 @@ function su() {
|
|
|
11355
11425
|
}
|
|
11356
11426
|
function iu() {
|
|
11357
11427
|
Fe("Users");
|
|
11358
|
-
const { user: e } = Ye(), n =
|
|
11428
|
+
const { user: e } = Ye(), n = We(), { data: a, isLoading: s } = he({
|
|
11359
11429
|
queryKey: ["auth-users"],
|
|
11360
11430
|
queryFn: () => q.authListUsers()
|
|
11361
11431
|
}), { data: o } = he({
|
|
@@ -11409,7 +11479,7 @@ function iu() {
|
|
|
11409
11479
|
mutationFn: (R) => q.authDeleteAccessProfile(R),
|
|
11410
11480
|
onSuccess: b,
|
|
11411
11481
|
onError: (R) => A(R.message)
|
|
11412
|
-
}), [
|
|
11482
|
+
}), [K, I] = C(null), F = Fr(), G = (R) => `${window.location.origin}/login?invite=${R}`, O = async (R) => {
|
|
11413
11483
|
try {
|
|
11414
11484
|
await navigator.clipboard.writeText(G(R)), I(R), setTimeout(() => I((z) => z === R ? null : z), 2e3);
|
|
11415
11485
|
} catch {
|
|
@@ -11453,7 +11523,7 @@ function iu() {
|
|
|
11453
11523
|
}
|
|
11454
11524
|
),
|
|
11455
11525
|
/* @__PURE__ */ t(
|
|
11456
|
-
|
|
11526
|
+
W,
|
|
11457
11527
|
{
|
|
11458
11528
|
onClick: () => d.mutate(),
|
|
11459
11529
|
disabled: !i.trim() || d.isPending,
|
|
@@ -11489,16 +11559,16 @@ function iu() {
|
|
|
11489
11559
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-500", children: (z = R.creation) == null ? void 0 : z.split("T")[0] }),
|
|
11490
11560
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-right", children: /* @__PURE__ */ r("div", { className: "flex items-center justify-end gap-2", children: [
|
|
11491
11561
|
/* @__PURE__ */ t(
|
|
11492
|
-
|
|
11562
|
+
W,
|
|
11493
11563
|
{
|
|
11494
11564
|
variant: "secondary",
|
|
11495
11565
|
size: "sm",
|
|
11496
11566
|
onClick: () => O(R.token),
|
|
11497
|
-
children:
|
|
11567
|
+
children: K === R.token ? "Copied!" : "Copy link"
|
|
11498
11568
|
}
|
|
11499
11569
|
),
|
|
11500
11570
|
/* @__PURE__ */ t(
|
|
11501
|
-
|
|
11571
|
+
W,
|
|
11502
11572
|
{
|
|
11503
11573
|
variant: "danger",
|
|
11504
11574
|
size: "sm",
|
|
@@ -11589,8 +11659,8 @@ function iu() {
|
|
|
11589
11659
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-700", children: R.hidden_classes.join(", ") || "nothing" }),
|
|
11590
11660
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-gray-700", children: Object.keys(((z = R.permissions) == null ? void 0 : z.doctypes) ?? {}).length + (((S = R.permissions) == null ? void 0 : S.default) != null ? 1 : 0) || "none" }),
|
|
11591
11661
|
/* @__PURE__ */ t("td", { className: "px-4 py-2 text-right", children: /* @__PURE__ */ r("div", { className: "flex items-center justify-end gap-2", children: [
|
|
11592
|
-
/* @__PURE__ */ t(
|
|
11593
|
-
/* @__PURE__ */ t(
|
|
11662
|
+
/* @__PURE__ */ t(W, { variant: "secondary", size: "sm", onClick: () => T(R, !1), children: "Edit" }),
|
|
11663
|
+
/* @__PURE__ */ t(W, { variant: "danger", size: "sm", onClick: () => V.mutate(R.name), children: "Delete" })
|
|
11594
11664
|
] }) })
|
|
11595
11665
|
] }, R.name);
|
|
11596
11666
|
}) })
|
|
@@ -11672,12 +11742,12 @@ function iu() {
|
|
|
11672
11742
|
] }),
|
|
11673
11743
|
N && /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: N }),
|
|
11674
11744
|
/* @__PURE__ */ r("div", { className: "flex gap-2", children: [
|
|
11675
|
-
/* @__PURE__ */ t(
|
|
11676
|
-
/* @__PURE__ */ t(
|
|
11745
|
+
/* @__PURE__ */ t(W, { onClick: () => _.mutate(), disabled: !f.profile.name.trim() || _.isPending, children: "Save profile" }),
|
|
11746
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => D(null), children: "Cancel" })
|
|
11677
11747
|
] })
|
|
11678
11748
|
] }) : /* @__PURE__ */ r(Ne, { children: [
|
|
11679
11749
|
N && /* @__PURE__ */ t("p", { className: "mb-2 text-sm text-red-600", children: N }),
|
|
11680
|
-
/* @__PURE__ */ t(
|
|
11750
|
+
/* @__PURE__ */ t(W, { variant: "secondary", onClick: () => T(m, !0), children: "New profile" })
|
|
11681
11751
|
] })
|
|
11682
11752
|
] })
|
|
11683
11753
|
] });
|
|
@@ -11693,7 +11763,7 @@ function Ot({ value: e, label: n }) {
|
|
|
11693
11763
|
const { t: a } = ee(), [s, o] = C(!1), [i, l] = C(!1);
|
|
11694
11764
|
return /* @__PURE__ */ r("div", { className: "space-y-2", children: [
|
|
11695
11765
|
/* @__PURE__ */ t("div", { className: "rounded-lg border border-line bg-surface p-3", children: /* @__PURE__ */ t("pre", { className: "whitespace-pre-wrap break-all font-mono text-xs text-fg", children: e }) }),
|
|
11696
|
-
/* @__PURE__ */ r(
|
|
11766
|
+
/* @__PURE__ */ r(W, { variant: "secondary", size: "sm", onClick: async () => {
|
|
11697
11767
|
try {
|
|
11698
11768
|
await navigator.clipboard.writeText(e), o(!0), l(!1);
|
|
11699
11769
|
} catch {
|
|
@@ -11708,7 +11778,7 @@ function Ot({ value: e, label: n }) {
|
|
|
11708
11778
|
}
|
|
11709
11779
|
function ou({ ownRole: e }) {
|
|
11710
11780
|
var D, N, A;
|
|
11711
|
-
const { t: n } = ee(), a =
|
|
11781
|
+
const { t: n } = ee(), a = We(), [s, o] = C(null), [i, l] = C(""), [c, h] = C("viewer"), [u, g] = C("mcp"), [d, v] = C(null), k = Xa.find((T) => T.id === s), x = he({ queryKey: ["connection-status"], queryFn: q.getConnectionStatus }), p = xe({
|
|
11712
11782
|
mutationFn: () => q.createApiKey(i.trim(), c, s),
|
|
11713
11783
|
onSuccess: (T) => {
|
|
11714
11784
|
v(T.token), a.invalidateQueries({ queryKey: ["api-keys"] });
|
|
@@ -11722,7 +11792,7 @@ http_headers = { Authorization = "Bearer ${d}" }`, f = ["viewer", "manager", "ad
|
|
|
11722
11792
|
/* @__PURE__ */ t("h3", { className: "text-base font-semibold text-fg", children: n("connections.title") }),
|
|
11723
11793
|
/* @__PURE__ */ t("p", { className: "mt-1 text-sm text-fg-muted", children: n("connections.subtitle") })
|
|
11724
11794
|
] }),
|
|
11725
|
-
/* @__PURE__ */ t("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-5", children: Xa.map(({ id: T, name: _, icon: V, oauth:
|
|
11795
|
+
/* @__PURE__ */ t("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-5", children: Xa.map(({ id: T, name: _, icon: V, oauth: K }) => /* @__PURE__ */ r(
|
|
11726
11796
|
"button",
|
|
11727
11797
|
{
|
|
11728
11798
|
type: "button",
|
|
@@ -11735,7 +11805,7 @@ http_headers = { Authorization = "Bearer ${d}" }`, f = ["viewer", "manager", "ad
|
|
|
11735
11805
|
children: [
|
|
11736
11806
|
/* @__PURE__ */ t(V, { size: 22, className: "text-brand", "aria-hidden": "true" }),
|
|
11737
11807
|
/* @__PURE__ */ t("span", { className: "text-sm font-semibold text-fg", children: _ || n("connections.other") }),
|
|
11738
|
-
/* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: n(
|
|
11808
|
+
/* @__PURE__ */ t("span", { className: "text-xs text-fg-muted", children: n(K ? "connections.signIn" : "connections.apiKey") })
|
|
11739
11809
|
]
|
|
11740
11810
|
},
|
|
11741
11811
|
T
|
|
@@ -11828,9 +11898,9 @@ http_headers = { Authorization = "Bearer ${d}" }`, f = ["viewer", "manager", "ad
|
|
|
11828
11898
|
/* @__PURE__ */ t(Ot, { value: `Authorization: Bearer ${d}`, label: n("connections.copyHeader") })
|
|
11829
11899
|
] })
|
|
11830
11900
|
] }),
|
|
11831
|
-
d ? /* @__PURE__ */ t(
|
|
11901
|
+
d ? /* @__PURE__ */ t(W, { variant: "secondary", onClick: () => {
|
|
11832
11902
|
v(null), p.reset();
|
|
11833
|
-
}, children: n("connections.done") }) : /* @__PURE__ */ t(
|
|
11903
|
+
}, children: n("connections.done") }) : /* @__PURE__ */ t(W, { onClick: () => p.mutate(), disabled: !w || !i.trim() || !c || s === "other" && !u || p.isPending, children: p.isPending ? n("common.loading") : n("settings.chatApiCreate") })
|
|
11834
11904
|
] })
|
|
11835
11905
|
] })
|
|
11836
11906
|
] });
|
|
@@ -12104,7 +12174,7 @@ function cu() {
|
|
|
12104
12174
|
),
|
|
12105
12175
|
h && /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: h }),
|
|
12106
12176
|
g && /* @__PURE__ */ t("p", { className: "text-sm text-green-700", children: e("settings.passwordChanged") }),
|
|
12107
|
-
/* @__PURE__ */ t(
|
|
12177
|
+
/* @__PURE__ */ t(W, { type: "submit", disabled: v.isPending || !a || !o || !l, children: v.isPending ? e("settings.changingPassword") : e("settings.changePassword") })
|
|
12108
12178
|
] }) });
|
|
12109
12179
|
}
|
|
12110
12180
|
function du() {
|
|
@@ -12169,7 +12239,7 @@ function du() {
|
|
|
12169
12239
|
),
|
|
12170
12240
|
c && /* @__PURE__ */ t("p", { className: "text-sm text-red-600", children: c }),
|
|
12171
12241
|
u && /* @__PURE__ */ t("p", { className: "text-sm text-green-700", children: e("settings.passwordSet") }),
|
|
12172
|
-
/* @__PURE__ */ t(
|
|
12242
|
+
/* @__PURE__ */ t(W, { type: "submit", disabled: d.isPending || !s || !i, children: d.isPending ? e("settings.changingPassword") : e("settings.setPassword") })
|
|
12173
12243
|
] })
|
|
12174
12244
|
] });
|
|
12175
12245
|
}
|
|
@@ -12208,7 +12278,7 @@ function uu() {
|
|
|
12208
12278
|
] });
|
|
12209
12279
|
}
|
|
12210
12280
|
function fs({ ownRole: e }) {
|
|
12211
|
-
const { t: n } = ee(), { user: a } = Ye(), s =
|
|
12281
|
+
const { t: n } = ee(), { user: a } = Ye(), s = We(), [o, i] = C(null), { data: l } = he({
|
|
12212
12282
|
queryKey: ["api-keys"],
|
|
12213
12283
|
queryFn: () => q.getApiKeys()
|
|
12214
12284
|
}), c = xe({
|
|
@@ -12240,7 +12310,7 @@ function fs({ ownRole: e }) {
|
|
|
12240
12310
|
/* @__PURE__ */ t(ou, { ownRole: e }),
|
|
12241
12311
|
/* @__PURE__ */ r("div", { className: "flex items-center justify-between border-t border-line pt-5", children: [
|
|
12242
12312
|
/* @__PURE__ */ t("h3", { className: "font-semibold text-fg", children: n("connections.existing") }),
|
|
12243
|
-
/* @__PURE__ */ t(
|
|
12313
|
+
/* @__PURE__ */ t(W, { variant: "ghost", size: "sm", onClick: () => s.invalidateQueries({ queryKey: ["api-keys"] }), children: n("connections.refresh") })
|
|
12244
12314
|
] }),
|
|
12245
12315
|
e === "admin" && /* @__PURE__ */ t("p", { className: "mb-3 text-xs text-fg-muted", children: n("settings.chatApiAdminAllNote") }),
|
|
12246
12316
|
d.length > 0 ? /* @__PURE__ */ t("div", { className: "mb-4 space-y-4", children: d.map((x) => /* @__PURE__ */ r("div", { children: [
|
|
@@ -12303,9 +12373,9 @@ function fs({ ownRole: e }) {
|
|
|
12303
12373
|
{ name: o.owner, key: o.keyName }
|
|
12304
12374
|
) }),
|
|
12305
12375
|
/* @__PURE__ */ r("div", { className: "mt-4 flex justify-end gap-2", children: [
|
|
12306
|
-
/* @__PURE__ */ t(
|
|
12376
|
+
/* @__PURE__ */ t(W, { variant: "secondary", size: "sm", onClick: () => i(null), children: n("common.cancel") }),
|
|
12307
12377
|
/* @__PURE__ */ t(
|
|
12308
|
-
|
|
12378
|
+
W,
|
|
12309
12379
|
{
|
|
12310
12380
|
variant: "danger",
|
|
12311
12381
|
size: "sm",
|
|
@@ -12395,9 +12465,9 @@ function mu({
|
|
|
12395
12465
|
/* @__PURE__ */ t("h3", { className: "text-base font-semibold text-fg", children: i(l === "chat" ? "settings.chatApiDeactivateTitle" : "settings.restApiDeactivateTitle") }),
|
|
12396
12466
|
/* @__PURE__ */ t("p", { className: "mt-3 text-sm text-fg-muted", children: i(l === "chat" ? "settings.chatApiDeactivateBody" : "settings.restApiDeactivateBody") }),
|
|
12397
12467
|
/* @__PURE__ */ r("div", { className: "mt-6 flex justify-end gap-2", children: [
|
|
12398
|
-
/* @__PURE__ */ t(
|
|
12468
|
+
/* @__PURE__ */ t(W, { variant: "secondary", size: "sm", onClick: () => c(null), children: i("common.cancel") }),
|
|
12399
12469
|
/* @__PURE__ */ t(
|
|
12400
|
-
|
|
12470
|
+
W,
|
|
12401
12471
|
{
|
|
12402
12472
|
variant: "danger",
|
|
12403
12473
|
size: "sm",
|
|
@@ -12416,7 +12486,7 @@ function mu({
|
|
|
12416
12486
|
] });
|
|
12417
12487
|
}
|
|
12418
12488
|
function pu() {
|
|
12419
|
-
const { user: e } = Ye(), { t: n } = ee(), a =
|
|
12489
|
+
const { user: e } = Ye(), { t: n } = ee(), a = We(), s = (e == null ? void 0 : e.role) === "admin", { data: o, isLoading: i } = he({
|
|
12420
12490
|
queryKey: ["settings"],
|
|
12421
12491
|
queryFn: () => q.getSettings()
|
|
12422
12492
|
}), l = xe({
|
|
@@ -12665,7 +12735,7 @@ function ir({ label: e, hidden: n, locked: a, onToggle: s }) {
|
|
|
12665
12735
|
);
|
|
12666
12736
|
}
|
|
12667
12737
|
function fu() {
|
|
12668
|
-
const { t: e } = ee(), n =
|
|
12738
|
+
const { t: e } = ee(), n = We(), { settings: a, isLoaded: s } = Bt(), o = ye(() => gu(a.nav_catalog), [a.nav_catalog]), i = ye(() => rr(o, Mn(a.nav_layout)), [o, a.nav_layout]), l = ye(() => rr(o, Mn(void 0)), [o]), [c, h] = C(i), { dirty: u, markDirty: g, markClean: d } = jt();
|
|
12669
12739
|
ie(() => {
|
|
12670
12740
|
u || h(i);
|
|
12671
12741
|
}, [i, u]);
|
|
@@ -12703,9 +12773,9 @@ function fu() {
|
|
|
12703
12773
|
] }),
|
|
12704
12774
|
/* @__PURE__ */ r("div", { className: "sticky top-0 z-20 flex flex-wrap items-center justify-end gap-2 rounded-xl bg-surface px-4 py-2 ring-1 ring-line shadow-card", children: [
|
|
12705
12775
|
p.error ? /* @__PURE__ */ t("p", { role: "alert", className: "mr-auto text-sm text-rose-700", children: p.error.message }) : u && /* @__PURE__ */ t("p", { className: "mr-auto text-sm text-fg-muted", children: e("menuLayout.unsaved") }),
|
|
12706
|
-
/* @__PURE__ */ t(
|
|
12776
|
+
/* @__PURE__ */ t(W, { variant: "ghost", size: "sm", disabled: w || p.isPending, onClick: () => v(l), children: e("menuLayout.reset") }),
|
|
12707
12777
|
u && /* @__PURE__ */ t(
|
|
12708
|
-
|
|
12778
|
+
W,
|
|
12709
12779
|
{
|
|
12710
12780
|
variant: "secondary",
|
|
12711
12781
|
size: "sm",
|
|
@@ -12716,7 +12786,7 @@ function fu() {
|
|
|
12716
12786
|
children: e("menuLayout.discard")
|
|
12717
12787
|
}
|
|
12718
12788
|
),
|
|
12719
|
-
/* @__PURE__ */ t(
|
|
12789
|
+
/* @__PURE__ */ t(Kt, { dirty: u, saving: p.isPending, onClick: () => p.mutate() })
|
|
12720
12790
|
] }),
|
|
12721
12791
|
/* @__PURE__ */ t(
|
|
12722
12792
|
ar,
|
|
@@ -12805,7 +12875,7 @@ function ys({ template: e }) {
|
|
|
12805
12875
|
] });
|
|
12806
12876
|
}
|
|
12807
12877
|
function vu({ canEdit: e, type: n }) {
|
|
12808
|
-
const { t: a } = ee(), s =
|
|
12878
|
+
const { t: a } = ee(), s = We(), { data: o } = Yr(!0, n.doctype), [i, l] = C({ intro_text: "", remarks: "" }), [c, h] = C(!1);
|
|
12809
12879
|
ie(() => {
|
|
12810
12880
|
o && l({ intro_text: o.intro_text, remarks: o.remarks });
|
|
12811
12881
|
}, [o]);
|
|
@@ -12839,14 +12909,14 @@ function vu({ canEdit: e, type: n }) {
|
|
|
12839
12909
|
o && /* @__PURE__ */ t("p", { className: "mt-2 text-xs text-fg-muted", children: a("pdfTemplates.textDefaultsPlaceholders", { placeholders: o.placeholders.join(", "), interpolation: { escapeValue: !1 } }) }),
|
|
12840
12910
|
u.error && /* @__PURE__ */ t("p", { role: "alert", className: "mt-2 text-sm text-rose-700", children: u.error.message }),
|
|
12841
12911
|
e && /* @__PURE__ */ r("div", { className: "mt-4 flex items-center gap-3", children: [
|
|
12842
|
-
/* @__PURE__ */ t(
|
|
12912
|
+
/* @__PURE__ */ t(W, { onClick: () => u.mutate(), disabled: !g || u.isPending, children: a("pdfTemplates.saveTexts") }),
|
|
12843
12913
|
c && !g && /* @__PURE__ */ t("span", { className: "text-sm text-fg-muted", children: a("pdfTemplates.textsSaved") })
|
|
12844
12914
|
] })
|
|
12845
12915
|
] });
|
|
12846
12916
|
}
|
|
12847
12917
|
function xu() {
|
|
12848
12918
|
var N;
|
|
12849
|
-
const { t: e } = ee(), { user: n } = Ye(), a = fn(n == null ? void 0 : n.role), s =
|
|
12919
|
+
const { t: e } = ee(), { user: n } = Ye(), a = fn(n == null ? void 0 : n.role), s = Ke(), o = We(), i = Fr(), l = Rt(), [c, h] = C(!1), [u, g] = St(), d = un(u.get("type")) ?? Wt[0], { data: v, isLoading: k, error: x } = mn(c, !0, d.doctype), { data: p } = mn(!1, fn(n == null ? void 0 : n.role)), w = ((p == null ? void 0 : p.templates) ?? []).filter((A) => !A.standard && A.doctype !== d.doctype), b = xe({
|
|
12850
12920
|
mutationFn: ({ action: A, args: T }) => q.runAction(A, T),
|
|
12851
12921
|
onSuccess: () => o.invalidateQueries({ queryKey: wt })
|
|
12852
12922
|
}), y = async (A) => {
|
|
@@ -12877,7 +12947,7 @@ function xu() {
|
|
|
12877
12947
|
/* @__PURE__ */ t("p", { className: "mt-1 max-w-2xl text-sm text-fg-muted", children: e("pdfTemplates.intro") }),
|
|
12878
12948
|
/* @__PURE__ */ t("p", { className: "mt-2 max-w-2xl text-xs text-fg-muted", children: e("pdfTemplates.chatHint") })
|
|
12879
12949
|
] }) }),
|
|
12880
|
-
/* @__PURE__ */ t("div", { role: "tablist", className: "mt-4 flex flex-wrap gap-1.5", children:
|
|
12950
|
+
/* @__PURE__ */ t("div", { role: "tablist", className: "mt-4 flex flex-wrap gap-1.5", children: Wt.map((A) => /* @__PURE__ */ t(
|
|
12881
12951
|
"button",
|
|
12882
12952
|
{
|
|
12883
12953
|
type: "button",
|
|
@@ -12893,7 +12963,7 @@ function xu() {
|
|
|
12893
12963
|
A.slug
|
|
12894
12964
|
)) }),
|
|
12895
12965
|
a && D && /* @__PURE__ */ r("div", { className: "mt-4 flex flex-wrap items-center gap-3", children: [
|
|
12896
|
-
/* @__PURE__ */ r(
|
|
12966
|
+
/* @__PURE__ */ r(W, { onClick: () => y(D), disabled: b.isPending, children: [
|
|
12897
12967
|
/* @__PURE__ */ t(Yn, { className: "h-4 w-4" }),
|
|
12898
12968
|
e("pdfTemplates.newFor", { type: e(`doctypes.${d.slug}.one`) })
|
|
12899
12969
|
] }),
|
|
@@ -12947,7 +13017,7 @@ function xu() {
|
|
|
12947
13017
|
] }),
|
|
12948
13018
|
a && /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
12949
13019
|
!A.default && A.published && !A.archived && /* @__PURE__ */ t(
|
|
12950
|
-
|
|
13020
|
+
W,
|
|
12951
13021
|
{
|
|
12952
13022
|
variant: "ghost",
|
|
12953
13023
|
size: "sm",
|
|
@@ -12959,12 +13029,12 @@ function xu() {
|
|
|
12959
13029
|
children: e("pdfTemplates.makeDefault")
|
|
12960
13030
|
}
|
|
12961
13031
|
),
|
|
12962
|
-
/* @__PURE__ */ r(
|
|
13032
|
+
/* @__PURE__ */ r(W, { variant: "ghost", size: "sm", disabled: b.isPending, onClick: () => y(A), children: [
|
|
12963
13033
|
/* @__PURE__ */ t(kr, { className: "h-4 w-4" }),
|
|
12964
13034
|
e("pdfTemplates.duplicate")
|
|
12965
13035
|
] }),
|
|
12966
13036
|
!A.standard && /* @__PURE__ */ t(
|
|
12967
|
-
|
|
13037
|
+
W,
|
|
12968
13038
|
{
|
|
12969
13039
|
variant: "ghost",
|
|
12970
13040
|
size: "sm",
|
|
@@ -12977,7 +13047,7 @@ function xu() {
|
|
|
12977
13047
|
}
|
|
12978
13048
|
),
|
|
12979
13049
|
!A.standard && A.used_by_documents === 0 && /* @__PURE__ */ t(
|
|
12980
|
-
|
|
13050
|
+
W,
|
|
12981
13051
|
{
|
|
12982
13052
|
variant: "ghost",
|
|
12983
13053
|
size: "sm",
|
|
@@ -13055,7 +13125,7 @@ function ku({ template: e, revision: n, source: a, doctype: s }) {
|
|
|
13055
13125
|
}
|
|
13056
13126
|
}
|
|
13057
13127
|
) }),
|
|
13058
|
-
/* @__PURE__ */ r(
|
|
13128
|
+
/* @__PURE__ */ r(W, { variant: "secondary", onClick: () => h(i.trim()), disabled: u.loading, children: [
|
|
13059
13129
|
/* @__PURE__ */ t(xr, { className: u.loading ? "h-4 w-4 animate-spin" : "h-4 w-4" }),
|
|
13060
13130
|
o("pdfTemplates.refresh")
|
|
13061
13131
|
] })
|
|
@@ -13072,7 +13142,7 @@ function ku({ template: e, revision: n, source: a, doctype: s }) {
|
|
|
13072
13142
|
] });
|
|
13073
13143
|
}
|
|
13074
13144
|
function Nu() {
|
|
13075
|
-
const { t: e } = ee(), { id: n = "" } = vt(), [a] = St(), s = n === "standard" ? a.get("doctype") || "Quotation" : void 0, o =
|
|
13145
|
+
const { t: e } = ee(), { id: n = "" } = vt(), [a] = St(), s = n === "standard" ? a.get("doctype") || "Quotation" : void 0, o = Ke(), i = We(), l = Rt(), { user: c } = Ye(), { data: h, error: u } = no(n, s), g = un(s ?? (h == null ? void 0 : h.doctype)) ?? Wt[0], d = fn(c == null ? void 0 : c.role) && !!h && !h.standard && !h.archived, v = d && bu(c == null ? void 0 : c.role), { dirty: k, markDirty: x, markClean: p } = jt(), [w, b] = C(""), [y, m] = C(""), [f, D] = C(0), [N, A] = C("draft"), [T, _] = C(""), V = me(null), K = me(null);
|
|
13076
13146
|
ie(() => {
|
|
13077
13147
|
!h || k || (b(h.standard ? h.html ?? "" : h.draft_html ?? ""), m(h.title));
|
|
13078
13148
|
}, [h, k]);
|
|
@@ -13179,9 +13249,9 @@ function Nu() {
|
|
|
13179
13249
|
] }) }) }),
|
|
13180
13250
|
d && /* @__PURE__ */ r("div", { className: "sticky top-0 z-20 flex flex-wrap items-center justify-end gap-2 rounded-xl bg-surface px-4 py-2 ring-1 ring-line shadow-card", children: [
|
|
13181
13251
|
F.error ? /* @__PURE__ */ t("p", { role: "alert", className: "mr-auto min-w-0 text-sm text-rose-700", children: F.error.message }) : T ? /* @__PURE__ */ t("p", { className: "mr-auto min-w-0 text-sm text-emerald-700", children: T }) : k && /* @__PURE__ */ t("p", { className: "mr-auto text-sm text-fg-muted", children: e("menuLayout.unsaved") }),
|
|
13182
|
-
h.published && h.unpublished_changes && /* @__PURE__ */ t(
|
|
13252
|
+
h.published && h.unpublished_changes && /* @__PURE__ */ t(W, { variant: "ghost", size: "sm", onClick: z, disabled: F.isPending, children: e("pdfTemplates.revert") }),
|
|
13183
13253
|
/* @__PURE__ */ t(
|
|
13184
|
-
|
|
13254
|
+
Kt,
|
|
13185
13255
|
{
|
|
13186
13256
|
dirty: k,
|
|
13187
13257
|
saving: F.isPending,
|
|
@@ -13190,7 +13260,7 @@ function Nu() {
|
|
|
13190
13260
|
}
|
|
13191
13261
|
),
|
|
13192
13262
|
/* @__PURE__ */ t(
|
|
13193
|
-
|
|
13263
|
+
W,
|
|
13194
13264
|
{
|
|
13195
13265
|
variant: "secondary",
|
|
13196
13266
|
onClick: R,
|
|
@@ -13284,7 +13354,7 @@ function Nu() {
|
|
|
13284
13354
|
/* @__PURE__ */ t(
|
|
13285
13355
|
"input",
|
|
13286
13356
|
{
|
|
13287
|
-
ref:
|
|
13357
|
+
ref: K,
|
|
13288
13358
|
type: "file",
|
|
13289
13359
|
className: "hidden",
|
|
13290
13360
|
multiple: !0,
|
|
@@ -13301,7 +13371,7 @@ function Nu() {
|
|
|
13301
13371
|
disabled: S,
|
|
13302
13372
|
onClick: () => {
|
|
13303
13373
|
var H;
|
|
13304
|
-
return (H =
|
|
13374
|
+
return (H = K.current) == null ? void 0 : H.click();
|
|
13305
13375
|
},
|
|
13306
13376
|
className: "mt-3 flex w-full flex-col items-center justify-center rounded-xl border border-dashed border-line bg-surface-subtle px-4 py-5 text-center transition-colors hover:border-brand/50 hover:bg-brand/5 disabled:opacity-60",
|
|
13307
13377
|
children: [
|
|
@@ -13380,7 +13450,7 @@ const Cu = [
|
|
|
13380
13450
|
// Reports
|
|
13381
13451
|
{ path: "reports/chart-of-accounts", element: /* @__PURE__ */ t(Vo, {}) },
|
|
13382
13452
|
{ path: "reports/trial-balance", element: /* @__PURE__ */ t(Mo, {}) },
|
|
13383
|
-
{ path: "reports/general-ledger", element: /* @__PURE__ */ t(
|
|
13453
|
+
{ path: "reports/general-ledger", element: /* @__PURE__ */ t(Ko, {}) },
|
|
13384
13454
|
{ path: "reports/stock-balance", element: /* @__PURE__ */ t(jo, {}) },
|
|
13385
13455
|
{ path: "reports/stock-availability", element: /* @__PURE__ */ t(Qo, {}) },
|
|
13386
13456
|
{ path: "reports/sales-backlog", element: /* @__PURE__ */ t(Yo, {}) },
|
|
@@ -13424,7 +13494,7 @@ function Pu() {
|
|
|
13424
13494
|
];
|
|
13425
13495
|
}
|
|
13426
13496
|
function Au({ slug: e, parentSlug: n, linkField: a }) {
|
|
13427
|
-
const { name: s = "" } = vt(), o =
|
|
13497
|
+
const { name: s = "" } = vt(), o = Ke();
|
|
13428
13498
|
return ie(() => {
|
|
13429
13499
|
let i = !0;
|
|
13430
13500
|
return q.getDocument(e, s).then((l) => {
|
|
@@ -13478,12 +13548,12 @@ export {
|
|
|
13478
13548
|
yi as AuthProvider,
|
|
13479
13549
|
Xi as ConfirmButton,
|
|
13480
13550
|
Si as DialogProvider,
|
|
13481
|
-
|
|
13551
|
+
Kr as DocPager,
|
|
13482
13552
|
Un as MentionEditor,
|
|
13483
13553
|
Qr as RecordNotes,
|
|
13484
13554
|
Hr as RecordNotesLink,
|
|
13485
13555
|
ps as SUPPORTED_LANGUAGES,
|
|
13486
|
-
|
|
13556
|
+
Kt as SaveButton,
|
|
13487
13557
|
q as api,
|
|
13488
13558
|
Xu as bootstrap,
|
|
13489
13559
|
Pu as buildRoutes,
|
|
@@ -13506,11 +13576,11 @@ export {
|
|
|
13506
13576
|
Zu as registerComponent,
|
|
13507
13577
|
Hu as registerDoctype,
|
|
13508
13578
|
Yu as registerMaster,
|
|
13509
|
-
|
|
13579
|
+
Ku as registerNavGroup,
|
|
13510
13580
|
ju as registerNavItem,
|
|
13511
13581
|
Du as registerRoute,
|
|
13512
13582
|
U as request,
|
|
13513
|
-
|
|
13583
|
+
Wu as setDateLocale,
|
|
13514
13584
|
$r as setListContext,
|
|
13515
13585
|
Ye as useAuth,
|
|
13516
13586
|
Rt as useConfirm,
|