@lambda-development/erp-core 0.3.4 → 0.4.0
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 +6 -0
- package/dist/i18n/locales/en.json.d.ts +6 -0
- package/dist/i18n/locales/fr.json.d.ts +6 -0
- package/dist/index.js +798 -762
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { jsx as e, jsxs as r, Fragment as we } from "react/jsx-runtime";
|
|
2
|
-
import { useState as
|
|
3
|
-
import { createRoot as
|
|
4
|
-
import { useQueryClient as We, useQuery as oe, useMutation as ie, QueryClientProvider as Ca, QueryClient as
|
|
5
|
-
import { NavLink as Ot, useLocation as
|
|
6
|
-
import { useTranslation as
|
|
7
|
-
import { BookOpen as
|
|
8
|
-
import { createColumnHelper as
|
|
9
|
-
import { createPortal as
|
|
10
|
-
import { ResponsiveContainer as
|
|
11
|
-
import
|
|
12
|
-
import { default as
|
|
2
|
+
import { useState as S, useEffect as se, useCallback as Pe, useContext as Kn, createContext as jn, useRef as te, useMemo as Ce, useLayoutEffect as un, StrictMode as ka } from "react";
|
|
3
|
+
import { createRoot as Sa } from "react-dom/client";
|
|
4
|
+
import { useQueryClient as We, useQuery as oe, useMutation as ie, QueryClientProvider as Ca, QueryClient as Da } from "@tanstack/react-query";
|
|
5
|
+
import { NavLink as Ot, useLocation as Ct, useNavigate as ze, Outlet as Aa, Navigate as Pa, Link as be, useSearchParams as qt, useParams as bt, createBrowserRouter as _a, RouterProvider as Ta } from "react-router-dom";
|
|
6
|
+
import { useTranslation as Z, initReactI18next as Ra } from "react-i18next";
|
|
7
|
+
import { BookOpen as Ia, ShoppingCart as Gn, CreditCard as Ba, FileText as nn, Package as Wn, BarChart3 as Ea, Database as La, Settings as Oa, MessageCircle as qa, ChevronDown as zt, ChevronRight as Mt, Plus as Hn, Trash2 as Qn, LineChart as za, TrendingUp as Ma, ArrowDownRight as Fa, ArrowUpRight as $a, Wallet as Ua, Receipt as mn, Info as Va } from "lucide-react";
|
|
8
|
+
import { createColumnHelper as Yn, useReactTable as Jn, getCoreRowModel as Zn, flexRender as It } from "@tanstack/react-table";
|
|
9
|
+
import { createPortal as Xn } from "react-dom";
|
|
10
|
+
import { ResponsiveContainer as Ka, LineChart as ja, CartesianGrid as pn, XAxis as hn, YAxis as gn, Tooltip as Vt, Line as Ga, PieChart as Wa, Pie as Ha, Cell as Qa, BarChart as Ya, Bar as Ja } from "recharts";
|
|
11
|
+
import ea from "i18next";
|
|
12
|
+
import { default as Mo } from "i18next";
|
|
13
13
|
let ct = "/api";
|
|
14
|
-
function
|
|
14
|
+
function Po(t) {
|
|
15
15
|
ct = t.replace(/\/+$/, "");
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function Za(t) {
|
|
18
18
|
return new URL(`${ct}${t}`, window.location.origin).toString();
|
|
19
19
|
}
|
|
20
20
|
class $e extends Error {
|
|
@@ -22,7 +22,7 @@ class $e extends Error {
|
|
|
22
22
|
super(a), this.status = n;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
function
|
|
25
|
+
function Xa(t) {
|
|
26
26
|
if (!t) return "Request failed";
|
|
27
27
|
if (typeof t == "string") return t;
|
|
28
28
|
if (Array.isArray(t))
|
|
@@ -37,7 +37,7 @@ function Za(t) {
|
|
|
37
37
|
}
|
|
38
38
|
return String(t);
|
|
39
39
|
}
|
|
40
|
-
async function
|
|
40
|
+
async function L(t, n) {
|
|
41
41
|
const a = await fetch(`${ct}${t}`, {
|
|
42
42
|
headers: { "Content-Type": "application/json" },
|
|
43
43
|
credentials: "include",
|
|
@@ -47,7 +47,7 @@ async function E(t, n) {
|
|
|
47
47
|
if (a.status === 401 && !t.startsWith("/auth/"))
|
|
48
48
|
throw window.location.href = "/login", new $e(401, "Session expired");
|
|
49
49
|
const s = await a.json().catch(() => ({ detail: a.statusText }));
|
|
50
|
-
throw new $e(a.status,
|
|
50
|
+
throw new $e(a.status, Xa(s.detail));
|
|
51
51
|
}
|
|
52
52
|
return a.json();
|
|
53
53
|
}
|
|
@@ -60,7 +60,7 @@ function Be(t) {
|
|
|
60
60
|
}
|
|
61
61
|
const I = {
|
|
62
62
|
// Generic request (used by sidebar for chat sessions)
|
|
63
|
-
request:
|
|
63
|
+
request: L,
|
|
64
64
|
// Chat attachments
|
|
65
65
|
uploadChatAttachment: async (t, n) => {
|
|
66
66
|
const a = new FormData();
|
|
@@ -80,33 +80,33 @@ const I = {
|
|
|
80
80
|
},
|
|
81
81
|
getChatAttachmentUrl: (t) => `${ct}/chat/attachments/${encodeURIComponent(t)}`,
|
|
82
82
|
// Chat
|
|
83
|
-
createChatSession: () =>
|
|
83
|
+
createChatSession: () => L(
|
|
84
84
|
"/chat/sessions",
|
|
85
85
|
{ method: "POST" }
|
|
86
86
|
),
|
|
87
|
-
getChatSession: (t) =>
|
|
87
|
+
getChatSession: (t) => L(
|
|
88
88
|
`/chat/sessions/${encodeURIComponent(t)}`
|
|
89
89
|
),
|
|
90
90
|
// Documents
|
|
91
|
-
listDocuments: (t, n) =>
|
|
91
|
+
listDocuments: (t, n) => L(
|
|
92
92
|
`/documents/${t}${Be(n)}`
|
|
93
93
|
),
|
|
94
|
-
getDocument: (t, n) =>
|
|
95
|
-
createDocument: (t, n) =>
|
|
96
|
-
updateDocument: (t, n, a) =>
|
|
94
|
+
getDocument: (t, n) => L(`/documents/${t}/${encodeURIComponent(n)}`),
|
|
95
|
+
createDocument: (t, n) => L(`/documents/${t}`, { method: "POST", body: JSON.stringify(n) }),
|
|
96
|
+
updateDocument: (t, n, a) => L(`/documents/${t}/${encodeURIComponent(n)}`, {
|
|
97
97
|
method: "PUT",
|
|
98
98
|
body: JSON.stringify(a)
|
|
99
99
|
}),
|
|
100
|
-
submitDocument: (t, n) =>
|
|
101
|
-
cancelDocument: (t, n) =>
|
|
102
|
-
discardDocument: (t, n) =>
|
|
103
|
-
convertDocument: (t, n, a) =>
|
|
100
|
+
submitDocument: (t, n) => L(`/documents/${t}/${encodeURIComponent(n)}/submit`, { method: "POST" }),
|
|
101
|
+
cancelDocument: (t, n) => L(`/documents/${t}/${encodeURIComponent(n)}/cancel`, { method: "POST" }),
|
|
102
|
+
discardDocument: (t, n) => L(`/documents/${t}/${encodeURIComponent(n)}/discard`, { method: "POST" }),
|
|
103
|
+
convertDocument: (t, n, a) => L(`/documents/${t}/${encodeURIComponent(n)}/convert`, {
|
|
104
104
|
method: "POST",
|
|
105
105
|
body: JSON.stringify({ target_doctype: a })
|
|
106
106
|
}),
|
|
107
107
|
// Proposal (Sammelofferte) extras — CRUD goes through the document methods
|
|
108
108
|
// above (doctype "proposal"); these cover the appendix blob + cover default.
|
|
109
|
-
getProposalCoverDefault: (t, n) =>
|
|
109
|
+
getProposalCoverDefault: (t, n) => L(
|
|
110
110
|
`/proposals/cover-default${Be({ company: t, customer: n })}`
|
|
111
111
|
),
|
|
112
112
|
uploadProposalAppendix: async (t, n) => {
|
|
@@ -125,115 +125,115 @@ const I = {
|
|
|
125
125
|
}
|
|
126
126
|
return s.json();
|
|
127
127
|
},
|
|
128
|
-
deleteProposalAppendix: (t) =>
|
|
128
|
+
deleteProposalAppendix: (t) => L(`/proposals/${encodeURIComponent(t)}/appendix`, { method: "DELETE" }),
|
|
129
129
|
proposalPdfUrl: (t) => `${ct}/documents/proposal/${encodeURIComponent(t)}/pdf`,
|
|
130
130
|
// Masters
|
|
131
|
-
listMasters: (t, n) =>
|
|
131
|
+
listMasters: (t, n) => L(
|
|
132
132
|
`/masters/${t}${Be(n)}`
|
|
133
133
|
),
|
|
134
|
-
searchMasters: (t, n) =>
|
|
135
|
-
searchDocuments: (t, n) =>
|
|
134
|
+
searchMasters: (t, n) => L(`/masters/${t}/search?q=${encodeURIComponent(n)}`),
|
|
135
|
+
searchDocuments: (t, n) => L(`/documents/${t}/search?q=${encodeURIComponent(n)}`),
|
|
136
136
|
searchLink: async (t, n) => {
|
|
137
137
|
try {
|
|
138
|
-
const a = await
|
|
138
|
+
const a = await L(`/masters/${t}/search?q=${encodeURIComponent(n)}`);
|
|
139
139
|
if (a.length > 0) return a;
|
|
140
140
|
} catch {
|
|
141
141
|
}
|
|
142
|
-
return
|
|
142
|
+
return L(`/documents/${t}/search?q=${encodeURIComponent(n)}`);
|
|
143
143
|
},
|
|
144
|
-
getMaster: (t, n) =>
|
|
145
|
-
currencies: (t) =>
|
|
144
|
+
getMaster: (t, n) => L(`/masters/${t}/${encodeURIComponent(n)}`),
|
|
145
|
+
currencies: (t) => L(
|
|
146
146
|
`/accounting/currencies${Be({ company: t })}`
|
|
147
147
|
),
|
|
148
|
-
createMaster: (t, n) =>
|
|
149
|
-
updateMaster: (t, n, a) =>
|
|
148
|
+
createMaster: (t, n) => L(`/masters/${t}`, { method: "POST", body: JSON.stringify(n) }),
|
|
149
|
+
updateMaster: (t, n, a) => L(`/masters/${t}/${encodeURIComponent(n)}`, {
|
|
150
150
|
method: "PUT",
|
|
151
151
|
body: JSON.stringify(a)
|
|
152
152
|
}),
|
|
153
|
-
deleteMaster: (t, n) =>
|
|
153
|
+
deleteMaster: (t, n) => L(`/masters/${t}/${encodeURIComponent(n)}`, { method: "DELETE" }),
|
|
154
154
|
// Reports
|
|
155
|
-
trialBalance: (t) =>
|
|
155
|
+
trialBalance: (t) => L(
|
|
156
156
|
`/reports/trial-balance${Be(t)}`
|
|
157
157
|
),
|
|
158
|
-
chartOfAccounts: (t) =>
|
|
158
|
+
chartOfAccounts: (t) => L(
|
|
159
159
|
`/reports/chart-of-accounts${Be(t)}`
|
|
160
160
|
),
|
|
161
|
-
generalLedger: (t) =>
|
|
162
|
-
stockBalance: (t) =>
|
|
163
|
-
dashboardSummary: (t) =>
|
|
164
|
-
profitAndLoss: (t) =>
|
|
165
|
-
balanceSheet: (t) =>
|
|
166
|
-
arAging: (t) =>
|
|
167
|
-
apAging: (t) =>
|
|
168
|
-
analyticsMetrics: () =>
|
|
169
|
-
analytics: (t) =>
|
|
170
|
-
runtimeDatasets: () =>
|
|
171
|
-
runtimeData: (t) =>
|
|
172
|
-
createRuntimeDraft: (t) =>
|
|
173
|
-
getRuntimeDraft: (t) =>
|
|
174
|
-
listRuntimeDrafts: () =>
|
|
175
|
-
deleteRuntimeDraft: (t) =>
|
|
161
|
+
generalLedger: (t) => L(`/reports/general-ledger${Be(t)}`),
|
|
162
|
+
stockBalance: (t) => L(`/reports/stock-balance${Be(t)}`),
|
|
163
|
+
dashboardSummary: (t) => L(`/reports/dashboard-summary${Be({ company: t })}`),
|
|
164
|
+
profitAndLoss: (t) => L(`/reports/profit-and-loss${Be(t)}`),
|
|
165
|
+
balanceSheet: (t) => L(`/reports/balance-sheet${Be(t)}`),
|
|
166
|
+
arAging: (t) => L(`/reports/ar-aging${Be(t)}`),
|
|
167
|
+
apAging: (t) => L(`/reports/ap-aging${Be(t)}`),
|
|
168
|
+
analyticsMetrics: () => L("/reports/analytics/metrics"),
|
|
169
|
+
analytics: (t) => L(`/reports/analytics${Be(t)}`),
|
|
170
|
+
runtimeDatasets: () => L("/reports/runtime/datasets"),
|
|
171
|
+
runtimeData: (t) => L("/reports/runtime/data", { method: "POST", body: JSON.stringify(t) }),
|
|
172
|
+
createRuntimeDraft: (t) => L("/reports/runtime/drafts", { method: "POST", body: JSON.stringify(t) }),
|
|
173
|
+
getRuntimeDraft: (t) => L(`/reports/runtime/drafts/${encodeURIComponent(t)}`),
|
|
174
|
+
listRuntimeDrafts: () => L("/reports/runtime/drafts"),
|
|
175
|
+
deleteRuntimeDraft: (t) => L(`/reports/runtime/drafts/${encodeURIComponent(t)}`, {
|
|
176
176
|
method: "DELETE"
|
|
177
177
|
}),
|
|
178
178
|
// Setup
|
|
179
|
-
setupStatus: () =>
|
|
180
|
-
createCompany: (t) =>
|
|
181
|
-
seedDemo: () =>
|
|
182
|
-
seedHistory: (t) =>
|
|
179
|
+
setupStatus: () => L("/setup/status"),
|
|
180
|
+
createCompany: (t) => L("/setup/company", { method: "POST", body: JSON.stringify(t) }),
|
|
181
|
+
seedDemo: () => L("/setup/seed-demo", { method: "POST" }),
|
|
182
|
+
seedHistory: (t) => L(
|
|
183
183
|
"/setup/seed-history",
|
|
184
184
|
{ method: "POST", body: JSON.stringify(t ?? {}) }
|
|
185
185
|
),
|
|
186
|
-
importAccountBalances: (t) =>
|
|
187
|
-
importStockBalances: (t) =>
|
|
188
|
-
importOutstandingInvoices: (t) =>
|
|
186
|
+
importAccountBalances: (t) => L("/setup/opening-balances/accounts", { method: "POST", body: JSON.stringify(t) }),
|
|
187
|
+
importStockBalances: (t) => L("/setup/opening-balances/stock", { method: "POST", body: JSON.stringify(t) }),
|
|
188
|
+
importOutstandingInvoices: (t) => L("/setup/opening-balances/invoices", { method: "POST", body: JSON.stringify(t) }),
|
|
189
189
|
// Auth
|
|
190
|
-
authSetupStatus: () =>
|
|
190
|
+
authSetupStatus: () => L("/auth/setup-status"),
|
|
191
191
|
// Social login is a full-page navigation, not a fetch — build the URL the
|
|
192
192
|
// browser should be sent to. `link` starts a "link to my account" flow.
|
|
193
193
|
oauthLoginUrl: (t, n) => {
|
|
194
194
|
const a = new URLSearchParams();
|
|
195
195
|
n != null && n.link && a.set("link", "1"), n != null && n.invite && a.set("invite", n.invite);
|
|
196
196
|
const s = a.toString() ? `?${a.toString()}` : "";
|
|
197
|
-
return
|
|
197
|
+
return Za(`/auth/${encodeURIComponent(t)}/login${s}`);
|
|
198
198
|
},
|
|
199
|
-
oauthListIdentities: () =>
|
|
200
|
-
authRegister: (t) =>
|
|
201
|
-
authLogin: (t, n) =>
|
|
202
|
-
authLogout: () =>
|
|
203
|
-
authMe: () =>
|
|
204
|
-
authChangePassword: (t, n) =>
|
|
199
|
+
oauthListIdentities: () => L("/auth/oauth/identities"),
|
|
200
|
+
authRegister: (t) => L("/auth/register", { method: "POST", body: JSON.stringify(t) }),
|
|
201
|
+
authLogin: (t, n) => L("/auth/login", { method: "POST", body: JSON.stringify({ email: t, password: n }) }),
|
|
202
|
+
authLogout: () => L("/auth/logout", { method: "POST" }),
|
|
203
|
+
authMe: () => L("/auth/me"),
|
|
204
|
+
authChangePassword: (t, n) => L("/auth/change-password", {
|
|
205
205
|
method: "POST",
|
|
206
206
|
body: JSON.stringify({ current_password: t, new_password: n })
|
|
207
207
|
}),
|
|
208
|
-
authSetPassword: (t) =>
|
|
208
|
+
authSetPassword: (t) => L("/auth/set-password", {
|
|
209
209
|
method: "POST",
|
|
210
210
|
body: JSON.stringify({ new_password: t })
|
|
211
211
|
}),
|
|
212
|
-
authInvite: (t, n) =>
|
|
213
|
-
authListUsers: () =>
|
|
214
|
-
authChangeRole: (t, n) =>
|
|
215
|
-
authDisableUser: (t) =>
|
|
216
|
-
authListInvites: () =>
|
|
217
|
-
authRevokeInvite: (t) =>
|
|
218
|
-
getPublicManagerStatus: () =>
|
|
219
|
-
createPublicManager: () =>
|
|
220
|
-
removePublicManager: () =>
|
|
221
|
-
getSettings: () =>
|
|
222
|
-
updateSettings: (t) =>
|
|
223
|
-
getApiKeys: () =>
|
|
224
|
-
createApiKey: (t, n) =>
|
|
225
|
-
revokeApiKey: (t) =>
|
|
212
|
+
authInvite: (t, n) => L("/auth/invite", { method: "POST", body: JSON.stringify({ email: t, role: n }) }),
|
|
213
|
+
authListUsers: () => L("/auth/users"),
|
|
214
|
+
authChangeRole: (t, n) => L(`/auth/users/${encodeURIComponent(t)}/role`, { method: "PUT", body: JSON.stringify({ role: n }) }),
|
|
215
|
+
authDisableUser: (t) => L(`/auth/users/${encodeURIComponent(t)}`, { method: "DELETE" }),
|
|
216
|
+
authListInvites: () => L("/auth/invites"),
|
|
217
|
+
authRevokeInvite: (t) => L(`/auth/invites/${encodeURIComponent(t)}`, { method: "DELETE" }),
|
|
218
|
+
getPublicManagerStatus: () => L("/auth/public-manager"),
|
|
219
|
+
createPublicManager: () => L("/auth/public-manager", { method: "POST" }),
|
|
220
|
+
removePublicManager: () => L("/auth/public-manager", { method: "DELETE" }),
|
|
221
|
+
getSettings: () => L("/auth/settings"),
|
|
222
|
+
updateSettings: (t) => L("/auth/settings", { method: "PUT", body: JSON.stringify(t) }),
|
|
223
|
+
getApiKeys: () => L("/auth/api-keys"),
|
|
224
|
+
createApiKey: (t, n) => L("/auth/api-keys", { method: "POST", body: JSON.stringify({ name: t, role: n }) }),
|
|
225
|
+
revokeApiKey: (t) => L(
|
|
226
226
|
`/auth/api-keys/${encodeURIComponent(t)}/revoke`,
|
|
227
227
|
{ method: "POST" }
|
|
228
228
|
),
|
|
229
|
-
deleteApiKey: (t) =>
|
|
229
|
+
deleteApiKey: (t) => L(
|
|
230
230
|
`/auth/api-keys/${encodeURIComponent(t)}`,
|
|
231
231
|
{ method: "DELETE" }
|
|
232
232
|
),
|
|
233
|
-
getDemoSpend: () =>
|
|
234
|
-
},
|
|
235
|
-
function
|
|
236
|
-
const [n, a] =
|
|
233
|
+
getDemoSpend: () => L("/admin/demo-spend")
|
|
234
|
+
}, ta = jn(null);
|
|
235
|
+
function er({ children: t }) {
|
|
236
|
+
const [n, a] = S(null), [s, i] = S(!0);
|
|
237
237
|
se(() => {
|
|
238
238
|
I.authMe().then((m) => a(m)).catch(() => a(null)).finally(() => i(!1));
|
|
239
239
|
}, []);
|
|
@@ -256,14 +256,14 @@ function Xa({ children: t }) {
|
|
|
256
256
|
} catch {
|
|
257
257
|
}
|
|
258
258
|
}, []);
|
|
259
|
-
return /* @__PURE__ */ e(
|
|
259
|
+
return /* @__PURE__ */ e(ta.Provider, { value: { user: n, loading: s, login: o, register: l, logout: c, refreshUser: g }, children: t });
|
|
260
260
|
}
|
|
261
261
|
function st() {
|
|
262
|
-
const t =
|
|
262
|
+
const t = Kn(ta);
|
|
263
263
|
if (!t) throw new Error("useAuth must be used within AuthProvider");
|
|
264
264
|
return t;
|
|
265
265
|
}
|
|
266
|
-
const
|
|
266
|
+
const na = jn(null), fn = {
|
|
267
267
|
quotation: { group: "Selling", item: "Quotation" },
|
|
268
268
|
"sales-order": { group: "Selling", item: "Sales Order" },
|
|
269
269
|
"sales-invoice": { group: "Selling", item: "Sales Invoice" },
|
|
@@ -289,7 +289,7 @@ const ta = Kn(null), fn = {
|
|
|
289
289
|
function Kt(t) {
|
|
290
290
|
return typeof t != "string" ? null : t.trim().toLowerCase().replace(/\s+/g, "-");
|
|
291
291
|
}
|
|
292
|
-
function
|
|
292
|
+
function tr(t, n) {
|
|
293
293
|
if (t === "create_custom_analytics_report" || t === "update_custom_analytics_report")
|
|
294
294
|
return { group: "Custom Analytics", item: "" };
|
|
295
295
|
if (!n) return null;
|
|
@@ -312,11 +312,11 @@ function bn(t) {
|
|
|
312
312
|
attachments: t.attachments
|
|
313
313
|
};
|
|
314
314
|
}
|
|
315
|
-
const
|
|
315
|
+
const aa = "lambda-erp:known-chat-sessions";
|
|
316
316
|
function an() {
|
|
317
317
|
if (typeof localStorage > "u") return /* @__PURE__ */ new Set();
|
|
318
318
|
try {
|
|
319
|
-
const t = localStorage.getItem(
|
|
319
|
+
const t = localStorage.getItem(aa);
|
|
320
320
|
if (!t) return /* @__PURE__ */ new Set();
|
|
321
321
|
const n = JSON.parse(t);
|
|
322
322
|
return new Set(Array.isArray(n) ? n.filter((a) => typeof a == "string") : []);
|
|
@@ -324,22 +324,22 @@ function an() {
|
|
|
324
324
|
return /* @__PURE__ */ new Set();
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
|
-
function
|
|
327
|
+
function ra(t) {
|
|
328
328
|
if (!(typeof localStorage > "u"))
|
|
329
329
|
try {
|
|
330
|
-
localStorage.setItem(
|
|
330
|
+
localStorage.setItem(aa, JSON.stringify([...t]));
|
|
331
331
|
} catch {
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
-
function
|
|
334
|
+
function sa(t) {
|
|
335
335
|
const n = an();
|
|
336
|
-
n.has(t) || (n.add(t),
|
|
336
|
+
n.has(t) || (n.add(t), ra(n));
|
|
337
337
|
}
|
|
338
338
|
function vn(t) {
|
|
339
339
|
const n = an();
|
|
340
|
-
n.delete(t) &&
|
|
340
|
+
n.delete(t) && ra(n);
|
|
341
341
|
}
|
|
342
|
-
function
|
|
342
|
+
function nr() {
|
|
343
343
|
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `req-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
344
344
|
}
|
|
345
345
|
function tt(t) {
|
|
@@ -347,8 +347,8 @@ function tt(t) {
|
|
|
347
347
|
const n = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(t) ? t.replace(" ", "T") : t, a = new Date(n).getTime();
|
|
348
348
|
return Number.isNaN(a) ? 0 : a;
|
|
349
349
|
}
|
|
350
|
-
function
|
|
351
|
-
const n = We(), [a, s] =
|
|
350
|
+
function ar({ children: t }) {
|
|
351
|
+
const n = We(), [a, s] = S([]), [i, o] = S({}), [l, c] = S({}), [g, m] = S({}), [h, u] = S({}), [N, x] = S({}), [v, f] = S({}), [T, P] = S({}), [b, d] = S(null), [p, _] = S("connecting"), [y, B] = S(0), D = te(null), O = te(null), G = te(/* @__PURE__ */ new Map()), ee = te(null), C = te({}), w = te({}), q = te(null);
|
|
352
352
|
function A(R) {
|
|
353
353
|
for (const V of G.current.values())
|
|
354
354
|
V.reject(new Error(R));
|
|
@@ -376,27 +376,27 @@ function nr({ children: t }) {
|
|
|
376
376
|
}
|
|
377
377
|
function _e(R) {
|
|
378
378
|
return [...R].sort((V, W) => {
|
|
379
|
-
const ve = tt(
|
|
380
|
-
return (tt(
|
|
379
|
+
const ve = tt(C.current[V.id]) || tt(V.last_message_at || void 0) || tt(V.created_at);
|
|
380
|
+
return (tt(C.current[W.id]) || tt(W.last_message_at || void 0) || tt(W.created_at)) - ve;
|
|
381
381
|
});
|
|
382
382
|
}
|
|
383
383
|
function pe(R) {
|
|
384
384
|
s((V) => _e(R(V)));
|
|
385
385
|
}
|
|
386
386
|
function fe(R, V) {
|
|
387
|
-
const W = V || (/* @__PURE__ */ new Date()).toISOString(), ve =
|
|
388
|
-
tt(W) >= tt(ve) && (
|
|
389
|
-
...
|
|
387
|
+
const W = V || (/* @__PURE__ */ new Date()).toISOString(), ve = C.current[R];
|
|
388
|
+
tt(W) >= tt(ve) && (C.current = {
|
|
389
|
+
...C.current,
|
|
390
390
|
[R]: W
|
|
391
391
|
});
|
|
392
392
|
}
|
|
393
393
|
function Ue(R) {
|
|
394
|
-
const V = { ...
|
|
394
|
+
const V = { ...C.current };
|
|
395
395
|
for (const W of R)
|
|
396
396
|
W.last_message_at && !V[W.id] && (V[W.id] = W.last_message_at);
|
|
397
|
-
|
|
397
|
+
C.current = V;
|
|
398
398
|
}
|
|
399
|
-
function
|
|
399
|
+
function E(R) {
|
|
400
400
|
const V = D.current;
|
|
401
401
|
if (!V || V.readyState !== WebSocket.OPEN)
|
|
402
402
|
throw new Error("Chat is disconnected.");
|
|
@@ -404,14 +404,14 @@ function nr({ children: t }) {
|
|
|
404
404
|
}
|
|
405
405
|
function ne(R, V, W) {
|
|
406
406
|
return new Promise((ve, xe) => {
|
|
407
|
-
const Ae =
|
|
407
|
+
const Ae = nr();
|
|
408
408
|
G.current.set(Ae, {
|
|
409
409
|
expectedType: W,
|
|
410
410
|
resolve: ve,
|
|
411
411
|
reject: xe
|
|
412
412
|
});
|
|
413
413
|
try {
|
|
414
|
-
|
|
414
|
+
E({ type: R, request_id: Ae, ...V });
|
|
415
415
|
} catch (ot) {
|
|
416
416
|
G.current.delete(Ae), xe(ot instanceof Error ? ot : new Error("Chat request failed."));
|
|
417
417
|
}
|
|
@@ -466,7 +466,7 @@ function nr({ children: t }) {
|
|
|
466
466
|
if (me === "session_created") {
|
|
467
467
|
const F = K.session;
|
|
468
468
|
if (!F) return;
|
|
469
|
-
|
|
469
|
+
sa(F.id), Ue([F]), pe((j) => [F, ...j.filter((Q) => Q.id !== F.id)]);
|
|
470
470
|
return;
|
|
471
471
|
}
|
|
472
472
|
if (me === "session_deleted" && M) {
|
|
@@ -492,8 +492,8 @@ function nr({ children: t }) {
|
|
|
492
492
|
const Q = { ...j };
|
|
493
493
|
return delete Q[M], Q;
|
|
494
494
|
});
|
|
495
|
-
const F = { ...
|
|
496
|
-
delete F[M],
|
|
495
|
+
const F = { ...C.current };
|
|
496
|
+
delete F[M], C.current = F;
|
|
497
497
|
return;
|
|
498
498
|
}
|
|
499
499
|
if (me === "history_loaded" && M) {
|
|
@@ -617,7 +617,7 @@ function nr({ children: t }) {
|
|
|
617
617
|
const Q = typeof K.report_id == "string" ? K.report_id : void 0, qe = typeof ((ot = F.args) == null ? void 0 : ot.report_id) == "string" ? F.args.report_id : void 0;
|
|
618
618
|
ge("Custom Analytics", Q || qe || ""), n.invalidateQueries({ queryKey: ["runtime-drafts"] });
|
|
619
619
|
} else {
|
|
620
|
-
const Q =
|
|
620
|
+
const Q = tr(F.tool, F.args);
|
|
621
621
|
Q && ge(Q.group, Q.item);
|
|
622
622
|
}
|
|
623
623
|
w.current = {
|
|
@@ -685,7 +685,7 @@ function nr({ children: t }) {
|
|
|
685
685
|
}
|
|
686
686
|
function Ve(R, V) {
|
|
687
687
|
try {
|
|
688
|
-
|
|
688
|
+
E({ type: "demo_typing_done", session_id: R, seq: V });
|
|
689
689
|
} catch {
|
|
690
690
|
}
|
|
691
691
|
}
|
|
@@ -724,7 +724,7 @@ function nr({ children: t }) {
|
|
|
724
724
|
session_id: R,
|
|
725
725
|
content: ve
|
|
726
726
|
};
|
|
727
|
-
return xe && (Ae.attachment_ids = W),
|
|
727
|
+
return xe && (Ae.attachment_ids = W), E(Ae), !0;
|
|
728
728
|
} catch {
|
|
729
729
|
return Y(R, !1), !1;
|
|
730
730
|
}
|
|
@@ -758,7 +758,7 @@ function nr({ children: t }) {
|
|
|
758
758
|
return R ? T[R] ?? null : null;
|
|
759
759
|
}
|
|
760
760
|
return /* @__PURE__ */ e(
|
|
761
|
-
|
|
761
|
+
na.Provider,
|
|
762
762
|
{
|
|
763
763
|
value: {
|
|
764
764
|
sessions: a,
|
|
@@ -786,7 +786,7 @@ function nr({ children: t }) {
|
|
|
786
786
|
);
|
|
787
787
|
}
|
|
788
788
|
function ut() {
|
|
789
|
-
const t =
|
|
789
|
+
const t = Kn(na);
|
|
790
790
|
if (!t)
|
|
791
791
|
throw new Error("useChat must be used within ChatProvider.");
|
|
792
792
|
return t;
|
|
@@ -794,7 +794,7 @@ function ut() {
|
|
|
794
794
|
const dt = [
|
|
795
795
|
{
|
|
796
796
|
label: "Introduction",
|
|
797
|
-
icon: /* @__PURE__ */ e(
|
|
797
|
+
icon: /* @__PURE__ */ e(Ia, { className: "h-4 w-4" }),
|
|
798
798
|
items: [
|
|
799
799
|
{ label: "Getting Started", path: "/tutorial" },
|
|
800
800
|
{ label: "Company Setup", path: "/setup" },
|
|
@@ -803,7 +803,7 @@ const dt = [
|
|
|
803
803
|
},
|
|
804
804
|
{
|
|
805
805
|
label: "Selling",
|
|
806
|
-
icon: /* @__PURE__ */ e(
|
|
806
|
+
icon: /* @__PURE__ */ e(Gn, { className: "h-4 w-4" }),
|
|
807
807
|
items: [
|
|
808
808
|
{ label: "Quotation", path: "/app/quotation" },
|
|
809
809
|
{ label: "Proposal", path: "/app/proposal" },
|
|
@@ -814,7 +814,7 @@ const dt = [
|
|
|
814
814
|
},
|
|
815
815
|
{
|
|
816
816
|
label: "Buying",
|
|
817
|
-
icon: /* @__PURE__ */ e(
|
|
817
|
+
icon: /* @__PURE__ */ e(Ba, { className: "h-4 w-4" }),
|
|
818
818
|
items: [
|
|
819
819
|
{ label: "Purchase Order", path: "/app/purchase-order" },
|
|
820
820
|
{ label: "Purchase Invoice", path: "/app/purchase-invoice" }
|
|
@@ -834,7 +834,7 @@ const dt = [
|
|
|
834
834
|
},
|
|
835
835
|
{
|
|
836
836
|
label: "Stock",
|
|
837
|
-
icon: /* @__PURE__ */ e(
|
|
837
|
+
icon: /* @__PURE__ */ e(Wn, { className: "h-4 w-4" }),
|
|
838
838
|
items: [
|
|
839
839
|
{ label: "Stock Entry", path: "/app/stock-entry" },
|
|
840
840
|
{ label: "Delivery Note", path: "/app/delivery-note" },
|
|
@@ -843,7 +843,7 @@ const dt = [
|
|
|
843
843
|
},
|
|
844
844
|
{
|
|
845
845
|
label: "Reports",
|
|
846
|
-
icon: /* @__PURE__ */ e(
|
|
846
|
+
icon: /* @__PURE__ */ e(Ea, { className: "h-4 w-4" }),
|
|
847
847
|
items: [
|
|
848
848
|
{ label: "Trial Balance", path: "/reports/trial-balance" },
|
|
849
849
|
{ label: "Profit & Loss", path: "/reports/profit-and-loss" },
|
|
@@ -868,7 +868,7 @@ const dt = [
|
|
|
868
868
|
},
|
|
869
869
|
{
|
|
870
870
|
label: "Settings",
|
|
871
|
-
icon: /* @__PURE__ */ e(
|
|
871
|
+
icon: /* @__PURE__ */ e(Oa, { className: "h-4 w-4" }),
|
|
872
872
|
items: [
|
|
873
873
|
{ label: "General", path: "/admin/settings" },
|
|
874
874
|
{ label: "Pricing Rule", path: "/app/pricing-rule" },
|
|
@@ -876,10 +876,10 @@ const dt = [
|
|
|
876
876
|
]
|
|
877
877
|
}
|
|
878
878
|
];
|
|
879
|
-
function
|
|
879
|
+
function rr() {
|
|
880
880
|
return dt;
|
|
881
881
|
}
|
|
882
|
-
function
|
|
882
|
+
function _o(t, n) {
|
|
883
883
|
const a = dt.findIndex((s) => s.label === t.label);
|
|
884
884
|
if (a >= 0) {
|
|
885
885
|
dt[a] = t;
|
|
@@ -887,25 +887,25 @@ function Po(t, n) {
|
|
|
887
887
|
}
|
|
888
888
|
(n == null ? void 0 : n.index) != null ? dt.splice(n.index, 0, t) : dt.push(t);
|
|
889
889
|
}
|
|
890
|
-
function
|
|
890
|
+
function To(t, n) {
|
|
891
891
|
const a = dt.find((s) => s.label === t);
|
|
892
892
|
a ? a.items.push(n) : dt.push({ label: t, icon: null, items: [n] });
|
|
893
893
|
}
|
|
894
894
|
let Jt = { appName: "Lambda ERP" };
|
|
895
|
-
function
|
|
895
|
+
function Ro(t) {
|
|
896
896
|
if (Jt = { ...Jt, ...t }, !(typeof document > "u") && (t.appName && (document.title = t.appName), t.tokens)) {
|
|
897
897
|
const n = document.documentElement;
|
|
898
898
|
for (const [a, s] of Object.entries(t.tokens))
|
|
899
899
|
n.style.setProperty(a.startsWith("--") ? a : `--${a}`, s);
|
|
900
900
|
}
|
|
901
901
|
}
|
|
902
|
-
function
|
|
902
|
+
function sr() {
|
|
903
903
|
return Jt;
|
|
904
904
|
}
|
|
905
|
-
function
|
|
905
|
+
function Ee(...t) {
|
|
906
906
|
return t.filter(Boolean).join(" ");
|
|
907
907
|
}
|
|
908
|
-
function
|
|
908
|
+
function Le(t, n = "USD") {
|
|
909
909
|
return new Intl.NumberFormat("en-US", {
|
|
910
910
|
style: "currency",
|
|
911
911
|
currency: n,
|
|
@@ -929,20 +929,20 @@ function Fe(t, n) {
|
|
|
929
929
|
const a = parseFloat(String(t ?? 0)) || 0;
|
|
930
930
|
return n !== void 0 ? parseFloat(a.toFixed(n)) : a;
|
|
931
931
|
}
|
|
932
|
-
const
|
|
932
|
+
const ia = "sidebar-collapsed";
|
|
933
933
|
function jt() {
|
|
934
934
|
try {
|
|
935
|
-
const t = localStorage.getItem(
|
|
935
|
+
const t = localStorage.getItem(ia);
|
|
936
936
|
return t ? new Set(JSON.parse(t)) : /* @__PURE__ */ new Set();
|
|
937
937
|
} catch {
|
|
938
938
|
return /* @__PURE__ */ new Set();
|
|
939
939
|
}
|
|
940
940
|
}
|
|
941
941
|
function xn(t) {
|
|
942
|
-
localStorage.setItem(
|
|
942
|
+
localStorage.setItem(ia, JSON.stringify([...t]));
|
|
943
943
|
}
|
|
944
944
|
function rn(t) {
|
|
945
|
-
const [n, a] =
|
|
945
|
+
const [n, a] = S(() => !jt().has(t)), s = Pe(() => {
|
|
946
946
|
a((o) => {
|
|
947
947
|
const l = jt();
|
|
948
948
|
return o ? l.add(t) : l.delete(t), xn(l), !o;
|
|
@@ -967,8 +967,8 @@ const sn = {
|
|
|
967
967
|
Settings: "bg-purple-300 text-purple-950 ring-2 ring-inset ring-purple-100",
|
|
968
968
|
"Custom Analytics": "bg-indigo-300 text-indigo-950 ring-2 ring-inset ring-indigo-100"
|
|
969
969
|
};
|
|
970
|
-
function
|
|
971
|
-
const [t, n] = rn("chats"), a =
|
|
970
|
+
function ir() {
|
|
971
|
+
const [t, n] = rn("chats"), a = Ct(), s = ze(), { t: i } = Z(), { sessions: o, createSession: l, deleteSession: c } = ut(), g = async () => {
|
|
972
972
|
try {
|
|
973
973
|
const h = await l();
|
|
974
974
|
s(`/chat/${h.id}`);
|
|
@@ -989,7 +989,7 @@ function sr() {
|
|
|
989
989
|
onClick: n,
|
|
990
990
|
className: "flex w-full items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-fg-muted transition-colors hover:text-fg",
|
|
991
991
|
children: [
|
|
992
|
-
/* @__PURE__ */ e(
|
|
992
|
+
/* @__PURE__ */ e(qa, { className: "h-4 w-4" }),
|
|
993
993
|
/* @__PURE__ */ e("span", { className: "flex-1 text-left", children: i("nav.chats") }),
|
|
994
994
|
t ? /* @__PURE__ */ e(zt, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Mt, { className: "h-3.5 w-3.5" })
|
|
995
995
|
]
|
|
@@ -1002,7 +1002,7 @@ function sr() {
|
|
|
1002
1002
|
onClick: g,
|
|
1003
1003
|
className: "flex w-full items-center gap-2 px-4 py-1.5 pl-10 text-sm text-brand transition-colors hover:bg-brand/5",
|
|
1004
1004
|
children: [
|
|
1005
|
-
/* @__PURE__ */ e(
|
|
1005
|
+
/* @__PURE__ */ e(Hn, { className: "h-3.5 w-3.5" }),
|
|
1006
1006
|
i("nav.newChat")
|
|
1007
1007
|
]
|
|
1008
1008
|
}
|
|
@@ -1014,7 +1014,7 @@ function sr() {
|
|
|
1014
1014
|
Ot,
|
|
1015
1015
|
{
|
|
1016
1016
|
to: `/chat/${h.id}`,
|
|
1017
|
-
className:
|
|
1017
|
+
className: Ee(
|
|
1018
1018
|
"relative block truncate px-4 py-1.5 pl-10 pr-8 text-sm transition-colors",
|
|
1019
1019
|
u ? "bg-surface-subtle font-medium text-fg" : "text-fg-muted hover:bg-surface-subtle hover:text-fg"
|
|
1020
1020
|
),
|
|
@@ -1028,7 +1028,7 @@ function sr() {
|
|
|
1028
1028
|
onClick: (N) => m(N, h.id),
|
|
1029
1029
|
className: "absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-fg-muted opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100",
|
|
1030
1030
|
title: i("nav.deleteChat"),
|
|
1031
|
-
children: /* @__PURE__ */ e(
|
|
1031
|
+
children: /* @__PURE__ */ e(Qn, { className: "h-3.5 w-3.5" })
|
|
1032
1032
|
}
|
|
1033
1033
|
)
|
|
1034
1034
|
] }, h.id);
|
|
@@ -1045,8 +1045,8 @@ function on() {
|
|
|
1045
1045
|
}
|
|
1046
1046
|
);
|
|
1047
1047
|
}
|
|
1048
|
-
function
|
|
1049
|
-
const [t, n, a] = rn("custom-analytics"), s =
|
|
1048
|
+
function or() {
|
|
1049
|
+
const [t, n, a] = rn("custom-analytics"), s = Ct(), i = ze(), o = We(), { t: l } = Z(), { navigationFlash: c, sessions: g, createSession: m } = ut(), h = (c == null ? void 0 : c.group) === "Custom Analytics", u = sn["Custom Analytics"], { data: N } = oe({
|
|
1050
1050
|
queryKey: ["runtime-drafts"],
|
|
1051
1051
|
queryFn: () => I.listRuntimeDrafts(),
|
|
1052
1052
|
staleTime: 3e4
|
|
@@ -1080,12 +1080,12 @@ function ir() {
|
|
|
1080
1080
|
{
|
|
1081
1081
|
type: "button",
|
|
1082
1082
|
onClick: n,
|
|
1083
|
-
className:
|
|
1083
|
+
className: Ee(
|
|
1084
1084
|
"flex w-full items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-fg-muted transition-all duration-300 hover:text-fg",
|
|
1085
1085
|
h && u
|
|
1086
1086
|
),
|
|
1087
1087
|
children: [
|
|
1088
|
-
/* @__PURE__ */ e(
|
|
1088
|
+
/* @__PURE__ */ e(za, { className: "h-4 w-4" }),
|
|
1089
1089
|
/* @__PURE__ */ e("span", { className: "flex-1 text-left", children: l("nav.customAnalytics") }),
|
|
1090
1090
|
t ? /* @__PURE__ */ e(zt, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ e(Mt, { className: "h-3.5 w-3.5" })
|
|
1091
1091
|
]
|
|
@@ -1098,7 +1098,7 @@ function ir() {
|
|
|
1098
1098
|
onClick: T,
|
|
1099
1099
|
className: "flex w-full items-center gap-2 px-4 py-1.5 pl-10 text-sm text-brand transition-colors hover:bg-brand/5",
|
|
1100
1100
|
children: [
|
|
1101
|
-
/* @__PURE__ */ e(
|
|
1101
|
+
/* @__PURE__ */ e(Hn, { className: "h-3.5 w-3.5" }),
|
|
1102
1102
|
l("nav.newAnalytics")
|
|
1103
1103
|
]
|
|
1104
1104
|
}
|
|
@@ -1110,7 +1110,7 @@ function ir() {
|
|
|
1110
1110
|
Ot,
|
|
1111
1111
|
{
|
|
1112
1112
|
to: b,
|
|
1113
|
-
className:
|
|
1113
|
+
className: Ee(
|
|
1114
1114
|
"relative block truncate px-4 py-1.5 pl-10 pr-8 text-sm transition-all duration-300",
|
|
1115
1115
|
!d && "text-fg-muted hover:bg-surface-subtle hover:text-fg",
|
|
1116
1116
|
d && "bg-surface-subtle font-medium text-fg",
|
|
@@ -1127,7 +1127,7 @@ function ir() {
|
|
|
1127
1127
|
onClick: (_) => f(_, P.id),
|
|
1128
1128
|
className: "absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-fg-muted opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100",
|
|
1129
1129
|
title: l("nav.deleteReport"),
|
|
1130
|
-
children: /* @__PURE__ */ e(
|
|
1130
|
+
children: /* @__PURE__ */ e(Qn, { className: "h-3.5 w-3.5" })
|
|
1131
1131
|
}
|
|
1132
1132
|
)
|
|
1133
1133
|
] }, P.id);
|
|
@@ -1135,15 +1135,15 @@ function ir() {
|
|
|
1135
1135
|
] })
|
|
1136
1136
|
] });
|
|
1137
1137
|
}
|
|
1138
|
-
function
|
|
1139
|
-
const [n, a] = rn(t.label), { t: s } =
|
|
1138
|
+
function lr({ group: t }) {
|
|
1139
|
+
const [n, a] = rn(t.label), { t: s } = Z(), { navigationFlash: i } = ut(), o = (i == null ? void 0 : i.group) === t.label, l = sn[t.label] ?? "bg-blue-300 text-blue-950 ring-2 ring-inset ring-blue-100";
|
|
1140
1140
|
return /* @__PURE__ */ r("div", { children: [
|
|
1141
1141
|
/* @__PURE__ */ r(
|
|
1142
1142
|
"button",
|
|
1143
1143
|
{
|
|
1144
1144
|
type: "button",
|
|
1145
1145
|
onClick: a,
|
|
1146
|
-
className:
|
|
1146
|
+
className: Ee(
|
|
1147
1147
|
"flex w-full items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-fg-muted transition-all duration-300 hover:text-fg",
|
|
1148
1148
|
o && l
|
|
1149
1149
|
),
|
|
@@ -1163,7 +1163,7 @@ function or({ group: t }) {
|
|
|
1163
1163
|
{
|
|
1164
1164
|
to: c.path,
|
|
1165
1165
|
end: g,
|
|
1166
|
-
className: ({ isActive: m }) =>
|
|
1166
|
+
className: ({ isActive: m }) => Ee(
|
|
1167
1167
|
"relative block px-4 py-1.5 pl-10 text-sm transition-all duration-300",
|
|
1168
1168
|
!m && "text-fg-muted hover:bg-surface-subtle hover:text-fg",
|
|
1169
1169
|
m && "bg-surface-subtle font-medium text-fg",
|
|
@@ -1178,10 +1178,10 @@ function or({ group: t }) {
|
|
|
1178
1178
|
}) })
|
|
1179
1179
|
] });
|
|
1180
1180
|
}
|
|
1181
|
-
const
|
|
1181
|
+
const cr = {
|
|
1182
1182
|
"/setup/opening-balances": "opening_balances_enabled"
|
|
1183
1183
|
};
|
|
1184
|
-
function
|
|
1184
|
+
function dr({ isMobileOpen: t = !1, onClose: n }) {
|
|
1185
1185
|
var c;
|
|
1186
1186
|
const { data: a } = oe({
|
|
1187
1187
|
queryKey: ["settings"],
|
|
@@ -1191,18 +1191,18 @@ function cr({ isMobileOpen: t = !1, onClose: n }) {
|
|
|
1191
1191
|
queryKey: ["setup-status"],
|
|
1192
1192
|
queryFn: () => I.setupStatus(),
|
|
1193
1193
|
staleTime: 6e4
|
|
1194
|
-
}), i = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], o = (i == null ? void 0 : i.company_name) || (i == null ? void 0 : i.name) ||
|
|
1194
|
+
}), i = (c = s == null ? void 0 : s.companies) == null ? void 0 : c[0], o = (i == null ? void 0 : i.company_name) || (i == null ? void 0 : i.name) || sr().appName, l = Ce(() => rr().map((m) => ({
|
|
1195
1195
|
...m,
|
|
1196
1196
|
items: m.items.filter((h) => {
|
|
1197
1197
|
if (h.path === "/setup" && (s != null && s.setup_complete)) return !1;
|
|
1198
|
-
const u =
|
|
1198
|
+
const u = cr[h.path];
|
|
1199
1199
|
return !u || !a ? !0 : a[u] !== "0";
|
|
1200
1200
|
})
|
|
1201
1201
|
})), [a, s]);
|
|
1202
1202
|
return /* @__PURE__ */ r(
|
|
1203
1203
|
"aside",
|
|
1204
1204
|
{
|
|
1205
|
-
className:
|
|
1205
|
+
className: Ee(
|
|
1206
1206
|
"fixed left-0 top-0 z-40 flex h-dvh w-64 flex-col border-r border-line bg-surface transition-transform duration-300 ease-out",
|
|
1207
1207
|
"md:translate-x-0",
|
|
1208
1208
|
t ? "translate-x-0 shadow-2xl" : "-translate-x-full"
|
|
@@ -1242,16 +1242,16 @@ function cr({ isMobileOpen: t = !1, onClose: n }) {
|
|
|
1242
1242
|
)
|
|
1243
1243
|
] }),
|
|
1244
1244
|
/* @__PURE__ */ r("nav", { className: "flex-1 overflow-y-auto py-3", children: [
|
|
1245
|
-
/* @__PURE__ */ e(sr, {}),
|
|
1246
1245
|
/* @__PURE__ */ e(ir, {}),
|
|
1247
|
-
|
|
1246
|
+
/* @__PURE__ */ e(or, {}),
|
|
1247
|
+
l.map((g) => /* @__PURE__ */ e(lr, { group: g }, g.label))
|
|
1248
1248
|
] })
|
|
1249
1249
|
]
|
|
1250
1250
|
}
|
|
1251
1251
|
);
|
|
1252
1252
|
}
|
|
1253
1253
|
const Nn = (t) => t.replace(/-/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
|
|
1254
|
-
function
|
|
1254
|
+
function ur(t, n) {
|
|
1255
1255
|
const a = t.split("/").filter(Boolean);
|
|
1256
1256
|
if (a[0] === "setup") return n("titles.setup");
|
|
1257
1257
|
if (a[0] === "tutorial") return n("titles.tutorial");
|
|
@@ -1270,17 +1270,17 @@ function dr(t, n) {
|
|
|
1270
1270
|
}
|
|
1271
1271
|
return n("titles.dashboard");
|
|
1272
1272
|
}
|
|
1273
|
-
function ur() {
|
|
1274
|
-
return /* @__PURE__ */ e(nr, { children: /* @__PURE__ */ e(mr, {}) });
|
|
1275
|
-
}
|
|
1276
1273
|
function mr() {
|
|
1277
|
-
|
|
1274
|
+
return /* @__PURE__ */ e(ar, { children: /* @__PURE__ */ e(pr, {}) });
|
|
1275
|
+
}
|
|
1276
|
+
function pr() {
|
|
1277
|
+
const { pathname: t } = Ct(), { user: n, logout: a } = st(), { navigationFlash: s } = ut(), { t: i } = Z(), o = ur(t, i), [l, c] = S(!1);
|
|
1278
1278
|
se(() => {
|
|
1279
1279
|
c(!1);
|
|
1280
1280
|
}, [t]);
|
|
1281
1281
|
const g = s ? sn[s.group] : null;
|
|
1282
1282
|
return /* @__PURE__ */ r("div", { className: "flex h-dvh bg-surface-muted", children: [
|
|
1283
|
-
/* @__PURE__ */ e(
|
|
1283
|
+
/* @__PURE__ */ e(dr, { isMobileOpen: l, onClose: () => c(!1) }),
|
|
1284
1284
|
l && /* @__PURE__ */ e(
|
|
1285
1285
|
"div",
|
|
1286
1286
|
{
|
|
@@ -1296,7 +1296,7 @@ function mr() {
|
|
|
1296
1296
|
"button",
|
|
1297
1297
|
{
|
|
1298
1298
|
onClick: () => c(!0),
|
|
1299
|
-
className:
|
|
1299
|
+
className: Ee(
|
|
1300
1300
|
"rounded p-1 text-gray-500 transition-all duration-300 hover:bg-gray-100 hover:text-gray-900 md:hidden",
|
|
1301
1301
|
g
|
|
1302
1302
|
),
|
|
@@ -1321,19 +1321,19 @@ function mr() {
|
|
|
1321
1321
|
)
|
|
1322
1322
|
] })
|
|
1323
1323
|
] }),
|
|
1324
|
-
/* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(
|
|
1324
|
+
/* @__PURE__ */ e("main", { className: "flex-1 overflow-auto p-4 md:p-6", children: /* @__PURE__ */ e(Aa, {}) })
|
|
1325
1325
|
] })
|
|
1326
1326
|
] });
|
|
1327
1327
|
}
|
|
1328
|
-
function
|
|
1328
|
+
function hr({ children: t }) {
|
|
1329
1329
|
const { user: n, loading: a } = st();
|
|
1330
|
-
return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(we, { children: t }) : /* @__PURE__ */ e(
|
|
1330
|
+
return a ? /* @__PURE__ */ e("div", { className: "flex h-dvh items-center justify-center", children: /* @__PURE__ */ e("div", { className: "text-gray-400", children: "Loading..." }) }) : n ? /* @__PURE__ */ e(we, { children: t }) : /* @__PURE__ */ e(Pa, { to: "/login", replace: !0 });
|
|
1331
1331
|
}
|
|
1332
1332
|
function $({ title: t, children: n, className: a, interactive: s }) {
|
|
1333
1333
|
return /* @__PURE__ */ r(
|
|
1334
1334
|
"div",
|
|
1335
1335
|
{
|
|
1336
|
-
className:
|
|
1336
|
+
className: Ee(
|
|
1337
1337
|
// Surface + 1px hairline ring + multi-layer soft shadow gives
|
|
1338
1338
|
// the card depth on a tinted page background. The shadow is
|
|
1339
1339
|
// closer in feel to Linear / Vercel than Tailwind's default
|
|
@@ -1350,7 +1350,7 @@ function $({ title: t, children: n, className: a, interactive: s }) {
|
|
|
1350
1350
|
}
|
|
1351
1351
|
);
|
|
1352
1352
|
}
|
|
1353
|
-
const
|
|
1353
|
+
const gr = {
|
|
1354
1354
|
default: "bg-brand/10 text-brand ring-1 ring-inset ring-brand/20",
|
|
1355
1355
|
success: "bg-emerald-50 text-emerald-700 ring-1 ring-inset ring-emerald-200",
|
|
1356
1356
|
warning: "bg-amber-50 text-amber-700 ring-1 ring-inset ring-amber-200",
|
|
@@ -1361,9 +1361,9 @@ function Tt({ variant: t = "default", dot: n, children: a, className: s }) {
|
|
|
1361
1361
|
return /* @__PURE__ */ r(
|
|
1362
1362
|
"span",
|
|
1363
1363
|
{
|
|
1364
|
-
className:
|
|
1364
|
+
className: Ee(
|
|
1365
1365
|
"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
|
|
1366
|
-
|
|
1366
|
+
gr[t],
|
|
1367
1367
|
s
|
|
1368
1368
|
),
|
|
1369
1369
|
children: [
|
|
@@ -1373,7 +1373,7 @@ function Tt({ variant: t = "default", dot: n, children: a, className: s }) {
|
|
|
1373
1373
|
}
|
|
1374
1374
|
);
|
|
1375
1375
|
}
|
|
1376
|
-
const
|
|
1376
|
+
const fr = {
|
|
1377
1377
|
Draft: "secondary",
|
|
1378
1378
|
Open: "default",
|
|
1379
1379
|
Submitted: "default",
|
|
@@ -1388,7 +1388,7 @@ const gr = {
|
|
|
1388
1388
|
Overdue: "danger"
|
|
1389
1389
|
};
|
|
1390
1390
|
function ln({ status: t }) {
|
|
1391
|
-
const { t: n } =
|
|
1391
|
+
const { t: n } = Z(), a = fr[t] ?? "secondary";
|
|
1392
1392
|
return /* @__PURE__ */ e(Tt, { variant: a, children: n(`status.${t}`, { defaultValue: t }) });
|
|
1393
1393
|
}
|
|
1394
1394
|
function Oe(t) {
|
|
@@ -1411,7 +1411,7 @@ function At({ title: t, value: n, icon: a, tone: s }) {
|
|
|
1411
1411
|
return /* @__PURE__ */ e($, { children: /* @__PURE__ */ r("div", { className: "flex items-start justify-between gap-4", children: [
|
|
1412
1412
|
/* @__PURE__ */ r("div", { className: "min-w-0", children: [
|
|
1413
1413
|
/* @__PURE__ */ e("p", { className: "text-sm font-medium text-fg-muted", children: t }),
|
|
1414
|
-
/* @__PURE__ */ e("p", { className: "mt-1.5 text-2xl font-semibold tracking-tight tabular-nums text-fg", children: ((c) =>
|
|
1414
|
+
/* @__PURE__ */ e("p", { className: "mt-1.5 text-2xl font-semibold tracking-tight tabular-nums text-fg", children: ((c) => Le(c, o))(n ?? 0) })
|
|
1415
1415
|
] }),
|
|
1416
1416
|
/* @__PURE__ */ e("div", { className: `shrink-0 rounded-lg p-2 ${i}`, children: /* @__PURE__ */ e(a, { className: "h-5 w-5", strokeWidth: 2 }) })
|
|
1417
1417
|
] }) });
|
|
@@ -1425,15 +1425,15 @@ function Pt() {
|
|
|
1425
1425
|
/* @__PURE__ */ e("div", { className: "h-9 w-9 shrink-0 animate-pulse rounded-lg bg-surface-subtle" })
|
|
1426
1426
|
] }) });
|
|
1427
1427
|
}
|
|
1428
|
-
const
|
|
1428
|
+
const yr = {
|
|
1429
1429
|
"Sales Invoice": mn,
|
|
1430
1430
|
"Purchase Invoice": mn,
|
|
1431
|
-
"Payment Entry":
|
|
1432
|
-
"Sales Order":
|
|
1431
|
+
"Payment Entry": Ua,
|
|
1432
|
+
"Sales Order": Gn,
|
|
1433
1433
|
Quotation: nn
|
|
1434
1434
|
};
|
|
1435
|
-
function
|
|
1436
|
-
const { t: n } =
|
|
1435
|
+
function br({ doc: t }) {
|
|
1436
|
+
const { t: n } = Z(), a = t.doctype ?? t.type ?? "Document", s = t.creation ?? t.date, i = yr[a] ?? nn, l = `/app/${a.toLowerCase().replace(/\s+/g, "-")}/${encodeURIComponent(t.name)}`;
|
|
1437
1437
|
return /* @__PURE__ */ r(
|
|
1438
1438
|
be,
|
|
1439
1439
|
{
|
|
@@ -1462,8 +1462,8 @@ function wt() {
|
|
|
1462
1462
|
/* @__PURE__ */ e("div", { className: "hidden h-3 w-16 animate-pulse rounded bg-surface-subtle sm:block" })
|
|
1463
1463
|
] });
|
|
1464
1464
|
}
|
|
1465
|
-
function
|
|
1466
|
-
const { t } =
|
|
1465
|
+
function vr() {
|
|
1466
|
+
const { t } = Z(), { data: n, isLoading: a } = oe({
|
|
1467
1467
|
queryKey: ["dashboard-summary"],
|
|
1468
1468
|
queryFn: () => I.dashboardSummary()
|
|
1469
1469
|
});
|
|
@@ -1479,7 +1479,7 @@ function br() {
|
|
|
1479
1479
|
{
|
|
1480
1480
|
title: t("dashboard.totalRevenue"),
|
|
1481
1481
|
value: n == null ? void 0 : n.total_revenue,
|
|
1482
|
-
icon:
|
|
1482
|
+
icon: Ma,
|
|
1483
1483
|
tone: "text-emerald-600 bg-emerald-500/10"
|
|
1484
1484
|
}
|
|
1485
1485
|
),
|
|
@@ -1488,7 +1488,7 @@ function br() {
|
|
|
1488
1488
|
{
|
|
1489
1489
|
title: t("dashboard.outstandingReceivable"),
|
|
1490
1490
|
value: n == null ? void 0 : n.outstanding_receivable,
|
|
1491
|
-
icon:
|
|
1491
|
+
icon: Fa,
|
|
1492
1492
|
tone: "text-sky-600 bg-sky-500/10"
|
|
1493
1493
|
}
|
|
1494
1494
|
),
|
|
@@ -1497,7 +1497,7 @@ function br() {
|
|
|
1497
1497
|
{
|
|
1498
1498
|
title: t("dashboard.outstandingPayable"),
|
|
1499
1499
|
value: n == null ? void 0 : n.outstanding_payable,
|
|
1500
|
-
icon:
|
|
1500
|
+
icon: $a,
|
|
1501
1501
|
tone: "text-amber-600 bg-amber-500/10"
|
|
1502
1502
|
}
|
|
1503
1503
|
),
|
|
@@ -1506,7 +1506,7 @@ function br() {
|
|
|
1506
1506
|
{
|
|
1507
1507
|
title: t("dashboard.totalStockValue"),
|
|
1508
1508
|
value: n == null ? void 0 : n.total_stock_value,
|
|
1509
|
-
icon:
|
|
1509
|
+
icon: Wn,
|
|
1510
1510
|
tone: "text-brand bg-brand/10"
|
|
1511
1511
|
}
|
|
1512
1512
|
)
|
|
@@ -1517,10 +1517,10 @@ function br() {
|
|
|
1517
1517
|
/* @__PURE__ */ e(wt, {}),
|
|
1518
1518
|
/* @__PURE__ */ e(wt, {}),
|
|
1519
1519
|
/* @__PURE__ */ e(wt, {})
|
|
1520
|
-
] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, i) => /* @__PURE__ */ e(
|
|
1520
|
+
] }) : n != null && n.recent_documents && n.recent_documents.length > 0 ? n.recent_documents.map((s, i) => /* @__PURE__ */ e(br, { doc: s }, `${s.name}-${i}`)) : /* @__PURE__ */ e("div", { className: "px-3 py-10 text-center text-sm text-fg-muted", children: t("dashboard.noRecentDocuments") }) }) })
|
|
1521
1521
|
] });
|
|
1522
1522
|
}
|
|
1523
|
-
function
|
|
1523
|
+
function xr(t, n) {
|
|
1524
1524
|
const { data: a, isLoading: s, error: i, refetch: o } = oe({
|
|
1525
1525
|
queryKey: ["documents", t, n],
|
|
1526
1526
|
queryFn: () => I.listDocuments(t, n),
|
|
@@ -1579,7 +1579,7 @@ const rt = [
|
|
|
1579
1579
|
{ name: "qty", label: "Qty", type: "number", required: !0 },
|
|
1580
1580
|
{ name: "rate", label: "Rate", type: "currency", required: !0 },
|
|
1581
1581
|
{ name: "amount", label: "Amount", type: "currency", readOnly: !0 }
|
|
1582
|
-
],
|
|
1582
|
+
], Nr = [
|
|
1583
1583
|
...rt,
|
|
1584
1584
|
{
|
|
1585
1585
|
name: "frequency",
|
|
@@ -1626,7 +1626,7 @@ const rt = [
|
|
|
1626
1626
|
{ name: "remarks", label: "Notes / Terms", type: "textarea" }
|
|
1627
1627
|
],
|
|
1628
1628
|
childTables: [
|
|
1629
|
-
{ key: "items", label: "Items", fields:
|
|
1629
|
+
{ key: "items", label: "Items", fields: Nr },
|
|
1630
1630
|
{ key: "taxes", label: "Taxes", fields: at }
|
|
1631
1631
|
],
|
|
1632
1632
|
listColumns: ["name", "customer", "transaction_date", "grand_total", "status"],
|
|
@@ -2213,16 +2213,16 @@ const rt = [
|
|
|
2213
2213
|
conversions: []
|
|
2214
2214
|
}
|
|
2215
2215
|
};
|
|
2216
|
-
function
|
|
2216
|
+
function oa(t) {
|
|
2217
2217
|
return cn[t];
|
|
2218
2218
|
}
|
|
2219
|
-
function
|
|
2219
|
+
function Io(t) {
|
|
2220
2220
|
cn[t.slug] = t;
|
|
2221
2221
|
}
|
|
2222
|
-
function
|
|
2222
|
+
function Bo() {
|
|
2223
2223
|
return Object.values(cn);
|
|
2224
2224
|
}
|
|
2225
|
-
const
|
|
2225
|
+
const wr = {
|
|
2226
2226
|
// Primary: brand-coloured fill + a 1px inset top highlight for depth
|
|
2227
2227
|
// (button-highlight shadow). On press, the button shifts down 1px —
|
|
2228
2228
|
// tiny detail, large perceived "this is responsive".
|
|
@@ -2230,7 +2230,7 @@ const Nr = {
|
|
|
2230
2230
|
secondary: "bg-surface text-fg ring-1 ring-line hover:bg-surface-subtle active:translate-y-px focus-visible:ring-fg/20",
|
|
2231
2231
|
danger: "bg-red-600 text-white shadow-button-highlight hover:bg-red-700 active:translate-y-px focus-visible:ring-red-500/40",
|
|
2232
2232
|
ghost: "bg-transparent text-fg-muted hover:bg-surface-subtle hover:text-fg focus-visible:ring-fg/20"
|
|
2233
|
-
},
|
|
2233
|
+
}, kr = {
|
|
2234
2234
|
sm: "h-8 px-3 text-sm",
|
|
2235
2235
|
md: "h-10 px-4 text-sm",
|
|
2236
2236
|
lg: "h-11 px-5 text-sm"
|
|
@@ -2250,7 +2250,7 @@ function H({
|
|
|
2250
2250
|
type: l,
|
|
2251
2251
|
disabled: a,
|
|
2252
2252
|
onClick: s,
|
|
2253
|
-
className:
|
|
2253
|
+
className: Ee(
|
|
2254
2254
|
// Layout + base interaction. focus-visible (not :focus) so
|
|
2255
2255
|
// mouse clicks don't leave a permanent ring; only keyboard
|
|
2256
2256
|
// navigation gets the visible outline.
|
|
@@ -2258,8 +2258,8 @@ function H({
|
|
|
2258
2258
|
"transition-all duration-150",
|
|
2259
2259
|
"focus-visible:outline-none focus-visible:ring-2",
|
|
2260
2260
|
"disabled:cursor-not-allowed disabled:opacity-50 disabled:active:translate-y-0",
|
|
2261
|
-
|
|
2262
|
-
|
|
2261
|
+
wr[t],
|
|
2262
|
+
kr[n],
|
|
2263
2263
|
o
|
|
2264
2264
|
),
|
|
2265
2265
|
children: i
|
|
@@ -2283,7 +2283,7 @@ function J({ label: t, hint: n, error: a, className: s, id: i, ...o }) {
|
|
|
2283
2283
|
id: l,
|
|
2284
2284
|
"aria-invalid": !!a || void 0,
|
|
2285
2285
|
"aria-describedby": a || n ? `${l}-help` : void 0,
|
|
2286
|
-
className:
|
|
2286
|
+
className: Ee(
|
|
2287
2287
|
// Bigger touch target (h-10) than the previous py-2 default;
|
|
2288
2288
|
// brand-coloured halo on focus instead of a single hard ring.
|
|
2289
2289
|
// text-sm is fine on desktop; the global media-query in
|
|
@@ -2303,7 +2303,7 @@ function J({ label: t, hint: n, error: a, className: s, id: i, ...o }) {
|
|
|
2303
2303
|
"p",
|
|
2304
2304
|
{
|
|
2305
2305
|
id: `${l}-help`,
|
|
2306
|
-
className:
|
|
2306
|
+
className: Ee(
|
|
2307
2307
|
"mt-1.5 text-xs",
|
|
2308
2308
|
a ? "text-red-600" : "text-fg-muted"
|
|
2309
2309
|
),
|
|
@@ -2312,7 +2312,7 @@ function J({ label: t, hint: n, error: a, className: s, id: i, ...o }) {
|
|
|
2312
2312
|
)
|
|
2313
2313
|
] });
|
|
2314
2314
|
}
|
|
2315
|
-
function
|
|
2315
|
+
function Sr(t) {
|
|
2316
2316
|
return typeof t == "string" ? { value: t, label: t } : t;
|
|
2317
2317
|
}
|
|
2318
2318
|
function He({ label: t, options: n, value: a, onChange: s, className: i, required: o, disabled: l }) {
|
|
@@ -2334,7 +2334,7 @@ function He({ label: t, options: n, value: a, onChange: s, className: i, require
|
|
|
2334
2334
|
onChange: s,
|
|
2335
2335
|
required: o,
|
|
2336
2336
|
disabled: l,
|
|
2337
|
-
className:
|
|
2337
|
+
className: Ee(
|
|
2338
2338
|
// Same shape as the Input primitive: h-10, surface bg, line ring,
|
|
2339
2339
|
// brand-tinted halo on focus.
|
|
2340
2340
|
"block h-10 w-full rounded-lg bg-surface px-3 text-sm text-fg",
|
|
@@ -2346,7 +2346,7 @@ function He({ label: t, options: n, value: a, onChange: s, className: i, require
|
|
|
2346
2346
|
children: [
|
|
2347
2347
|
/* @__PURE__ */ e("option", { value: "", children: "Select..." }),
|
|
2348
2348
|
n.map((g) => {
|
|
2349
|
-
const { value: m, label: h } =
|
|
2349
|
+
const { value: m, label: h } = Sr(g);
|
|
2350
2350
|
return /* @__PURE__ */ e("option", { value: m, children: h }, m);
|
|
2351
2351
|
})
|
|
2352
2352
|
]
|
|
@@ -2355,7 +2355,7 @@ function He({ label: t, options: n, value: a, onChange: s, className: i, require
|
|
|
2355
2355
|
] });
|
|
2356
2356
|
}
|
|
2357
2357
|
function Cr({ text: t }) {
|
|
2358
|
-
const [n, a] =
|
|
2358
|
+
const [n, a] = S(!1);
|
|
2359
2359
|
return /* @__PURE__ */ r("span", { className: "relative ml-1 inline-flex", children: [
|
|
2360
2360
|
/* @__PURE__ */ e(
|
|
2361
2361
|
"button",
|
|
@@ -2374,8 +2374,8 @@ function Cr({ text: t }) {
|
|
|
2374
2374
|
] })
|
|
2375
2375
|
] });
|
|
2376
2376
|
}
|
|
2377
|
-
function
|
|
2378
|
-
const { t } =
|
|
2377
|
+
function Dr() {
|
|
2378
|
+
const { t } = Z(), [n, a] = S(!1), s = [
|
|
2379
2379
|
["# Heading", t("notesMarkup.heading", { defaultValue: "bold heading" })],
|
|
2380
2380
|
["*italic* **bold**", t("notesMarkup.emphasis", { defaultValue: "italic / bold" })],
|
|
2381
2381
|
["---", t("notesMarkup.rule", { defaultValue: "horizontal divider line" })],
|
|
@@ -2400,7 +2400,7 @@ function Sr() {
|
|
|
2400
2400
|
className: "inline-flex h-4 w-4 items-center justify-center rounded-full text-fg-muted hover:text-fg",
|
|
2401
2401
|
onClick: () => a((i) => !i),
|
|
2402
2402
|
"aria-label": t("notesMarkup.title", { defaultValue: "Formatting help" }),
|
|
2403
|
-
children: /* @__PURE__ */ e(
|
|
2403
|
+
children: /* @__PURE__ */ e(Va, { className: "h-3.5 w-3.5" })
|
|
2404
2404
|
}
|
|
2405
2405
|
),
|
|
2406
2406
|
n && /* @__PURE__ */ r("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-80 rounded-md bg-gray-900 px-3 py-2.5 text-xs leading-relaxed text-white shadow-lg", children: [
|
|
@@ -2417,7 +2417,7 @@ function Sr() {
|
|
|
2417
2417
|
}
|
|
2418
2418
|
);
|
|
2419
2419
|
}
|
|
2420
|
-
function
|
|
2420
|
+
function Ar(t, n = !0) {
|
|
2421
2421
|
const { data: a } = oe({
|
|
2422
2422
|
queryKey: ["currencies", ""],
|
|
2423
2423
|
queryFn: () => I.currencies(t),
|
|
@@ -2426,14 +2426,14 @@ function Dr(t, n = !0) {
|
|
|
2426
2426
|
});
|
|
2427
2427
|
return (a == null ? void 0 : a.currencies) ?? [];
|
|
2428
2428
|
}
|
|
2429
|
-
const
|
|
2429
|
+
const Pr = /* @__PURE__ */ new Set([
|
|
2430
2430
|
"customer",
|
|
2431
2431
|
"supplier",
|
|
2432
2432
|
"item",
|
|
2433
2433
|
"warehouse"
|
|
2434
2434
|
]);
|
|
2435
2435
|
function Xt(t, n) {
|
|
2436
|
-
return !t || !n ? null :
|
|
2436
|
+
return !t || !n ? null : Pr.has(t) ? `/masters/${t}/${encodeURIComponent(n)}` : t === "account" ? `/reports/general-ledger?account=${encodeURIComponent(n)}` : null;
|
|
2437
2437
|
}
|
|
2438
2438
|
function wn({ label: t, hint: n, extra: a }) {
|
|
2439
2439
|
return /* @__PURE__ */ r("label", { className: "mb-1.5 block text-sm font-medium text-fg", children: [
|
|
@@ -2442,14 +2442,14 @@ function wn({ label: t, hint: n, extra: a }) {
|
|
|
2442
2442
|
a
|
|
2443
2443
|
] });
|
|
2444
2444
|
}
|
|
2445
|
-
function
|
|
2445
|
+
function _r({
|
|
2446
2446
|
field: t,
|
|
2447
2447
|
value: n,
|
|
2448
2448
|
onChange: a,
|
|
2449
2449
|
disabled: s,
|
|
2450
2450
|
hideLabel: i
|
|
2451
2451
|
}) {
|
|
2452
|
-
const [o, l] =
|
|
2452
|
+
const [o, l] = S(n ?? ""), [c, g] = S(!1), m = te(null), [h, u] = S(null), { data: N } = oe({
|
|
2453
2453
|
queryKey: ["link-search", t.linkDoctype, o],
|
|
2454
2454
|
queryFn: () => I.searchLink(t.linkDoctype, o),
|
|
2455
2455
|
enabled: !!t.linkDoctype && c
|
|
@@ -2484,7 +2484,7 @@ function Pr({
|
|
|
2484
2484
|
onBlur: () => setTimeout(() => g(!1), 200)
|
|
2485
2485
|
}
|
|
2486
2486
|
),
|
|
2487
|
-
c && N && N.length > 0 && h &&
|
|
2487
|
+
c && N && N.length > 0 && h && Xn(
|
|
2488
2488
|
/* @__PURE__ */ e(
|
|
2489
2489
|
"ul",
|
|
2490
2490
|
{
|
|
@@ -2517,7 +2517,7 @@ function Rt({
|
|
|
2517
2517
|
currency: l = "USD"
|
|
2518
2518
|
}) {
|
|
2519
2519
|
var x;
|
|
2520
|
-
const { t: c } =
|
|
2520
|
+
const { t: c } = Z(), g = s || !!t.readOnly, m = () => o ? null : /* @__PURE__ */ e(wn, { label: c(`fields.${t.label}`, { defaultValue: t.label }), hint: t.hint }), h = t.type === "select" && t.optionsSource === "currency", u = Ar(void 0, h);
|
|
2521
2521
|
if (g) {
|
|
2522
2522
|
if (t.type === "link" && n) {
|
|
2523
2523
|
const T = t.linkDoctypeField && i ? String(i[t.linkDoctypeField] ?? "").toLowerCase().replace(/\s+/g, "-") : t.linkDoctype, P = Xt(T, String(n));
|
|
@@ -2535,7 +2535,7 @@ function Rt({
|
|
|
2535
2535
|
] });
|
|
2536
2536
|
}
|
|
2537
2537
|
let v = n ?? "-";
|
|
2538
|
-
t.type === "currency" && typeof n == "number" && (v =
|
|
2538
|
+
t.type === "currency" && typeof n == "number" && (v = Le(n, l));
|
|
2539
2539
|
const f = [
|
|
2540
2540
|
o ? "text-sm text-fg" : "py-2 text-sm text-fg",
|
|
2541
2541
|
t.type === "textarea" ? "whitespace-pre-line" : ""
|
|
@@ -2550,7 +2550,7 @@ function Rt({
|
|
|
2550
2550
|
return /* @__PURE__ */ r("div", { children: [
|
|
2551
2551
|
/* @__PURE__ */ e(m, {}),
|
|
2552
2552
|
/* @__PURE__ */ e(
|
|
2553
|
-
|
|
2553
|
+
_r,
|
|
2554
2554
|
{
|
|
2555
2555
|
field: v,
|
|
2556
2556
|
value: n ?? "",
|
|
@@ -2583,7 +2583,7 @@ function Rt({
|
|
|
2583
2583
|
{
|
|
2584
2584
|
label: c(`fields.${t.label}`, { defaultValue: t.label }),
|
|
2585
2585
|
hint: t.hint,
|
|
2586
|
-
extra: v ? /* @__PURE__ */ e(
|
|
2586
|
+
extra: v ? /* @__PURE__ */ e(Dr, {}) : void 0
|
|
2587
2587
|
}
|
|
2588
2588
|
),
|
|
2589
2589
|
/* @__PURE__ */ e(
|
|
@@ -2613,14 +2613,14 @@ function Rt({
|
|
|
2613
2613
|
)
|
|
2614
2614
|
] });
|
|
2615
2615
|
}
|
|
2616
|
-
function
|
|
2616
|
+
function Tr({
|
|
2617
2617
|
tableDef: t,
|
|
2618
2618
|
rows: n,
|
|
2619
2619
|
onChange: a,
|
|
2620
2620
|
readOnly: s,
|
|
2621
2621
|
currency: i = "USD"
|
|
2622
2622
|
}) {
|
|
2623
|
-
const { t: o } =
|
|
2623
|
+
const { t: o } = Z(), l = (m, h, u) => {
|
|
2624
2624
|
const N = n.map(
|
|
2625
2625
|
(x, v) => v === m ? { ...x, [h]: u } : x
|
|
2626
2626
|
);
|
|
@@ -2675,7 +2675,7 @@ function _r({
|
|
|
2675
2675
|
!s && /* @__PURE__ */ e("div", { className: "mt-2", children: /* @__PURE__ */ e(H, { variant: "secondary", size: "sm", onClick: c, children: o("common.addRow") }) })
|
|
2676
2676
|
] });
|
|
2677
2677
|
}
|
|
2678
|
-
function
|
|
2678
|
+
function Rr({
|
|
2679
2679
|
isNew: t,
|
|
2680
2680
|
doctype: n,
|
|
2681
2681
|
name: a,
|
|
@@ -2689,7 +2689,7 @@ function Tr({
|
|
|
2689
2689
|
onConvert: h,
|
|
2690
2690
|
onDiscard: u
|
|
2691
2691
|
}) {
|
|
2692
|
-
const { t: N } =
|
|
2692
|
+
const { t: N } = Z(), [x, v] = S(!1), [f, T] = S(!1);
|
|
2693
2693
|
if (!l) return null;
|
|
2694
2694
|
const P = !t && n && a ? `/api/documents/${n}/${encodeURIComponent(a)}/pdf` : null, b = !t && l.canCancel && s === 1;
|
|
2695
2695
|
return /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
@@ -2754,14 +2754,14 @@ function kn(t, n) {
|
|
|
2754
2754
|
}
|
|
2755
2755
|
return a;
|
|
2756
2756
|
}
|
|
2757
|
-
function
|
|
2757
|
+
function Sn() {
|
|
2758
2758
|
var Ue;
|
|
2759
|
-
const { doctype: t, name: n } = bt(), a = ze(), s = We(), { t: i } =
|
|
2759
|
+
const { doctype: t, name: n } = bt(), a = ze(), s = We(), { t: i } = Z(), o = oa(t ?? ""), l = !n, [c, g] = S({}), [m, h] = S(!1), { data: u, isLoading: N } = oe({
|
|
2760
2760
|
queryKey: ["document", t, n],
|
|
2761
2761
|
queryFn: () => I.getDocument(t, n),
|
|
2762
2762
|
enabled: !!t && !!n && !l
|
|
2763
|
-
}), x =
|
|
2764
|
-
() => !!(o != null && o.fields.some((
|
|
2763
|
+
}), x = Ce(
|
|
2764
|
+
() => !!(o != null && o.fields.some((E) => E.name === "currency")),
|
|
2765
2765
|
[o]
|
|
2766
2766
|
), v = o == null ? void 0 : o.partyField, f = v ? c[v] : void 0, T = Oe(c.company), { data: P } = oe({
|
|
2767
2767
|
queryKey: ["master", v, f],
|
|
@@ -2771,13 +2771,13 @@ function Cn() {
|
|
|
2771
2771
|
});
|
|
2772
2772
|
se(() => {
|
|
2773
2773
|
if (!l || !x || m) return;
|
|
2774
|
-
let
|
|
2774
|
+
let E;
|
|
2775
2775
|
if (f) {
|
|
2776
2776
|
if (!P) return;
|
|
2777
|
-
|
|
2777
|
+
E = P.default_currency || T;
|
|
2778
2778
|
} else
|
|
2779
|
-
|
|
2780
|
-
|
|
2779
|
+
E = T;
|
|
2780
|
+
E && E !== c.currency && g((ne) => ({ ...ne, currency: E }));
|
|
2781
2781
|
}, [
|
|
2782
2782
|
l,
|
|
2783
2783
|
x,
|
|
@@ -2788,33 +2788,33 @@ function Cn() {
|
|
|
2788
2788
|
c.currency
|
|
2789
2789
|
]), se(() => {
|
|
2790
2790
|
if (l && o) {
|
|
2791
|
-
const
|
|
2791
|
+
const E = {};
|
|
2792
2792
|
o.fields.forEach((ne) => {
|
|
2793
|
-
ne.type === "date" ?
|
|
2793
|
+
ne.type === "date" ? E[ne.name] = (/* @__PURE__ */ new Date()).toISOString().split("T")[0] : E[ne.name] = ne.default ?? "";
|
|
2794
2794
|
}), o.childTables.forEach((ne) => {
|
|
2795
|
-
|
|
2796
|
-
}),
|
|
2795
|
+
E[ne.key] = [];
|
|
2796
|
+
}), E.docstatus = 0, g(E);
|
|
2797
2797
|
} else u && g(u);
|
|
2798
2798
|
}, [l, u, o]);
|
|
2799
2799
|
const b = ie({
|
|
2800
|
-
mutationFn: (
|
|
2801
|
-
onSuccess: (
|
|
2802
|
-
s.invalidateQueries({ queryKey: ["documents", t] }), a(`/app/${t}/${
|
|
2800
|
+
mutationFn: (E) => I.createDocument(t, E),
|
|
2801
|
+
onSuccess: (E) => {
|
|
2802
|
+
s.invalidateQueries({ queryKey: ["documents", t] }), a(`/app/${t}/${E.name}`, { replace: !0 });
|
|
2803
2803
|
}
|
|
2804
2804
|
}), d = ie({
|
|
2805
|
-
mutationFn: (
|
|
2806
|
-
onSuccess: (
|
|
2807
|
-
s.invalidateQueries({ queryKey: ["document", t, n] }), s.invalidateQueries({ queryKey: ["documents", t] }), g(
|
|
2805
|
+
mutationFn: (E) => I.updateDocument(t, n, E),
|
|
2806
|
+
onSuccess: (E) => {
|
|
2807
|
+
s.invalidateQueries({ queryKey: ["document", t, n] }), s.invalidateQueries({ queryKey: ["documents", t] }), g(E);
|
|
2808
2808
|
}
|
|
2809
2809
|
}), p = ie({
|
|
2810
2810
|
mutationFn: () => I.submitDocument(t, n),
|
|
2811
|
-
onSuccess: (
|
|
2812
|
-
g(
|
|
2811
|
+
onSuccess: (E) => {
|
|
2812
|
+
g(E), s.invalidateQueries({ queryKey: ["document", t, n] }), s.invalidateQueries({ queryKey: ["documents", t] });
|
|
2813
2813
|
}
|
|
2814
2814
|
}), _ = ie({
|
|
2815
2815
|
mutationFn: () => I.cancelDocument(t, n),
|
|
2816
|
-
onSuccess: (
|
|
2817
|
-
g(
|
|
2816
|
+
onSuccess: (E) => {
|
|
2817
|
+
g(E), s.invalidateQueries({ queryKey: ["document", t, n] }), s.invalidateQueries({ queryKey: ["documents", t] });
|
|
2818
2818
|
}
|
|
2819
2819
|
}), y = ie({
|
|
2820
2820
|
mutationFn: () => I.discardDocument(t, n),
|
|
@@ -2822,23 +2822,23 @@ function Cn() {
|
|
|
2822
2822
|
s.invalidateQueries({ queryKey: ["documents", t] }), a(`/app/${t}`, { replace: !0 });
|
|
2823
2823
|
}
|
|
2824
2824
|
}), B = ie({
|
|
2825
|
-
mutationFn: (
|
|
2826
|
-
onSuccess: (
|
|
2825
|
+
mutationFn: (E) => I.convertDocument(t, n, E),
|
|
2826
|
+
onSuccess: (E, ne) => {
|
|
2827
2827
|
const Re = ne.toLowerCase().replace(/\s+/g, "-");
|
|
2828
|
-
a(`/app/${Re}/${
|
|
2828
|
+
a(`/app/${Re}/${E.name}`);
|
|
2829
2829
|
}
|
|
2830
2830
|
}), D = Pe(
|
|
2831
|
-
(
|
|
2832
|
-
|
|
2833
|
-
const De = { ...Re, [
|
|
2834
|
-
return
|
|
2831
|
+
(E, ne) => {
|
|
2832
|
+
E === "currency" && h(!0), g((Re) => {
|
|
2833
|
+
const De = { ...Re, [E]: ne };
|
|
2834
|
+
return E === "currency" && (De.conversion_rate = 0), kn(De, o);
|
|
2835
2835
|
});
|
|
2836
2836
|
},
|
|
2837
2837
|
[o]
|
|
2838
2838
|
), O = Pe(
|
|
2839
|
-
(
|
|
2839
|
+
(E, ne) => {
|
|
2840
2840
|
g((Re) => {
|
|
2841
|
-
const De = { ...Re, [
|
|
2841
|
+
const De = { ...Re, [E]: ne };
|
|
2842
2842
|
return kn(De, o);
|
|
2843
2843
|
});
|
|
2844
2844
|
},
|
|
@@ -2847,10 +2847,10 @@ function Cn() {
|
|
|
2847
2847
|
l ? b.mutate(c) : d.mutate(c);
|
|
2848
2848
|
}, ee = () => {
|
|
2849
2849
|
p.mutate();
|
|
2850
|
-
},
|
|
2850
|
+
}, C = () => {
|
|
2851
2851
|
_.mutate();
|
|
2852
|
-
}, w = (
|
|
2853
|
-
B.mutate(
|
|
2852
|
+
}, w = (E) => {
|
|
2853
|
+
B.mutate(E);
|
|
2854
2854
|
}, q = () => {
|
|
2855
2855
|
y.mutate();
|
|
2856
2856
|
};
|
|
@@ -2861,7 +2861,7 @@ function Cn() {
|
|
|
2861
2861
|
] });
|
|
2862
2862
|
if (!l && N)
|
|
2863
2863
|
return /* @__PURE__ */ e("p", { className: "text-fg-muted", children: i("common.loading") });
|
|
2864
|
-
const A = c.docstatus ?? 0, z = !!c.discarded, Y = A >= 1 || z, re = c.currency || T, ce = Fe(c.conversion_rate ?? 1), ge = o.fields.filter((
|
|
2864
|
+
const A = c.docstatus ?? 0, z = !!c.discarded, Y = A >= 1 || z, re = c.currency || T, ce = Fe(c.conversion_rate ?? 1), ge = o.fields.filter((E) => !E.readOnly), _e = ge.filter((E) => E.type !== "textarea"), pe = ge.filter((E) => E.type === "textarea"), fe = o.fields.filter((E) => E.readOnly);
|
|
2865
2865
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
2866
2866
|
/* @__PURE__ */ r("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
2867
2867
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-3", children: [
|
|
@@ -2882,7 +2882,7 @@ function Cn() {
|
|
|
2882
2882
|
)
|
|
2883
2883
|
] }),
|
|
2884
2884
|
/* @__PURE__ */ e(
|
|
2885
|
-
|
|
2885
|
+
Rr,
|
|
2886
2886
|
{
|
|
2887
2887
|
isNew: l,
|
|
2888
2888
|
doctype: t,
|
|
@@ -2893,7 +2893,7 @@ function Cn() {
|
|
|
2893
2893
|
discarded: z,
|
|
2894
2894
|
onSave: G,
|
|
2895
2895
|
onSubmit: ee,
|
|
2896
|
-
onCancel:
|
|
2896
|
+
onCancel: C,
|
|
2897
2897
|
onConvert: w,
|
|
2898
2898
|
onDiscard: q
|
|
2899
2899
|
}
|
|
@@ -2901,68 +2901,68 @@ function Cn() {
|
|
|
2901
2901
|
] }),
|
|
2902
2902
|
(b.error || d.error || p.error || _.error) && /* @__PURE__ */ e("div", { className: "rounded-lg bg-rose-50 p-4 text-sm text-rose-700 ring-1 ring-rose-200", children: ((Ue = b.error ?? d.error ?? p.error ?? _.error) == null ? void 0 : Ue.message) ?? i("common.errorOccurred") }),
|
|
2903
2903
|
/* @__PURE__ */ r($, { children: [
|
|
2904
|
-
/* @__PURE__ */ e("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: _e.map((
|
|
2904
|
+
/* @__PURE__ */ e("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: _e.map((E) => /* @__PURE__ */ e(
|
|
2905
2905
|
Rt,
|
|
2906
2906
|
{
|
|
2907
|
-
field:
|
|
2908
|
-
value: c[
|
|
2909
|
-
onChange: (ne) => D(
|
|
2907
|
+
field: E,
|
|
2908
|
+
value: c[E.name],
|
|
2909
|
+
onChange: (ne) => D(E.name, ne),
|
|
2910
2910
|
readOnly: Y,
|
|
2911
2911
|
rowData: c,
|
|
2912
2912
|
currency: re
|
|
2913
2913
|
},
|
|
2914
|
-
|
|
2914
|
+
E.name
|
|
2915
2915
|
)) }),
|
|
2916
|
-
pe.length > 0 && /* @__PURE__ */ e("div", { className: "mt-4 space-y-4", children: pe.map((
|
|
2916
|
+
pe.length > 0 && /* @__PURE__ */ e("div", { className: "mt-4 space-y-4", children: pe.map((E) => /* @__PURE__ */ e(
|
|
2917
2917
|
Rt,
|
|
2918
2918
|
{
|
|
2919
|
-
field:
|
|
2920
|
-
value: c[
|
|
2921
|
-
onChange: (ne) => D(
|
|
2919
|
+
field: E,
|
|
2920
|
+
value: c[E.name],
|
|
2921
|
+
onChange: (ne) => D(E.name, ne),
|
|
2922
2922
|
readOnly: Y,
|
|
2923
2923
|
rowData: c,
|
|
2924
2924
|
currency: re
|
|
2925
2925
|
},
|
|
2926
|
-
|
|
2926
|
+
E.name
|
|
2927
2927
|
)) })
|
|
2928
2928
|
] }),
|
|
2929
|
-
o.childTables.map((
|
|
2930
|
-
|
|
2929
|
+
o.childTables.map((E) => /* @__PURE__ */ e(
|
|
2930
|
+
Tr,
|
|
2931
2931
|
{
|
|
2932
|
-
tableDef:
|
|
2933
|
-
rows: c[
|
|
2934
|
-
onChange: (ne) => O(
|
|
2932
|
+
tableDef: E,
|
|
2933
|
+
rows: c[E.key] ?? [],
|
|
2934
|
+
onChange: (ne) => O(E.key, ne),
|
|
2935
2935
|
readOnly: Y,
|
|
2936
2936
|
currency: re
|
|
2937
2937
|
},
|
|
2938
|
-
|
|
2938
|
+
E.key
|
|
2939
2939
|
)),
|
|
2940
|
-
fe.length > 0 && /* @__PURE__ */ e($, { title: i("common.totals"), children: /* @__PURE__ */ e("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: fe.map((
|
|
2940
|
+
fe.length > 0 && /* @__PURE__ */ e($, { title: i("common.totals"), children: /* @__PURE__ */ e("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-3", children: fe.map((E) => /* @__PURE__ */ e(
|
|
2941
2941
|
Rt,
|
|
2942
2942
|
{
|
|
2943
|
-
field:
|
|
2944
|
-
value: c[
|
|
2943
|
+
field: E,
|
|
2944
|
+
value: c[E.name],
|
|
2945
2945
|
onChange: () => {
|
|
2946
2946
|
},
|
|
2947
2947
|
readOnly: !0,
|
|
2948
2948
|
currency: re
|
|
2949
2949
|
},
|
|
2950
|
-
|
|
2950
|
+
E.name
|
|
2951
2951
|
)) }) })
|
|
2952
2952
|
] });
|
|
2953
2953
|
}
|
|
2954
2954
|
function ye(t) {
|
|
2955
2955
|
return t.toISOString().split("T")[0];
|
|
2956
2956
|
}
|
|
2957
|
-
function
|
|
2957
|
+
function la(t) {
|
|
2958
2958
|
const n = new Date(t), a = n.getDay(), s = a === 0 ? 6 : a - 1;
|
|
2959
2959
|
return n.setDate(n.getDate() - s), n;
|
|
2960
2960
|
}
|
|
2961
|
-
function
|
|
2962
|
-
const n =
|
|
2961
|
+
function Ir(t) {
|
|
2962
|
+
const n = la(t);
|
|
2963
2963
|
return n.setDate(n.getDate() + 6), n;
|
|
2964
2964
|
}
|
|
2965
|
-
function
|
|
2965
|
+
function Cn(t) {
|
|
2966
2966
|
return new Date(t.getFullYear(), t.getMonth(), 1);
|
|
2967
2967
|
}
|
|
2968
2968
|
function Bt(t) {
|
|
@@ -2979,10 +2979,10 @@ function tn(t) {
|
|
|
2979
2979
|
function Dn(t) {
|
|
2980
2980
|
return new Date(t.getFullYear(), 0, 1);
|
|
2981
2981
|
}
|
|
2982
|
-
function
|
|
2982
|
+
function Et(t) {
|
|
2983
2983
|
return new Date(t.getFullYear(), 11, 31);
|
|
2984
2984
|
}
|
|
2985
|
-
const
|
|
2985
|
+
const Br = [
|
|
2986
2986
|
{
|
|
2987
2987
|
label: "Today",
|
|
2988
2988
|
range: () => {
|
|
@@ -2992,11 +2992,11 @@ const Ir = [
|
|
|
2992
2992
|
},
|
|
2993
2993
|
{
|
|
2994
2994
|
label: "This Week",
|
|
2995
|
-
range: () => [ye(
|
|
2995
|
+
range: () => [ye(la(/* @__PURE__ */ new Date())), ye(Ir(/* @__PURE__ */ new Date()))]
|
|
2996
2996
|
},
|
|
2997
2997
|
{
|
|
2998
2998
|
label: "This Month",
|
|
2999
|
-
range: () => [ye(
|
|
2999
|
+
range: () => [ye(Cn(/* @__PURE__ */ new Date())), ye(Bt(/* @__PURE__ */ new Date()))]
|
|
3000
3000
|
},
|
|
3001
3001
|
{
|
|
3002
3002
|
label: "This Quarter",
|
|
@@ -3004,13 +3004,13 @@ const Ir = [
|
|
|
3004
3004
|
},
|
|
3005
3005
|
{
|
|
3006
3006
|
label: "This Year",
|
|
3007
|
-
range: () => [ye(Dn(/* @__PURE__ */ new Date())), ye(
|
|
3007
|
+
range: () => [ye(Dn(/* @__PURE__ */ new Date())), ye(Et(/* @__PURE__ */ new Date()))]
|
|
3008
3008
|
},
|
|
3009
3009
|
{
|
|
3010
3010
|
label: "Last Month",
|
|
3011
3011
|
range: () => {
|
|
3012
3012
|
const t = /* @__PURE__ */ new Date(), n = new Date(t.getFullYear(), t.getMonth() - 1, 1);
|
|
3013
|
-
return [ye(
|
|
3013
|
+
return [ye(Cn(n)), ye(Bt(n))];
|
|
3014
3014
|
}
|
|
3015
3015
|
},
|
|
3016
3016
|
{
|
|
@@ -3024,12 +3024,12 @@ const Ir = [
|
|
|
3024
3024
|
label: "Last Year",
|
|
3025
3025
|
range: () => {
|
|
3026
3026
|
const t = new Date((/* @__PURE__ */ new Date()).getFullYear() - 1, 6, 1);
|
|
3027
|
-
return [ye(Dn(t)), ye(
|
|
3027
|
+
return [ye(Dn(t)), ye(Et(t))];
|
|
3028
3028
|
}
|
|
3029
3029
|
}
|
|
3030
3030
|
];
|
|
3031
3031
|
function $t({ onSelect: t }) {
|
|
3032
|
-
return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children:
|
|
3032
|
+
return /* @__PURE__ */ e("div", { className: "flex flex-wrap gap-1.5", children: Br.map((n) => /* @__PURE__ */ e(
|
|
3033
3033
|
"button",
|
|
3034
3034
|
{
|
|
3035
3035
|
type: "button",
|
|
@@ -3052,8 +3052,8 @@ function dn({ onSelect: t }) {
|
|
|
3052
3052
|
return ye(Bt(new Date(a.getFullYear(), a.getMonth() - 1, 1)));
|
|
3053
3053
|
} },
|
|
3054
3054
|
{ label: "End of This Quarter", value: () => ye(tn(/* @__PURE__ */ new Date())) },
|
|
3055
|
-
{ label: "End of This Year", value: () => ye(
|
|
3056
|
-
{ label: "End of Last Year", value: () => ye(
|
|
3055
|
+
{ label: "End of This Year", value: () => ye(Et(/* @__PURE__ */ new Date())) },
|
|
3056
|
+
{ label: "End of Last Year", value: () => ye(Et(new Date((/* @__PURE__ */ new Date()).getFullYear() - 1, 0, 1))) }
|
|
3057
3057
|
].map((a) => /* @__PURE__ */ e(
|
|
3058
3058
|
"button",
|
|
3059
3059
|
{
|
|
@@ -3065,14 +3065,14 @@ function dn({ onSelect: t }) {
|
|
|
3065
3065
|
a.label
|
|
3066
3066
|
)) });
|
|
3067
3067
|
}
|
|
3068
|
-
const
|
|
3068
|
+
const Er = ["All", "Draft", "Submitted", "Cancelled"], Lr = /* @__PURE__ */ new Set([
|
|
3069
3069
|
"grand_total",
|
|
3070
3070
|
"outstanding_amount",
|
|
3071
3071
|
"paid_amount",
|
|
3072
3072
|
"total_debit",
|
|
3073
3073
|
"total_amount",
|
|
3074
3074
|
"net_total"
|
|
3075
|
-
]),
|
|
3075
|
+
]), Or = /* @__PURE__ */ new Set([
|
|
3076
3076
|
"transaction_date",
|
|
3077
3077
|
"posting_date",
|
|
3078
3078
|
"due_date",
|
|
@@ -3089,25 +3089,25 @@ const Br = ["All", "Draft", "Submitted", "Cancelled"], Lr = /* @__PURE__ */ new
|
|
|
3089
3089
|
account: "account",
|
|
3090
3090
|
cost_center: "cost-center"
|
|
3091
3091
|
};
|
|
3092
|
-
function
|
|
3092
|
+
function qr(t) {
|
|
3093
3093
|
if (typeof t != "string") return null;
|
|
3094
3094
|
const n = t.toLowerCase();
|
|
3095
3095
|
return n === "customer" ? "customer" : n === "supplier" ? "supplier" : null;
|
|
3096
3096
|
}
|
|
3097
|
-
const
|
|
3098
|
-
function
|
|
3099
|
-
const { t } =
|
|
3100
|
-
const
|
|
3101
|
-
return i !== "All" && (
|
|
3102
|
-
}, [i, o, l, c, g, h]), { data: d, isLoading: p } =
|
|
3097
|
+
const zr = ["25", "50", "100", "200"];
|
|
3098
|
+
function Mr() {
|
|
3099
|
+
const { t } = Z(), n = Oe(), { doctype: a } = bt(), s = oa(a ?? ""), [i] = ae("status", "All"), [o] = ae("from", ""), [l] = ae("to", ""), [c] = ae("discarded", ""), [g] = ae("per_page", 50), [m] = ae("page", 1), h = m - 1, u = Ye(), N = (C) => u({ page: C === 0 ? null : C + 1 }), x = (C) => u({ status: C === "All" ? null : C, page: null }), v = (C) => u({ from: C || null, page: null }), f = (C) => u({ to: C || null, page: null }), T = (C) => u({ discarded: C ? "1" : null, page: null }), P = (C) => u({ per_page: C, page: null }), b = Ce(() => {
|
|
3100
|
+
const C = {};
|
|
3101
|
+
return i !== "All" && (C.status = i), o && (C.from_date = o), l && (C.to_date = l), c && (C.include_discarded = "true"), C.limit = g, C.offset = h * g, C;
|
|
3102
|
+
}, [i, o, l, c, g, h]), { data: d, isLoading: p } = xr(a ?? "", b), _ = (d == null ? void 0 : d.rows) ?? [], y = (d == null ? void 0 : d.total) ?? 0, B = Math.max(1, Math.ceil(y / g)), D = y === 0 ? 0 : h * g + 1, O = Math.min(y, (h + 1) * g), G = Ce(() => {
|
|
3103
3103
|
if (!s) return [];
|
|
3104
|
-
const
|
|
3104
|
+
const C = Yn(), w = (q) => {
|
|
3105
3105
|
const A = q.split("_").map((z) => z.charAt(0).toUpperCase() + z.slice(1)).join(" ");
|
|
3106
3106
|
return t(`fields.${A}`, { defaultValue: A });
|
|
3107
3107
|
};
|
|
3108
3108
|
return s.listColumns.map((q) => {
|
|
3109
3109
|
if (q === "name")
|
|
3110
|
-
return
|
|
3110
|
+
return C.accessor("name", {
|
|
3111
3111
|
header: t("fields.Name", { defaultValue: "Name" }),
|
|
3112
3112
|
cell: (A) => /* @__PURE__ */ e(
|
|
3113
3113
|
be,
|
|
@@ -3119,25 +3119,25 @@ function zr() {
|
|
|
3119
3119
|
)
|
|
3120
3120
|
});
|
|
3121
3121
|
if (q === "status")
|
|
3122
|
-
return
|
|
3122
|
+
return C.accessor("status", {
|
|
3123
3123
|
header: t("fields.Status", { defaultValue: "Status" }),
|
|
3124
3124
|
cell: (A) => /* @__PURE__ */ e(ln, { status: A.getValue() })
|
|
3125
3125
|
});
|
|
3126
3126
|
if (Lr.has(q))
|
|
3127
|
-
return
|
|
3127
|
+
return C.accessor(q, {
|
|
3128
3128
|
header: w(q),
|
|
3129
3129
|
cell: (A) => {
|
|
3130
3130
|
var z;
|
|
3131
|
-
return
|
|
3131
|
+
return Le(A.getValue(), ((z = A.row.original) == null ? void 0 : z.currency) || n);
|
|
3132
3132
|
}
|
|
3133
3133
|
});
|
|
3134
3134
|
if (q === "party")
|
|
3135
|
-
return
|
|
3135
|
+
return C.accessor("party", {
|
|
3136
3136
|
header: t("fields.Party", { defaultValue: "Party" }),
|
|
3137
3137
|
cell: (A) => {
|
|
3138
3138
|
const z = A.getValue();
|
|
3139
3139
|
if (!z) return "-";
|
|
3140
|
-
const Y =
|
|
3140
|
+
const Y = qr(A.row.original.party_type), re = Y ? Xt(Y, String(z)) : null;
|
|
3141
3141
|
return re ? /* @__PURE__ */ e(
|
|
3142
3142
|
be,
|
|
3143
3143
|
{
|
|
@@ -3151,7 +3151,7 @@ function zr() {
|
|
|
3151
3151
|
});
|
|
3152
3152
|
if (An[q]) {
|
|
3153
3153
|
const A = An[q];
|
|
3154
|
-
return
|
|
3154
|
+
return C.accessor(q, {
|
|
3155
3155
|
header: w(q),
|
|
3156
3156
|
cell: (z) => {
|
|
3157
3157
|
const Y = z.getValue();
|
|
@@ -3169,17 +3169,17 @@ function zr() {
|
|
|
3169
3169
|
}
|
|
3170
3170
|
});
|
|
3171
3171
|
}
|
|
3172
|
-
return
|
|
3172
|
+
return Or.has(q) ? C.accessor(q, {
|
|
3173
3173
|
header: w(q),
|
|
3174
3174
|
cell: (A) => Ft(A.getValue())
|
|
3175
|
-
}) :
|
|
3175
|
+
}) : C.accessor(q, {
|
|
3176
3176
|
header: w(q)
|
|
3177
3177
|
});
|
|
3178
3178
|
});
|
|
3179
|
-
}, [s, t, n]), ee =
|
|
3179
|
+
}, [s, t, n]), ee = Jn({
|
|
3180
3180
|
data: _,
|
|
3181
3181
|
columns: G,
|
|
3182
|
-
getCoreRowModel:
|
|
3182
|
+
getCoreRowModel: Zn()
|
|
3183
3183
|
});
|
|
3184
3184
|
return s ? /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
3185
3185
|
/* @__PURE__ */ e("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ e(be, { to: `/app/${s.slug}/new`, children: /* @__PURE__ */ e(H, { children: t("common.new") }) }) }),
|
|
@@ -3188,12 +3188,12 @@ function zr() {
|
|
|
3188
3188
|
He,
|
|
3189
3189
|
{
|
|
3190
3190
|
label: t("fields.Status", { defaultValue: "Status" }),
|
|
3191
|
-
options:
|
|
3192
|
-
value:
|
|
3193
|
-
label:
|
|
3191
|
+
options: Er.map((C) => ({
|
|
3192
|
+
value: C,
|
|
3193
|
+
label: C === "All" ? t("common.all") : t(`status.${C}`, { defaultValue: C })
|
|
3194
3194
|
})),
|
|
3195
3195
|
value: i,
|
|
3196
|
-
onChange: (
|
|
3196
|
+
onChange: (C) => x(C.target.value)
|
|
3197
3197
|
}
|
|
3198
3198
|
),
|
|
3199
3199
|
/* @__PURE__ */ e(
|
|
@@ -3202,7 +3202,7 @@ function zr() {
|
|
|
3202
3202
|
label: t("fields.From Date", { defaultValue: "From Date" }),
|
|
3203
3203
|
type: "date",
|
|
3204
3204
|
value: o,
|
|
3205
|
-
onChange: (
|
|
3205
|
+
onChange: (C) => v(C.target.value)
|
|
3206
3206
|
}
|
|
3207
3207
|
),
|
|
3208
3208
|
/* @__PURE__ */ e(
|
|
@@ -3211,7 +3211,7 @@ function zr() {
|
|
|
3211
3211
|
label: t("fields.To Date", { defaultValue: "To Date" }),
|
|
3212
3212
|
type: "date",
|
|
3213
3213
|
value: l,
|
|
3214
|
-
onChange: (
|
|
3214
|
+
onChange: (C) => f(C.target.value)
|
|
3215
3215
|
}
|
|
3216
3216
|
),
|
|
3217
3217
|
/* @__PURE__ */ r("label", { className: "flex h-10 items-center gap-2 text-sm text-fg-muted", children: [
|
|
@@ -3221,16 +3221,16 @@ function zr() {
|
|
|
3221
3221
|
type: "checkbox",
|
|
3222
3222
|
className: "h-4 w-4 rounded border-line text-brand focus:ring-brand/30",
|
|
3223
3223
|
checked: !!c,
|
|
3224
|
-
onChange: (
|
|
3224
|
+
onChange: (C) => T(C.target.checked)
|
|
3225
3225
|
}
|
|
3226
3226
|
),
|
|
3227
3227
|
t("common.showDiscarded")
|
|
3228
3228
|
] })
|
|
3229
3229
|
] }),
|
|
3230
|
-
/* @__PURE__ */ e($t, { onSelect: (
|
|
3230
|
+
/* @__PURE__ */ e($t, { onSelect: (C, w) => u({ from: C, to: w, page: null }) }),
|
|
3231
3231
|
p ? /* @__PURE__ */ e("p", { className: "text-fg-muted", children: t("common.loading") }) : _.length === 0 ? /* @__PURE__ */ e("p", { className: "py-8 text-center text-fg-muted", children: t("reports.noDocuments") }) : /* @__PURE__ */ r(we, { children: [
|
|
3232
3232
|
/* @__PURE__ */ e("div", { className: "overflow-x-auto rounded-xl bg-surface ring-1 ring-line shadow-card", children: /* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-line text-sm", children: [
|
|
3233
|
-
/* @__PURE__ */ e("thead", { className: "bg-surface-subtle", children: ee.getHeaderGroups().map((
|
|
3233
|
+
/* @__PURE__ */ e("thead", { className: "bg-surface-subtle", children: ee.getHeaderGroups().map((C) => /* @__PURE__ */ e("tr", { children: C.headers.map((w) => /* @__PURE__ */ e(
|
|
3234
3234
|
"th",
|
|
3235
3235
|
{
|
|
3236
3236
|
className: "px-4 py-3 text-left text-xs font-medium uppercase tracking-wide text-fg-muted",
|
|
@@ -3240,11 +3240,11 @@ function zr() {
|
|
|
3240
3240
|
)
|
|
3241
3241
|
},
|
|
3242
3242
|
w.id
|
|
3243
|
-
)) },
|
|
3244
|
-
/* @__PURE__ */ e("tbody", { className: "divide-y divide-line", children: ee.getRowModel().rows.map((
|
|
3243
|
+
)) }, C.id)) }),
|
|
3244
|
+
/* @__PURE__ */ e("tbody", { className: "divide-y divide-line", children: ee.getRowModel().rows.map((C) => /* @__PURE__ */ e("tr", { className: "transition-colors hover:bg-surface-subtle", children: C.getVisibleCells().map((w) => /* @__PURE__ */ e("td", { className: "px-4 py-2.5 text-fg", children: It(
|
|
3245
3245
|
w.column.columnDef.cell,
|
|
3246
3246
|
w.getContext()
|
|
3247
|
-
) }, w.id)) },
|
|
3247
|
+
) }, w.id)) }, C.id)) })
|
|
3248
3248
|
] }) }),
|
|
3249
3249
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-center justify-between gap-3 text-sm text-fg-muted", children: [
|
|
3250
3250
|
/* @__PURE__ */ r("div", { children: [
|
|
@@ -3267,9 +3267,9 @@ function zr() {
|
|
|
3267
3267
|
"select",
|
|
3268
3268
|
{
|
|
3269
3269
|
value: g,
|
|
3270
|
-
onChange: (
|
|
3270
|
+
onChange: (C) => P(Number(C.target.value)),
|
|
3271
3271
|
className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
|
|
3272
|
-
children:
|
|
3272
|
+
children: zr.map((C) => /* @__PURE__ */ e("option", { value: C, children: C }, C))
|
|
3273
3273
|
}
|
|
3274
3274
|
)
|
|
3275
3275
|
] }),
|
|
@@ -3308,14 +3308,14 @@ function zr() {
|
|
|
3308
3308
|
a
|
|
3309
3309
|
] });
|
|
3310
3310
|
}
|
|
3311
|
-
function
|
|
3311
|
+
function Se({
|
|
3312
3312
|
label: t,
|
|
3313
3313
|
value: n,
|
|
3314
3314
|
onChange: a,
|
|
3315
3315
|
linkDoctype: s,
|
|
3316
3316
|
readOnly: i
|
|
3317
3317
|
}) {
|
|
3318
|
-
const [o, l] =
|
|
3318
|
+
const [o, l] = S(n ?? ""), [c, g] = S([]), [m, h] = S(!1), [u, N] = S(!1), [x, v] = S({}), f = te(null), T = te(null), P = te(null), b = te(null), d = te(!1);
|
|
3319
3319
|
se(() => {
|
|
3320
3320
|
l(n ?? "");
|
|
3321
3321
|
}, [n]);
|
|
@@ -3362,9 +3362,9 @@ function Ce({
|
|
|
3362
3362
|
};
|
|
3363
3363
|
return se(() => {
|
|
3364
3364
|
const O = (G) => {
|
|
3365
|
-
var
|
|
3365
|
+
var C, w;
|
|
3366
3366
|
const ee = G.target;
|
|
3367
|
-
(
|
|
3367
|
+
(C = T.current) != null && C.contains(ee) || (w = P.current) != null && w.contains(ee) || h(!1);
|
|
3368
3368
|
};
|
|
3369
3369
|
return document.addEventListener("mousedown", O), () => document.removeEventListener("mousedown", O);
|
|
3370
3370
|
}, []), i ? /* @__PURE__ */ r("div", { children: [
|
|
@@ -3384,13 +3384,13 @@ function Ce({
|
|
|
3384
3384
|
},
|
|
3385
3385
|
onBlur: D,
|
|
3386
3386
|
placeholder: `Search ${s}...`,
|
|
3387
|
-
className:
|
|
3387
|
+
className: Ee(
|
|
3388
3388
|
"block h-9 w-full rounded-lg bg-surface px-3 text-sm text-fg ring-1 ring-line transition-all placeholder:text-fg-muted/70 focus:outline-none focus:ring-2 focus:ring-brand/30",
|
|
3389
3389
|
u && "bg-surface-subtle"
|
|
3390
3390
|
)
|
|
3391
3391
|
}
|
|
3392
3392
|
),
|
|
3393
|
-
m && c.length > 0 &&
|
|
3393
|
+
m && c.length > 0 && Xn(
|
|
3394
3394
|
/* @__PURE__ */ e("div", { ref: P, style: x, className: "max-h-48 overflow-y-auto rounded-lg bg-surface ring-1 ring-line shadow-card-hover", children: c.map((O, G) => {
|
|
3395
3395
|
const ee = O.name ?? O.id ?? String(O);
|
|
3396
3396
|
return /* @__PURE__ */ e(
|
|
@@ -3416,9 +3416,9 @@ const _t = () => ({
|
|
|
3416
3416
|
position_title: "",
|
|
3417
3417
|
position_blurb: "",
|
|
3418
3418
|
is_recommended: 0
|
|
3419
|
-
}),
|
|
3419
|
+
}), Fr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
3420
3420
|
function Pn() {
|
|
3421
|
-
const { name: t } = bt(), n = !t, a = ze(), s = We(), { t: i } =
|
|
3421
|
+
const { name: t } = bt(), n = !t, a = ze(), s = We(), { t: i } = Z(), o = (w, q) => i(w, { defaultValue: q }), [l, c] = S({
|
|
3422
3422
|
title: "Offerte",
|
|
3423
3423
|
customer: "",
|
|
3424
3424
|
company: "",
|
|
@@ -3426,7 +3426,7 @@ function Pn() {
|
|
|
3426
3426
|
partner_name: "",
|
|
3427
3427
|
partner_email: "",
|
|
3428
3428
|
cover_letter: ""
|
|
3429
|
-
}), [g, m] =
|
|
3429
|
+
}), [g, m] = S([_t()]), [h, u] = S(null), [N, x] = S(!1), [v, f] = S(null), T = te(null), P = (w, q) => c((A) => ({ ...A, [w]: q })), { data: b } = oe({
|
|
3430
3430
|
queryKey: ["document", "proposal", t],
|
|
3431
3431
|
queryFn: () => I.getDocument("proposal", t),
|
|
3432
3432
|
enabled: !n
|
|
@@ -3489,7 +3489,7 @@ function Pn() {
|
|
|
3489
3489
|
x(!1);
|
|
3490
3490
|
}
|
|
3491
3491
|
}
|
|
3492
|
-
},
|
|
3492
|
+
}, C = async () => {
|
|
3493
3493
|
if (!n) {
|
|
3494
3494
|
x(!0);
|
|
3495
3495
|
try {
|
|
@@ -3528,8 +3528,8 @@ function Pn() {
|
|
|
3528
3528
|
/* @__PURE__ */ r("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
3529
3529
|
/* @__PURE__ */ e(J, { label: o("fields.Title", "Title"), value: l.title, onChange: (w) => P("title", w.target.value) }),
|
|
3530
3530
|
/* @__PURE__ */ e(J, { label: o("fields.Date", "Date"), type: "date", value: l.proposal_date, onChange: (w) => P("proposal_date", w.target.value) }),
|
|
3531
|
-
/* @__PURE__ */ e(
|
|
3532
|
-
/* @__PURE__ */ e(
|
|
3531
|
+
/* @__PURE__ */ e(Se, { label: o("fields.Customer", "Customer"), value: l.customer, onChange: (w) => P("customer", w), linkDoctype: "customer", readOnly: !1 }),
|
|
3532
|
+
/* @__PURE__ */ e(Se, { label: o("fields.Company", "Company"), value: l.company, onChange: (w) => P("company", w), linkDoctype: "company", readOnly: !1 }),
|
|
3533
3533
|
/* @__PURE__ */ e(J, { label: o("fields.Partner", "Account Manager"), value: l.partner_name, onChange: (w) => P("partner_name", w.target.value) }),
|
|
3534
3534
|
/* @__PURE__ */ e(J, { label: o("fields.Partner Email", "Account Manager Email"), value: l.partner_email, onChange: (w) => P("partner_email", w.target.value) })
|
|
3535
3535
|
] }),
|
|
@@ -3556,8 +3556,8 @@ function Pn() {
|
|
|
3556
3556
|
] }),
|
|
3557
3557
|
g.map((w, q) => /* @__PURE__ */ r("div", { className: "rounded-lg p-3 ring-1 ring-line", children: [
|
|
3558
3558
|
/* @__PURE__ */ r("div", { className: "mb-2 flex items-center gap-2", children: [
|
|
3559
|
-
/* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children:
|
|
3560
|
-
/* @__PURE__ */ e("div", { className: "flex-1", children: /* @__PURE__ */ e(
|
|
3559
|
+
/* @__PURE__ */ e("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-brand/10 text-sm font-bold text-brand", children: Fr[q] ?? q + 1 }),
|
|
3560
|
+
/* @__PURE__ */ e("div", { className: "flex-1", children: /* @__PURE__ */ e(Se, { label: "", value: w.quotation, onChange: (A) => B(q, { quotation: A }), linkDoctype: "quotation", readOnly: !1 }) }),
|
|
3561
3561
|
/* @__PURE__ */ e("button", { type: "button", onClick: () => G(q, -1), disabled: q === 0, className: "px-1 text-fg-muted disabled:opacity-30", children: "↑" }),
|
|
3562
3562
|
/* @__PURE__ */ e("button", { type: "button", onClick: () => G(q, 1), disabled: q === g.length - 1, className: "px-1 text-fg-muted disabled:opacity-30", children: "↓" }),
|
|
3563
3563
|
/* @__PURE__ */ e("button", { type: "button", onClick: () => O(q), className: "px-1 text-red-500 hover:text-red-700", children: "✕" })
|
|
@@ -3579,7 +3579,7 @@ function Pn() {
|
|
|
3579
3579
|
"📎 ",
|
|
3580
3580
|
h
|
|
3581
3581
|
] }),
|
|
3582
|
-
/* @__PURE__ */ e("button", { type: "button", onClick:
|
|
3582
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: C, disabled: N, className: "text-red-500 hover:underline", children: o("common.remove", "Remove") })
|
|
3583
3583
|
] }) : /* @__PURE__ */ r("div", { children: [
|
|
3584
3584
|
/* @__PURE__ */ e("input", { ref: T, type: "file", accept: "application/pdf", onChange: ee, className: "hidden" }),
|
|
3585
3585
|
/* @__PURE__ */ e(H, { size: "sm", variant: "secondary", disabled: N, onClick: () => {
|
|
@@ -3591,10 +3591,10 @@ function Pn() {
|
|
|
3591
3591
|
] })
|
|
3592
3592
|
] });
|
|
3593
3593
|
}
|
|
3594
|
-
const
|
|
3595
|
-
function
|
|
3594
|
+
const $r = ["25", "50", "100", "200"];
|
|
3595
|
+
function Ur() {
|
|
3596
3596
|
var d;
|
|
3597
|
-
const { type: t } = bt(), n = ze(), s = (d =
|
|
3597
|
+
const { type: t } = bt(), n = ze(), s = (d = Ct().state) == null ? void 0 : d.notice, [i] = ae("per_page", 50), [o] = ae("page", 1), l = o - 1, c = Ye(), g = (p) => c({ page: p === 0 ? null : p + 1 }), m = (p) => c({ per_page: p, page: null }), { data: h, isLoading: u } = oe({
|
|
3598
3598
|
queryKey: ["masters", t, l, i],
|
|
3599
3599
|
queryFn: () => I.listMasters(t, {
|
|
3600
3600
|
include_disabled: 1,
|
|
@@ -3602,9 +3602,9 @@ function $r() {
|
|
|
3602
3602
|
offset: l * i
|
|
3603
3603
|
}),
|
|
3604
3604
|
enabled: !!t
|
|
3605
|
-
}), N = (h == null ? void 0 : h.rows) ?? [], x = (h == null ? void 0 : h.total) ?? 0, v = Math.max(1, Math.ceil(x / i)), f = x === 0 ? 0 : l * i + 1, T = Math.min(x, (l + 1) * i), P =
|
|
3605
|
+
}), N = (h == null ? void 0 : h.rows) ?? [], x = (h == null ? void 0 : h.total) ?? 0, v = Math.max(1, Math.ceil(x / i)), f = x === 0 ? 0 : l * i + 1, T = Math.min(x, (l + 1) * i), P = Ce(() => {
|
|
3606
3606
|
if (!N || N.length === 0) return [];
|
|
3607
|
-
const p =
|
|
3607
|
+
const p = Yn();
|
|
3608
3608
|
return Object.keys(N[0]).map(
|
|
3609
3609
|
(y) => p.accessor(y, {
|
|
3610
3610
|
header: y.split("_").map((B) => B.charAt(0).toUpperCase() + B.slice(1)).join(" "),
|
|
@@ -3625,10 +3625,10 @@ function $r() {
|
|
|
3625
3625
|
}
|
|
3626
3626
|
})
|
|
3627
3627
|
);
|
|
3628
|
-
}, [N, t]), b =
|
|
3628
|
+
}, [N, t]), b = Jn({
|
|
3629
3629
|
data: N,
|
|
3630
3630
|
columns: P,
|
|
3631
|
-
getCoreRowModel:
|
|
3631
|
+
getCoreRowModel: Zn()
|
|
3632
3632
|
});
|
|
3633
3633
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
3634
3634
|
s && /* @__PURE__ */ e("div", { className: "rounded-md bg-amber-50 px-4 py-3 text-sm text-amber-800", children: s }),
|
|
@@ -3680,7 +3680,7 @@ function $r() {
|
|
|
3680
3680
|
value: i,
|
|
3681
3681
|
onChange: (p) => m(Number(p.target.value)),
|
|
3682
3682
|
className: "h-8 rounded-md bg-surface px-2 text-sm text-fg ring-1 ring-line transition-all focus:outline-none focus:ring-2 focus:ring-brand/30",
|
|
3683
|
-
children:
|
|
3683
|
+
children: $r.map((p) => /* @__PURE__ */ e("option", { value: p, children: p }, p))
|
|
3684
3684
|
}
|
|
3685
3685
|
)
|
|
3686
3686
|
] }),
|
|
@@ -3714,7 +3714,7 @@ function $r() {
|
|
|
3714
3714
|
] })
|
|
3715
3715
|
] });
|
|
3716
3716
|
}
|
|
3717
|
-
const
|
|
3717
|
+
const Vr = {
|
|
3718
3718
|
customer: [
|
|
3719
3719
|
{ name: "name", label: "ID", type: "text", required: !0 },
|
|
3720
3720
|
{ name: "customer_name", label: "Customer Name", type: "text", required: !0 },
|
|
@@ -3777,7 +3777,7 @@ const Ur = {
|
|
|
3777
3777
|
{ name: "tax_id", label: "Tax ID", type: "text" },
|
|
3778
3778
|
{ name: "iban", label: "IBAN", type: "text" }
|
|
3779
3779
|
]
|
|
3780
|
-
},
|
|
3780
|
+
}, Kr = {
|
|
3781
3781
|
customer: "Customer",
|
|
3782
3782
|
supplier: "Supplier",
|
|
3783
3783
|
item: "Item",
|
|
@@ -3786,7 +3786,7 @@ const Ur = {
|
|
|
3786
3786
|
}, _n = /* @__PURE__ */ new Set(["customer", "supplier", "item", "warehouse"]);
|
|
3787
3787
|
function Tn() {
|
|
3788
3788
|
var B;
|
|
3789
|
-
const { type: t, name: n } = bt(), a = ze(), s = We(), { t: i } =
|
|
3789
|
+
const { type: t, name: n } = bt(), a = ze(), s = We(), { t: i } = Z(), o = !n || n === "new", l = Kr[t ?? ""] ?? t ?? "", c = i(`masters.${t}.one`, { defaultValue: l }), g = Vr[t ?? ""] ?? [], m = (D) => i(`fields.${D.label}`, { defaultValue: D.label }), [h, u] = S({}), { data: N, isLoading: x } = oe({
|
|
3790
3790
|
queryKey: ["master", t, n],
|
|
3791
3791
|
queryFn: () => I.getMaster(t, n),
|
|
3792
3792
|
enabled: !!t && !!n && !o
|
|
@@ -3898,12 +3898,12 @@ function Tn() {
|
|
|
3898
3898
|
}
|
|
3899
3899
|
)
|
|
3900
3900
|
] }, D.name);
|
|
3901
|
-
const
|
|
3901
|
+
const C = D.type === "number" || D.type === "currency" ? "number" : D.type === "date" ? "date" : "text";
|
|
3902
3902
|
return /* @__PURE__ */ e(
|
|
3903
3903
|
J,
|
|
3904
3904
|
{
|
|
3905
3905
|
label: m(D),
|
|
3906
|
-
type:
|
|
3906
|
+
type: C,
|
|
3907
3907
|
step: D.type === "currency" ? "0.01" : void 0,
|
|
3908
3908
|
required: ee,
|
|
3909
3909
|
readOnly: G,
|
|
@@ -3911,7 +3911,7 @@ function Tn() {
|
|
|
3911
3911
|
value: h[D.name] ?? "",
|
|
3912
3912
|
onChange: (w) => p(
|
|
3913
3913
|
D.name,
|
|
3914
|
-
|
|
3914
|
+
C === "number" ? parseFloat(w.target.value) || 0 : w.target.value
|
|
3915
3915
|
)
|
|
3916
3916
|
},
|
|
3917
3917
|
D.name
|
|
@@ -3919,67 +3919,67 @@ function Tn() {
|
|
|
3919
3919
|
}) }) })
|
|
3920
3920
|
] });
|
|
3921
3921
|
}
|
|
3922
|
-
function
|
|
3922
|
+
function jr(t) {
|
|
3923
3923
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3924
3924
|
queryKey: ["report", "trial-balance", t],
|
|
3925
3925
|
queryFn: () => I.trialBalance(t)
|
|
3926
3926
|
});
|
|
3927
3927
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3928
3928
|
}
|
|
3929
|
-
function
|
|
3929
|
+
function Gr(t) {
|
|
3930
3930
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3931
3931
|
queryKey: ["report", "chart-of-accounts", t],
|
|
3932
3932
|
queryFn: () => I.chartOfAccounts(t)
|
|
3933
3933
|
});
|
|
3934
3934
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3935
3935
|
}
|
|
3936
|
-
function
|
|
3936
|
+
function Wr(t) {
|
|
3937
3937
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3938
3938
|
queryKey: ["report", "general-ledger", t],
|
|
3939
3939
|
queryFn: () => I.generalLedger(t)
|
|
3940
3940
|
});
|
|
3941
3941
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3942
3942
|
}
|
|
3943
|
-
function
|
|
3943
|
+
function Hr(t) {
|
|
3944
3944
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3945
3945
|
queryKey: ["report", "stock-balance", t],
|
|
3946
3946
|
queryFn: () => I.stockBalance(t)
|
|
3947
3947
|
});
|
|
3948
3948
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3949
3949
|
}
|
|
3950
|
-
function
|
|
3950
|
+
function Qr(t) {
|
|
3951
3951
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3952
3952
|
queryKey: ["report", "profit-and-loss", t],
|
|
3953
3953
|
queryFn: () => I.profitAndLoss(t)
|
|
3954
3954
|
});
|
|
3955
3955
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3956
3956
|
}
|
|
3957
|
-
function
|
|
3957
|
+
function Yr(t) {
|
|
3958
3958
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3959
3959
|
queryKey: ["report", "balance-sheet", t],
|
|
3960
3960
|
queryFn: () => I.balanceSheet(t)
|
|
3961
3961
|
});
|
|
3962
3962
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3963
3963
|
}
|
|
3964
|
-
function
|
|
3964
|
+
function Jr(t) {
|
|
3965
3965
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3966
3966
|
queryKey: ["report", "ar-aging", t],
|
|
3967
3967
|
queryFn: () => I.arAging(t)
|
|
3968
3968
|
});
|
|
3969
3969
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3970
3970
|
}
|
|
3971
|
-
function
|
|
3971
|
+
function Zr(t) {
|
|
3972
3972
|
const { data: n, isLoading: a, error: s, refetch: i } = oe({
|
|
3973
3973
|
queryKey: ["report", "ap-aging", t],
|
|
3974
3974
|
queryFn: () => I.apAging(t)
|
|
3975
3975
|
});
|
|
3976
3976
|
return { data: n, isLoading: a, error: s, refetch: i };
|
|
3977
3977
|
}
|
|
3978
|
-
function
|
|
3979
|
-
const { t } =
|
|
3978
|
+
function Xr() {
|
|
3979
|
+
const { t } = Z(), [n] = ae("company", ""), [a] = ae("from", ""), [s] = ae("to", ""), i = Ye(), [o, l] = S(n), [c, g] = S(a), [m, h] = S(s), u = Oe(o), N = (d) => Le(d, u), x = Ce(() => {
|
|
3980
3980
|
const d = {};
|
|
3981
3981
|
return n && (d.company = n), a && (d.from_date = a), s && (d.to_date = s), d;
|
|
3982
|
-
}, [n, a, s]), { data: v, isLoading: f, refetch: T } =
|
|
3982
|
+
}, [n, a, s]), { data: v, isLoading: f, refetch: T } = jr(x), P = () => {
|
|
3983
3983
|
i({
|
|
3984
3984
|
company: o || null,
|
|
3985
3985
|
from: c || null,
|
|
@@ -3989,7 +3989,7 @@ function Zr() {
|
|
|
3989
3989
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
3990
3990
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
3991
3991
|
/* @__PURE__ */ e(
|
|
3992
|
-
|
|
3992
|
+
Se,
|
|
3993
3993
|
{
|
|
3994
3994
|
label: t("fields.Company", { defaultValue: "Company" }),
|
|
3995
3995
|
value: o,
|
|
@@ -4052,17 +4052,17 @@ function Zr() {
|
|
|
4052
4052
|
] })
|
|
4053
4053
|
] });
|
|
4054
4054
|
}
|
|
4055
|
-
const
|
|
4056
|
-
function
|
|
4057
|
-
const { t } =
|
|
4055
|
+
const es = ["Asset", "Liability", "Equity", "Income", "Expense"];
|
|
4056
|
+
function ts() {
|
|
4057
|
+
const { t } = Z(), n = (/* @__PURE__ */ new Date()).getFullYear(), [a, s] = S(String(n)), [i, o] = S(/* @__PURE__ */ new Set()), l = Ce(() => {
|
|
4058
4058
|
const b = [];
|
|
4059
4059
|
for (let d = n; d >= n - 6; d--)
|
|
4060
4060
|
b.push({ value: String(d), label: String(d) });
|
|
4061
4061
|
return b.push({ value: "all", label: t("coa.allTime", { defaultValue: "All time" }) }), b;
|
|
4062
|
-
}, [n, t]), c =
|
|
4062
|
+
}, [n, t]), c = Ce(() => {
|
|
4063
4063
|
const b = {};
|
|
4064
4064
|
return a !== "all" && (b.from_date = `${a}-01-01`, b.to_date = `${a}-12-31`), b;
|
|
4065
|
-
}, [a]), { data: g, isLoading: m } =
|
|
4065
|
+
}, [a]), { data: g, isLoading: m } = Gr(c), h = Oe(""), u = (b) => Le(b, h), N = (g == null ? void 0 : g.accounts) ?? [], { childrenOf: x, rootsByType: v } = Ce(() => {
|
|
4066
4066
|
const b = new Map(N.map((_) => [_.name, _])), d = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map();
|
|
4067
4067
|
for (const _ of N)
|
|
4068
4068
|
if (_.parent_account && b.has(_.parent_account)) {
|
|
@@ -4132,21 +4132,21 @@ function es() {
|
|
|
4132
4132
|
] }),
|
|
4133
4133
|
m && /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("common.loading", { defaultValue: "Loading…" }) }) }),
|
|
4134
4134
|
!m && N.length === 0 && /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-fg-muted", children: t("coa.empty", { defaultValue: "No accounts found. Complete the company setup first." }) }) }),
|
|
4135
|
-
!m &&
|
|
4135
|
+
!m && es.filter((b) => (v.get(b) ?? []).length > 0).map((b) => /* @__PURE__ */ r($, { children: [
|
|
4136
4136
|
/* @__PURE__ */ e("h3", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-fg-muted", children: t(`coa.rootType.${b}`, { defaultValue: b }) }),
|
|
4137
4137
|
/* @__PURE__ */ e("div", { children: (v.get(b) ?? []).map((d) => P(d, 0)) })
|
|
4138
4138
|
] }, b))
|
|
4139
4139
|
] });
|
|
4140
4140
|
}
|
|
4141
|
-
function
|
|
4141
|
+
function ns(t) {
|
|
4142
4142
|
return t.toLowerCase().replace(/\s+/g, "-");
|
|
4143
4143
|
}
|
|
4144
|
-
const
|
|
4145
|
-
function
|
|
4146
|
-
const { t } =
|
|
4144
|
+
const as = ["25", "50", "100", "200"];
|
|
4145
|
+
function rs() {
|
|
4146
|
+
const { t } = Z(), [n] = ae("account", ""), [a] = ae("party", ""), [s] = ae("from", ""), [i] = ae("to", ""), [o] = ae("per_page", 50), [l] = ae("page", 1), c = l - 1, g = Ye(), m = (A) => g({ page: A === 0 ? null : A + 1 }), h = (A) => g({ per_page: A, page: null }), [u, N] = S(n), [x, v] = S(a), [f, T] = S(s), [P, b] = S(i), d = Oe(), p = (A) => Le(A, d), _ = Ce(() => {
|
|
4147
4147
|
const A = {};
|
|
4148
4148
|
return n && (A.account = n), a && (A.party = a), s && (A.from_date = s), i && (A.to_date = i), A.limit = String(o), A.offset = String(c * o), A;
|
|
4149
|
-
}, [n, a, s, i, o, c]), { data: y, isLoading: B, refetch: D } =
|
|
4149
|
+
}, [n, a, s, i, o, c]), { data: y, isLoading: B, refetch: D } = Wr(_), O = (y == null ? void 0 : y.rows) ?? [], G = (y == null ? void 0 : y.total) ?? 0, ee = Math.max(1, Math.ceil(G / o)), C = G === 0 ? 0 : c * o + 1, w = Math.min(G, (c + 1) * o), q = () => {
|
|
4150
4150
|
g({
|
|
4151
4151
|
account: u || null,
|
|
4152
4152
|
party: x || null,
|
|
@@ -4158,7 +4158,7 @@ function as() {
|
|
|
4158
4158
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4159
4159
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4160
4160
|
/* @__PURE__ */ e(
|
|
4161
|
-
|
|
4161
|
+
Se,
|
|
4162
4162
|
{
|
|
4163
4163
|
label: t("fields.Account", { defaultValue: "Account" }),
|
|
4164
4164
|
value: u,
|
|
@@ -4168,7 +4168,7 @@ function as() {
|
|
|
4168
4168
|
}
|
|
4169
4169
|
),
|
|
4170
4170
|
/* @__PURE__ */ e(
|
|
4171
|
-
|
|
4171
|
+
Se,
|
|
4172
4172
|
{
|
|
4173
4173
|
label: t("fields.Party", { defaultValue: "Party" }),
|
|
4174
4174
|
value: x,
|
|
@@ -4223,7 +4223,7 @@ function as() {
|
|
|
4223
4223
|
/* @__PURE__ */ e("td", { className: "px-4 py-2", children: A.voucher_type && A.voucher_no ? /* @__PURE__ */ e(
|
|
4224
4224
|
be,
|
|
4225
4225
|
{
|
|
4226
|
-
to: `/app/${
|
|
4226
|
+
to: `/app/${ns(A.voucher_type)}/${A.voucher_no}`,
|
|
4227
4227
|
className: "font-medium text-blue-600 hover:text-blue-800",
|
|
4228
4228
|
children: A.voucher_no
|
|
4229
4229
|
}
|
|
@@ -4235,7 +4235,7 @@ function as() {
|
|
|
4235
4235
|
t("common.showing"),
|
|
4236
4236
|
" ",
|
|
4237
4237
|
/* @__PURE__ */ r("span", { className: "font-medium text-gray-900", children: [
|
|
4238
|
-
|
|
4238
|
+
C,
|
|
4239
4239
|
"–",
|
|
4240
4240
|
w
|
|
4241
4241
|
] }),
|
|
@@ -4253,7 +4253,7 @@ function as() {
|
|
|
4253
4253
|
value: o,
|
|
4254
4254
|
onChange: (A) => h(Number(A.target.value)),
|
|
4255
4255
|
className: "rounded border border-gray-300 bg-white px-2 py-1 text-sm",
|
|
4256
|
-
children:
|
|
4256
|
+
children: as.map((A) => /* @__PURE__ */ e("option", { value: A, children: A }, A))
|
|
4257
4257
|
}
|
|
4258
4258
|
)
|
|
4259
4259
|
] }),
|
|
@@ -4289,11 +4289,11 @@ function as() {
|
|
|
4289
4289
|
] })
|
|
4290
4290
|
] });
|
|
4291
4291
|
}
|
|
4292
|
-
function
|
|
4293
|
-
const { t } =
|
|
4292
|
+
function ss() {
|
|
4293
|
+
const { t } = Z(), [n] = ae("item_code", ""), [a] = ae("warehouse", ""), s = Ye(), [i, o] = S(n), [l, c] = S(a), g = Oe(), m = (f) => Le(f, g), h = Ce(() => {
|
|
4294
4294
|
const f = {};
|
|
4295
4295
|
return n && (f.item_code = n), a && (f.warehouse = a), f;
|
|
4296
|
-
}, [n, a]), { data: u, isLoading: N, refetch: x } =
|
|
4296
|
+
}, [n, a]), { data: u, isLoading: N, refetch: x } = Hr(h), v = () => {
|
|
4297
4297
|
s({
|
|
4298
4298
|
item_code: i || null,
|
|
4299
4299
|
warehouse: l || null
|
|
@@ -4302,7 +4302,7 @@ function rs() {
|
|
|
4302
4302
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4303
4303
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4304
4304
|
/* @__PURE__ */ e(
|
|
4305
|
-
|
|
4305
|
+
Se,
|
|
4306
4306
|
{
|
|
4307
4307
|
label: t("fields.Item Code", { defaultValue: "Item Code" }),
|
|
4308
4308
|
value: i,
|
|
@@ -4312,7 +4312,7 @@ function rs() {
|
|
|
4312
4312
|
}
|
|
4313
4313
|
),
|
|
4314
4314
|
/* @__PURE__ */ e(
|
|
4315
|
-
|
|
4315
|
+
Se,
|
|
4316
4316
|
{
|
|
4317
4317
|
label: t("fields.Warehouse", { defaultValue: "Warehouse" }),
|
|
4318
4318
|
value: l,
|
|
@@ -4343,11 +4343,11 @@ function rs() {
|
|
|
4343
4343
|
] }) }) })
|
|
4344
4344
|
] });
|
|
4345
4345
|
}
|
|
4346
|
-
function
|
|
4347
|
-
const { t } =
|
|
4346
|
+
function is() {
|
|
4347
|
+
const { t } = Z(), [n] = ae("company", ""), [a] = ae("from", ""), [s] = ae("to", ""), i = Ye(), [o, l] = S(n), c = Oe(o), g = (d) => Le(d, c), [m, h] = S(a), [u, N] = S(s), x = Ce(() => {
|
|
4348
4348
|
const d = {};
|
|
4349
4349
|
return n && (d.company = n), a && (d.from_date = a), s && (d.to_date = s), d;
|
|
4350
|
-
}, [n, a, s]), { data: v, isLoading: f, refetch: T } =
|
|
4350
|
+
}, [n, a, s]), { data: v, isLoading: f, refetch: T } = Qr(x), P = () => {
|
|
4351
4351
|
i({
|
|
4352
4352
|
company: o || null,
|
|
4353
4353
|
from: m || null,
|
|
@@ -4356,7 +4356,7 @@ function ss() {
|
|
|
4356
4356
|
}, b = v && (v.income && v.income.length > 0 || v.expense && v.expense.length > 0);
|
|
4357
4357
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4358
4358
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4359
|
-
/* @__PURE__ */ e(
|
|
4359
|
+
/* @__PURE__ */ e(Se, { label: t("fields.Company", { defaultValue: "Company" }), value: o, onChange: l, linkDoctype: "company", readOnly: !1 }),
|
|
4360
4360
|
/* @__PURE__ */ e(J, { label: t("fields.From Date", { defaultValue: "From Date" }), type: "date", value: m, onChange: (d) => h(d.target.value) }),
|
|
4361
4361
|
/* @__PURE__ */ e(J, { label: t("fields.To Date", { defaultValue: "To Date" }), type: "date", value: u, onChange: (d) => N(d.target.value) }),
|
|
4362
4362
|
/* @__PURE__ */ e(H, { onClick: P, children: t("common.apply") })
|
|
@@ -4408,7 +4408,7 @@ function ss() {
|
|
|
4408
4408
|
] });
|
|
4409
4409
|
}
|
|
4410
4410
|
function Gt({ title: t, rows: n, total: a, totalLabel: s, currency: i }) {
|
|
4411
|
-
const { t: o } =
|
|
4411
|
+
const { t: o } = Z(), l = (c) => Le(c, i);
|
|
4412
4412
|
return /* @__PURE__ */ r($, { children: [
|
|
4413
4413
|
/* @__PURE__ */ e("h3", { className: "mb-3 text-base font-semibold text-gray-800", children: t }),
|
|
4414
4414
|
/* @__PURE__ */ r("table", { className: "min-w-full divide-y divide-gray-200 text-sm", children: [
|
|
@@ -4427,17 +4427,17 @@ function Gt({ title: t, rows: n, total: a, totalLabel: s, currency: i }) {
|
|
|
4427
4427
|
] })
|
|
4428
4428
|
] });
|
|
4429
4429
|
}
|
|
4430
|
-
function
|
|
4430
|
+
function os() {
|
|
4431
4431
|
var P, b, d;
|
|
4432
|
-
const { t } =
|
|
4432
|
+
const { t } = Z(), [n] = ae("company", ""), [a] = ae("as_of_date", ""), s = Ye(), [i, o] = S(n), [l, c] = S(a), g = Oe(i), m = (p) => Le(p, g), h = Ce(() => {
|
|
4433
4433
|
const p = {};
|
|
4434
4434
|
return n && (p.company = n), a && (p.as_of_date = a), p;
|
|
4435
|
-
}, [n, a]), { data: u, isLoading: N, refetch: x } =
|
|
4435
|
+
}, [n, a]), { data: u, isLoading: N, refetch: x } = Yr(h), v = () => {
|
|
4436
4436
|
s({ company: i || null, as_of_date: l || null }), x();
|
|
4437
4437
|
}, f = u && (((P = u.assets) == null ? void 0 : P.length) > 0 || ((b = u.liabilities) == null ? void 0 : b.length) > 0 || ((d = u.equity) == null ? void 0 : d.length) > 0), T = u ? Math.abs(u.total_assets - u.total_liabilities_and_equity) < 0.01 : !1;
|
|
4438
4438
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4439
4439
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4440
|
-
/* @__PURE__ */ e(
|
|
4440
|
+
/* @__PURE__ */ e(Se, { label: t("fields.Company", { defaultValue: "Company" }), value: i, onChange: o, linkDoctype: "company", readOnly: !1 }),
|
|
4441
4441
|
/* @__PURE__ */ e(J, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (p) => c(p.target.value) }),
|
|
4442
4442
|
/* @__PURE__ */ e(H, { onClick: v, children: t("common.apply") })
|
|
4443
4443
|
] }),
|
|
@@ -4466,16 +4466,16 @@ function is() {
|
|
|
4466
4466
|
] }) : /* @__PURE__ */ e("p", { className: "py-8 text-center text-gray-400", children: t("reports.noData") })
|
|
4467
4467
|
] });
|
|
4468
4468
|
}
|
|
4469
|
-
function
|
|
4470
|
-
const { t } =
|
|
4469
|
+
function ls() {
|
|
4470
|
+
const { t } = Z(), [n] = ae("company", ""), [a] = ae("as_of_date", ""), s = Ye(), [i, o] = S(n), [l, c] = S(a), g = Oe(i), m = (f) => Le(f, g), h = Ce(() => {
|
|
4471
4471
|
const f = {};
|
|
4472
4472
|
return n && (f.company = n), a && (f.as_of_date = a), f;
|
|
4473
|
-
}, [n, a]), { data: u, isLoading: N, refetch: x } =
|
|
4473
|
+
}, [n, a]), { data: u, isLoading: N, refetch: x } = Jr(h), v = () => {
|
|
4474
4474
|
s({ company: i || null, as_of_date: l || null }), x();
|
|
4475
4475
|
};
|
|
4476
4476
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4477
4477
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4478
|
-
/* @__PURE__ */ e(
|
|
4478
|
+
/* @__PURE__ */ e(Se, { label: t("fields.Company", { defaultValue: "Company" }), value: i, onChange: o, linkDoctype: "company", readOnly: !1 }),
|
|
4479
4479
|
/* @__PURE__ */ e(J, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (f) => c(f.target.value) }),
|
|
4480
4480
|
/* @__PURE__ */ e(H, { onClick: v, children: t("common.apply") })
|
|
4481
4481
|
] }),
|
|
@@ -4524,16 +4524,16 @@ function os() {
|
|
|
4524
4524
|
] }) }) })
|
|
4525
4525
|
] });
|
|
4526
4526
|
}
|
|
4527
|
-
function
|
|
4528
|
-
const { t } =
|
|
4527
|
+
function cs() {
|
|
4528
|
+
const { t } = Z(), [n] = ae("company", ""), [a] = ae("as_of_date", ""), s = Ye(), [i, o] = S(n), [l, c] = S(a), g = Oe(i), m = (f) => Le(f, g), h = Ce(() => {
|
|
4529
4529
|
const f = {};
|
|
4530
4530
|
return n && (f.company = n), a && (f.as_of_date = a), f;
|
|
4531
|
-
}, [n, a]), { data: u, isLoading: N, refetch: x } =
|
|
4531
|
+
}, [n, a]), { data: u, isLoading: N, refetch: x } = Zr(h), v = () => {
|
|
4532
4532
|
s({ company: i || null, as_of_date: l || null }), x();
|
|
4533
4533
|
};
|
|
4534
4534
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4535
4535
|
/* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
4536
|
-
/* @__PURE__ */ e(
|
|
4536
|
+
/* @__PURE__ */ e(Se, { label: t("fields.Company", { defaultValue: "Company" }), value: i, onChange: o, linkDoctype: "company", readOnly: !1 }),
|
|
4537
4537
|
/* @__PURE__ */ e(J, { label: t("fields.As of Date", { defaultValue: "As of Date" }), type: "date", value: l, onChange: (f) => c(f.target.value) }),
|
|
4538
4538
|
/* @__PURE__ */ e(H, { onClick: v, children: t("common.apply") })
|
|
4539
4539
|
] }),
|
|
@@ -4582,8 +4582,8 @@ function ls() {
|
|
|
4582
4582
|
] }) }) })
|
|
4583
4583
|
] });
|
|
4584
4584
|
}
|
|
4585
|
-
const
|
|
4586
|
-
function
|
|
4585
|
+
const ca = '(function(){"use strict";function u(r,t){const e=Number(r??0)||0;return t==null?e:Number(e.toFixed(t))}const p={flt:u,sum(r,t){return r.reduce((e,a)=>typeof t=="function"?e+u(t(a)):typeof t=="string"?e+u(a[t]):e+u(a),0)},count(r){return r.length},sortBy(r,t,e="asc"){const n=(e===!0?"desc":e===!1?"asc":e)==="desc"?-1:1;return[...r].sort((s,i)=>{const c=s[t],o=i[t];return c==null&&o==null?0:c==null?1:o==null?-1:c<o?-1*n:c>o?1*n:0})},topN(r,t,e=10){return typeof t=="number"?r.slice(0,t):p.sortBy(r,t,"desc").slice(0,e)},group(r,t,e){if(typeof t=="function"){const s=new Map;for(const i of r){const c=t(i),o=JSON.stringify(c);s.has(o)||s.set(o,{key:c,rows:[]}),s.get(o).rows.push(i)}return Array.from(s.values())}const a=t,n=new Map;for(const s of r){const i=a.map(f=>s[f]),c=JSON.stringify(i);if(!n.has(c)){const f={};a.forEach((l,m)=>{f[l]=i[m]});for(const[l,[m]]of Object.entries(e||{}))f[l]=0;n.set(c,f)}const o=n.get(c);for(const[f,[l,m]]of Object.entries(e||{}))l==="count"?o[f]=u(o[f])+1:o[f]=u(o[f])+u(s[m||f])}return Array.from(n.values())},leftJoin(r,t,e,a=e){const n=new Map(t.map(s=>[s[a],s]));return r.map(s=>({...s,...n.get(s[e])||{}}))},monthKey(r){return String(r??"").slice(0,7)},quarterKey(r){const t=String(r??""),e=t.slice(0,4),a=Number(t.slice(5,7));return!e||!a?"":`${e}-Q${Math.floor((a+2)/3)}`},yearKey(r){return String(r??"").slice(0,4)},pivot(r,t,e,a){const n=new Map;for(const s of r){const i=String(s[t]??"—"),c=String(s[e]??"—");n.has(i)||n.set(i,{[t]:i});const o=n.get(i);o[c]=u(o[c])+u(s[a])}return Array.from(n.values())}};function y(r){if(!r||typeof r!="object")throw new Error("Transform must return an object");if(r.tables&&!Array.isArray(r.tables))throw new Error("tables must be an array");if(r.charts&&!Array.isArray(r.charts))throw new Error("charts must be an array");if(r.kpis&&!Array.isArray(r.kpis))throw new Error("kpis must be an array");return r}self.onmessage=r=>{try{const t=Object.fromEntries(r.data.datasets.map(s=>[s.name,s.rows])),e=r.data.datasets.map(s=>s.name).filter(s=>/^[$A-Z_][0-9A-Z_$]*$/i.test(s)).map(s=>`const ${s} = datasets[${JSON.stringify(s)}];`).join(`\n`),n=new Function("datasets","params","helpers",`"use strict";\n${e}\n${r.data.transformJs}`)(t,r.data.params||{},p);self.postMessage({ok:!0,output:y(n)})}catch(t){self.postMessage({ok:!1,error:t instanceof Error?t.message:String(t)})}}})();\n//# sourceMappingURL=report-runtime.worker-DrBTCfV6.js.map\n', Rn = typeof self < "u" && self.Blob && new Blob([ca], { type: "text/javascript;charset=utf-8" });
|
|
4586
|
+
function ds(t) {
|
|
4587
4587
|
let n;
|
|
4588
4588
|
try {
|
|
4589
4589
|
if (n = Rn && (self.URL || self.webkitURL).createObjectURL(Rn), !n) throw "";
|
|
@@ -4595,7 +4595,7 @@ function cs(t) {
|
|
|
4595
4595
|
}), a;
|
|
4596
4596
|
} catch {
|
|
4597
4597
|
return new Worker(
|
|
4598
|
-
"data:text/javascript;charset=utf-8," + encodeURIComponent(
|
|
4598
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(ca),
|
|
4599
4599
|
{
|
|
4600
4600
|
name: t == null ? void 0 : t.name
|
|
4601
4601
|
}
|
|
@@ -4604,7 +4604,7 @@ function cs(t) {
|
|
|
4604
4604
|
n && (self.URL || self.webkitURL).revokeObjectURL(n);
|
|
4605
4605
|
}
|
|
4606
4606
|
}
|
|
4607
|
-
function
|
|
4607
|
+
function us() {
|
|
4608
4608
|
const t = /* @__PURE__ */ new Date(), n = t.toISOString().slice(0, 10), a = new Date(t);
|
|
4609
4609
|
a.setMonth(a.getMonth() - 12);
|
|
4610
4610
|
const s = a.toISOString().slice(0, 10);
|
|
@@ -4675,15 +4675,15 @@ return {
|
|
|
4675
4675
|
2
|
|
4676
4676
|
);
|
|
4677
4677
|
}
|
|
4678
|
-
const
|
|
4679
|
-
function
|
|
4680
|
-
const t = ze(), { sessions: n, createSession: a } = ut(), [s] = ae("report_id", ""), [i] = ae("metric", ""), [o] = ae("group_by", ""), [l] = ae("from", ""), [c] = ae("to", ""), [g] = ae("company", ""), [m, h] =
|
|
4678
|
+
const da = us();
|
|
4679
|
+
function ms() {
|
|
4680
|
+
const t = ze(), { sessions: n, createSession: a } = ut(), [s] = ae("report_id", ""), [i] = ae("metric", ""), [o] = ae("group_by", ""), [l] = ae("from", ""), [c] = ae("to", ""), [g] = ae("company", ""), [m, h] = S(da), [u, N] = S([]), [x, v] = S(null), [f, T] = S(""), [P, b] = S(!1), [d, p] = S(!1), [_, y] = S(""), B = te(null), D = te(""), O = te(""), G = te(0), ee = Ce(() => !i || !o ? "" : JSON.stringify(fs({
|
|
4681
4681
|
metric: i,
|
|
4682
4682
|
groupBy: o,
|
|
4683
4683
|
fromDate: l || void 0,
|
|
4684
4684
|
toDate: c || void 0,
|
|
4685
4685
|
company: g || void 0
|
|
4686
|
-
}), null, 2), [i, o, l, c, g]),
|
|
4686
|
+
}), null, 2), [i, o, l, c, g]), C = async (z) => {
|
|
4687
4687
|
var ce;
|
|
4688
4688
|
const Y = ++G.current, re = () => G.current === Y;
|
|
4689
4689
|
T(""), b(!0);
|
|
@@ -4691,15 +4691,15 @@ function us() {
|
|
|
4691
4691
|
const _e = JSON.parse(z ?? m), pe = await I.runtimeData({ requests: _e.data_requests || [] });
|
|
4692
4692
|
if (!re()) return;
|
|
4693
4693
|
N(pe.datasets), (ce = B.current) == null || ce.terminate();
|
|
4694
|
-
const fe = new
|
|
4694
|
+
const fe = new ds();
|
|
4695
4695
|
B.current = fe;
|
|
4696
|
-
const Ue = await new Promise((
|
|
4696
|
+
const Ue = await new Promise((E, ne) => {
|
|
4697
4697
|
const Re = window.setTimeout(() => {
|
|
4698
4698
|
fe.terminate(), ne(new Error("Report runtime exceeded 4 seconds"));
|
|
4699
4699
|
}, 4e3);
|
|
4700
4700
|
fe.onmessage = (De) => {
|
|
4701
4701
|
var Ve, Me;
|
|
4702
|
-
window.clearTimeout(Re), fe.terminate(), B.current === fe && (B.current = null), (Ve = De.data) != null && Ve.ok ?
|
|
4702
|
+
window.clearTimeout(Re), fe.terminate(), B.current === fe && (B.current = null), (Ve = De.data) != null && Ve.ok ? E(De.data.output) : ne(new Error(((Me = De.data) == null ? void 0 : Me.error) || "Runtime failed"));
|
|
4703
4703
|
}, fe.postMessage({
|
|
4704
4704
|
datasets: pe.datasets,
|
|
4705
4705
|
params: {},
|
|
@@ -4720,18 +4720,18 @@ function us() {
|
|
|
4720
4720
|
return s ? D.current === s ? void 0 : (p(!0), T(""), I.getRuntimeDraft(s).then((Y) => {
|
|
4721
4721
|
if (z) return;
|
|
4722
4722
|
const re = JSON.stringify(Y.definition, null, 2);
|
|
4723
|
-
return D.current = s, O.current = re, y(Y.source_chat_session_id || ""), h(re),
|
|
4723
|
+
return D.current = s, O.current = re, y(Y.source_chat_session_id || ""), h(re), C(re);
|
|
4724
4724
|
}).catch((Y) => {
|
|
4725
4725
|
z || (v(null), T(Y instanceof Error ? Y.message : String(Y)));
|
|
4726
4726
|
}).finally(() => {
|
|
4727
4727
|
z || p(!1);
|
|
4728
4728
|
}), () => {
|
|
4729
4729
|
z = !0;
|
|
4730
|
-
}) : (D.current = "", O.current = "", y(""), ee && (O.current = ee, h(ee),
|
|
4730
|
+
}) : (D.current = "", O.current = "", y(""), ee && (O.current = ee, h(ee), C(ee)), () => {
|
|
4731
4731
|
z = !0;
|
|
4732
4732
|
});
|
|
4733
4733
|
}, [s, ee]);
|
|
4734
|
-
const w = !!(!s && ee), q =
|
|
4734
|
+
const w = !!(!s && ee), q = Ce(() => gs(x), [x]), A = async () => {
|
|
4735
4735
|
var pe;
|
|
4736
4736
|
const z = m.trim() !== O.current.trim(), Y = s || "unsaved-runtime-report", re = u.map((fe) => ({
|
|
4737
4737
|
name: fe.name,
|
|
@@ -4780,10 +4780,10 @@ function us() {
|
|
|
4780
4780
|
s
|
|
4781
4781
|
] }) : w ? /* @__PURE__ */ e("div", { className: "text-xs text-gray-500", children: "Loaded runtime report from legacy URL filters." }) : null,
|
|
4782
4782
|
s ? /* @__PURE__ */ e(H, { variant: "secondary", onClick: () => void A(), children: "Fix In Chat" }) : null,
|
|
4783
|
-
/* @__PURE__ */ e(H, { onClick: () => void
|
|
4783
|
+
/* @__PURE__ */ e(H, { onClick: () => void C(), disabled: P, children: P ? "Running..." : "Run Report" })
|
|
4784
4784
|
] })
|
|
4785
4785
|
] }) }),
|
|
4786
|
-
d ? /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : f ? /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: f }) }) : x ? /* @__PURE__ */ e(
|
|
4786
|
+
d ? /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Loading draft..." }) }) : f ? /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: f }) }) : x ? /* @__PURE__ */ e(ps, { output: x }) : /* @__PURE__ */ e($, { children: /* @__PURE__ */ e("p", { className: "text-sm text-gray-600", children: "Edit the runtime JSON below or open a draft from chat, then run the report." }) }),
|
|
4787
4787
|
u.length > 0 && /* @__PURE__ */ e($, { title: "Fetched Datasets", children: /* @__PURE__ */ e("div", { className: "space-y-4", children: u.map((z) => /* @__PURE__ */ r("div", { className: "rounded-md border border-gray-200 p-4", children: [
|
|
4788
4788
|
/* @__PURE__ */ r("div", { className: "flex items-baseline justify-between gap-4", children: [
|
|
4789
4789
|
/* @__PURE__ */ r("div", { children: [
|
|
@@ -4812,12 +4812,12 @@ function us() {
|
|
|
4812
4812
|
] })
|
|
4813
4813
|
] });
|
|
4814
4814
|
}
|
|
4815
|
-
function
|
|
4815
|
+
function ps({ output: t }) {
|
|
4816
4816
|
var i, o;
|
|
4817
4817
|
const n = Oe(), a = (t.tables ?? []).map((l, c) => ({
|
|
4818
4818
|
...l,
|
|
4819
4819
|
id: l.id || `table_${c + 1}`
|
|
4820
|
-
})), s =
|
|
4820
|
+
})), s = ua(a);
|
|
4821
4821
|
return /* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
4822
4822
|
/* @__PURE__ */ r($, { children: [
|
|
4823
4823
|
/* @__PURE__ */ e("div", { className: "flex items-baseline justify-between gap-4", children: /* @__PURE__ */ r("div", { children: [
|
|
@@ -4833,10 +4833,10 @@ function ms({ output: t }) {
|
|
|
4833
4833
|
const g = l.dataTable ? s.get(l.dataTable) : void 0, m = l.data ?? (g == null ? void 0 : g.rows) ?? [];
|
|
4834
4834
|
if (!m.length)
|
|
4835
4835
|
return /* @__PURE__ */ e($, { title: l.title, children: /* @__PURE__ */ e("p", { className: "text-sm text-red-600", children: "Chart has no usable data." }) }, l.id || `chart_${c + 1}`);
|
|
4836
|
-
const h = l.type === "pie" ? [] : m.map((x) => String(x[l.x] ?? "")), u =
|
|
4836
|
+
const h = l.type === "pie" ? [] : m.map((x) => String(x[l.x] ?? "")), u = xs(h), N = Math.max(320, 200 + u.axisHeight);
|
|
4837
4837
|
return /* @__PURE__ */ r($, { children: [
|
|
4838
4838
|
/* @__PURE__ */ e("div", { className: "pb-3 text-sm font-semibold text-gray-700", children: l.title }),
|
|
4839
|
-
/* @__PURE__ */ e("div", { style: { height: N }, className: "w-full", children: /* @__PURE__ */ e(
|
|
4839
|
+
/* @__PURE__ */ e("div", { style: { height: N }, className: "w-full", children: /* @__PURE__ */ e(Ka, { width: "100%", height: "100%", children: l.type === "line" ? /* @__PURE__ */ r(ja, { data: m, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
|
|
4840
4840
|
/* @__PURE__ */ e(pn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
|
|
4841
4841
|
/* @__PURE__ */ e(
|
|
4842
4842
|
hn,
|
|
@@ -4851,11 +4851,11 @@ function ms({ output: t }) {
|
|
|
4851
4851
|
),
|
|
4852
4852
|
/* @__PURE__ */ e(gn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: In }),
|
|
4853
4853
|
/* @__PURE__ */ e(Vt, { formatter: (x) => kt(x, Wt(g, l.y), n) }),
|
|
4854
|
-
/* @__PURE__ */ e(
|
|
4855
|
-
] }) : l.type === "pie" ? /* @__PURE__ */ r(
|
|
4854
|
+
/* @__PURE__ */ e(Ga, { type: "monotone", dataKey: l.y, stroke: "#3b82f6", strokeWidth: 2, dot: { r: 3 } })
|
|
4855
|
+
] }) : l.type === "pie" ? /* @__PURE__ */ r(Wa, { children: [
|
|
4856
4856
|
/* @__PURE__ */ e(Vt, { formatter: (x) => kt(x, Wt(g, l.y), n) }),
|
|
4857
|
-
/* @__PURE__ */ e(
|
|
4858
|
-
] }) : /* @__PURE__ */ r(
|
|
4857
|
+
/* @__PURE__ */ e(Ha, { data: m, dataKey: l.y, nameKey: l.x, outerRadius: 110, children: m.map((x, v) => /* @__PURE__ */ e(Qa, { fill: Bn[v % Bn.length] }, v)) })
|
|
4858
|
+
] }) : /* @__PURE__ */ r(Ya, { data: m, margin: { top: 10, right: 20, left: 0, bottom: 0 }, children: [
|
|
4859
4859
|
/* @__PURE__ */ e(pn, { strokeDasharray: "3 3", stroke: "#f3f4f6" }),
|
|
4860
4860
|
/* @__PURE__ */ e(
|
|
4861
4861
|
hn,
|
|
@@ -4870,7 +4870,7 @@ function ms({ output: t }) {
|
|
|
4870
4870
|
),
|
|
4871
4871
|
/* @__PURE__ */ e(gn, { tick: { fill: "#6b7280", fontSize: 12 }, tickFormatter: In }),
|
|
4872
4872
|
/* @__PURE__ */ e(Vt, { formatter: (x) => kt(x, Wt(g, l.y), n) }),
|
|
4873
|
-
/* @__PURE__ */ e(
|
|
4873
|
+
/* @__PURE__ */ e(Ja, { dataKey: l.y, fill: "#3b82f6", radius: [4, 4, 0, 0] })
|
|
4874
4874
|
] }) }) })
|
|
4875
4875
|
] }, l.id || `chart_${c + 1}`);
|
|
4876
4876
|
}),
|
|
@@ -4880,21 +4880,21 @@ function ms({ output: t }) {
|
|
|
4880
4880
|
] }) }) }, l.id))
|
|
4881
4881
|
] });
|
|
4882
4882
|
}
|
|
4883
|
-
function
|
|
4883
|
+
function hs(t) {
|
|
4884
4884
|
return t.replace(/_/g, " ").replace(/\b\w/g, (n) => n.toUpperCase());
|
|
4885
4885
|
}
|
|
4886
|
-
function
|
|
4886
|
+
function ua(t) {
|
|
4887
4887
|
const n = /* @__PURE__ */ new Map();
|
|
4888
4888
|
for (const a of t)
|
|
4889
4889
|
n.set(a.id, a), a.title && n.set(a.title, a);
|
|
4890
4890
|
return n;
|
|
4891
4891
|
}
|
|
4892
|
-
function
|
|
4892
|
+
function gs(t) {
|
|
4893
4893
|
if (!t) return [];
|
|
4894
4894
|
const n = (t.tables ?? []).map((i, o) => ({
|
|
4895
4895
|
...i,
|
|
4896
4896
|
id: i.id || `table_${o + 1}`
|
|
4897
|
-
})), a =
|
|
4897
|
+
})), a = ua(n), s = [];
|
|
4898
4898
|
for (const i of t.charts ?? []) {
|
|
4899
4899
|
const o = i.dataTable ? a.get(i.dataTable) : void 0, l = i.data ?? (o == null ? void 0 : o.rows) ?? [];
|
|
4900
4900
|
if (!l.length) {
|
|
@@ -4905,8 +4905,8 @@ function hs(t) {
|
|
|
4905
4905
|
}
|
|
4906
4906
|
return s;
|
|
4907
4907
|
}
|
|
4908
|
-
function
|
|
4909
|
-
const n = `${
|
|
4908
|
+
function fs(t) {
|
|
4909
|
+
const n = `${ys(t.metric)} by ${hs(t.groupBy)}`, a = t.groupBy === "month" ? "helpers.monthKey" : t.groupBy === "quarter" ? "helpers.quarterKey" : "helpers.yearKey";
|
|
4910
4910
|
if (t.metric === "sales_revenue")
|
|
4911
4911
|
return yt({
|
|
4912
4912
|
title: n,
|
|
@@ -5009,7 +5009,7 @@ function gs(t) {
|
|
|
5009
5009
|
},
|
|
5010
5010
|
fields: [t.groupBy === "warehouse" ? "warehouse" : "item_code", "stock_value"],
|
|
5011
5011
|
chartType: "bar"
|
|
5012
|
-
}) : JSON.parse(
|
|
5012
|
+
}) : JSON.parse(da);
|
|
5013
5013
|
}
|
|
5014
5014
|
function yt(t) {
|
|
5015
5015
|
const n = Object.fromEntries(Object.entries(t.filters).filter(([, s]) => s !== void 0)), a = ["month", "quarter", "year"].includes(t.groupBy) ? `${t.timeBucket}(row.${t.keyField})` : `row.${t.keyField} || "—"`;
|
|
@@ -5065,7 +5065,7 @@ return {
|
|
|
5065
5065
|
};`
|
|
5066
5066
|
};
|
|
5067
5067
|
}
|
|
5068
|
-
function
|
|
5068
|
+
function ys(t) {
|
|
5069
5069
|
return {
|
|
5070
5070
|
sales_revenue: "Sales Revenue",
|
|
5071
5071
|
sales_returns: "Sales Returns",
|
|
@@ -5082,34 +5082,34 @@ function Wt(t, n) {
|
|
|
5082
5082
|
return ((a = t == null ? void 0 : t.columns.find((i) => i.key === n)) == null ? void 0 : a.type) || ((s = t == null ? void 0 : t.columns.find((i) => i.key === n)) == null ? void 0 : s.format);
|
|
5083
5083
|
}
|
|
5084
5084
|
function kt(t, n, a) {
|
|
5085
|
-
return n === "currency" ?
|
|
5085
|
+
return n === "currency" ? Le(Fe(t), a) : n === "percent" ? `${(Fe(t) * 100).toFixed(1)}%` : n === "number" ? Zt(Fe(t)) : n === "date" ? Ft(String(t ?? "")) : typeof t == "number" ? Zt(t) : String(t ?? "");
|
|
5086
5086
|
}
|
|
5087
5087
|
function In(t) {
|
|
5088
5088
|
const n = Math.abs(t);
|
|
5089
5089
|
return n >= 1e6 ? `${(t / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(t / 1e3).toFixed(0)}k` : String(t);
|
|
5090
5090
|
}
|
|
5091
|
-
const Bn = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"],
|
|
5091
|
+
const Bn = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4"], bs = '12px -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
5092
5092
|
let Ht = null;
|
|
5093
|
-
function
|
|
5093
|
+
function vs(t, n = bs) {
|
|
5094
5094
|
if (typeof document > "u") return t.length * 7;
|
|
5095
5095
|
Ht || (Ht = document.createElement("canvas"));
|
|
5096
5096
|
const a = Ht.getContext("2d");
|
|
5097
5097
|
return a ? (a.font = n, a.measureText(t).width) : t.length * 7;
|
|
5098
5098
|
}
|
|
5099
|
-
function
|
|
5099
|
+
function xs(t) {
|
|
5100
5100
|
if (!t.length) return { angle: 0, axisHeight: 30, maxWidth: 0 };
|
|
5101
|
-
const n = t.map((c) =>
|
|
5101
|
+
const n = t.map((c) => vs(c)), a = Math.max(1, ...n);
|
|
5102
5102
|
let s = 0;
|
|
5103
5103
|
a > 55 && (s = -30), a > 110 && (s = -45), a > 200 && (s = -60), a > 300 && (s = -90);
|
|
5104
5104
|
const i = Math.abs(s) * Math.PI / 180, o = s === 0 ? 20 : Math.abs(s) === 90 ? a : Math.ceil(a * Math.sin(i)), l = Math.min(280, Math.max(30, o + 18));
|
|
5105
5105
|
return { angle: s, axisHeight: l, maxWidth: a };
|
|
5106
5106
|
}
|
|
5107
|
-
const
|
|
5108
|
-
function
|
|
5107
|
+
const Ns = ["USD", "EUR", "GBP", "CHF", "JPY", "CAD", "AUD", "CNY", "INR"];
|
|
5108
|
+
function ws() {
|
|
5109
5109
|
const t = We(), { data: n, isLoading: a } = oe({
|
|
5110
5110
|
queryKey: ["setup-status"],
|
|
5111
5111
|
queryFn: () => I.setupStatus()
|
|
5112
|
-
}), [s, i] =
|
|
5112
|
+
}), [s, i] = S(""), [o, l] = S("USD"), [c, g] = S({
|
|
5113
5113
|
address: "",
|
|
5114
5114
|
city: "",
|
|
5115
5115
|
zip_code: "",
|
|
@@ -5117,7 +5117,7 @@ function Ns() {
|
|
|
5117
5117
|
email: "",
|
|
5118
5118
|
phone: "",
|
|
5119
5119
|
tax_id: ""
|
|
5120
|
-
}), m = (y) => (B) => g((D) => ({ ...D, [y]: B.target.value })), [h, u] =
|
|
5120
|
+
}), m = (y) => (B) => g((D) => ({ ...D, [y]: B.target.value })), [h, u] = S("quick"), [N, x] = S(!1), [v, f] = S(null), T = ie({
|
|
5121
5121
|
mutationFn: () => I.createCompany({ name: s, currency: o, ...c })
|
|
5122
5122
|
}), P = ie({
|
|
5123
5123
|
mutationFn: () => I.seedDemo()
|
|
@@ -5138,7 +5138,7 @@ function Ns() {
|
|
|
5138
5138
|
return /* @__PURE__ */ e("p", { className: "text-gray-500", children: "Loading..." });
|
|
5139
5139
|
if (n != null && n.setup_complete && !N)
|
|
5140
5140
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
5141
|
-
/* @__PURE__ */ e($, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((y, B) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(
|
|
5141
|
+
/* @__PURE__ */ e($, { title: "Companies", children: n.companies && n.companies.length > 0 ? /* @__PURE__ */ e("ul", { className: "divide-y divide-gray-100", children: n.companies.map((y, B) => /* @__PURE__ */ e("li", { className: "py-3", children: /* @__PURE__ */ e(ks, { company: y }) }, B)) }) : /* @__PURE__ */ e("p", { className: "text-gray-400", children: "No companies found" }) }),
|
|
5142
5142
|
/* @__PURE__ */ e(be, { to: "/", className: "text-blue-600 hover:text-blue-800 text-sm font-medium", children: "Go to Dashboard" })
|
|
5143
5143
|
] });
|
|
5144
5144
|
if (N)
|
|
@@ -5173,7 +5173,7 @@ function Ns() {
|
|
|
5173
5173
|
He,
|
|
5174
5174
|
{
|
|
5175
5175
|
label: "Currency",
|
|
5176
|
-
options:
|
|
5176
|
+
options: Ns,
|
|
5177
5177
|
value: o,
|
|
5178
5178
|
onChange: (y) => l(y.target.value)
|
|
5179
5179
|
}
|
|
@@ -5268,7 +5268,7 @@ function Ns() {
|
|
|
5268
5268
|
] }) })
|
|
5269
5269
|
] });
|
|
5270
5270
|
}
|
|
5271
|
-
function
|
|
5271
|
+
function ks({ company: t }) {
|
|
5272
5272
|
const n = [
|
|
5273
5273
|
[t.city, t.zip_code].filter(Boolean).join(" "),
|
|
5274
5274
|
t.country
|
|
@@ -5309,7 +5309,7 @@ function ws({ company: t }) {
|
|
|
5309
5309
|
t.default_currency && /* @__PURE__ */ e("span", { className: "shrink-0 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-600", children: t.default_currency })
|
|
5310
5310
|
] });
|
|
5311
5311
|
}
|
|
5312
|
-
const
|
|
5312
|
+
const Ss = [
|
|
5313
5313
|
{
|
|
5314
5314
|
number: 1,
|
|
5315
5315
|
title: "Set Up Your Company",
|
|
@@ -5446,7 +5446,7 @@ const ks = [
|
|
|
5446
5446
|
]
|
|
5447
5447
|
}
|
|
5448
5448
|
];
|
|
5449
|
-
function
|
|
5449
|
+
function ma() {
|
|
5450
5450
|
const t = ze(), { sessions: n, createSession: a } = ut();
|
|
5451
5451
|
return async (s) => {
|
|
5452
5452
|
var o;
|
|
@@ -5462,7 +5462,7 @@ function ua() {
|
|
|
5462
5462
|
};
|
|
5463
5463
|
}
|
|
5464
5464
|
function Cs() {
|
|
5465
|
-
const { t } =
|
|
5465
|
+
const { t } = Z(), n = ma();
|
|
5466
5466
|
return /* @__PURE__ */ e($, { className: "border-emerald-200 bg-gradient-to-br from-emerald-50 to-white", children: /* @__PURE__ */ r("div", { className: "flex flex-col gap-4 md:flex-row md:items-start", children: [
|
|
5467
5467
|
/* @__PURE__ */ e("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-lg font-bold text-emerald-700", children: "▶" }),
|
|
5468
5468
|
/* @__PURE__ */ r("div", { className: "flex-1 space-y-3", children: [
|
|
@@ -5497,8 +5497,8 @@ function Cs() {
|
|
|
5497
5497
|
] })
|
|
5498
5498
|
] }) });
|
|
5499
5499
|
}
|
|
5500
|
-
function
|
|
5501
|
-
const { t } =
|
|
5500
|
+
function Ds() {
|
|
5501
|
+
const { t } = Z(), n = ma(), a = [
|
|
5502
5502
|
t("tutorial.caPrompt1"),
|
|
5503
5503
|
t("tutorial.caPrompt2"),
|
|
5504
5504
|
t("tutorial.caPrompt3"),
|
|
@@ -5556,8 +5556,8 @@ function Ss() {
|
|
|
5556
5556
|
] })
|
|
5557
5557
|
] }) });
|
|
5558
5558
|
}
|
|
5559
|
-
function
|
|
5560
|
-
const { t } =
|
|
5559
|
+
function As() {
|
|
5560
|
+
const { t } = Z(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
|
|
5561
5561
|
return /* @__PURE__ */ r($, { children: [
|
|
5562
5562
|
/* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.flowTitle") }),
|
|
5563
5563
|
/* @__PURE__ */ r("div", { className: "space-y-4 text-sm text-gray-600", children: [
|
|
@@ -5627,8 +5627,8 @@ function Ds() {
|
|
|
5627
5627
|
] })
|
|
5628
5628
|
] });
|
|
5629
5629
|
}
|
|
5630
|
-
function
|
|
5631
|
-
const { t } =
|
|
5630
|
+
function Ps() {
|
|
5631
|
+
const { t } = Z(), n = (a) => t(`tutorial.chips.${a}`, { defaultValue: a });
|
|
5632
5632
|
return /* @__PURE__ */ r($, { children: [
|
|
5633
5633
|
/* @__PURE__ */ e("h3", { className: "text-base font-semibold text-gray-900 mb-3", children: t("tutorial.lifecycleTitle") }),
|
|
5634
5634
|
/* @__PURE__ */ r("div", { className: "space-y-2 text-sm text-gray-600", children: [
|
|
@@ -5663,8 +5663,8 @@ function As() {
|
|
|
5663
5663
|
] })
|
|
5664
5664
|
] });
|
|
5665
5665
|
}
|
|
5666
|
-
function
|
|
5667
|
-
const { t } =
|
|
5666
|
+
function _s() {
|
|
5667
|
+
const { t } = Z();
|
|
5668
5668
|
return /* @__PURE__ */ r("div", { className: "mx-auto max-w-3xl space-y-6", children: [
|
|
5669
5669
|
/* @__PURE__ */ r("div", { children: [
|
|
5670
5670
|
/* @__PURE__ */ e("h2", { className: "text-xl font-semibold text-gray-900", children: t("tutorial.pageTitle") }),
|
|
@@ -5688,10 +5688,10 @@ function Ps() {
|
|
|
5688
5688
|
/* @__PURE__ */ e("p", { className: "mt-4 text-sm text-gray-500", children: t("tutorial.manualIntro") })
|
|
5689
5689
|
] }),
|
|
5690
5690
|
/* @__PURE__ */ e(Cs, {}),
|
|
5691
|
-
/* @__PURE__ */ e(Ss, {}),
|
|
5692
5691
|
/* @__PURE__ */ e(Ds, {}),
|
|
5693
5692
|
/* @__PURE__ */ e(As, {}),
|
|
5694
|
-
|
|
5693
|
+
/* @__PURE__ */ e(Ps, {}),
|
|
5694
|
+
Ss.map((n) => {
|
|
5695
5695
|
var a;
|
|
5696
5696
|
return /* @__PURE__ */ e($, { children: /* @__PURE__ */ r("div", { className: "flex gap-4", children: [
|
|
5697
5697
|
/* @__PURE__ */ e("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100 text-sm font-bold text-blue-700", children: n.number }),
|
|
@@ -5752,17 +5752,17 @@ function Ps() {
|
|
|
5752
5752
|
] }) })
|
|
5753
5753
|
] });
|
|
5754
5754
|
}
|
|
5755
|
-
const Qt = 5,
|
|
5755
|
+
const Qt = 5, Ts = 10 * 1024 * 1024, Rs = /* @__PURE__ */ new Set([
|
|
5756
5756
|
"image/png",
|
|
5757
5757
|
"image/jpeg",
|
|
5758
5758
|
"image/gif",
|
|
5759
5759
|
"image/webp",
|
|
5760
5760
|
"application/pdf"
|
|
5761
5761
|
]);
|
|
5762
|
-
function
|
|
5762
|
+
function Is(t) {
|
|
5763
5763
|
return new Promise((n) => window.setTimeout(n, t));
|
|
5764
5764
|
}
|
|
5765
|
-
function
|
|
5765
|
+
function Bs(t) {
|
|
5766
5766
|
return new Promise((n, a) => {
|
|
5767
5767
|
const s = new FileReader();
|
|
5768
5768
|
s.onloadend = () => {
|
|
@@ -5771,14 +5771,14 @@ function Is(t) {
|
|
|
5771
5771
|
}, s.onerror = () => a(s.error ?? new Error("Could not read audio.")), s.readAsDataURL(t);
|
|
5772
5772
|
});
|
|
5773
5773
|
}
|
|
5774
|
-
function
|
|
5774
|
+
function En(t) {
|
|
5775
5775
|
if (!t) return "";
|
|
5776
5776
|
const n = new Date(t);
|
|
5777
5777
|
if (isNaN(n.getTime())) return "";
|
|
5778
5778
|
const a = /* @__PURE__ */ new Date();
|
|
5779
5779
|
return n.getFullYear() === a.getFullYear() && n.getMonth() === a.getMonth() && n.getDate() === a.getDate() ? n.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : n.getFullYear() === a.getFullYear() ? n.toLocaleDateString([], { day: "numeric", month: "short" }) : n.toLocaleDateString([], { day: "numeric", month: "short", year: "numeric" });
|
|
5780
5780
|
}
|
|
5781
|
-
function
|
|
5781
|
+
function Ln(t) {
|
|
5782
5782
|
if (!t) return "";
|
|
5783
5783
|
const n = new Date(t);
|
|
5784
5784
|
return isNaN(n.getTime()) ? "" : n.toLocaleString([], {
|
|
@@ -5792,7 +5792,7 @@ function En(t) {
|
|
|
5792
5792
|
});
|
|
5793
5793
|
}
|
|
5794
5794
|
function On() {
|
|
5795
|
-
const { t } =
|
|
5795
|
+
const { t } = Z(), { sessionId: n } = bt(), a = ze(), s = Ct(), [i] = qt(), o = i.get("demo") === "1", [l, c] = S(""), [g, m] = S(""), [h, u] = S([]), [N, x] = S(""), [v, f] = S(!1), [T, P] = S("idle"), b = te(null), d = te(null), p = te([]), {
|
|
5796
5796
|
connectionStatus: _,
|
|
5797
5797
|
connectionVersion: y,
|
|
5798
5798
|
createSession: B,
|
|
@@ -5800,7 +5800,7 @@ function On() {
|
|
|
5800
5800
|
completeDemoTyping: O,
|
|
5801
5801
|
loadHistory: G,
|
|
5802
5802
|
loadMoreHistory: ee,
|
|
5803
|
-
sendMessage:
|
|
5803
|
+
sendMessage: C,
|
|
5804
5804
|
transcribeAudio: w,
|
|
5805
5805
|
getMessages: q,
|
|
5806
5806
|
hasMoreHistory: A,
|
|
@@ -5808,7 +5808,7 @@ function On() {
|
|
|
5808
5808
|
isThinking: Y,
|
|
5809
5809
|
getDemoStatus: re,
|
|
5810
5810
|
getDemoTypingCue: ce
|
|
5811
|
-
} = ut(), ge = te(null), _e = te(null), pe = te(null), fe = te(null), [Ue,
|
|
5811
|
+
} = ut(), ge = te(null), _e = te(null), pe = te(null), fe = te(null), [Ue, E] = S(0), ne = te(!1), Re = te(null), De = te(0), Ve = te(!0), Me = te(null), vt = te(!1), mt = te(null), Je = q(n), ke = _ === "connected", Te = Y(n), Ke = re(n), Qe = ce(n), Ie = o || Ke === "running", pt = A(n), it = z(n), ht = Je[Je.length - 1], R = ht ? `${ht.type}:${ht.timestamp || ""}:${ht.content}` : "empty", V = Pe(() => {
|
|
5812
5812
|
vt.current = !0, mt.current !== null && window.clearTimeout(mt.current), mt.current = window.setTimeout(() => {
|
|
5813
5813
|
vt.current = !1, mt.current = null;
|
|
5814
5814
|
}, 600);
|
|
@@ -5816,37 +5816,37 @@ function On() {
|
|
|
5816
5816
|
const U = ge.current;
|
|
5817
5817
|
if (!U) return;
|
|
5818
5818
|
V(), U.scrollTo({ top: U.scrollHeight, behavior: k });
|
|
5819
|
-
const
|
|
5819
|
+
const X = () => {
|
|
5820
5820
|
const de = ge.current;
|
|
5821
5821
|
de && (!Ve.current && !Ie && !Te || de.scrollTop + de.clientHeight >= de.scrollHeight - 2 || (V(), de.scrollTo({ top: de.scrollHeight, behavior: "auto" })));
|
|
5822
5822
|
};
|
|
5823
|
-
requestAnimationFrame(
|
|
5823
|
+
requestAnimationFrame(X), window.setTimeout(X, 120);
|
|
5824
5824
|
}, [Ie, Te, V]);
|
|
5825
5825
|
un(() => {
|
|
5826
5826
|
const k = ge.current, U = Me.current;
|
|
5827
5827
|
if (!k || U === null) return;
|
|
5828
|
-
const
|
|
5829
|
-
|
|
5828
|
+
const X = k.scrollHeight - U;
|
|
5829
|
+
X > 0 && (k.scrollTop = k.scrollTop + X), Me.current = null;
|
|
5830
5830
|
}, [Je.length]), se(() => {
|
|
5831
5831
|
Me.current === null && (!Ve.current && !Ie && !Te || W(Ie ? "auto" : "smooth"));
|
|
5832
5832
|
}, [R, Ie, Te, W]), se(() => {
|
|
5833
5833
|
const k = ge.current;
|
|
5834
5834
|
if (!k || typeof ResizeObserver > "u") return;
|
|
5835
5835
|
let U = 0;
|
|
5836
|
-
const
|
|
5836
|
+
const X = new ResizeObserver(() => {
|
|
5837
5837
|
Me.current === null && (!Ve.current && !Ie && !Te || (cancelAnimationFrame(U), U = requestAnimationFrame(() => {
|
|
5838
5838
|
const he = ge.current;
|
|
5839
5839
|
if (!he) return;
|
|
5840
5840
|
he.scrollHeight - he.scrollTop - he.clientHeight <= 120 && (V(), he.scrollTo({ top: he.scrollHeight, behavior: "auto" }));
|
|
5841
5841
|
})));
|
|
5842
5842
|
}), de = k.firstElementChild;
|
|
5843
|
-
return de &&
|
|
5844
|
-
|
|
5843
|
+
return de && X.observe(de), X.observe(k), () => {
|
|
5844
|
+
X.disconnect(), cancelAnimationFrame(U);
|
|
5845
5845
|
};
|
|
5846
5846
|
}, [Ie, Te, V]), un(() => {
|
|
5847
5847
|
const k = fe.current;
|
|
5848
|
-
if (!k || (
|
|
5849
|
-
const U = new ResizeObserver(() =>
|
|
5848
|
+
if (!k || (E(k.offsetHeight), typeof ResizeObserver > "u")) return;
|
|
5849
|
+
const U = new ResizeObserver(() => E(k.offsetHeight));
|
|
5850
5850
|
return U.observe(k), () => U.disconnect();
|
|
5851
5851
|
}, []);
|
|
5852
5852
|
const ve = Pe(() => {
|
|
@@ -5857,7 +5857,7 @@ function On() {
|
|
|
5857
5857
|
});
|
|
5858
5858
|
}, [n, it, pt, ee]), xe = te(null);
|
|
5859
5859
|
se(() => {
|
|
5860
|
-
m(""), Re.current = null, De.current += 1, n &&
|
|
5860
|
+
m(""), Re.current = null, De.current += 1, n && sa(n);
|
|
5861
5861
|
const k = s.state;
|
|
5862
5862
|
k != null && k.prefillMessage && xe.current !== k ? (xe.current = k, c(k.prefillMessage), window.setTimeout(() => {
|
|
5863
5863
|
var U;
|
|
@@ -5887,8 +5887,8 @@ function On() {
|
|
|
5887
5887
|
}, [Te, ke]);
|
|
5888
5888
|
function ot(k) {
|
|
5889
5889
|
if (vt.current) return;
|
|
5890
|
-
const U = k.currentTarget,
|
|
5891
|
-
Ve.current =
|
|
5890
|
+
const U = k.currentTarget, X = U.scrollHeight - U.scrollTop - U.clientHeight;
|
|
5891
|
+
Ve.current = X < 80;
|
|
5892
5892
|
}
|
|
5893
5893
|
se(() => {
|
|
5894
5894
|
!n || !ke || !o || Re.current !== n && (Re.current = n, m(""), D(n).catch((k) => {
|
|
@@ -5905,12 +5905,12 @@ function On() {
|
|
|
5905
5905
|
se(() => {
|
|
5906
5906
|
if (!Qe || !n || Ze.current === Qe.seq) return;
|
|
5907
5907
|
Ze.current = Qe.seq;
|
|
5908
|
-
const k = n, U = Qe.content,
|
|
5908
|
+
const k = n, U = Qe.content, X = U.length > 0 ? Math.max(8, Qe.typingMs / U.length) : 0, de = Qe.seq, he = ++De.current;
|
|
5909
5909
|
async function et() {
|
|
5910
5910
|
c("");
|
|
5911
5911
|
for (const ft of U) {
|
|
5912
5912
|
if (he !== De.current) return;
|
|
5913
|
-
c((je) => je + ft), await
|
|
5913
|
+
c((je) => je + ft), await Is(X);
|
|
5914
5914
|
}
|
|
5915
5915
|
he === De.current && K.current(k, de);
|
|
5916
5916
|
}
|
|
@@ -5922,18 +5922,18 @@ function On() {
|
|
|
5922
5922
|
if (!n) return;
|
|
5923
5923
|
x("");
|
|
5924
5924
|
const U = Array.from(k);
|
|
5925
|
-
u((
|
|
5926
|
-
const de = [...
|
|
5925
|
+
u((X) => {
|
|
5926
|
+
const de = [...X];
|
|
5927
5927
|
for (const he of U) {
|
|
5928
5928
|
if (de.length >= Qt) {
|
|
5929
5929
|
x(`Maximum ${Qt} attachments per message.`);
|
|
5930
5930
|
break;
|
|
5931
5931
|
}
|
|
5932
|
-
if (!
|
|
5932
|
+
if (!Rs.has(he.type)) {
|
|
5933
5933
|
x(`Unsupported file type: ${he.type || he.name}`);
|
|
5934
5934
|
continue;
|
|
5935
5935
|
}
|
|
5936
|
-
if (he.size >
|
|
5936
|
+
if (he.size > Ts) {
|
|
5937
5937
|
x(`"${he.name}" is too large (max 10 MB).`);
|
|
5938
5938
|
continue;
|
|
5939
5939
|
}
|
|
@@ -5957,8 +5957,8 @@ function On() {
|
|
|
5957
5957
|
});
|
|
5958
5958
|
}, [n]), M = (k) => {
|
|
5959
5959
|
u((U) => {
|
|
5960
|
-
const
|
|
5961
|
-
return
|
|
5960
|
+
const X = U.find((de) => de.localId === k);
|
|
5961
|
+
return X != null && X.previewUrl && URL.revokeObjectURL(X.previewUrl), U.filter((de) => de.localId !== k);
|
|
5962
5962
|
});
|
|
5963
5963
|
}, F = (k) => {
|
|
5964
5964
|
k.dataTransfer.types.includes("Files") && (k.preventDefault(), f(!0));
|
|
@@ -5969,16 +5969,16 @@ function On() {
|
|
|
5969
5969
|
k.preventDefault(), f(!1), k.dataTransfer.files && k.dataTransfer.files.length > 0 && me(k.dataTransfer.files);
|
|
5970
5970
|
}, qe = (k) => {
|
|
5971
5971
|
const U = [];
|
|
5972
|
-
for (const
|
|
5973
|
-
if (
|
|
5974
|
-
const de =
|
|
5972
|
+
for (const X of k.clipboardData.items)
|
|
5973
|
+
if (X.kind === "file") {
|
|
5974
|
+
const de = X.getAsFile();
|
|
5975
5975
|
de && U.push(de);
|
|
5976
5976
|
}
|
|
5977
5977
|
U.length > 0 && (k.preventDefault(), me(U));
|
|
5978
5978
|
}, Ne = h.some((k) => k.uploading), le = h.some((k) => k.error), ue = h.filter((k) => k.uploadedId && !k.error).map((k) => k.uploadedId);
|
|
5979
5979
|
function gt() {
|
|
5980
5980
|
const k = l.trim();
|
|
5981
|
-
if (n && !(!k && ue.length === 0) && !Ne &&
|
|
5981
|
+
if (n && !(!k && ue.length === 0) && !Ne && C(n, k, ue.length > 0 ? ue : void 0)) {
|
|
5982
5982
|
for (const U of h)
|
|
5983
5983
|
U.previewUrl && URL.revokeObjectURL(U.previewUrl);
|
|
5984
5984
|
u([]), x(""), c("");
|
|
@@ -5989,12 +5989,12 @@ function On() {
|
|
|
5989
5989
|
}
|
|
5990
5990
|
function Xe(k) {
|
|
5991
5991
|
const U = k.trim();
|
|
5992
|
-
U && (c((
|
|
5993
|
-
const
|
|
5994
|
-
|
|
5992
|
+
U && (c((X) => X.trim() ? `${X.trim()} ${U}` : U), window.setTimeout(() => {
|
|
5993
|
+
const X = pe.current;
|
|
5994
|
+
X && (X.focus(), X.style.height = "auto", X.style.height = Math.min(Math.max(X.scrollHeight, 48), 120) + "px");
|
|
5995
5995
|
}, 0));
|
|
5996
5996
|
}
|
|
5997
|
-
async function
|
|
5997
|
+
async function xa() {
|
|
5998
5998
|
if (T !== "idle") return;
|
|
5999
5999
|
let k;
|
|
6000
6000
|
try {
|
|
@@ -6005,20 +6005,20 @@ function On() {
|
|
|
6005
6005
|
}
|
|
6006
6006
|
x("");
|
|
6007
6007
|
const U = new MediaRecorder(k);
|
|
6008
|
-
d.current = U, p.current = [], U.ondataavailable = (
|
|
6009
|
-
|
|
6008
|
+
d.current = U, p.current = [], U.ondataavailable = (X) => {
|
|
6009
|
+
X.data.size > 0 && p.current.push(X.data);
|
|
6010
6010
|
}, U.onstop = async () => {
|
|
6011
6011
|
var ft;
|
|
6012
6012
|
k.getTracks().forEach((je) => je.stop());
|
|
6013
|
-
const
|
|
6014
|
-
if (p.current = [], d.current = null,
|
|
6013
|
+
const X = p.current;
|
|
6014
|
+
if (p.current = [], d.current = null, X.length === 0) {
|
|
6015
6015
|
P("idle");
|
|
6016
6016
|
return;
|
|
6017
6017
|
}
|
|
6018
|
-
const de = U.mimeType || ((ft =
|
|
6018
|
+
const de = U.mimeType || ((ft = X[0]) == null ? void 0 : ft.type) || "audio/webm", he = new Blob(X, { type: de }), et = (de.split(";")[0].split("/")[1] || "webm").toLowerCase();
|
|
6019
6019
|
P("transcribing");
|
|
6020
6020
|
try {
|
|
6021
|
-
const je = await
|
|
6021
|
+
const je = await Bs(he), lt = await w(je, et, n);
|
|
6022
6022
|
Xe(lt);
|
|
6023
6023
|
} catch (je) {
|
|
6024
6024
|
x(je instanceof Error ? je.message : t("chat.transcribeFailed"));
|
|
@@ -6027,12 +6027,12 @@ function On() {
|
|
|
6027
6027
|
}
|
|
6028
6028
|
}, U.start(), P("recording");
|
|
6029
6029
|
}
|
|
6030
|
-
function
|
|
6030
|
+
function Na() {
|
|
6031
6031
|
const k = d.current;
|
|
6032
6032
|
k && k.state !== "inactive" && k.stop();
|
|
6033
6033
|
}
|
|
6034
|
-
function
|
|
6035
|
-
T === "recording" ?
|
|
6034
|
+
function wa() {
|
|
6035
|
+
T === "recording" ? Na() : T === "idle" && xa();
|
|
6036
6036
|
}
|
|
6037
6037
|
return n ? /* @__PURE__ */ r(
|
|
6038
6038
|
"div",
|
|
@@ -6172,7 +6172,7 @@ function On() {
|
|
|
6172
6172
|
/* @__PURE__ */ e(
|
|
6173
6173
|
"button",
|
|
6174
6174
|
{
|
|
6175
|
-
onClick:
|
|
6175
|
+
onClick: wa,
|
|
6176
6176
|
disabled: !ke || !n || Te || Ie || T === "transcribing",
|
|
6177
6177
|
className: `flex h-11 w-11 shrink-0 items-center justify-center rounded-lg transition-all disabled:cursor-not-allowed disabled:opacity-40 md:h-10 md:w-10 ${T === "recording" ? "bg-rose-500/10 text-rose-600 hover:bg-rose-500/20" : "text-fg-muted hover:bg-surface-subtle hover:text-fg"}`,
|
|
6178
6178
|
title: t(T === "recording" ? "chat.voiceStop" : T === "transcribing" ? "chat.voiceTranscribing" : "chat.voiceStart"),
|
|
@@ -6219,7 +6219,7 @@ function On() {
|
|
|
6219
6219
|
}
|
|
6220
6220
|
) : /* @__PURE__ */ e("div", { className: "flex h-full items-center justify-center text-fg-muted", children: t("chat.creating") });
|
|
6221
6221
|
}
|
|
6222
|
-
function
|
|
6222
|
+
function Es({ attachments: t }) {
|
|
6223
6223
|
return !t || t.length === 0 ? null : /* @__PURE__ */ e("div", { className: "mt-1 flex flex-wrap gap-1.5", children: t.map((n) => {
|
|
6224
6224
|
const a = I.getChatAttachmentUrl(n.id), s = n.mime_type.startsWith("image/");
|
|
6225
6225
|
return /* @__PURE__ */ r(
|
|
@@ -6242,11 +6242,11 @@ function Bs({ attachments: t }) {
|
|
|
6242
6242
|
function Ls({ message: t }) {
|
|
6243
6243
|
return t.type === "user" ? /* @__PURE__ */ e("div", { className: "flex justify-end", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-br-md bg-gradient-to-b from-brand to-brand/90 px-4 py-2.5 text-sm text-brand-fg ring-1 ring-black/10 shadow-bubble-user", children: [
|
|
6244
6244
|
/* @__PURE__ */ e("div", { className: "whitespace-pre-wrap", children: t.content }),
|
|
6245
|
-
/* @__PURE__ */ e(
|
|
6246
|
-
t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title:
|
|
6245
|
+
/* @__PURE__ */ e(Es, { attachments: t.attachments }),
|
|
6246
|
+
t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-brand-fg/70", title: Ln(t.timestamp), children: En(t.timestamp) })
|
|
6247
6247
|
] }) }) : t.type === "assistant" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "max-w-[80%] break-words rounded-2xl rounded-bl-md bg-surface px-4 py-2.5 text-sm text-fg ring-1 ring-line shadow-card", children: [
|
|
6248
|
-
/* @__PURE__ */ e(
|
|
6249
|
-
t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title:
|
|
6248
|
+
/* @__PURE__ */ e(Os, { content: t.content }),
|
|
6249
|
+
t.timestamp && /* @__PURE__ */ e("div", { className: "mt-1 text-right text-[10px] text-fg-muted", title: Ln(t.timestamp), children: En(t.timestamp) })
|
|
6250
6250
|
] }) }) : t.type === "thinking" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ r("div", { className: "flex items-center gap-2 rounded-full bg-surface px-3 py-1.5 text-xs text-fg-muted ring-1 ring-line shadow-card", children: [
|
|
6251
6251
|
/* @__PURE__ */ e("span", { className: "inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-brand" }),
|
|
6252
6252
|
t.content,
|
|
@@ -6285,7 +6285,7 @@ function Ls({ message: t }) {
|
|
|
6285
6285
|
}
|
|
6286
6286
|
) }) : t.type === "error" ? /* @__PURE__ */ e("div", { className: "flex justify-start", children: /* @__PURE__ */ e("div", { className: "max-w-[80%] rounded-2xl rounded-bl-md bg-rose-50 px-4 py-2.5 text-sm text-rose-700 ring-1 ring-rose-200 shadow-card", children: t.content }) }) : null;
|
|
6287
6287
|
}
|
|
6288
|
-
function
|
|
6288
|
+
function Os({ content: t }) {
|
|
6289
6289
|
const n = t.split(`
|
|
6290
6290
|
`), a = [];
|
|
6291
6291
|
let s = !1, i = [];
|
|
@@ -6321,15 +6321,15 @@ function Es({ content: t }) {
|
|
|
6321
6321
|
a.push(
|
|
6322
6322
|
/* @__PURE__ */ r("div", { className: "ml-3 flex gap-1", children: [
|
|
6323
6323
|
/* @__PURE__ */ e("span", { className: "text-fg-muted", children: "•" }),
|
|
6324
|
-
/* @__PURE__ */ e("span", { children:
|
|
6324
|
+
/* @__PURE__ */ e("span", { children: Lt(c) })
|
|
6325
6325
|
] }, l)
|
|
6326
6326
|
);
|
|
6327
6327
|
} else o.trim() === "" ? a.push(/* @__PURE__ */ e("div", { className: "h-2" }, l)) : a.push(
|
|
6328
|
-
/* @__PURE__ */ e("p", { className: "leading-relaxed", children:
|
|
6328
|
+
/* @__PURE__ */ e("p", { className: "leading-relaxed", children: Lt(o) }, l)
|
|
6329
6329
|
);
|
|
6330
6330
|
}), /* @__PURE__ */ e("div", { children: a });
|
|
6331
6331
|
}
|
|
6332
|
-
function
|
|
6332
|
+
function pa(t, n, a) {
|
|
6333
6333
|
const s = t.startsWith("/") && !t.startsWith("/api/"), i = "font-medium text-brand underline decoration-brand/40 underline-offset-2 transition-colors hover:decoration-brand";
|
|
6334
6334
|
return s ? /* @__PURE__ */ e(be, { to: t, className: i, children: n }, a) : /* @__PURE__ */ e(
|
|
6335
6335
|
"a",
|
|
@@ -6343,53 +6343,53 @@ function ma(t, n, a) {
|
|
|
6343
6343
|
a
|
|
6344
6344
|
);
|
|
6345
6345
|
}
|
|
6346
|
-
const
|
|
6347
|
-
function
|
|
6346
|
+
const qs = /(https?:\/\/[^\s)\]}"'<>]+|\/(?:reports|app|masters|admin|chat|setup|tutorial)[^\s)\]}"'<>]*)/g;
|
|
6347
|
+
function Lt(t) {
|
|
6348
6348
|
return t.split(/(\[[^\]]+\]\([^)]+\)|\*\*[^*]+?\*\*|`[^`]+`)/g).flatMap((a, s) => {
|
|
6349
6349
|
const i = a.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
|
|
6350
6350
|
if (i) {
|
|
6351
6351
|
const [, o, l] = i;
|
|
6352
|
-
return
|
|
6352
|
+
return pa(l, Lt(o), s);
|
|
6353
6353
|
}
|
|
6354
|
-
return a.startsWith("**") && a.endsWith("**") && a.length > 4 ? /* @__PURE__ */ e("strong", { className: "font-semibold", children:
|
|
6354
|
+
return a.startsWith("**") && a.endsWith("**") && a.length > 4 ? /* @__PURE__ */ e("strong", { className: "font-semibold", children: Lt(a.slice(2, -2)) }, s) : a.startsWith("`") && a.endsWith("`") ? /* @__PURE__ */ e(
|
|
6355
6355
|
"code",
|
|
6356
6356
|
{
|
|
6357
6357
|
className: "rounded bg-gray-200 px-1 py-0.5 text-xs font-mono",
|
|
6358
6358
|
children: a.slice(1, -1)
|
|
6359
6359
|
},
|
|
6360
6360
|
s
|
|
6361
|
-
) :
|
|
6361
|
+
) : zs(a, `${s}`);
|
|
6362
6362
|
});
|
|
6363
6363
|
}
|
|
6364
|
-
function
|
|
6364
|
+
function zs(t, n) {
|
|
6365
6365
|
const a = [];
|
|
6366
6366
|
let s = 0, i;
|
|
6367
|
-
const o = new RegExp(
|
|
6367
|
+
const o = new RegExp(qs.source, "g");
|
|
6368
6368
|
let l = 0;
|
|
6369
6369
|
for (; (i = o.exec(t)) !== null; ) {
|
|
6370
6370
|
const c = i.index;
|
|
6371
6371
|
let g = i[0], m = "";
|
|
6372
6372
|
for (; g.length > 0 && /[.,;:!?]$/.test(g); )
|
|
6373
6373
|
m = g.slice(-1) + m, g = g.slice(0, -1);
|
|
6374
|
-
c > s && a.push(t.slice(s, c)), a.push(
|
|
6374
|
+
c > s && a.push(t.slice(s, c)), a.push(pa(g, g, `${n}-u${l}`)), m && a.push(m), s = c + i[0].length, l += 1;
|
|
6375
6375
|
}
|
|
6376
6376
|
return s < t.length && a.push(t.slice(s)), a.length > 0 ? a : [t];
|
|
6377
6377
|
}
|
|
6378
|
-
function
|
|
6379
|
-
const t = ze(), [n] = qt(), { user: a, login: s, register: i } = st(), { t: o } =
|
|
6378
|
+
function Ms() {
|
|
6379
|
+
const t = ze(), [n] = qt(), { user: a, login: s, register: i } = st(), { t: o } = Z(), l = n.get("invite") || "", [c, g] = S(l ? "register" : "login"), [m, h] = S(!1), [u, N] = S(!1), [x, v] = S([]), [f, T] = S(!0), [P, b] = S(""), [d, p] = S(""), [_, y] = S(""), [B, D] = S(""), [O, G] = S("");
|
|
6380
6380
|
se(() => {
|
|
6381
6381
|
a && a.role !== "public_manager" && t("/", { replace: !0 });
|
|
6382
6382
|
}, [a, t]), se(() => {
|
|
6383
|
-
I.authSetupStatus().then((
|
|
6384
|
-
h(
|
|
6383
|
+
I.authSetupStatus().then((C) => {
|
|
6384
|
+
h(C.registration_open), N(C.first_run), v(C.oauth_providers ?? []), C.first_run && g("register");
|
|
6385
6385
|
}).catch(() => {
|
|
6386
6386
|
}).finally(() => T(!1));
|
|
6387
6387
|
}, []), se(() => {
|
|
6388
|
-
const
|
|
6389
|
-
|
|
6388
|
+
const C = n.get("oauth_error");
|
|
6389
|
+
C && b(o(`login.oauthError.${C}`, { defaultValue: o("login.oauthError.generic") }));
|
|
6390
6390
|
}, [n, o]);
|
|
6391
|
-
const ee = async (
|
|
6392
|
-
if (
|
|
6391
|
+
const ee = async (C) => {
|
|
6392
|
+
if (C.preventDefault(), b(""), c === "register") {
|
|
6393
6393
|
if (B !== O) {
|
|
6394
6394
|
b(o("login.passwordsNoMatch"));
|
|
6395
6395
|
return;
|
|
@@ -6424,7 +6424,7 @@ function zs() {
|
|
|
6424
6424
|
{
|
|
6425
6425
|
label: o("login.fullName"),
|
|
6426
6426
|
value: _,
|
|
6427
|
-
onChange: (
|
|
6427
|
+
onChange: (C) => y(C.target.value),
|
|
6428
6428
|
required: !0
|
|
6429
6429
|
}
|
|
6430
6430
|
),
|
|
@@ -6434,7 +6434,7 @@ function zs() {
|
|
|
6434
6434
|
label: o("login.email"),
|
|
6435
6435
|
type: "email",
|
|
6436
6436
|
value: d,
|
|
6437
|
-
onChange: (
|
|
6437
|
+
onChange: (C) => p(C.target.value),
|
|
6438
6438
|
required: !0
|
|
6439
6439
|
}
|
|
6440
6440
|
),
|
|
@@ -6444,7 +6444,7 @@ function zs() {
|
|
|
6444
6444
|
label: o("login.password"),
|
|
6445
6445
|
type: "password",
|
|
6446
6446
|
value: B,
|
|
6447
|
-
onChange: (
|
|
6447
|
+
onChange: (C) => D(C.target.value),
|
|
6448
6448
|
required: !0
|
|
6449
6449
|
}
|
|
6450
6450
|
),
|
|
@@ -6454,7 +6454,7 @@ function zs() {
|
|
|
6454
6454
|
label: o("login.confirmPassword"),
|
|
6455
6455
|
type: "password",
|
|
6456
6456
|
value: O,
|
|
6457
|
-
onChange: (
|
|
6457
|
+
onChange: (C) => G(C.target.value),
|
|
6458
6458
|
required: !0
|
|
6459
6459
|
}
|
|
6460
6460
|
),
|
|
@@ -6466,20 +6466,20 @@ function zs() {
|
|
|
6466
6466
|
/* @__PURE__ */ e("span", { className: "text-xs uppercase tracking-wide text-fg-muted", children: o("login.orContinueWith") }),
|
|
6467
6467
|
/* @__PURE__ */ e("div", { className: "h-px flex-1 bg-border" })
|
|
6468
6468
|
] }),
|
|
6469
|
-
/* @__PURE__ */ e("div", { className: "space-y-2", children: x.map((
|
|
6469
|
+
/* @__PURE__ */ e("div", { className: "space-y-2", children: x.map((C) => /* @__PURE__ */ r(
|
|
6470
6470
|
"button",
|
|
6471
6471
|
{
|
|
6472
6472
|
type: "button",
|
|
6473
6473
|
onClick: () => {
|
|
6474
|
-
window.location.href = I.oauthLoginUrl(
|
|
6474
|
+
window.location.href = I.oauthLoginUrl(C, { invite: l || void 0 });
|
|
6475
6475
|
},
|
|
6476
6476
|
className: "flex w-full items-center justify-center gap-2 rounded-lg border border-border bg-surface px-4 py-2 text-sm font-medium text-fg transition-colors hover:bg-surface-muted",
|
|
6477
6477
|
children: [
|
|
6478
|
-
/* @__PURE__ */ e(
|
|
6479
|
-
o("login.continueWithProvider", { provider:
|
|
6478
|
+
/* @__PURE__ */ e($s, { provider: C }),
|
|
6479
|
+
o("login.continueWithProvider", { provider: Fs(C) })
|
|
6480
6480
|
]
|
|
6481
6481
|
},
|
|
6482
|
-
|
|
6482
|
+
C
|
|
6483
6483
|
)) })
|
|
6484
6484
|
] })
|
|
6485
6485
|
] }),
|
|
@@ -6509,10 +6509,10 @@ function zs() {
|
|
|
6509
6509
|
] }) })
|
|
6510
6510
|
] }) });
|
|
6511
6511
|
}
|
|
6512
|
-
function
|
|
6512
|
+
function Fs(t) {
|
|
6513
6513
|
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
6514
6514
|
}
|
|
6515
|
-
function
|
|
6515
|
+
function $s({ provider: t }) {
|
|
6516
6516
|
return t === "google" ? /* @__PURE__ */ r("svg", { className: "h-4 w-4", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
|
|
6517
6517
|
/* @__PURE__ */ e("path", { fill: "#EA4335", d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" }),
|
|
6518
6518
|
/* @__PURE__ */ e("path", { fill: "#4285F4", d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" }),
|
|
@@ -6520,8 +6520,8 @@ function Fs({ provider: t }) {
|
|
|
6520
6520
|
/* @__PURE__ */ e("path", { fill: "#34A853", d: "M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" })
|
|
6521
6521
|
] }) : t === "apple" ? /* @__PURE__ */ e("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ e("path", { d: "M16.365 1.43c0 1.14-.42 2.22-1.14 3.03-.78.9-2.06 1.6-3.12 1.5-.13-1.1.42-2.28 1.08-3.03.78-.9 2.13-1.56 3.18-1.5zM20.7 17.1c-.56 1.3-.83 1.88-1.55 3.03-1 1.6-2.42 3.6-4.18 3.62-1.56.02-1.96-1.02-4.07-1-2.12.01-2.56 1.02-4.12 1.01-1.76-.02-3.1-1.82-4.1-3.42C-.3 16.9-.6 11.16 1.7 8.1c1.16-1.54 3-2.51 4.85-2.51 1.87 0 3.05 1.02 4.6 1.02 1.5 0 2.42-1.02 4.6-1.02 1.62 0 3.34.88 4.56 2.4-4.01 2.2-3.36 7.92 0 9.11z" }) }) : null;
|
|
6522
6522
|
}
|
|
6523
|
-
function
|
|
6524
|
-
const t = ze(), n = te(!1), [a, s] =
|
|
6523
|
+
function Us() {
|
|
6524
|
+
const t = ze(), n = te(!1), [a, s] = S("");
|
|
6525
6525
|
return se(() => {
|
|
6526
6526
|
n.current || (n.current = !0, I.createChatSession().then((i) => {
|
|
6527
6527
|
t(`/chat/${i.id}?demo=1`, { replace: !0 });
|
|
@@ -6552,8 +6552,8 @@ function zn() {
|
|
|
6552
6552
|
function Mn() {
|
|
6553
6553
|
return { type: "sales", party: "", amount: "", due_date: "", remarks: "" };
|
|
6554
6554
|
}
|
|
6555
|
-
function
|
|
6556
|
-
const t = ze(), n = We(), [a, s] =
|
|
6555
|
+
function Vs() {
|
|
6556
|
+
const t = ze(), n = We(), [a, s] = S(""), [i, o] = S((/* @__PURE__ */ new Date()).toISOString().split("T")[0]), [l, c] = S(""), [g, m] = S([qn()]), [h, u] = S([zn()]), [N, x] = S([Mn()]), [v, f] = S({}), T = ie({
|
|
6557
6557
|
mutationFn: () => I.importAccountBalances({
|
|
6558
6558
|
company: a,
|
|
6559
6559
|
posting_date: i,
|
|
@@ -6599,7 +6599,7 @@ function Us() {
|
|
|
6599
6599
|
return /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
6600
6600
|
/* @__PURE__ */ e("p", { className: "text-sm text-gray-500", children: "Import balances from your previous system. Each section creates the appropriate documents (Journal Entry, Stock Entry, or Invoices) and submits them automatically." }),
|
|
6601
6601
|
/* @__PURE__ */ e($, { title: "Common Settings", children: /* @__PURE__ */ r("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
6602
|
-
/* @__PURE__ */ e(
|
|
6602
|
+
/* @__PURE__ */ e(Se, { label: "Company", value: a, onChange: s, linkDoctype: "company", readOnly: !1 }),
|
|
6603
6603
|
/* @__PURE__ */ e(J, { label: "As-of Date", type: "date", value: i, onChange: (p) => o(p.target.value) })
|
|
6604
6604
|
] }) }),
|
|
6605
6605
|
/* @__PURE__ */ r($, { title: "1. Account Balances", children: [
|
|
@@ -6613,13 +6613,13 @@ function Us() {
|
|
|
6613
6613
|
/* @__PURE__ */ e("th", { className: "px-2 py-2 text-right font-medium text-gray-500", children: "Credit" })
|
|
6614
6614
|
] }) }),
|
|
6615
6615
|
/* @__PURE__ */ e("tbody", { children: g.map((p, _) => /* @__PURE__ */ r("tr", { children: [
|
|
6616
|
-
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e(
|
|
6616
|
+
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e(Se, { value: p.account, onChange: (y) => d(g, m, _, "account", y), linkDoctype: "account", readOnly: !1, label: "" }) }),
|
|
6617
6617
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ r("select", { value: p.party_type, onChange: (y) => d(g, m, _, "party_type", y.target.value), className: "w-full rounded border border-gray-300 px-2 py-1.5 text-sm", children: [
|
|
6618
6618
|
/* @__PURE__ */ e("option", { value: "", children: "—" }),
|
|
6619
6619
|
/* @__PURE__ */ e("option", { value: "Customer", children: "Customer" }),
|
|
6620
6620
|
/* @__PURE__ */ e("option", { value: "Supplier", children: "Supplier" })
|
|
6621
6621
|
] }) }),
|
|
6622
|
-
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: p.party_type ? /* @__PURE__ */ e(
|
|
6622
|
+
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: p.party_type ? /* @__PURE__ */ e(Se, { label: "", value: p.party, onChange: (y) => d(g, m, _, "party", y), linkDoctype: p.party_type.toLowerCase(), readOnly: !1 }) : /* @__PURE__ */ e("span", { className: "text-gray-300 text-xs", children: "set party type first" }) }),
|
|
6623
6623
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: p.debit, onChange: (y) => d(g, m, _, "debit", y.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0.00" }) }),
|
|
6624
6624
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: p.credit, onChange: (y) => d(g, m, _, "credit", y.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0.00" }) })
|
|
6625
6625
|
] }, _)) })
|
|
@@ -6636,7 +6636,7 @@ function Us() {
|
|
|
6636
6636
|
] }),
|
|
6637
6637
|
/* @__PURE__ */ r($, { title: "2. Stock Balances", children: [
|
|
6638
6638
|
/* @__PURE__ */ e("p", { className: "mb-3 text-xs text-gray-500", children: "Enter your current inventory. Creates a Stock Entry (Opening Stock) — posts Dr Stock In Hand / Cr Opening Balance Equity so the P&L isn't distorted by day-one inventory." }),
|
|
6639
|
-
/* @__PURE__ */ e("div", { className: "mb-3", children: /* @__PURE__ */ e(
|
|
6639
|
+
/* @__PURE__ */ e("div", { className: "mb-3", children: /* @__PURE__ */ e(Se, { label: "Warehouse", value: l, onChange: c, linkDoctype: "warehouse", readOnly: !1 }) }),
|
|
6640
6640
|
/* @__PURE__ */ e("div", { children: /* @__PURE__ */ r("table", { className: "min-w-full text-sm", children: [
|
|
6641
6641
|
/* @__PURE__ */ e("thead", { className: "bg-gray-50", children: /* @__PURE__ */ r("tr", { children: [
|
|
6642
6642
|
/* @__PURE__ */ e("th", { className: "px-2 py-2 text-left font-medium text-gray-500", children: "Item" }),
|
|
@@ -6644,7 +6644,7 @@ function Us() {
|
|
|
6644
6644
|
/* @__PURE__ */ e("th", { className: "px-2 py-2 text-right font-medium text-gray-500", children: "Rate" })
|
|
6645
6645
|
] }) }),
|
|
6646
6646
|
/* @__PURE__ */ e("tbody", { children: h.map((p, _) => /* @__PURE__ */ r("tr", { children: [
|
|
6647
|
-
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e(
|
|
6647
|
+
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e(Se, { label: "", value: p.item_code, onChange: (y) => d(h, u, _, "item_code", y), linkDoctype: "item", readOnly: !1 }) }),
|
|
6648
6648
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: p.qty, onChange: (y) => d(h, u, _, "qty", y.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0" }) }),
|
|
6649
6649
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e("input", { type: "number", value: p.rate, onChange: (y) => d(h, u, _, "rate", y.target.value), className: "w-24 rounded border border-gray-300 px-2 py-1.5 text-right text-sm", placeholder: "0.00" }) })
|
|
6650
6650
|
] }, _)) })
|
|
@@ -6678,7 +6678,7 @@ function Us() {
|
|
|
6678
6678
|
/* @__PURE__ */ e("option", { value: "purchase", children: "Purchase (AP)" })
|
|
6679
6679
|
] }) }),
|
|
6680
6680
|
/* @__PURE__ */ e("td", { className: "px-2 py-1", children: /* @__PURE__ */ e(
|
|
6681
|
-
|
|
6681
|
+
Se,
|
|
6682
6682
|
{
|
|
6683
6683
|
label: "",
|
|
6684
6684
|
value: p.party,
|
|
@@ -6718,14 +6718,14 @@ function Us() {
|
|
|
6718
6718
|
] })
|
|
6719
6719
|
] });
|
|
6720
6720
|
}
|
|
6721
|
-
function
|
|
6721
|
+
function Ks() {
|
|
6722
6722
|
const { user: t } = st(), n = We(), { data: a, isLoading: s } = oe({
|
|
6723
6723
|
queryKey: ["auth-users"],
|
|
6724
6724
|
queryFn: () => I.authListUsers()
|
|
6725
6725
|
}), { data: i } = oe({
|
|
6726
6726
|
queryKey: ["auth-invites"],
|
|
6727
6727
|
queryFn: () => I.authListInvites()
|
|
6728
|
-
}), [o, l] =
|
|
6728
|
+
}), [o, l] = S(""), [c, g] = S("viewer"), [m, h] = S(null), u = ie({
|
|
6729
6729
|
mutationFn: () => I.authInvite(o, c),
|
|
6730
6730
|
onSuccess: (d) => {
|
|
6731
6731
|
h(d), l(""), n.invalidateQueries({ queryKey: ["auth-invites"] });
|
|
@@ -6739,7 +6739,7 @@ function Vs() {
|
|
|
6739
6739
|
}), v = ie({
|
|
6740
6740
|
mutationFn: (d) => I.authRevokeInvite(d),
|
|
6741
6741
|
onSuccess: () => n.invalidateQueries({ queryKey: ["auth-invites"] })
|
|
6742
|
-
}), [f, T] =
|
|
6742
|
+
}), [f, T] = S(null), P = (d) => `${window.location.origin}/login?invite=${d}`, b = async (d) => {
|
|
6743
6743
|
try {
|
|
6744
6744
|
await navigator.clipboard.writeText(P(d)), T(d), setTimeout(() => T((p) => p === d ? null : p), 2e3);
|
|
6745
6745
|
} catch {
|
|
@@ -6879,98 +6879,98 @@ function Vs() {
|
|
|
6879
6879
|
] }) })
|
|
6880
6880
|
] });
|
|
6881
6881
|
}
|
|
6882
|
-
const Ks = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, js = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Gs = { logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Ws = { 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" }, Hs = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, Qs = { 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" } }, Ys = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, Js = { 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." } }, Zs = { 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", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API." }, Xs = { 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" }, ei = { 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" }, ti = { 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}}." }, ni = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, ai = { 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." }, ri = { "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" }, si = { "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code" }, ii = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, oi = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), li = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, ci = { period: "Period", allTime: "All time", semantics: "Balance-sheet accounts: closing balance at period end. P&L accounts: movement within the period. Click an account for its ledger.", empty: "No accounts found. Complete the company setup first.", disabled: "disabled", rootType: { Asset: "Assets", Liability: "Liabilities", Equity: "Equity", Income: "Income", Expense: "Expenses" } }, di = {
|
|
6883
|
-
common:
|
|
6884
|
-
language:
|
|
6885
|
-
header:
|
|
6886
|
-
titles:
|
|
6887
|
-
doctypes:
|
|
6888
|
-
masters:
|
|
6889
|
-
nav:
|
|
6890
|
-
login:
|
|
6891
|
-
settings:
|
|
6892
|
-
status:
|
|
6893
|
-
reports:
|
|
6894
|
-
masterForm:
|
|
6895
|
-
dashboard:
|
|
6896
|
-
chat:
|
|
6897
|
-
conversions:
|
|
6898
|
-
fields:
|
|
6899
|
-
tables:
|
|
6900
|
-
tutorial:
|
|
6901
|
-
notesMarkup:
|
|
6902
|
-
coa:
|
|
6903
|
-
}, ui = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, mi = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, pi = { logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, hi = { 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" }, gi = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, fi = { 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" } }, yi = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, bi = { 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." } }, vi = { 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", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat." }, xi = { 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" }, Ni = { 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" }, wi = { 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." }, ki = { Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname" }, Ci = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Si = { "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" }, Di = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Ai = { 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." }, Pi = /* @__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?"}'), _i = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, Ti = { 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" } }, Ri = {
|
|
6904
|
-
common:
|
|
6905
|
-
language:
|
|
6906
|
-
header:
|
|
6907
|
-
titles:
|
|
6908
|
-
doctypes:
|
|
6909
|
-
masters:
|
|
6910
|
-
nav:
|
|
6911
|
-
login:
|
|
6912
|
-
settings:
|
|
6913
|
-
status:
|
|
6914
|
-
reports:
|
|
6915
|
-
masterForm:
|
|
6916
|
-
fields:
|
|
6882
|
+
const js = { save: "Save", saving: "Saving...", submit: "Submit", cancel: "Cancel", cancelDoc: "Cancel", cancelDocAbort: "Don't cancel", cancelDocConfirmBtn: "Yes, cancel document", discardDraft: "Discard draft", keepDraft: "Keep", discardDraftConfirm: "Discard draft", showDiscarded: "Show discarded", delete: "Delete", edit: "Edit", pdf: "PDF", addRow: "Add Row", loading: "Loading...", enable: "Enable", disable: "Disable", refresh: "Refresh", refreshing: "Refreshing", areYouSure: "Are you sure?", all: "All", apply: "Apply", new: "New", prev: "Prev", next: "Next", perPage: "Per page", page: "Page", of: "of", showing: "Showing", total: "Total", totals: "Totals", errorOccurred: "An error occurred" }, Gs = { title: "Language", help: "Choose the language for the interface. Your choice is saved in this browser.", label: "Language" }, Ws = { logout: "Logout", openMenu: "Open menu", closeMenu: "Close menu", new: "New {{label}}" }, Hs = { 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" }, Qs = { quotation: { one: "Quotation", other: "Quotations" }, proposal: { one: "Proposal", other: "Proposals" }, "sales-order": { one: "Sales Order", other: "Sales Orders" }, "sales-invoice": { one: "Sales Invoice", other: "Sales Invoices" }, "pos-invoice": { one: "POS Invoice", other: "POS Invoices" }, "purchase-order": { one: "Purchase Order", other: "Purchase Orders" }, "purchase-invoice": { one: "Purchase Invoice", other: "Purchase Invoices" }, "payment-entry": { one: "Payment Entry", other: "Payment Entries" }, "journal-entry": { one: "Journal Entry", other: "Journal Entries" }, "bank-transaction": { one: "Bank Transaction", other: "Bank Transactions" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Subscription", other: "Subscriptions" }, "stock-entry": { one: "Stock Entry", other: "Stock Entries" }, "delivery-note": { one: "Delivery Note", other: "Delivery Notes" }, "purchase-receipt": { one: "Purchase Receipt", other: "Purchase Receipts" }, "pricing-rule": { one: "Pricing Rule", other: "Pricing Rules" } }, Ys = { 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" } }, Js = { chats: "Chats", newChat: "New Chat", deleteChat: "Delete chat", customAnalytics: "Custom Analytics", newAnalytics: "New Analytics", deleteReport: "Delete report", groups: { Introduction: "Introduction", Selling: "Selling", Buying: "Buying", Accounting: "Accounting", Stock: "Stock", Reports: "Reports", Masters: "Masters", Settings: "Settings" }, items: { "Getting Started": "Getting Started", "Company Setup": "Company Setup", "Opening Balances": "Opening Balances", Quotation: "Quotation", Proposal: "Proposals", "Sales Order": "Sales Order", "Sales Invoice": "Sales Invoice", "POS Invoice": "POS Invoice", "Purchase Order": "Purchase Order", "Purchase Invoice": "Purchase Invoice", "Payment Entry": "Payment Entry", "Journal Entry": "Journal Entry", "Bank Transaction": "Bank Transaction", Budget: "Budget", Subscription: "Subscription", "Stock Entry": "Stock Entry", "Delivery Note": "Delivery Note", "Purchase Receipt": "Purchase Receipt", "Trial Balance": "Trial Balance", "Profit & Loss": "Profit & Loss", "Balance Sheet": "Balance Sheet", "General Ledger": "General Ledger", "AR Aging": "AR Aging", "AP Aging": "AP Aging", Analytics: "Analytics", "Stock Balance": "Stock Balance", Company: "Company", Customer: "Customer", Supplier: "Supplier", Item: "Item", Warehouse: "Warehouse", General: "General", "Pricing Rule": "Pricing Rule", "Users & Team": "Users & Team", "Chart of Accounts": "Chart of Accounts" } }, Zs = { 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." } }, Xs = { pdfTitle: "PDF & Print", pageSize: "Page Size", pdfHelp: "A4 is standard internationally (210 x 297 mm). Letter is standard in the US (8.5 x 11 in).", passwordTitle: "Change Password", currentPassword: "Current password", newPassword: "New password", confirmNewPassword: "Confirm new password", changePassword: "Change password", changingPassword: "Changing...", passwordChanged: "Password changed.", setPasswordTitle: "Set a Password", setPasswordBody: "Your account signs in with Google. Set a password to also sign in with email and password — a handy fallback if you ever lose access to your Google account.", setPassword: "Set password", passwordSet: "Password set.", linkedAccountsTitle: "Linked Accounts", linkedAccountsBody: "Link a Google or Apple account to sign in without a password.", linked: "Linked", linkProvider: "Link {{provider}}", openingTitle: "Opening Balances", openingBody: "The Opening Balances page allows importing account balances, stock, and outstanding invoices from a previous system.", openingEnabled: "Currently enabled — accessible under Introduction > Opening Balances.", openingDisabled: "Currently disabled — the page is hidden from the sidebar.", signupTitle: "Public Signup", signupBody: "Allow anyone to create their own account (as a viewer) without an invite. When off, new users can only join via an invite link.", signupEnabled: "Currently enabled — anyone with the URL can register as a viewer.", signupDisabled: "Currently disabled — registration is invite-only.", chatApiTitle: "Chat API", apiTitle: "Programmatic API", restApiBody: "Let connectors and scripts drive this ERP over its REST API (documents, masters, reports) with the same Bearer API keys. Off by default.", restApiEnabled: "Currently enabled — issued keys can call /api/documents, /api/masters, and the rest of the REST API.", restApiDisabled: "Currently disabled — the REST API only accepts the session cookie; keys are rejected.", restApiDeactivateTitle: "Deactivate the REST API?", restApiDeactivateBody: "Bearer-key access to the REST API will be switched off — connectors and scripts are rejected until you turn it back on. The web app (session cookie) is unaffected, and your API keys are NOT deleted: they start working again the instant you re-enable the API.", chatApiBody: "Let external applications talk to this ERP's chat agent over an HTTP API, using Bearer API keys. Off by default.", chatApiEnabled: "Currently enabled — issued keys can call POST /api/v1/chat.", chatApiDisabled: "Currently disabled — the API returns 404 and keys don't work.", chatApiDeactivateTitle: "Deactivate the chat API?", chatApiDeactivateBody: "The chat API will be switched off — every programmatic request (Bearer API keys) is rejected until you turn it back on. Your API keys are NOT deleted: they stay saved and start working again the instant you re-enable the API.", chatApiDeactivateConfirm: "Deactivate API", chatApiKeysTitle: "API keys", chatApiTokenOnce: "Copy this token now — it won't be shown again.", chatApiCopy: "Copy", chatApiDismiss: "Dismiss", chatApiRevoked: "revoked", chatApiRevoke: "Revoke", chatApiNoKeys: "No API keys yet.", chatApiName: "Name", chatApiRole: "Role", chatApiCreate: "Create key", chatApiWarn: "A key acts with your identity and at most your role — treat it like a password. Revoke first, then delete.", publicTitle: "Public Access (Demo Mode)", publicActive: "Active", publicActiveBody: "Public access is enabled. Anyone can use the application without logging in. All visitors get manager-level permissions.", disablePublic: "Disable Public Access", disabling: "Disabling...", publicInactiveBody: "Enable public access to let anyone use the application without an account. Useful for demos and showcases. All visitors get manager-level permissions and share the same identity.", enablePublic: "Enable Public Access", enableWarning: "This will allow anyone to access the application without logging in. They will be able to create, edit, and submit documents. Your admin account still requires login.", yesEnable: "Yes, Enable", enabling: "Enabling...", tokenSpendTitle: "Token Spend", chatApiDelete: "Delete", chatApiYourKeys: "Your keys", chatApiYouBadge: "you", chatApiUnknownUser: "Unknown user", chatApiAdminAllNote: "You're an admin — the list below includes every user's keys, grouped by owner. Your own keys are shown first.", chatApiConfirmTitle: "This key isn't yours", chatApiConfirmRevokeBody: '"{{key}}" belongs to {{name}}. Revoking it will immediately break their API access. Continue?', chatApiConfirmDeleteBody: '"{{key}}" belongs to {{name}}. Deleting it permanently removes their key. Continue?', chatApiPersonal: "Personal Bearer keys for the programmatic chat API. A key acts as YOU: it is capped at your role, follows role changes live, and dies with your account. Requires the admin to have enabled the Chat API." }, ei = { 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" }, ti = { 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" }, ni = { 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}}." }, ai = { totalRevenue: "Total Revenue", outstandingReceivable: "Outstanding Receivable", outstandingPayable: "Outstanding Payable", totalStockValue: "Total Stock Value", recentDocuments: "Recent Documents", noRecentDocuments: "No recent documents" }, ri = { 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." }, si = { "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" }, ii = { "% Billed": "% Billed", "% Delivered": "% Delivered", Account: "Account", Address: "Address", Allocated: "Allocated", Amount: "Amount", "As of Date": "As of Date", Balance: "Balance", "Bank Account": "Bank Account", "Billing Interval": "Billing Interval", "Budget Amount": "Budget Amount", Buying: "Buying", Change: "Change", City: "City", Company: "Company", "Company Name": "Company Name", "Cost Center": "Cost Center", Country: "Country", Credit: "Credit", "Credit Limit": "Credit Limit", Currency: "Currency", "Current Period End": "Current Period End", "Contact Person": "Contact Person", "Contact Email": "Contact Email", "Contact Phone": "Contact Phone", "Current Period Start": "Current Period Start", Customer: "Customer", "Customer Group": "Customer Group", "Customer Name": "Customer Name", Date: "Date", Debit: "Debit", "Delivery Date": "Delivery Date", Deposit: "Deposit", Description: "Description", "Discount %": "Discount %", "Discount Amt": "Discount Amt", "Discount Percentage": "Discount Percentage", "Due Date": "Due Date", Email: "Email", Enabled: "Enabled", "End Date": "End Date", "Expense Account": "Expense Account", "Fiscal Year": "Fiscal Year", "From Date": "From Date", "Grand Total": "Grand Total", Frequency: "Frequency", ID: "ID", "If Exceeded": "If Exceeded", "Income Account": "Income Account", "Incoming Value": "Incoming Value", Invoice: "Invoice", Item: "Item", "Item Code": "Item Code", "Item Group": "Item Group", "Item Name": "Item Name", "Matched Doc": "Matched Doc", "Matched Type": "Matched Type", "Min Qty": "Min Qty", Mode: "Mode", Month: "Month", Name: "Name", "Net Total": "Net Total", "Notes / Terms": "Notes / Terms", "Outgoing Value": "Outgoing Value", Outstanding: "Outstanding", "Outstanding Amount": "Outstanding Amount", "Paid Amount": "Paid Amount", "Paid From": "Paid From", "Paid To": "Paid To", Party: "Party", "Party Type": "Party Type", "Payment Type": "Payment Type", Phone: "Phone", "Plan Items": "Plan Items", "Posting Date": "Posting Date", Priority: "Priority", Qty: "Qty", Rate: "Rate", "Rate (%)": "Rate (%)", "Rate Or Discount": "Rate Or Discount", "Reference No": "Reference No", Remark: "Remark", Selling: "Selling", Source: "Source", "Source Warehouse": "Source Warehouse", "Standard Rate": "Standard Rate", "Start Date": "Start Date", Status: "Status", "Stock Entry Type": "Stock Entry Type", "Stock UOM": "Stock UOM", "Stock Value": "Stock Value", Supplier: "Supplier", "Supplier Group": "Supplier Group", "Supplier Name": "Supplier Name", Target: "Target", "Target Warehouse": "Target Warehouse", Tax: "Tax", "Tax ID": "Tax ID", Territory: "Territory", Title: "Title", "To Date": "To Date", Total: "Total", "Total Amount": "Total Amount", "Total Credit": "Total Credit", "Total Debit": "Total Debit", "Transaction Date": "Transaction Date", Type: "Type", Unallocated: "Unallocated", "Update Stock": "Update Stock", "Valid From": "Valid From", "Valid Till": "Valid Till", "Valid Upto": "Valid Upto", "Valuation Rate": "Valuation Rate", "Voucher No": "Voucher No", "Voucher Type": "Voucher Type", Warehouse: "Warehouse", "Warehouse Name": "Warehouse Name", Withdrawal: "Withdrawal", "Zip Code": "Zip Code" }, oi = { accounts: "accounts", items: "items", monthly_distribution: "monthly_distribution", payments: "payments", plans: "plans", references: "references", taxes: "taxes" }, li = /* @__PURE__ */ JSON.parse(`{"chips":{"Cancelled":"Cancelled","Credit Note":"Credit Note","DN Return":"DN Return","Debit Note":"Debit Note","Delivery Note":"Delivery Note","Draft":"Draft","Payment Entry":"Payment Entry","Purchase Invoice":"Purchase Invoice","Purchase Order":"Purchase Order","Purchase Receipt":"Purchase Receipt","Quotation":"Quotation","Sales Invoice":"Sales Invoice","Sales Order":"Sales Order","Submitted":"Submitted"},"links":{"AP Aging":"AP Aging","AR Aging":"AR Aging","Balance Sheet":"Balance Sheet","Customers":"Customers","Delivery Notes":"Delivery Notes","General Ledger":"General Ledger","Go to Setup":"Go to Setup","Items":"Items","New Journal Entry":"New Journal Entry","New Payment Entry":"New Payment Entry","New Purchase Order":"New Purchase Order","New Quotation":"New Quotation","New Stock Entry":"New Stock Entry","Open AI Chat":"Open AI Chat","Profit & Loss":"Profit & Loss","Purchase Invoices":"Purchase Invoices","Purchase Receipts":"Purchase Receipts","Sales Invoices":"Sales Invoices","Stock Balance":"Stock Balance","Suppliers":"Suppliers","Trial Balance":"Trial Balance","View Quotations":"View Quotations","Warehouses":"Warehouses"},"steps":{"1":{"title":"Set Up Your Company","description":"Create a company with a base currency. This generates your Chart of Accounts (30 standard accounts across Assets, Liabilities, Equity, Income, and Expenses) and a default Cost Center. You can also seed demo data with sample customers, suppliers, and items to get started quickly."},"2":{"title":"Create Master Data","description":"Before you can transact, you need master records. Create at least one Customer, one Supplier, one Item (with a standard rate), and one Warehouse. If you seeded demo data in Step 1, these already exist.","tip":"Items have a standard rate that auto-fills when you add them to documents. You can always override the rate per transaction."},"3":{"title":"Create a Quotation","description":"A Quotation is a non-binding offer to a customer. Select a customer, add line items with quantities and rates, optionally add tax rows, then save. Quotations have no financial impact — they don't create accounting or stock entries. Set a validity date so the offer expires automatically."},"4":{"title":"Submit and Convert to Sales Order","description":"Open your saved Quotation and click Submit to confirm it. Then click “Create Sales Order” to convert it. The Sales Order represents a confirmed commitment from the customer. It still has no financial impact, but it reserves stock for planning purposes.","tip":"Only submitted documents can be converted to the next step. Draft → Submit → Convert is the standard flow. For quick deals, you can skip the Sales Order and go directly from Quotation to Sales Invoice or Delivery Note."},"5":{"title":"Check Stock Before Fulfilling","description":"Before you can deliver, check if you actually have the item in stock. Go to the Stock Balance report and look up the item. If your warehouse has zero quantity, you’ll need to bring stock in first — either through a Purchase Order (buying from a supplier) or a Stock Entry (manual receipt).","tip":"This is a common real-world scenario: you sell something, then realize you need to buy it first. The ERP handles both flows."},"6":{"title":"Purchase Cycle: Buy Stock from a Supplier","description":"If you need to buy stock, you have two valid paths. The standard path is Purchase Order -> Purchase Receipt -> Purchase Invoice: use this when goods arrive before or separately from the supplier bill. If the bill and receipt happen together, you can create the Purchase Invoice directly and enable Update Stock so the same document both receives inventory and records Accounts Payable.","tip":"Use Purchase Receipt first when receiving goods separately. Use Purchase Invoice with Update Stock when one step should both receive stock and book the supplier bill. In that direct path, set a warehouse on each stock item row."},"7":{"title":"Create a Delivery Note","description":"Now that you have stock, go back to your submitted Sales Order and click “Create Delivery Note.” Set the warehouse on each item row (where the goods ship from), then submit. This moves inventory out of the warehouse — your stock balance decreases.","tip":"The Delivery Note is the shipping document. It reduces stock but doesn’t create an invoice. You can deliver and invoice separately."},"8":{"title":"Create and Submit the Sales Invoice","description":"From the submitted Sales Order, create a Sales Invoice. When you submit the invoice, GL entries are posted: Accounts Receivable is debited (the customer owes you) and Sales Revenue is credited (income earned). If taxes are configured, Tax Payable is also credited. The outstanding amount shows what the customer still owes."},"9":{"title":"Record Customer Payments","description":"Create a Payment Entry to record money received from the customer. Set the payment type to “Receive,” select the customer, specify the amount, and allocate it against the Sales Invoice. You can make partial payments — the invoice’s outstanding amount updates accordingly. Create additional Payment Entries until the invoice is fully paid.","tip":"Partial payments are common. A 10,000 invoice might be paid as 3,000 now and 7,000 later. Each Payment Entry reduces the outstanding amount."},"10":{"title":"Stock Entries (Manual Inventory)","description":"Use Stock Entries for inventory movements that aren’t tied to purchases or sales. Material Receipt adds stock (opening balances, adjustments). Material Issue removes stock (write-offs, internal consumption). Material Transfer moves stock between warehouses. Each entry updates the stock ledger with moving-average valuation.","tip":"For purchased goods, use Purchase Receipts instead of Stock Entries — they link to the Purchase Order and give you a proper audit trail."},"11":{"title":"Journal Entries","description":"Journal Entries are manual accounting adjustments — expense accruals, corrections, reclassifications, opening balances. Each entry must have balanced debits and credits (total debit = total credit). Use these when no other document type fits."},"12":{"title":"Salary Payments","description":"Lambda ERP handles salaries through the existing accounting tools. First, accrue the salary expense: create a Journal Entry that debits Salary Expense and credits Salary Payable for the total payroll amount. Then pay the employees: create another Journal Entry (or Payment Entry) that debits Salary Payable and credits your bank account. This two-step process keeps your books accurate — the expense is recorded in the right period, and the cash outflow is tracked separately.","tip":"You can ask the AI assistant to do this for you: “Accrue 15,000 in salaries for April” followed by “Pay the April salaries from bank.” It will create the right journal entries automatically."},"13":{"title":"Returns and Credit Notes","description":"When a customer returns goods or you need to issue a credit, create a return. Returns use the same document type with negative quantities. Open a submitted Sales Invoice and create a Credit Note (Sales Invoice return) — this reverses the GL entries and reduces the original invoice’s outstanding amount. For stock, create a Delivery Note return to bring goods back into the warehouse. On the buying side, create a Debit Note (Purchase Invoice return) to reverse a supplier bill, or a Purchase Receipt return to send goods back.","tip":"A Credit Note is just a Sales Invoice with is_return=1 and negative quantities. The same GL logic runs — negative amounts automatically flip to the correct debit/credit sides. For a full sales return, you need both a Credit Note (financials) and a Delivery Note return (stock)."},"14":{"title":"Run Reports","description":"Check your books. The Profit & Loss shows income vs expenses and net profit for a period. The Balance Sheet shows your financial position (assets = liabilities + equity). AR Aging shows who owes you money and how overdue it is. AP Aging shows what you owe suppliers. The Trial Balance verifies double-entry integrity. The General Ledger shows every individual posting. Stock Balance shows current inventory."},"15":{"title":"Working in Foreign Currencies","description":"Your books are kept in a single base currency (chosen at company setup), but you can transact in any currency. Set a currency on an invoice or bill — or give a customer or supplier a default currency — and the exchange rate for that date is looked up automatically and stored on the document. The document keeps its amounts in its own currency, while the General Ledger always posts in your base currency. When you later collect or pay at a different rate, the realized exchange gain or loss is booked automatically to an Exchange Gain/Loss account. You can even hold a foreign-currency bank balance and convert it later at your bank’s rate — the difference versus its carried value is realized then. At month end you can revalue open foreign balances to the closing rate (an unrealized gain/loss that reverses next period), and you can view any financial statement translated into another currency for display.","tip":"This is easiest through the AI chat — try “Create a sales invoice for Lumiere Audio in EUR,” “Show me the balance sheet in EUR,” or “What’s our unrealized FX exposure at month end?” The seeded demo already includes a EUR customer (Lumiere Audio SARL) whose invoice was collected at a different rate, plus an open EUR supplier bill — open the General Ledger to see the realized FX postings."}},"caTitle":"Dynamic Analytics — Chat Your Way to Any Chart","caBadge":"Signature Feature","caBody":"Need a report the presets can’t give you? Just describe it in chat. The assistant calls a code-specialist model that writes the report for you, runs it live over your ERP data, and returns a sharable link. The chart or table renders in seconds and is saved as a draft under Custom Analytics in the sidebar — you can reopen it, share the URL with teammates, or ask the assistant to refine it.","caTryAsking":"Try asking (click to prefill in chat):","caPrompt1":"Show me top 10 customers by revenue this year as a bar chart","caPrompt2":"Monthly purchases trend by supplier over all months and label x-axis with supplier name","caPrompt3":"Best selling items by quantity, with a table and a chart","caPrompt4":"Which customers owe me the most right now?","caTryInChat":"Try it in chat","caOpenWorkspace":"Open Analytics workspace","flowTitle":"Document Flow Overview","salesCycle":"Sales Cycle","flowShortcut":"Shortcut: Quotation can skip Sales Order and go directly to Sales Invoice or Delivery Note","purchaseCycle":"Purchase Cycle","returns":"Returns","legendStock":"stock impact","legendGl":"GL impact","legendCash":"cash impact","legendReversal":"reversal","lifecycleTitle":"Document Lifecycle","lcDraftLabel":"Draft:","lcDraftDesc":"Editable. No financial or stock impact.","lcSubmittedLabel":"Submitted:","lcSubmittedDesc":"Locked. GL entries and stock ledger entries are posted.","lcCancelledLabel":"Cancelled:","lcCancelledDesc":"All entries reversed. Document is permanently archived.","lcNoDelete":"There is no delete. To void a draft: submit it, then cancel it.","lcCorrect":"To correct a submitted document: cancel it and create a new one.","pageTitle":"Getting Started with Lambda ERP","intro":"Lambda ERP is an AI Native ERP System, with all functionality — like creating orders, checking inventory, recording payments — being accessible through a chat interface. It instructs, reasons and checks all your daily business tasks.","openChat":"Open AI Chat","tipLabel":"Tip:","topTip":"The AI chat can also give you direct links to documents and downloadable PDFs. Just ask it to create or look up a document and it will include clickable links in its response.","manualIntro":"If you want to fully understand how things work under the hood, or prefer to do things manually, here’s a full business cycle step by step.","readyTitle":"You're Ready","readyBody1":"You now understand the full cycle. A typical real-world scenario looks like this: you receive a customer order (Quotation → Sales Order), check stock, buy what you need (Purchase Order → Purchase Receipt → Purchase Invoice → Payment), deliver to the customer (Delivery Note), bill them (Sales Invoice), and collect payment (Payment Entry). If something comes back, create a Credit Note and Delivery Note return to reverse the financials and stock. The Trial Balance confirms everything is balanced.","readyBody2":"You can also use the AI chat to do all of this through natural conversation — just describe what you need and it will create the right documents for you.","setupTitle":"Set Up Your Company — Guided by AI","setupBadge":"Start Here","setupBody":"Tell the assistant what kind of business you run, and it builds your chart of accounts for you — tailored to your sector, with the right accounts and sensible defaults already wired up. It explains each decision and only creates anything once you approve.","setupSectors":"Tailored for services, retail & POS, hospitality, wholesale & distribution, import/export, manufacturing, and construction.","setupGetStarted":"Get started in chat","setupManual":"Prefer a manual form? Use the classic setup.","setupManualLink":"Classic setup","setupPrompt":"I'd like to set up my company. Can you guide me through it?"}`), ci = { title: "Formatting help", intro: "The Notes / Terms text supports light formatting on the PDF:", heading: "bold heading", emphasis: "italic / bold", rule: "horizontal divider line", price: "right-aligned price beside the text above (e.g. Monthly | CHF 380.—)", block: "Separate blocks with a blank line." }, di = { 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" } }, ui = {
|
|
6883
|
+
common: js,
|
|
6884
|
+
language: Gs,
|
|
6885
|
+
header: Ws,
|
|
6886
|
+
titles: Hs,
|
|
6887
|
+
doctypes: Qs,
|
|
6888
|
+
masters: Ys,
|
|
6889
|
+
nav: Js,
|
|
6890
|
+
login: Zs,
|
|
6891
|
+
settings: Xs,
|
|
6892
|
+
status: ei,
|
|
6893
|
+
reports: ti,
|
|
6894
|
+
masterForm: ni,
|
|
6895
|
+
dashboard: ai,
|
|
6896
|
+
chat: ri,
|
|
6897
|
+
conversions: si,
|
|
6898
|
+
fields: ii,
|
|
6899
|
+
tables: oi,
|
|
6900
|
+
tutorial: li,
|
|
6901
|
+
notesMarkup: ci,
|
|
6902
|
+
coa: di
|
|
6903
|
+
}, mi = { save: "Speichern", saving: "Speichern...", submit: "Buchen", cancel: "Abbrechen", cancelDoc: "Stornieren", cancelDocAbort: "Nicht stornieren", cancelDocConfirmBtn: "Definitiv stornieren", discardDraft: "Entwurf verwerfen", keepDraft: "Behalten", discardDraftConfirm: "Verwerfen", showDiscarded: "Verworfene anzeigen", delete: "Löschen", edit: "Bearbeiten", pdf: "PDF", addRow: "Zeile hinzufügen", loading: "Lädt...", enable: "Aktivieren", disable: "Deaktivieren", refresh: "Aktualisieren", refreshing: "Aktualisiert...", areYouSure: "Sind Sie sicher?", all: "Alle", apply: "Anwenden", new: "Neu", prev: "Zurück", next: "Weiter", perPage: "Pro Seite", page: "Seite", of: "von", showing: "Zeige", total: "Gesamt", totals: "Summen", errorOccurred: "Ein Fehler ist aufgetreten" }, pi = { title: "Sprache", help: "Wählen Sie die Sprache der Oberfläche. Ihre Auswahl wird in diesem Browser gespeichert.", label: "Sprache" }, hi = { logout: "Abmelden", openMenu: "Menü öffnen", closeMenu: "Menü schließen", new: "Neu: {{label}}" }, gi = { 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" }, fi = { quotation: { one: "Angebot", other: "Angebote" }, proposal: { one: "Sammelofferte", other: "Sammelofferten" }, "sales-order": { one: "Kundenauftrag", other: "Kundenaufträge" }, "sales-invoice": { one: "Ausgangsrechnung", other: "Ausgangsrechnungen" }, "pos-invoice": { one: "Kassenbeleg", other: "Kassenbelege" }, "purchase-order": { one: "Bestellung", other: "Bestellungen" }, "purchase-invoice": { one: "Eingangsrechnung", other: "Eingangsrechnungen" }, "payment-entry": { one: "Zahlung", other: "Zahlungen" }, "journal-entry": { one: "Buchungssatz", other: "Buchungssätze" }, "bank-transaction": { one: "Banktransaktion", other: "Banktransaktionen" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Lagerbuchung", other: "Lagerbuchungen" }, "delivery-note": { one: "Lieferschein", other: "Lieferscheine" }, "purchase-receipt": { one: "Wareneingang", other: "Wareneingänge" }, "pricing-rule": { one: "Preisregel", other: "Preisregeln" } }, yi = { company: { one: "Unternehmen", other: "Unternehmen" }, customer: { one: "Kunde", other: "Kunden" }, supplier: { one: "Lieferant", other: "Lieferanten" }, item: { one: "Artikel", other: "Artikel" }, warehouse: { one: "Lager", other: "Lager" } }, bi = { chats: "Chats", newChat: "Neuer Chat", deleteChat: "Chat löschen", customAnalytics: "Eigene Analysen", newAnalytics: "Neue Analyse", deleteReport: "Bericht löschen", groups: { Introduction: "Einführung", Selling: "Verkauf", Buying: "Einkauf", Accounting: "Buchhaltung", Stock: "Lager", Reports: "Berichte", Masters: "Stammdaten", Settings: "Einstellungen" }, items: { "Getting Started": "Erste Schritte", "Company Setup": "Unternehmenseinrichtung", "Opening Balances": "Eröffnungsbilanzen", Quotation: "Angebot", Proposal: "Sammelofferte", "Sales Order": "Kundenauftrag", "Sales Invoice": "Ausgangsrechnung", "POS Invoice": "Kassenbeleg", "Purchase Order": "Bestellung", "Purchase Invoice": "Eingangsrechnung", "Payment Entry": "Zahlung", "Journal Entry": "Buchungssatz", "Bank Transaction": "Banktransaktion", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Lagerbuchung", "Delivery Note": "Lieferschein", "Purchase Receipt": "Wareneingang", "Trial Balance": "Rohbilanz", "Profit & Loss": "Gewinn- und Verlustrechnung", "Balance Sheet": "Bilanz", "General Ledger": "Hauptbuch", "AR Aging": "Offene Posten Debitoren", "AP Aging": "Offene Posten Kreditoren", Analytics: "Analysen", "Stock Balance": "Lagerbestand", Company: "Unternehmen", Customer: "Kunde", Supplier: "Lieferant", Item: "Artikel", Warehouse: "Lager", General: "Allgemein", "Pricing Rule": "Preisregel", "Users & Team": "Benutzer & Team", "Chart of Accounts": "Kontenplan" } }, vi = { 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." } }, xi = { pdfTitle: "PDF & Druck", pageSize: "Seitengröße", pdfHelp: "A4 ist international Standard (210 x 297 mm). Letter ist Standard in den USA (8,5 x 11 Zoll).", passwordTitle: "Passwort ändern", currentPassword: "Aktuelles Passwort", newPassword: "Neues Passwort", confirmNewPassword: "Neues Passwort bestätigen", changePassword: "Passwort ändern", changingPassword: "Wird geändert...", passwordChanged: "Passwort geändert.", setPasswordTitle: "Passwort festlegen", setPasswordBody: "Ihr Konto meldet sich mit Google an. Legen Sie ein Passwort fest, um sich auch mit E-Mail und Passwort anzumelden — ein praktischer Rückfall, falls Sie den Zugang zu Ihrem Google-Konto verlieren.", setPassword: "Passwort festlegen", passwordSet: "Passwort festgelegt.", linkedAccountsTitle: "Verknüpfte Konten", linkedAccountsBody: "Verknüpfen Sie ein Google- oder Apple-Konto, um sich ohne Passwort anzumelden.", linked: "Verknüpft", linkProvider: "{{provider}} verknüpfen", openingTitle: "Eröffnungsbilanzen", openingBody: "Auf der Seite Eröffnungsbilanzen können Kontensalden, Lagerbestände und offene Rechnungen aus einem früheren System importiert werden.", openingEnabled: "Derzeit aktiviert — erreichbar unter Einführung > Eröffnungsbilanzen.", openingDisabled: "Derzeit deaktiviert — die Seite ist in der Seitenleiste ausgeblendet.", signupTitle: "Öffentliche Registrierung", signupBody: "Erlauben Sie es jedem, ohne Einladung ein eigenes Konto (als Betrachter) zu erstellen. Wenn deaktiviert, können neue Benutzer nur über einen Einladungslink beitreten.", signupEnabled: "Derzeit aktiviert — jeder mit der URL kann sich als Betrachter registrieren.", signupDisabled: "Derzeit deaktiviert — die Registrierung erfolgt nur per Einladung.", chatApiTitle: "Chat-API", apiTitle: "Programmatische API", restApiBody: "Konnektoren und Skripten erlauben, dieses ERP über seine REST-API (Belege, Stammdaten, Berichte) mit denselben Bearer-API-Schlüsseln zu steuern. Standardmäßig deaktiviert.", restApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können /api/documents, /api/masters und die übrige REST-API aufrufen.", restApiDisabled: "Derzeit deaktiviert — die REST-API akzeptiert nur das Sitzungs-Cookie; Schlüssel werden abgewiesen.", restApiDeactivateTitle: "REST-API deaktivieren?", restApiDeactivateBody: "Der Bearer-Schlüssel-Zugriff auf die REST-API wird abgeschaltet — Konnektoren und Skripte werden abgewiesen, bis Sie ihn wieder einschalten. Die Web-App (Sitzungs-Cookie) ist nicht betroffen, und Ihre API-Schlüssel werden NICHT gelöscht: Sie funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiBody: "Externen Anwendungen erlauben, über eine HTTP-API mit dem Chat-Agenten dieses ERPs zu sprechen — per Bearer-API-Schlüssel. Standardmäßig deaktiviert.", chatApiEnabled: "Derzeit aktiviert — ausgestellte Schlüssel können POST /api/v1/chat aufrufen.", chatApiDisabled: "Derzeit deaktiviert — die API liefert 404 und Schlüssel funktionieren nicht.", chatApiDeactivateTitle: "Chat-API deaktivieren?", chatApiDeactivateBody: "Die Chat-API wird abgeschaltet — jede programmatische Anfrage (Bearer-API-Schlüssel) wird abgewiesen, bis Sie sie wieder einschalten. Ihre API-Schlüssel werden NICHT gelöscht: Sie bleiben gespeichert und funktionieren wieder, sobald Sie die API erneut aktivieren.", chatApiDeactivateConfirm: "API deaktivieren", chatApiKeysTitle: "API-Schlüssel", chatApiTokenOnce: "Kopieren Sie diesen Token jetzt — er wird nicht erneut angezeigt.", chatApiCopy: "Kopieren", chatApiDismiss: "Schließen", chatApiRevoked: "widerrufen", chatApiRevoke: "Widerrufen", chatApiNoKeys: "Noch keine API-Schlüssel.", chatApiName: "Name", chatApiRole: "Rolle", chatApiCreate: "Schlüssel erstellen", chatApiWarn: "Ein Key handelt mit Ihrer Identität und höchstens Ihrer Rolle — wie ein Passwort behandeln. Erst widerrufen, dann löschen.", publicTitle: "Öffentlicher Zugriff (Demomodus)", publicActive: "Aktiv", publicActiveBody: "Der öffentliche Zugriff ist aktiviert. Jeder kann die Anwendung ohne Anmeldung nutzen. Alle Besucher erhalten Manager-Rechte.", disablePublic: "Öffentlichen Zugriff deaktivieren", disabling: "Wird deaktiviert...", publicInactiveBody: "Aktivieren Sie den öffentlichen Zugriff, damit jeder die Anwendung ohne Konto nutzen kann. Nützlich für Demos und Präsentationen. Alle Besucher erhalten Manager-Rechte und teilen sich dieselbe Identität.", enablePublic: "Öffentlichen Zugriff aktivieren", enableWarning: "Dadurch kann jeder ohne Anmeldung auf die Anwendung zugreifen. Besucher können Dokumente erstellen, bearbeiten und buchen. Ihr Administratorkonto erfordert weiterhin eine Anmeldung.", yesEnable: "Ja, aktivieren", enabling: "Wird aktiviert...", tokenSpendTitle: "Token-Ausgaben", chatApiDelete: "Löschen", chatApiYourKeys: "Ihre Schlüssel", chatApiYouBadge: "Sie", chatApiUnknownUser: "Unbekannter Benutzer", chatApiAdminAllNote: "Als Administrator enthält die Liste unten die Schlüssel aller Benutzer, nach Eigentümer gruppiert. Ihre eigenen stehen oben.", chatApiConfirmTitle: "Dieser Schlüssel gehört nicht Ihnen", chatApiConfirmRevokeBody: "„{{key}}“ gehört {{name}}. Beim Widerrufen verliert diese Person sofort den API-Zugriff. Fortfahren?", chatApiConfirmDeleteBody: "„{{key}}“ gehört {{name}}. Beim Löschen wird der Schlüssel dieser Person dauerhaft entfernt. Fortfahren?", chatApiPersonal: "Persönliche Bearer-Keys für die programmatische Chat-API. Ein Key handelt als SIE: begrenzt auf Ihre Rolle, folgt Rollenänderungen live und erlischt mit Ihrem Konto. Setzt voraus, dass der Admin die Chat-API aktiviert hat." }, Ni = { 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" }, wi = { 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" }, ki = { 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." }, Si = { Account: "Konto", Amount: "Betrag", Balance: "Saldo", Credit: "Haben", Debit: "Soll", Date: "Datum", Party: "Partner", "Party Type": "Partnertyp", "Voucher Type": "Belegart", "Voucher No": "Belegnr.", Invoice: "Rechnung", Customer: "Kunde", Supplier: "Lieferant", "Due Date": "Fälligkeitsdatum", Outstanding: "Offen", "Outstanding Amount": "Offener Betrag", "Item Code": "Artikelnr.", "Item Name": "Artikelname", Item: "Artikel", Warehouse: "Lager", Qty: "Menge", "Valuation Rate": "Bewertungspreis", "Stock Value": "Lagerwert", Name: "Name", Status: "Status", Company: "Unternehmen", "From Date": "Von Datum", "To Date": "Bis Datum", "As of Date": "Stichtag", "Valid Till": "Gültig bis", "Net Total": "Nettobetrag", Tax: "Steuer", "Grand Total": "Gesamtbetrag", Frequency: "Frequenz", "Notes / Terms": "Notizen / Bedingungen", "Posting Date": "Buchungsdatum", "Transaction Date": "Belegdatum", "Delivery Date": "Lieferdatum", "% Delivered": "% geliefert", "% Billed": "% abgerechnet", "Update Stock": "Lager aktualisieren", "Payment Type": "Zahlungsart", "Paid From": "Bezahlt von", "Paid To": "Bezahlt an", "Paid Amount": "Zahlbetrag", Type: "Art", Total: "Gesamt", Allocated: "Zugeordnet", Unallocated: "Nicht zugeordnet", Remark: "Bemerkung", "Total Debit": "Summe Soll", "Total Credit": "Summe Haben", "Cost Center": "Kostenstelle", "Source Warehouse": "Quelllager", "Target Warehouse": "Ziellager", Source: "Quelle", Target: "Ziel", "Incoming Value": "Eingangswert", "Outgoing Value": "Ausgangswert", Rate: "Preis", "Income Account": "Ertragskonto", "Expense Account": "Aufwandskonto", Description: "Beschreibung", "Rate (%)": "Satz (%)", Mode: "Art", Change: "Rückgeld", Currency: "Währung", Title: "Titel", Selling: "Verkauf", Buying: "Einkauf", "Discount %": "Rabatt %", "Discount Amt": "Rabattbetrag", "Min Qty": "Mindestmenge", "Valid From": "Gültig ab", "Valid Upto": "Gültig bis", Priority: "Priorität", Enabled: "Aktiviert", "Fiscal Year": "Geschäftsjahr", "Budget Amount": "Budgetbetrag", "If Exceeded": "Bei Überschreitung", Month: "Monat", "Bank Account": "Bankkonto", Deposit: "Einzahlung", Withdrawal: "Auszahlung", "Reference No": "Referenznr.", "Matched Type": "Zugeordnete Art", "Matched Doc": "Zugeordneter Beleg", "Start Date": "Startdatum", "End Date": "Enddatum", "Billing Interval": "Abrechnungsintervall", "Current Period Start": "Aktueller Periodenbeginn", "Current Period End": "Aktuelles Periodenende", "Plan Items": "Planpositionen", "Total Amount": "Gesamtbetrag", "Stock Entry Type": "Lagerbuchungsart", "Rate Or Discount": "Preis oder Rabatt", "Discount Percentage": "Rabattprozentsatz", ID: "ID", "Customer Name": "Kundenname", "Customer Group": "Kundengruppe", Territory: "Region", "Credit Limit": "Kreditlimit", Email: "E-Mail", Phone: "Telefon", Address: "Adresse", City: "Stadt", "Zip Code": "PLZ", Country: "Land", "Tax ID": "Steuernummer", "Contact Person": "Ansprechperson", "Contact Email": "E-Mail Ansprechperson", "Contact Phone": "Telefon Ansprechperson", "Supplier Name": "Lieferantenname", "Supplier Group": "Lieferantengruppe", "Item Group": "Artikelgruppe", "Stock UOM": "Lagereinheit", "Standard Rate": "Standardpreis", "Warehouse Name": "Lagername", "Company Name": "Firmenname" }, Ci = { items: "Positionen", taxes: "Steuern", references: "Zahlungsreferenzen", accounts: "Kontobuchungen", payments: "Zahlungen", plans: "Planpositionen", monthly_distribution: "Monatliche Verteilung" }, Di = { "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" }, Ai = { totalRevenue: "Gesamtumsatz", outstandingReceivable: "Offene Forderungen", outstandingPayable: "Offene Verbindlichkeiten", totalStockValue: "Gesamter Lagerwert", recentDocuments: "Letzte Dokumente", noRecentDocuments: "Keine aktuellen Dokumente" }, Pi = { 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." }, _i = /* @__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?"}'), Ti = { title: "Formatierungshilfe", intro: "Der Text unter Notizen / Konditionen unterstützt eine einfache Formatierung im PDF:", heading: "fette Überschrift", emphasis: "kursiv / fett", rule: "horizontale Trennlinie", price: "rechtsbündiger Preis neben dem Text darüber (z. B. Monatlich | CHF 380.—)", block: "Trennen Sie Blöcke durch eine Leerzeile." }, Ri = { 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" } }, Ii = {
|
|
6904
|
+
common: mi,
|
|
6905
|
+
language: pi,
|
|
6906
|
+
header: hi,
|
|
6907
|
+
titles: gi,
|
|
6908
|
+
doctypes: fi,
|
|
6909
|
+
masters: yi,
|
|
6910
|
+
nav: bi,
|
|
6911
|
+
login: vi,
|
|
6912
|
+
settings: xi,
|
|
6913
|
+
status: Ni,
|
|
6914
|
+
reports: wi,
|
|
6915
|
+
masterForm: ki,
|
|
6916
|
+
fields: Si,
|
|
6917
6917
|
tables: Ci,
|
|
6918
|
-
conversions:
|
|
6919
|
-
dashboard:
|
|
6920
|
-
chat:
|
|
6921
|
-
tutorial:
|
|
6922
|
-
notesMarkup:
|
|
6923
|
-
coa:
|
|
6924
|
-
}, Ii = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Bi = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Li = { logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Ei = { 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" }, Oi = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, qi = { 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" } }, zi = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, Mi = { 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." } }, Fi = { 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", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat." }, $i = { 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é" }, Ui = { 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é" }, Vi = { 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}}." }, Ki = { Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société" }, ji = { 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" }, Gi = { "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" }, Wi = { 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" }, Hi = { 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." }, Qi = /* @__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 ?"}`), Yi = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, Ji = { 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" } }, Zi = {
|
|
6925
|
-
common:
|
|
6926
|
-
language:
|
|
6918
|
+
conversions: Di,
|
|
6919
|
+
dashboard: Ai,
|
|
6920
|
+
chat: Pi,
|
|
6921
|
+
tutorial: _i,
|
|
6922
|
+
notesMarkup: Ti,
|
|
6923
|
+
coa: Ri
|
|
6924
|
+
}, Bi = { save: "Enregistrer", saving: "Enregistrement...", submit: "Valider", cancel: "Annuler", cancelDoc: "Annuler", cancelDocAbort: "Ne pas annuler", cancelDocConfirmBtn: "Annuler définitivement", discardDraft: "Supprimer le brouillon", keepDraft: "Conserver", discardDraftConfirm: "Supprimer", showDiscarded: "Afficher les supprimés", delete: "Supprimer", edit: "Modifier", pdf: "PDF", addRow: "Ajouter une ligne", loading: "Chargement...", enable: "Activer", disable: "Désactiver", refresh: "Actualiser", refreshing: "Actualisation", areYouSure: "Êtes-vous sûr ?", all: "Tous", apply: "Appliquer", new: "Nouveau", prev: "Précédent", next: "Suivant", perPage: "Par page", page: "Page", of: "sur", showing: "Affichage", total: "Total", totals: "Totaux", errorOccurred: "Une erreur s'est produite" }, Ei = { title: "Langue", help: "Choisissez la langue de l'interface. Votre choix est enregistré dans ce navigateur.", label: "Langue" }, Li = { logout: "Déconnexion", openMenu: "Ouvrir le menu", closeMenu: "Fermer le menu", new: "Nouveau : {{label}}" }, Oi = { 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" }, qi = { quotation: { one: "Devis", other: "Devis" }, proposal: { one: "Offre groupée", other: "Offres groupées" }, "sales-order": { one: "Commande client", other: "Commandes client" }, "sales-invoice": { one: "Facture de vente", other: "Factures de vente" }, "pos-invoice": { one: "Ticket de caisse", other: "Tickets de caisse" }, "purchase-order": { one: "Bon de commande", other: "Bons de commande" }, "purchase-invoice": { one: "Facture d'achat", other: "Factures d'achat" }, "payment-entry": { one: "Paiement", other: "Paiements" }, "journal-entry": { one: "Écriture comptable", other: "Écritures comptables" }, "bank-transaction": { one: "Transaction bancaire", other: "Transactions bancaires" }, budget: { one: "Budget", other: "Budgets" }, subscription: { one: "Abonnement", other: "Abonnements" }, "stock-entry": { one: "Mouvement de stock", other: "Mouvements de stock" }, "delivery-note": { one: "Bon de livraison", other: "Bons de livraison" }, "purchase-receipt": { one: "Bon de réception", other: "Bons de réception" }, "pricing-rule": { one: "Règle de prix", other: "Règles de prix" } }, zi = { 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" } }, Mi = { chats: "Discussions", newChat: "Nouvelle discussion", deleteChat: "Supprimer la discussion", customAnalytics: "Analyses personnalisées", newAnalytics: "Nouvelle analyse", deleteReport: "Supprimer le rapport", groups: { Introduction: "Introduction", Selling: "Ventes", Buying: "Achats", Accounting: "Comptabilité", Stock: "Stock", Reports: "Rapports", Masters: "Données de base", Settings: "Paramètres" }, items: { "Getting Started": "Premiers pas", "Company Setup": "Configuration de l'entreprise", "Opening Balances": "Soldes d'ouverture", Quotation: "Devis", Proposal: "Offre groupée", "Sales Order": "Commande client", "Sales Invoice": "Facture de vente", "POS Invoice": "Ticket de caisse", "Purchase Order": "Bon de commande", "Purchase Invoice": "Facture d'achat", "Payment Entry": "Paiement", "Journal Entry": "Écriture comptable", "Bank Transaction": "Transaction bancaire", Budget: "Budget", Subscription: "Abonnement", "Stock Entry": "Mouvement de stock", "Delivery Note": "Bon de livraison", "Purchase Receipt": "Bon de réception", "Trial Balance": "Balance comptable", "Profit & Loss": "Compte de résultat", "Balance Sheet": "Bilan", "General Ledger": "Grand livre", "AR Aging": "Balance âgée clients", "AP Aging": "Balance âgée fournisseurs", Analytics: "Analyses", "Stock Balance": "Solde de stock", Company: "Société", Customer: "Client", Supplier: "Fournisseur", Item: "Article", Warehouse: "Entrepôt", General: "Général", "Pricing Rule": "Règle de prix", "Users & Team": "Utilisateurs et équipe", "Chart of Accounts": "Plan comptable" } }, Fi = { 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." } }, $i = { pdfTitle: "PDF et impression", pageSize: "Format de page", pdfHelp: "A4 est la norme internationale (210 x 297 mm). Letter est la norme aux États-Unis (8,5 x 11 po).", passwordTitle: "Changer le mot de passe", currentPassword: "Mot de passe actuel", newPassword: "Nouveau mot de passe", confirmNewPassword: "Confirmer le nouveau mot de passe", changePassword: "Changer le mot de passe", changingPassword: "Modification...", passwordChanged: "Mot de passe modifié.", setPasswordTitle: "Définir un mot de passe", setPasswordBody: "Votre compte se connecte avec Google. Définissez un mot de passe pour vous connecter aussi avec e-mail et mot de passe — un recours pratique si vous perdez l'accès à votre compte Google.", setPassword: "Définir le mot de passe", passwordSet: "Mot de passe défini.", linkedAccountsTitle: "Comptes liés", linkedAccountsBody: "Liez un compte Google ou Apple pour vous connecter sans mot de passe.", linked: "Lié", linkProvider: "Lier {{provider}}", openingTitle: "Soldes d'ouverture", openingBody: "La page Soldes d'ouverture permet d'importer les soldes des comptes, le stock et les factures impayées d'un système précédent.", openingEnabled: "Actuellement activé — accessible sous Introduction > Soldes d'ouverture.", openingDisabled: "Actuellement désactivé — la page est masquée dans la barre latérale.", signupTitle: "Inscription publique", signupBody: "Permettre à quiconque de créer son propre compte (en tant que lecteur) sans invitation. Lorsque désactivé, les nouveaux utilisateurs ne peuvent rejoindre que via un lien d'invitation.", signupEnabled: "Actuellement activé — toute personne disposant de l'URL peut s'inscrire en tant que lecteur.", signupDisabled: "Actuellement désactivé — l'inscription se fait uniquement sur invitation.", chatApiTitle: "API de chat", apiTitle: "API programmatique", restApiBody: "Permettre à des connecteurs et scripts de piloter cet ERP via son API REST (documents, données de base, rapports) avec les mêmes clés API Bearer. Désactivé par défaut.", restApiEnabled: "Actuellement activé — les clés émises peuvent appeler /api/documents, /api/masters et le reste de l'API REST.", restApiDisabled: "Actuellement désactivé — l'API REST n'accepte que le cookie de session ; les clés sont rejetées.", restApiDeactivateTitle: "Désactiver l'API REST ?", restApiDeactivateBody: "L'accès par clé Bearer à l'API REST sera désactivé — les connecteurs et scripts sont rejetés jusqu'à sa réactivation. L'application web (cookie de session) n'est pas affectée, et vos clés API ne sont PAS supprimées : elles fonctionnent à nouveau dès que vous réactivez l'API.", chatApiBody: "Permettre à des applications externes de dialoguer avec l'agent de chat de cet ERP via une API HTTP, à l'aide de clés API Bearer. Désactivé par défaut.", chatApiEnabled: "Actuellement activé — les clés émises peuvent appeler POST /api/v1/chat.", chatApiDisabled: "Actuellement désactivé — l'API renvoie 404 et les clés ne fonctionnent pas.", chatApiDeactivateTitle: "Désactiver l'API chat ?", chatApiDeactivateBody: "L'API chat sera désactivée — toute requête programmatique (clés API Bearer) est rejetée jusqu'à sa réactivation. Vos clés API ne sont PAS supprimées : elles restent enregistrées et fonctionnent à nouveau dès que vous réactivez l'API.", chatApiDeactivateConfirm: "Désactiver l'API", chatApiKeysTitle: "Clés API", chatApiTokenOnce: "Copiez ce jeton maintenant — il ne sera plus affiché.", chatApiCopy: "Copier", chatApiDismiss: "Fermer", chatApiRevoked: "révoquée", chatApiRevoke: "Révoquer", chatApiNoKeys: "Aucune clé API pour l'instant.", chatApiName: "Nom", chatApiRole: "Rôle", chatApiCreate: "Créer une clé", chatApiWarn: "Une clé agit avec votre identité et au plus votre rôle — à traiter comme un mot de passe. Révoquer d'abord, puis supprimer.", publicTitle: "Accès public (mode démo)", publicActive: "Actif", publicActiveBody: "L'accès public est activé. N'importe qui peut utiliser l'application sans se connecter. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire.", disablePublic: "Désactiver l'accès public", disabling: "Désactivation...", publicInactiveBody: "Activez l'accès public pour permettre à quiconque d'utiliser l'application sans compte. Utile pour les démos et présentations. Tous les visiteurs obtiennent des autorisations de niveau gestionnaire et partagent la même identité.", enablePublic: "Activer l'accès public", enableWarning: "Cela permettra à quiconque d'accéder à l'application sans se connecter. Ils pourront créer, modifier et valider des documents. Votre compte administrateur nécessite toujours une connexion.", yesEnable: "Oui, activer", enabling: "Activation...", tokenSpendTitle: "Dépenses de jetons", chatApiDelete: "Supprimer", chatApiYourKeys: "Vos clés", chatApiYouBadge: "vous", chatApiUnknownUser: "Utilisateur inconnu", chatApiAdminAllNote: "En tant qu'administrateur, la liste ci-dessous inclut les clés de tous les utilisateurs, groupées par propriétaire. Les vôtres apparaissent en premier.", chatApiConfirmTitle: "Cette clé ne vous appartient pas", chatApiConfirmRevokeBody: "« {{key}} » appartient à {{name}}. La révoquer coupera immédiatement son accès à l'API. Continuer ?", chatApiConfirmDeleteBody: "« {{key}} » appartient à {{name}}. La supprimer retire définitivement sa clé. Continuer ?", chatApiPersonal: "Clés Bearer personnelles pour l'API de chat programmatique. Une clé agit en VOTRE nom : plafonnée à votre rôle, elle suit les changements de rôle en direct et expire avec votre compte. Nécessite que l'admin ait activé l'API de chat." }, Ui = { 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é" }, Vi = { 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é" }, Ki = { 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}}." }, ji = { Account: "Compte", Amount: "Montant", Balance: "Solde", Credit: "Crédit", Debit: "Débit", Date: "Date", Party: "Tiers", "Party Type": "Type de tiers", "Voucher Type": "Type de pièce", "Voucher No": "N° de pièce", Invoice: "Facture", Customer: "Client", Supplier: "Fournisseur", "Due Date": "Date d'échéance", Outstanding: "Encours", "Outstanding Amount": "Montant dû", "Item Code": "Code article", "Item Name": "Nom de l'article", Item: "Article", Warehouse: "Entrepôt", Qty: "Qté", "Valuation Rate": "Coût unitaire", "Stock Value": "Valeur du stock", Name: "Nom", Status: "Statut", Company: "Société", "From Date": "Date de début", "To Date": "Date de fin", "As of Date": "À la date", "Valid Till": "Valable jusqu'au", "Net Total": "Total net", Tax: "Taxe", "Grand Total": "Total TTC", Frequency: "Fréquence", "Notes / Terms": "Notes / Conditions", "Posting Date": "Date de comptabilisation", "Transaction Date": "Date de transaction", "Delivery Date": "Date de livraison", "% Delivered": "% livré", "% Billed": "% facturé", "Update Stock": "Mettre à jour le stock", "Payment Type": "Type de paiement", "Paid From": "Payé depuis", "Paid To": "Payé à", "Paid Amount": "Montant payé", Type: "Type", Total: "Total", Allocated: "Affecté", Unallocated: "Non affecté", Remark: "Remarque", "Total Debit": "Total débit", "Total Credit": "Total crédit", "Cost Center": "Centre de coûts", "Source Warehouse": "Entrepôt source", "Target Warehouse": "Entrepôt cible", Source: "Source", Target: "Cible", "Incoming Value": "Valeur entrante", "Outgoing Value": "Valeur sortante", Rate: "Prix unitaire", "Income Account": "Compte de produits", "Expense Account": "Compte de charges", Description: "Description", "Rate (%)": "Taux (%)", Mode: "Mode", Change: "Monnaie rendue", Currency: "Devise", Title: "Titre", Selling: "Vente", Buying: "Achat", "Discount %": "Remise %", "Discount Amt": "Montant remise", "Min Qty": "Qté min", "Valid From": "Valable à partir du", "Valid Upto": "Valable jusqu'au", Priority: "Priorité", Enabled: "Activé", "Fiscal Year": "Exercice", "Budget Amount": "Montant du budget", "If Exceeded": "Si dépassé", Month: "Mois", "Bank Account": "Compte bancaire", Deposit: "Dépôt", Withdrawal: "Retrait", "Reference No": "N° de référence", "Matched Type": "Type rapproché", "Matched Doc": "Pièce rapprochée", "Start Date": "Date de début", "End Date": "Date de fin", "Billing Interval": "Intervalle de facturation", "Current Period Start": "Début période actuelle", "Current Period End": "Fin période actuelle", "Plan Items": "Articles du plan", "Total Amount": "Montant total", "Stock Entry Type": "Type de mouvement de stock", "Rate Or Discount": "Prix ou remise", "Discount Percentage": "Pourcentage de remise", ID: "ID", "Customer Name": "Nom du client", "Customer Group": "Groupe de clients", Territory: "Territoire", "Credit Limit": "Limite de crédit", Email: "E-mail", Phone: "Téléphone", Address: "Adresse", City: "Ville", "Zip Code": "Code postal", Country: "Pays", "Tax ID": "N° de TVA", "Contact Person": "Personne de contact", "Contact Email": "E-mail du contact", "Contact Phone": "Téléphone du contact", "Supplier Name": "Nom du fournisseur", "Supplier Group": "Groupe de fournisseurs", "Item Group": "Groupe d'articles", "Stock UOM": "Unité de stock", "Standard Rate": "Prix standard", "Warehouse Name": "Nom de l'entrepôt", "Company Name": "Nom de la société" }, Gi = { 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" }, Wi = { "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" }, Hi = { 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" }, Qi = { 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." }, Yi = /* @__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 ?"}`), Ji = { title: "Aide au formatage", intro: "Le texte des Notes / Conditions prend en charge une mise en forme légère sur le PDF :", heading: "titre en gras", emphasis: "italique / gras", rule: "ligne de séparation horizontale", price: "prix aligné à droite à côté du texte ci-dessus (p. ex. Mensuel | CHF 380.—)", block: "Séparez les blocs par une ligne vide." }, Zi = { 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" } }, Xi = {
|
|
6925
|
+
common: Bi,
|
|
6926
|
+
language: Ei,
|
|
6927
6927
|
header: Li,
|
|
6928
|
-
titles:
|
|
6929
|
-
doctypes:
|
|
6930
|
-
masters:
|
|
6931
|
-
nav:
|
|
6932
|
-
login:
|
|
6933
|
-
settings:
|
|
6934
|
-
status:
|
|
6935
|
-
reports:
|
|
6936
|
-
masterForm:
|
|
6937
|
-
fields:
|
|
6938
|
-
tables:
|
|
6939
|
-
conversions:
|
|
6940
|
-
dashboard:
|
|
6941
|
-
chat:
|
|
6942
|
-
tutorial:
|
|
6943
|
-
notesMarkup:
|
|
6944
|
-
coa:
|
|
6945
|
-
},
|
|
6928
|
+
titles: Oi,
|
|
6929
|
+
doctypes: qi,
|
|
6930
|
+
masters: zi,
|
|
6931
|
+
nav: Mi,
|
|
6932
|
+
login: Fi,
|
|
6933
|
+
settings: $i,
|
|
6934
|
+
status: Ui,
|
|
6935
|
+
reports: Vi,
|
|
6936
|
+
masterForm: Ki,
|
|
6937
|
+
fields: ji,
|
|
6938
|
+
tables: Gi,
|
|
6939
|
+
conversions: Wi,
|
|
6940
|
+
dashboard: Hi,
|
|
6941
|
+
chat: Qi,
|
|
6942
|
+
tutorial: Yi,
|
|
6943
|
+
notesMarkup: Ji,
|
|
6944
|
+
coa: Zi
|
|
6945
|
+
}, ha = [
|
|
6946
6946
|
{ code: "en", label: "English" },
|
|
6947
6947
|
{ code: "de", label: "Deutsch" },
|
|
6948
6948
|
{ code: "fr", label: "Français" }
|
|
6949
|
-
],
|
|
6950
|
-
function
|
|
6951
|
-
return !!t &&
|
|
6949
|
+
], ga = "lambda-erp:language";
|
|
6950
|
+
function eo(t) {
|
|
6951
|
+
return !!t && ha.some((n) => n.code === t);
|
|
6952
6952
|
}
|
|
6953
|
-
function
|
|
6953
|
+
function to() {
|
|
6954
6954
|
try {
|
|
6955
|
-
const t = localStorage.getItem(
|
|
6956
|
-
if (
|
|
6955
|
+
const t = localStorage.getItem(ga);
|
|
6956
|
+
if (eo(t)) return t;
|
|
6957
6957
|
} catch {
|
|
6958
6958
|
}
|
|
6959
6959
|
return "en";
|
|
6960
6960
|
}
|
|
6961
|
-
function
|
|
6961
|
+
function no(t) {
|
|
6962
6962
|
try {
|
|
6963
|
-
localStorage.setItem(
|
|
6963
|
+
localStorage.setItem(ga, t);
|
|
6964
6964
|
} catch {
|
|
6965
6965
|
}
|
|
6966
6966
|
}
|
|
6967
|
-
|
|
6967
|
+
ea.use(Ra).init({
|
|
6968
6968
|
resources: {
|
|
6969
|
-
en: { translation:
|
|
6970
|
-
de: { translation:
|
|
6971
|
-
fr: { translation:
|
|
6969
|
+
en: { translation: ui },
|
|
6970
|
+
de: { translation: Ii },
|
|
6971
|
+
fr: { translation: Xi }
|
|
6972
6972
|
},
|
|
6973
|
-
lng:
|
|
6973
|
+
lng: to(),
|
|
6974
6974
|
fallbackLng: "en",
|
|
6975
6975
|
// any key missing in de/fr falls back to the English value
|
|
6976
6976
|
interpolation: { escapeValue: !1 },
|
|
@@ -6978,15 +6978,15 @@ Xn.use(Ta).init({
|
|
|
6978
6978
|
react: { useSuspense: !1 }
|
|
6979
6979
|
// resources are bundled synchronously — no Suspense needed
|
|
6980
6980
|
});
|
|
6981
|
-
|
|
6982
|
-
function
|
|
6981
|
+
ea.on("languageChanged", no);
|
|
6982
|
+
function ao({ label: t }) {
|
|
6983
6983
|
var i;
|
|
6984
|
-
const { t: n, i18n: a } =
|
|
6984
|
+
const { t: n, i18n: a } = Z(), s = ((i = a.language) == null ? void 0 : i.split("-")[0]) ?? "en";
|
|
6985
6985
|
return /* @__PURE__ */ e(
|
|
6986
6986
|
He,
|
|
6987
6987
|
{
|
|
6988
6988
|
label: t === null ? void 0 : t ?? n("language.label"),
|
|
6989
|
-
options:
|
|
6989
|
+
options: ha.map((o) => ({ value: o.code, label: o.label })),
|
|
6990
6990
|
value: s,
|
|
6991
6991
|
onChange: (o) => a.changeLanguage(o.target.value)
|
|
6992
6992
|
}
|
|
@@ -7003,9 +7003,9 @@ const Fn = [
|
|
|
7003
7003
|
function Ge(t) {
|
|
7004
7004
|
return t === 0 ? "$0.00" : t < 0.01 ? `$${t.toFixed(4)}` : `$${t.toFixed(2)}`;
|
|
7005
7005
|
}
|
|
7006
|
-
function
|
|
7006
|
+
function ro({ demoActive: t }) {
|
|
7007
7007
|
var P, b;
|
|
7008
|
-
const { t: n } =
|
|
7008
|
+
const { t: n } = Z(), [a, s] = S("1h"), { data: i, isLoading: o, isFetching: l, error: c, refetch: g, dataUpdatedAt: m } = oe({
|
|
7009
7009
|
queryKey: ["demo-spend"],
|
|
7010
7010
|
queryFn: () => I.getDemoSpend(),
|
|
7011
7011
|
// Refresh once a minute — demo spend changes slowly; no need to poll harder.
|
|
@@ -7131,11 +7131,11 @@ function ao({ demoActive: t }) {
|
|
|
7131
7131
|
] })
|
|
7132
7132
|
),
|
|
7133
7133
|
/* @__PURE__ */ r("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: [
|
|
7134
|
-
t ? /* @__PURE__ */ e(
|
|
7135
|
-
/* @__PURE__ */ e(
|
|
7136
|
-
/* @__PURE__ */ e(
|
|
7134
|
+
t ? /* @__PURE__ */ e(St, { label: "Demo spend", value: Ge(u.demo_usd) }) : /* @__PURE__ */ e(St, { label: "Cost", value: Ge(u.total_usd) }),
|
|
7135
|
+
/* @__PURE__ */ e(St, { label: "Calls", value: u.call_count.toLocaleString() }),
|
|
7136
|
+
/* @__PURE__ */ e(St, { label: "Unique IPs", value: u.unique_ips.toLocaleString() }),
|
|
7137
7137
|
/* @__PURE__ */ e(
|
|
7138
|
-
|
|
7138
|
+
St,
|
|
7139
7139
|
{
|
|
7140
7140
|
label: "Tokens (in/out)",
|
|
7141
7141
|
value: `${u.prompt_tokens.toLocaleString()} / ${u.completion_tokens.toLocaleString()}`
|
|
@@ -7181,14 +7181,14 @@ function ao({ demoActive: t }) {
|
|
|
7181
7181
|
] })
|
|
7182
7182
|
] });
|
|
7183
7183
|
}
|
|
7184
|
-
function
|
|
7184
|
+
function St({ label: t, value: n }) {
|
|
7185
7185
|
return /* @__PURE__ */ r("div", { className: "rounded-md bg-gray-50 px-3 py-2", children: [
|
|
7186
7186
|
/* @__PURE__ */ e("div", { className: "text-xs font-medium uppercase tracking-wide text-gray-500", children: t }),
|
|
7187
7187
|
/* @__PURE__ */ e("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-gray-900", children: n })
|
|
7188
7188
|
] });
|
|
7189
7189
|
}
|
|
7190
|
-
function
|
|
7191
|
-
const { t } =
|
|
7190
|
+
function so() {
|
|
7191
|
+
const { t } = Z(), { user: n } = st(), [a, s] = S(""), [i, o] = S(""), [l, c] = S(""), [g, m] = S(""), [h, u] = S(!1), N = ie({
|
|
7192
7192
|
mutationFn: () => I.authChangePassword(a, i),
|
|
7193
7193
|
onSuccess: () => {
|
|
7194
7194
|
u(!0), m(""), s(""), o(""), c(""), setTimeout(() => u(!1), 4e3);
|
|
@@ -7264,8 +7264,8 @@ function ro() {
|
|
|
7264
7264
|
/* @__PURE__ */ e(H, { type: "submit", disabled: N.isPending || !a || !i || !l, children: N.isPending ? t("settings.changingPassword") : t("settings.changePassword") })
|
|
7265
7265
|
] }) });
|
|
7266
7266
|
}
|
|
7267
|
-
function
|
|
7268
|
-
const { t } =
|
|
7267
|
+
function io() {
|
|
7268
|
+
const { t } = Z(), { user: n, refreshUser: a } = st(), [s, i] = S(""), [o, l] = S(""), [c, g] = S(""), [m, h] = S(!1), u = ie({
|
|
7269
7269
|
mutationFn: () => I.authSetPassword(s),
|
|
7270
7270
|
onSuccess: async () => {
|
|
7271
7271
|
h(!0), g(""), i(""), l(""), await a();
|
|
@@ -7330,8 +7330,8 @@ function so() {
|
|
|
7330
7330
|
] })
|
|
7331
7331
|
] });
|
|
7332
7332
|
}
|
|
7333
|
-
function
|
|
7334
|
-
const { t } =
|
|
7333
|
+
function oo() {
|
|
7334
|
+
const { t } = Z(), { data: n } = oe({
|
|
7335
7335
|
queryKey: ["auth-setup-status"],
|
|
7336
7336
|
queryFn: () => I.authSetupStatus()
|
|
7337
7337
|
}), { data: a } = oe({
|
|
@@ -7365,8 +7365,8 @@ function io() {
|
|
|
7365
7365
|
] });
|
|
7366
7366
|
}
|
|
7367
7367
|
const Yt = { viewer: 1, manager: 2, admin: 3 };
|
|
7368
|
-
function
|
|
7369
|
-
const { t: n } =
|
|
7368
|
+
function fa({ ownRole: t }) {
|
|
7369
|
+
const { t: n } = Z(), { user: a } = st(), s = We(), [i, o] = S(""), [l, c] = S(t in Yt ? t : "viewer"), [g, m] = S(null), [h, u] = S(null), N = ["viewer", "manager", "admin"].filter(
|
|
7370
7370
|
(y) => Yt[y] <= (Yt[t] ?? 1)
|
|
7371
7371
|
), { data: x } = oe({
|
|
7372
7372
|
queryKey: ["api-keys"],
|
|
@@ -7382,7 +7382,7 @@ function ga({ ownRole: t }) {
|
|
|
7382
7382
|
}), T = ie({
|
|
7383
7383
|
mutationFn: (y) => I.deleteApiKey(y),
|
|
7384
7384
|
onSuccess: () => s.invalidateQueries({ queryKey: ["api-keys"] })
|
|
7385
|
-
}), P = (y) => y.is_mine ?? y.user === (a == null ? void 0 : a.name), b = (y) => y.owner_full_name || y.owner_email || y.user || n("settings.chatApiUnknownUser"), d =
|
|
7385
|
+
}), P = (y) => y.is_mine ?? y.user === (a == null ? void 0 : a.name), b = (y) => y.owner_full_name || y.owner_email || y.user || n("settings.chatApiUnknownUser"), d = Ce(() => {
|
|
7386
7386
|
const y = /* @__PURE__ */ new Map();
|
|
7387
7387
|
for (const B of x ?? []) {
|
|
7388
7388
|
const D = B.is_mine ?? B.user === (a == null ? void 0 : a.name), O = D ? "__me__" : B.user ?? "__unknown__";
|
|
@@ -7522,59 +7522,91 @@ function ga({ ownRole: t }) {
|
|
|
7522
7522
|
)
|
|
7523
7523
|
] });
|
|
7524
7524
|
}
|
|
7525
|
-
function
|
|
7525
|
+
function $n({
|
|
7526
7526
|
enabled: t,
|
|
7527
7527
|
onToggle: n,
|
|
7528
|
-
|
|
7528
|
+
body: a,
|
|
7529
|
+
statusOn: s,
|
|
7530
|
+
statusOff: i
|
|
7529
7531
|
}) {
|
|
7530
|
-
const { t:
|
|
7531
|
-
return /* @__PURE__ */ r(
|
|
7532
|
-
/* @__PURE__ */ r("div", {
|
|
7533
|
-
/* @__PURE__ */
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7532
|
+
const { t: o } = Z();
|
|
7533
|
+
return /* @__PURE__ */ r("div", { className: "flex items-center justify-between", children: [
|
|
7534
|
+
/* @__PURE__ */ r("div", { children: [
|
|
7535
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-gray-700", children: a }),
|
|
7536
|
+
/* @__PURE__ */ e("p", { className: "mt-1 text-xs text-gray-400", children: t ? s : i })
|
|
7537
|
+
] }),
|
|
7538
|
+
/* @__PURE__ */ e(
|
|
7539
|
+
"button",
|
|
7540
|
+
{
|
|
7541
|
+
onClick: n,
|
|
7542
|
+
className: `ml-4 shrink-0 rounded-full px-4 py-1.5 text-sm font-medium ${t ? "bg-red-50 text-red-700 hover:bg-red-100" : "bg-green-50 text-green-700 hover:bg-green-100"}`,
|
|
7543
|
+
children: o(t ? "common.disable" : "common.enable")
|
|
7544
|
+
}
|
|
7545
|
+
)
|
|
7546
|
+
] });
|
|
7547
|
+
}
|
|
7548
|
+
function lo({
|
|
7549
|
+
chatEnabled: t,
|
|
7550
|
+
restEnabled: n,
|
|
7551
|
+
onToggleChat: a,
|
|
7552
|
+
onToggleRest: s,
|
|
7553
|
+
ownRole: i
|
|
7554
|
+
}) {
|
|
7555
|
+
const { t: o } = Z(), [l, c] = S(null);
|
|
7556
|
+
return /* @__PURE__ */ r($, { title: o("settings.apiTitle"), children: [
|
|
7557
|
+
/* @__PURE__ */ r("div", { className: "space-y-4", children: [
|
|
7537
7558
|
/* @__PURE__ */ e(
|
|
7538
|
-
|
|
7559
|
+
$n,
|
|
7539
7560
|
{
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7561
|
+
enabled: t,
|
|
7562
|
+
onToggle: () => t ? c("chat") : a(),
|
|
7563
|
+
body: o("settings.chatApiBody"),
|
|
7564
|
+
statusOn: o("settings.chatApiEnabled"),
|
|
7565
|
+
statusOff: o("settings.chatApiDisabled")
|
|
7566
|
+
}
|
|
7567
|
+
),
|
|
7568
|
+
/* @__PURE__ */ e("div", { className: "border-t border-gray-100" }),
|
|
7569
|
+
/* @__PURE__ */ e(
|
|
7570
|
+
$n,
|
|
7571
|
+
{
|
|
7572
|
+
enabled: n,
|
|
7573
|
+
onToggle: () => n ? c("rest") : s(),
|
|
7574
|
+
body: o("settings.restApiBody"),
|
|
7575
|
+
statusOn: o("settings.restApiEnabled"),
|
|
7576
|
+
statusOff: o("settings.restApiDisabled")
|
|
7545
7577
|
}
|
|
7546
7578
|
)
|
|
7547
7579
|
] }),
|
|
7548
|
-
t && /* @__PURE__ */ r("div", { className: "mt-4 border-t border-gray-100 pt-4", children: [
|
|
7549
|
-
/* @__PURE__ */ e("div", { className: "mb-2 text-xs font-medium text-gray-500", children:
|
|
7550
|
-
/* @__PURE__ */ e(
|
|
7580
|
+
(t || n) && /* @__PURE__ */ r("div", { className: "mt-4 border-t border-gray-100 pt-4", children: [
|
|
7581
|
+
/* @__PURE__ */ e("div", { className: "mb-2 text-xs font-medium text-gray-500", children: o("settings.chatApiKeysTitle") }),
|
|
7582
|
+
/* @__PURE__ */ e(fa, { ownRole: i })
|
|
7551
7583
|
] }),
|
|
7552
|
-
|
|
7584
|
+
l && /* @__PURE__ */ e(
|
|
7553
7585
|
"div",
|
|
7554
7586
|
{
|
|
7555
7587
|
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
7556
|
-
onClick: () =>
|
|
7588
|
+
onClick: () => c(null),
|
|
7557
7589
|
children: /* @__PURE__ */ r(
|
|
7558
7590
|
"div",
|
|
7559
7591
|
{
|
|
7560
7592
|
className: "w-full max-w-md rounded-xl border border-line bg-surface p-6 shadow-xl",
|
|
7561
7593
|
role: "dialog",
|
|
7562
7594
|
"aria-modal": "true",
|
|
7563
|
-
onClick: (
|
|
7595
|
+
onClick: (g) => g.stopPropagation(),
|
|
7564
7596
|
children: [
|
|
7565
|
-
/* @__PURE__ */ e("h3", { className: "text-base font-semibold text-fg", children:
|
|
7566
|
-
/* @__PURE__ */ e("p", { className: "mt-3 text-sm text-fg-muted", children:
|
|
7597
|
+
/* @__PURE__ */ e("h3", { className: "text-base font-semibold text-fg", children: o(l === "chat" ? "settings.chatApiDeactivateTitle" : "settings.restApiDeactivateTitle") }),
|
|
7598
|
+
/* @__PURE__ */ e("p", { className: "mt-3 text-sm text-fg-muted", children: o(l === "chat" ? "settings.chatApiDeactivateBody" : "settings.restApiDeactivateBody") }),
|
|
7567
7599
|
/* @__PURE__ */ r("div", { className: "mt-6 flex justify-end gap-2", children: [
|
|
7568
|
-
/* @__PURE__ */ e(H, { variant: "secondary", size: "sm", onClick: () =>
|
|
7600
|
+
/* @__PURE__ */ e(H, { variant: "secondary", size: "sm", onClick: () => c(null), children: o("common.cancel") }),
|
|
7569
7601
|
/* @__PURE__ */ e(
|
|
7570
7602
|
H,
|
|
7571
7603
|
{
|
|
7572
7604
|
variant: "danger",
|
|
7573
7605
|
size: "sm",
|
|
7574
7606
|
onClick: () => {
|
|
7575
|
-
|
|
7607
|
+
l === "chat" ? a() : s(), c(null);
|
|
7576
7608
|
},
|
|
7577
|
-
children:
|
|
7609
|
+
children: o("settings.chatApiDeactivateConfirm")
|
|
7578
7610
|
}
|
|
7579
7611
|
)
|
|
7580
7612
|
] })
|
|
@@ -7585,8 +7617,8 @@ function oo({
|
|
|
7585
7617
|
)
|
|
7586
7618
|
] });
|
|
7587
7619
|
}
|
|
7588
|
-
function
|
|
7589
|
-
const { user: t } = st(), { t: n } =
|
|
7620
|
+
function co() {
|
|
7621
|
+
const { user: t } = st(), { t: n } = Z(), a = We(), s = (t == null ? void 0 : t.role) === "admin", { data: i, isLoading: o } = oe({
|
|
7590
7622
|
queryKey: ["settings"],
|
|
7591
7623
|
queryFn: () => I.getSettings()
|
|
7592
7624
|
}), l = ie({
|
|
@@ -7595,7 +7627,7 @@ function lo() {
|
|
|
7595
7627
|
}), { data: c } = oe({
|
|
7596
7628
|
queryKey: ["public-manager"],
|
|
7597
7629
|
queryFn: () => I.getPublicManagerStatus()
|
|
7598
|
-
}), [g, m] =
|
|
7630
|
+
}), [g, m] = S(!1), h = ie({
|
|
7599
7631
|
mutationFn: () => I.createPublicManager(),
|
|
7600
7632
|
onSuccess: () => {
|
|
7601
7633
|
a.invalidateQueries({ queryKey: ["public-manager"] }), m(!1);
|
|
@@ -7606,11 +7638,11 @@ function lo() {
|
|
|
7606
7638
|
});
|
|
7607
7639
|
return o ? /* @__PURE__ */ e("p", { className: "text-gray-500", children: n("common.loading") }) : /* @__PURE__ */ r("div", { className: "space-y-6", children: [
|
|
7608
7640
|
/* @__PURE__ */ r($, { title: n("language.title"), children: [
|
|
7609
|
-
/* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(
|
|
7641
|
+
/* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: /* @__PURE__ */ e("div", { className: "w-64", children: /* @__PURE__ */ e(ao, {}) }) }),
|
|
7610
7642
|
/* @__PURE__ */ e("p", { className: "mt-2 text-xs text-gray-400", children: n("language.help") })
|
|
7611
7643
|
] }),
|
|
7612
|
-
(t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(
|
|
7613
|
-
(t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(
|
|
7644
|
+
(t == null ? void 0 : t.role) !== "public_manager" && ((t == null ? void 0 : t.has_password) === !1 ? /* @__PURE__ */ e(io, {}) : /* @__PURE__ */ e(so, {})),
|
|
7645
|
+
(t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ e(oo, {}),
|
|
7614
7646
|
/* @__PURE__ */ r($, { title: n("settings.pdfTitle"), children: [
|
|
7615
7647
|
/* @__PURE__ */ e("div", { className: "flex flex-wrap items-end gap-4", children: s ? /* @__PURE__ */ e(
|
|
7616
7648
|
He,
|
|
@@ -7659,20 +7691,24 @@ function lo() {
|
|
|
7659
7691
|
)
|
|
7660
7692
|
] }) }),
|
|
7661
7693
|
s && /* @__PURE__ */ e(
|
|
7662
|
-
|
|
7694
|
+
lo,
|
|
7663
7695
|
{
|
|
7664
|
-
|
|
7696
|
+
chatEnabled: (i == null ? void 0 : i.chat_api_enabled) === "1",
|
|
7697
|
+
restEnabled: (i == null ? void 0 : i.rest_api_enabled) === "1",
|
|
7665
7698
|
ownRole: (t == null ? void 0 : t.role) ?? "viewer",
|
|
7666
|
-
|
|
7699
|
+
onToggleChat: () => l.mutate({
|
|
7667
7700
|
chat_api_enabled: (i == null ? void 0 : i.chat_api_enabled) === "1" ? "0" : "1"
|
|
7701
|
+
}),
|
|
7702
|
+
onToggleRest: () => l.mutate({
|
|
7703
|
+
rest_api_enabled: (i == null ? void 0 : i.rest_api_enabled) === "1" ? "0" : "1"
|
|
7668
7704
|
})
|
|
7669
7705
|
}
|
|
7670
7706
|
),
|
|
7671
7707
|
!s && (t == null ? void 0 : t.role) !== "public_manager" && /* @__PURE__ */ r($, { title: n("settings.chatApiKeysTitle"), children: [
|
|
7672
7708
|
/* @__PURE__ */ e("p", { className: "mb-3 text-sm text-gray-700", children: n("settings.chatApiPersonal") }),
|
|
7673
|
-
/* @__PURE__ */ e(
|
|
7709
|
+
/* @__PURE__ */ e(fa, { ownRole: (t == null ? void 0 : t.role) ?? "viewer" })
|
|
7674
7710
|
] }),
|
|
7675
|
-
s && /* @__PURE__ */ e(
|
|
7711
|
+
s && /* @__PURE__ */ e(ro, { demoActive: !!(c != null && c.active) }),
|
|
7676
7712
|
s && /* @__PURE__ */ e($, { title: n("settings.publicTitle"), children: c != null && c.active ? /* @__PURE__ */ r("div", { children: [
|
|
7677
7713
|
/* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
|
|
7678
7714
|
/* @__PURE__ */ e("span", { className: "inline-block h-2 w-2 rounded-full bg-green-500" }),
|
|
@@ -7723,25 +7759,25 @@ function lo() {
|
|
|
7723
7759
|
] }) })
|
|
7724
7760
|
] });
|
|
7725
7761
|
}
|
|
7726
|
-
const
|
|
7727
|
-
function
|
|
7728
|
-
|
|
7762
|
+
const ya = {};
|
|
7763
|
+
function Eo(t, n) {
|
|
7764
|
+
ya[t] = n;
|
|
7729
7765
|
}
|
|
7730
|
-
function
|
|
7731
|
-
return
|
|
7766
|
+
function uo(t, n) {
|
|
7767
|
+
return ya[t] ?? n;
|
|
7732
7768
|
}
|
|
7733
|
-
function
|
|
7734
|
-
const t =
|
|
7769
|
+
function mo() {
|
|
7770
|
+
const t = uo("Dashboard", vr);
|
|
7735
7771
|
return /* @__PURE__ */ e(t, {});
|
|
7736
7772
|
}
|
|
7737
|
-
const
|
|
7738
|
-
{ path: "/login", element: /* @__PURE__ */ e(
|
|
7739
|
-
{ path: "/demo", element: /* @__PURE__ */ e(
|
|
7740
|
-
],
|
|
7741
|
-
{ index: !0, element: /* @__PURE__ */ e(
|
|
7742
|
-
{ path: "setup", element: /* @__PURE__ */ e(
|
|
7743
|
-
{ path: "setup/opening-balances", element: /* @__PURE__ */ e(
|
|
7744
|
-
{ path: "tutorial", element: /* @__PURE__ */ e(
|
|
7773
|
+
const po = [
|
|
7774
|
+
{ path: "/login", element: /* @__PURE__ */ e(Ms, {}) },
|
|
7775
|
+
{ path: "/demo", element: /* @__PURE__ */ e(Us, {}) }
|
|
7776
|
+
], ho = [
|
|
7777
|
+
{ index: !0, element: /* @__PURE__ */ e(mo, {}) },
|
|
7778
|
+
{ path: "setup", element: /* @__PURE__ */ e(ws, {}) },
|
|
7779
|
+
{ path: "setup/opening-balances", element: /* @__PURE__ */ e(Vs, {}) },
|
|
7780
|
+
{ path: "tutorial", element: /* @__PURE__ */ e(_s, {}) },
|
|
7745
7781
|
{ path: "chat", element: /* @__PURE__ */ e(On, {}) },
|
|
7746
7782
|
{ path: "chat/:sessionId", element: /* @__PURE__ */ e(On, {}) },
|
|
7747
7783
|
// Proposal (Sammelofferte) — a custom builder; the list reuses the generic
|
|
@@ -7750,89 +7786,89 @@ const mo = [
|
|
|
7750
7786
|
{ path: "app/proposal/new", element: /* @__PURE__ */ e(Pn, {}) },
|
|
7751
7787
|
{ path: "app/proposal/:name", element: /* @__PURE__ */ e(Pn, {}) },
|
|
7752
7788
|
// Documents
|
|
7753
|
-
{ path: "app/:doctype", element: /* @__PURE__ */ e(
|
|
7754
|
-
{ path: "app/:doctype/new", element: /* @__PURE__ */ e(
|
|
7755
|
-
{ path: "app/:doctype/:name", element: /* @__PURE__ */ e(
|
|
7789
|
+
{ path: "app/:doctype", element: /* @__PURE__ */ e(Mr, {}) },
|
|
7790
|
+
{ path: "app/:doctype/new", element: /* @__PURE__ */ e(Sn, {}) },
|
|
7791
|
+
{ path: "app/:doctype/:name", element: /* @__PURE__ */ e(Sn, {}) },
|
|
7756
7792
|
// Masters (reuse same routes - the components detect whether it's a doctype or master)
|
|
7757
|
-
{ path: "masters/:type", element: /* @__PURE__ */ e(
|
|
7793
|
+
{ path: "masters/:type", element: /* @__PURE__ */ e(Ur, {}) },
|
|
7758
7794
|
{ path: "masters/:type/new", element: /* @__PURE__ */ e(Tn, {}) },
|
|
7759
7795
|
{ path: "masters/:type/:name", element: /* @__PURE__ */ e(Tn, {}) },
|
|
7760
7796
|
// Reports
|
|
7761
|
-
{ path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(
|
|
7762
|
-
{ path: "reports/trial-balance", element: /* @__PURE__ */ e(
|
|
7763
|
-
{ path: "reports/general-ledger", element: /* @__PURE__ */ e(
|
|
7764
|
-
{ path: "reports/stock-balance", element: /* @__PURE__ */ e(
|
|
7765
|
-
{ path: "reports/profit-and-loss", element: /* @__PURE__ */ e(
|
|
7766
|
-
{ path: "reports/balance-sheet", element: /* @__PURE__ */ e(
|
|
7767
|
-
{ path: "reports/ar-aging", element: /* @__PURE__ */ e(
|
|
7768
|
-
{ path: "reports/ap-aging", element: /* @__PURE__ */ e(
|
|
7769
|
-
{ path: "reports/analytics", element: /* @__PURE__ */ e(
|
|
7797
|
+
{ path: "reports/chart-of-accounts", element: /* @__PURE__ */ e(ts, {}) },
|
|
7798
|
+
{ path: "reports/trial-balance", element: /* @__PURE__ */ e(Xr, {}) },
|
|
7799
|
+
{ path: "reports/general-ledger", element: /* @__PURE__ */ e(rs, {}) },
|
|
7800
|
+
{ path: "reports/stock-balance", element: /* @__PURE__ */ e(ss, {}) },
|
|
7801
|
+
{ path: "reports/profit-and-loss", element: /* @__PURE__ */ e(is, {}) },
|
|
7802
|
+
{ path: "reports/balance-sheet", element: /* @__PURE__ */ e(os, {}) },
|
|
7803
|
+
{ path: "reports/ar-aging", element: /* @__PURE__ */ e(ls, {}) },
|
|
7804
|
+
{ path: "reports/ap-aging", element: /* @__PURE__ */ e(cs, {}) },
|
|
7805
|
+
{ path: "reports/analytics", element: /* @__PURE__ */ e(ms, {}) },
|
|
7770
7806
|
// Admin
|
|
7771
|
-
{ path: "admin/users", element: /* @__PURE__ */ e(
|
|
7772
|
-
{ path: "admin/settings", element: /* @__PURE__ */ e(
|
|
7773
|
-
],
|
|
7807
|
+
{ path: "admin/users", element: /* @__PURE__ */ e(Ks, {}) },
|
|
7808
|
+
{ path: "admin/settings", element: /* @__PURE__ */ e(co, {}) }
|
|
7809
|
+
], ba = [], va = [];
|
|
7774
7810
|
function Lo(t, n) {
|
|
7775
|
-
(n == null ? void 0 : n.area) === "top" ?
|
|
7811
|
+
(n == null ? void 0 : n.area) === "top" ? ba.push(t) : va.push(t);
|
|
7776
7812
|
}
|
|
7777
|
-
const
|
|
7778
|
-
function
|
|
7813
|
+
const Un = (t) => t.index ? "__index__" : t.path ?? "";
|
|
7814
|
+
function Vn(t, n) {
|
|
7779
7815
|
const a = [...t];
|
|
7780
7816
|
for (const s of n) {
|
|
7781
|
-
const i =
|
|
7817
|
+
const i = Un(s), o = a.findIndex((l) => Un(l) === i);
|
|
7782
7818
|
o >= 0 ? a[o] = s : a.push(s);
|
|
7783
7819
|
}
|
|
7784
7820
|
return a;
|
|
7785
7821
|
}
|
|
7786
|
-
function
|
|
7822
|
+
function go() {
|
|
7787
7823
|
return [
|
|
7788
|
-
...
|
|
7824
|
+
...Vn(po, ba),
|
|
7789
7825
|
{
|
|
7790
7826
|
path: "/",
|
|
7791
|
-
element: /* @__PURE__ */ e(
|
|
7792
|
-
children:
|
|
7827
|
+
element: /* @__PURE__ */ e(hr, { children: /* @__PURE__ */ e(mr, {}) }),
|
|
7828
|
+
children: Vn(ho, va)
|
|
7793
7829
|
}
|
|
7794
7830
|
];
|
|
7795
7831
|
}
|
|
7796
|
-
function
|
|
7797
|
-
return new
|
|
7832
|
+
function fo() {
|
|
7833
|
+
return new Da({
|
|
7798
7834
|
defaultOptions: {
|
|
7799
7835
|
queries: { retry: 1, refetchOnWindowFocus: !1 }
|
|
7800
7836
|
}
|
|
7801
7837
|
});
|
|
7802
7838
|
}
|
|
7803
|
-
function
|
|
7839
|
+
function Oo(t = {}) {
|
|
7804
7840
|
const n = t.rootElement ?? document.getElementById("root");
|
|
7805
7841
|
if (!n)
|
|
7806
7842
|
throw new Error('bootstrap: no mount element (pass rootElement or add <div id="root">)');
|
|
7807
|
-
const a = t.queryClient ??
|
|
7808
|
-
|
|
7809
|
-
/* @__PURE__ */ e(
|
|
7843
|
+
const a = t.queryClient ?? fo(), s = _a(go());
|
|
7844
|
+
Sa(n).render(
|
|
7845
|
+
/* @__PURE__ */ e(ka, { children: /* @__PURE__ */ e(Ca, { client: a, children: /* @__PURE__ */ e(er, { children: /* @__PURE__ */ e(Ta, { router: s }) }) }) })
|
|
7810
7846
|
);
|
|
7811
7847
|
}
|
|
7812
7848
|
export {
|
|
7813
7849
|
$e as ApiError,
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7850
|
+
mr as AppShell,
|
|
7851
|
+
er as AuthProvider,
|
|
7852
|
+
ha as SUPPORTED_LANGUAGES,
|
|
7817
7853
|
I as api,
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7854
|
+
Oo as bootstrap,
|
|
7855
|
+
go as buildRoutes,
|
|
7856
|
+
Po as configureApiBase,
|
|
7857
|
+
Ro as configureBranding,
|
|
7858
|
+
fo as createAppQueryClient,
|
|
7859
|
+
Bo as getAllDoctypeConfigs,
|
|
7860
|
+
sr as getBranding,
|
|
7861
|
+
uo as getComponent,
|
|
7862
|
+
oa as getDoctypeConfig,
|
|
7863
|
+
rr as getNavGroups,
|
|
7864
|
+
to as getStoredLanguage,
|
|
7865
|
+
Mo as i18n,
|
|
7866
|
+
Eo as registerComponent,
|
|
7867
|
+
Io as registerDoctype,
|
|
7868
|
+
_o as registerNavGroup,
|
|
7869
|
+
To as registerNavItem,
|
|
7834
7870
|
Lo as registerRoute,
|
|
7835
|
-
|
|
7871
|
+
L as request,
|
|
7836
7872
|
st as useAuth
|
|
7837
7873
|
};
|
|
7838
7874
|
//# sourceMappingURL=index.js.map
|