@apptimate/core-lib 6.6.0 → 6.8.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/package.json +1 -1
- package/src/api-services/finance-shared.client.ts +5 -0
- package/src/api-services/inventory/items.client.ts +3 -2
- package/src/constants/menus.ts +35 -11
- package/src/constants/storageKeys.ts +4 -1
- package/src/utils/PriceCalculationService.ts +9 -1
- package/src/utils/apiProxy.ts +6 -0
- package/src/utils/httpClient.ts +19 -0
package/package.json
CHANGED
|
@@ -53,3 +53,8 @@ export async function getChartOfAccountsLookupShared(type?: string): Promise<IAp
|
|
|
53
53
|
const response = await sendRequest({ url: `${BASE}/chart-of-accounts/lookup`, method: "GET", params });
|
|
54
54
|
return response.responseData as IApiResponse;
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
export async function getDirectTransactionsShared(params?: any): Promise<IApiResponse> {
|
|
58
|
+
const response = await sendRequest({ url: `${BASE}/direct-transactions`, method: "GET", params });
|
|
59
|
+
return response.responseData as IApiResponse;
|
|
60
|
+
}
|
|
@@ -34,8 +34,9 @@ export async function deleteItem(id: number): Promise<IApiResponse> {
|
|
|
34
34
|
return response.responseData as IApiResponse;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export async function lookupItems(): Promise<IApiResponse> {
|
|
38
|
-
const
|
|
37
|
+
export async function lookupItems(params?: Record<string, string | number | boolean>): Promise<IApiResponse> {
|
|
38
|
+
const queryParams = params ? new URLSearchParams(params as Record<string, string>).toString() : "";
|
|
39
|
+
const response = await sendRequest({ url: `${BASE}/lookup${queryParams ? `?${queryParams}` : ""}`, method: "GET" });
|
|
39
40
|
return response.responseData as IApiResponse;
|
|
40
41
|
}
|
|
41
42
|
|
package/src/constants/menus.ts
CHANGED
|
@@ -78,11 +78,11 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
78
78
|
{ key: 'core__organizations', label: 'Organizations', path: '/organizations', module: 'Core', defaultGroup: 'User Management', permission: 'organization.view' },
|
|
79
79
|
{ key: 'core__parties', label: 'Parties', path: '/parties', module: 'Core', defaultGroup: 'User Management', permission: 'party.view' },
|
|
80
80
|
{ key: 'core__party_groups', label: 'Party Groups', path: '/party-groups', module: 'Core', defaultGroup: 'User Management', permission: 'party_group.view' },
|
|
81
|
-
{ key: 'core__activity_logs', label: 'Activity Logs', path: '/activity-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'activity_log.view' },
|
|
82
|
-
{ key: 'core__api_requests', label: 'API Requests', path: '/system/api-requests', module: 'Core', defaultGroup: 'System Auditing', permission: 'api_request_log.view' },
|
|
83
|
-
{ key: 'core__feature_access_logs', label: 'Feature Access Logs', path: '/system/feature-access-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'feature_access_log.view' },
|
|
84
|
-
{ key: 'core__issue_logs', label: 'Issue Logs', path: '/system/issue-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'issue_log.view' },
|
|
85
|
-
{ key: 'core__feature_registry', label: 'Feature Registry', path: '/system/features', module: 'Core', defaultGroup: 'System Auditing', permission: 'feature.view' },
|
|
81
|
+
// { key: 'core__activity_logs', label: 'Activity Logs', path: '/activity-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'activity_log.view' },
|
|
82
|
+
// { key: 'core__api_requests', label: 'API Requests', path: '/system/api-requests', module: 'Core', defaultGroup: 'System Auditing', permission: 'api_request_log.view' },
|
|
83
|
+
// { key: 'core__feature_access_logs', label: 'Feature Access Logs', path: '/system/feature-access-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'feature_access_log.view' },
|
|
84
|
+
// { key: 'core__issue_logs', label: 'Issue Logs', path: '/system/issue-logs', module: 'Core', defaultGroup: 'System Auditing', permission: 'issue_log.view' },
|
|
85
|
+
// { key: 'core__feature_registry', label: 'Feature Registry', path: '/system/features', module: 'Core', defaultGroup: 'System Auditing', permission: 'feature.view' },
|
|
86
86
|
{ key: 'core__menu_config', label: 'Menu Configuration', path: '/menu-config', module: 'Core', defaultGroup: 'System', permission: 'menu_config.view' },
|
|
87
87
|
{ key: 'core__printables', label: 'Printable Templates', path: '/system/printables', module: 'Core', defaultGroup: 'System', permission: 'printable_template.view' },
|
|
88
88
|
{ key: 'core__email_templates', label: 'Email Templates', path: '/system/email-templates', module: 'Core', defaultGroup: 'System', permission: 'email_template.view' },
|
|
@@ -94,6 +94,12 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
94
94
|
{ key: 'core__field_configs', label: 'Field Configurations', path: '/settings/field-configs', module: 'Core', defaultGroup: 'Configuration', permission: 'entity_field_config.view' },
|
|
95
95
|
{ key: 'core__email_services', label: 'Integrations', path: '/settings/integrations', module: 'Core', defaultGroup: 'Configuration', permission: 'email_connection.view' },
|
|
96
96
|
{ key: 'core__approval_workflows', label: 'Approval Workflows', path: '/settings/approvals', module: 'Core', defaultGroup: 'Configuration', permission: null },
|
|
97
|
+
{ key: 'core__commission_salespersons', label: 'Salespersons', path: '/commission/salespersons', module: 'Core', defaultGroup: 'Commission', permission: 'commission_salesperson.view' },
|
|
98
|
+
{ key: 'core__commission_plans', label: 'Commission Plans', path: '/commission/plans', module: 'Core', defaultGroup: 'Commission', permission: 'commission_plan.view' },
|
|
99
|
+
{ key: 'core__commission_assignments', label: 'Assignments', path: '/commission/assignments', module: 'Core', defaultGroup: 'Commission', permission: 'commission_assignment.view' },
|
|
100
|
+
{ key: 'core__commission_transactions', label: 'Transactions', path: '/commission/transactions', module: 'Core', defaultGroup: 'Commission', permission: 'commission_transaction.view' },
|
|
101
|
+
{ key: 'core__commission_adjustments', label: 'Adjustments', path: '/commission/adjustments', module: 'Core', defaultGroup: 'Commission', permission: 'commission_adjustment.view' },
|
|
102
|
+
{ key: 'core__commission_payouts', label: 'Payout Batches', path: '/commission/payouts', module: 'Core', defaultGroup: 'Commission', permission: 'commission_payout.view' },
|
|
97
103
|
|
|
98
104
|
// ── Inventory Module ──
|
|
99
105
|
{ key: 'inventory__items', label: 'Items', path: '/inventory/items', module: 'Inventory', defaultGroup: 'Catalog', permission: null },
|
|
@@ -126,8 +132,7 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
126
132
|
{ key: 'procurement__orders', label: 'Purchase Orders', path: '/procurement/orders', module: 'Procurement', defaultGroup: 'Orders', permission: null },
|
|
127
133
|
{ key: 'procurement__grn', label: 'Goods Receipt', path: '/procurement/grns', module: 'Procurement', defaultGroup: 'Receiving', permission: null },
|
|
128
134
|
{ key: 'procurement__settings', label: 'Settings', path: '/procurement/settings', module: 'Procurement', defaultGroup: 'Configuration', permission: 'procurement_setting.view' },
|
|
129
|
-
{ key: 'procurement__invoices', label: 'Invoices', path: '/
|
|
130
|
-
{ key: 'procurement__payments', label: 'Payments', path: '/finance/payments', module: 'Procurement', defaultGroup: 'Finance', permission: null },
|
|
135
|
+
{ key: 'procurement__invoices', label: 'Supplier Invoices', path: '/procurement/invoices', module: 'Procurement', defaultGroup: 'Post-Purchase', permission: null },
|
|
131
136
|
|
|
132
137
|
// ── Finance Module ──
|
|
133
138
|
{ key: 'finance__invoices', label: 'Invoices', path: '/finance/invoices', module: 'Finance', defaultGroup: 'Transactions', permission: 'finance.invoice.view' },
|
|
@@ -253,6 +258,7 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
253
258
|
{ key: 'construction__hierarchy', label: 'Hierarchy', path: '/construction/hierarchy', module: 'Construction', defaultGroup: 'Project Planning', permission: null },
|
|
254
259
|
{ key: 'construction__team', label: 'Team', path: '/construction/team', module: 'Construction', defaultGroup: 'Project Planning', permission: null },
|
|
255
260
|
{ key: 'construction__budget', label: 'Budget', path: '/construction/budget', module: 'Construction', defaultGroup: 'Project Planning', permission: null },
|
|
261
|
+
{ key: 'construction__expenses', label: 'Expenses', path: '/construction/expenses', module: 'Construction', defaultGroup: 'Project Planning', permission: null },
|
|
256
262
|
|
|
257
263
|
{ key: 'construction__main_contract', label: 'Client', path: '/construction/contracts/main-contract', module: 'Construction', defaultGroup: 'Contracts & Billing', permission: null },
|
|
258
264
|
{ key: 'construction__subcontractors', label: 'Subcontractors', path: '/construction/contracts/subcontractors', module: 'Construction', defaultGroup: 'Contracts & Billing', permission: null },
|
|
@@ -289,16 +295,22 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
|
|
|
289
295
|
{ key: 'construction__safety_incidents', label: 'Incident Log', path: '/construction/safety/incidents', module: 'Construction', defaultGroup: 'Quality & Safety', permission: null },
|
|
290
296
|
{ key: 'construction__ptw', label: 'Permit to Work', path: '/construction/safety/ptw', module: 'Construction', defaultGroup: 'Quality & Safety', permission: null },
|
|
291
297
|
|
|
292
|
-
{ key: '
|
|
298
|
+
{ key: 'construction__documents', label: 'Documents', path: '/construction/document-control/documents', module: 'Construction', defaultGroup: 'Document Control', permission: null },
|
|
293
299
|
{ key: 'construction__rfis', label: 'RFIs', path: '/construction/document-control/rfis', module: 'Construction', defaultGroup: 'Document Control', permission: null },
|
|
294
300
|
|
|
295
301
|
{ key: 'construction__test_types', label: 'Test Types', path: '/construction/settings/test-types', module: 'Construction', defaultGroup: 'Configuration', permission: null },
|
|
296
302
|
{ key: 'construction__material_types', label: 'Material Types', path: '/construction/settings/material-types', module: 'Construction', defaultGroup: 'Configuration', permission: 'construction_material_type.view' },
|
|
303
|
+
{ key: 'construction__document_categories', label: 'Document Categories', path: '/construction/settings/document-categories', module: 'Construction', defaultGroup: 'Configuration', permission: 'construction_document_category.view' },
|
|
297
304
|
{ key: 'construction__project_categories', label: 'Project Categories', path: '/construction/settings/project-categories', module: 'Construction', defaultGroup: 'Configuration', permission: 'project_category.view' },
|
|
298
305
|
{ key: 'construction__daily_tasks', label: 'Daily Tasks', path: '/construction/settings/daily-tasks', module: 'Construction', defaultGroup: 'Configuration', permission: null },
|
|
299
306
|
{ key: 'construction__incident_notifications', label: 'Incident Reminders', path: '/construction/settings/incident-notifications', module: 'Construction', defaultGroup: 'Configuration', permission: null },
|
|
300
307
|
{ key: 'construction__settings', label: 'Settings', path: '/construction/settings', module: 'Construction', defaultGroup: 'Configuration', permission: null },
|
|
301
308
|
|
|
309
|
+
// ── Production Module ──
|
|
310
|
+
{ key: 'production_min__dashboard', label: 'Dashboard', path: '/production-min', module: 'Production', defaultGroup: 'Overview', permission: null },
|
|
311
|
+
{ key: 'production_min__phantom_boms', label: 'Phantom BOMs', path: '/production-min/boms', module: 'Production', defaultGroup: 'Operations', permission: null },
|
|
312
|
+
{ key: 'production_min__settings', label: 'Settings', path: '/production-min/settings', module: 'Production', defaultGroup: 'Configuration', permission: null },
|
|
313
|
+
|
|
302
314
|
// ── CRM Module ──
|
|
303
315
|
{ key: 'crm__spaces', label: 'Spaces', path: '/crm/spaces', module: 'CRM', defaultGroup: 'Sales', permission: 'crm_space.view' },
|
|
304
316
|
{ key: 'crm__tasks', label: 'Tasks', path: '/crm/tasks', module: 'CRM', defaultGroup: 'Operations', permission: 'crm_task.view' },
|
|
@@ -392,6 +404,7 @@ export const MENU_PRESETS: MenuPreset[] = [
|
|
|
392
404
|
'core__activity_logs', 'core__api_requests', 'core__feature_access_logs',
|
|
393
405
|
'core__issue_logs', 'core__feature_registry', 'core__menu_config',
|
|
394
406
|
'core__printables', 'core__email_templates', 'core__template_groups', 'core__currencies', 'core__settings', 'core__field_configs', 'core__email_services', 'core__approval_workflows',
|
|
407
|
+
'core__commission_salespersons', 'core__commission_plans', 'core__commission_assignments', 'core__commission_transactions', 'core__commission_adjustments', 'core__commission_payouts',
|
|
395
408
|
],
|
|
396
409
|
},
|
|
397
410
|
{
|
|
@@ -423,7 +436,7 @@ export const MENU_PRESETS: MenuPreset[] = [
|
|
|
423
436
|
iconName: 'Truck',
|
|
424
437
|
secondaryItems: [
|
|
425
438
|
'procurement__orders', 'procurement__grn',
|
|
426
|
-
'procurement__invoices',
|
|
439
|
+
'procurement__invoices',
|
|
427
440
|
'procurement__settings',
|
|
428
441
|
],
|
|
429
442
|
},
|
|
@@ -541,11 +554,20 @@ export const MENU_PRESETS: MenuPreset[] = [
|
|
|
541
554
|
'construction__project_categories',
|
|
542
555
|
'construction__test_types',
|
|
543
556
|
'construction__material_types',
|
|
557
|
+
'construction__document_categories',
|
|
544
558
|
'construction__daily_tasks',
|
|
545
559
|
'construction__incident_notifications',
|
|
546
560
|
'construction__settings',
|
|
547
561
|
],
|
|
548
562
|
},
|
|
563
|
+
{
|
|
564
|
+
id: 'production_min',
|
|
565
|
+
label: 'Production',
|
|
566
|
+
iconName: 'Factory',
|
|
567
|
+
secondaryItems: [
|
|
568
|
+
'production_min__phantom_boms',
|
|
569
|
+
],
|
|
570
|
+
},
|
|
549
571
|
{
|
|
550
572
|
id: 'crm',
|
|
551
573
|
label: 'CRM',
|
|
@@ -613,12 +635,13 @@ const PROJECT_KEY_MAPPING: Record<string, string> = {
|
|
|
613
635
|
'project_hierarchy': 'construction__hierarchy',
|
|
614
636
|
'project_team': 'construction__team',
|
|
615
637
|
'project_budget': 'construction__budget',
|
|
638
|
+
'project_expenses': 'construction__expenses',
|
|
616
639
|
'project_resource_calendar': 'construction__schedule_calendar',
|
|
617
640
|
'project_progress_billing': 'construction__ipcs',
|
|
618
641
|
'project_variations': 'construction__variations',
|
|
619
642
|
'project_boq': 'construction__boq',
|
|
620
643
|
'project_boq_revisions': 'construction__boq_revisions',
|
|
621
|
-
'
|
|
644
|
+
'project_documents': 'construction__documents',
|
|
622
645
|
'project_rfis': 'construction__rfis',
|
|
623
646
|
'project_dsr': 'construction__dsr',
|
|
624
647
|
'project_progress_updates': 'construction__progress_updates',
|
|
@@ -671,13 +694,14 @@ export const getProjectConstructionGroups = (projectId: string | number): MainMe
|
|
|
671
694
|
items: [
|
|
672
695
|
{ id: 'project_boq', label: 'Bill of Quantities (BOQ)', path: `/construction/projects/${projectId}/boq` },
|
|
673
696
|
{ id: 'project_boq_revisions', label: 'BOQ Revisions', path: `/construction/projects/${projectId}/boq/revisions` },
|
|
697
|
+
{ id: 'project_expenses', label: 'Direct Expenses', path: `/construction/projects/${projectId}/expenses` },
|
|
674
698
|
]
|
|
675
699
|
},
|
|
676
700
|
{
|
|
677
701
|
id: 'project_document_control',
|
|
678
702
|
label: 'Document Control',
|
|
679
703
|
items: [
|
|
680
|
-
{ id: '
|
|
704
|
+
{ id: 'project_documents', label: 'Documents', path: `/construction/projects/${projectId}/documents` },
|
|
681
705
|
{ id: 'project_rfis', label: 'RFIs', path: `/construction/projects/${projectId}/rfis` },
|
|
682
706
|
]
|
|
683
707
|
},
|
|
@@ -12,5 +12,8 @@ export const local_storage = {
|
|
|
12
12
|
user_info: { name: 'user_info', secretName: 'USER_INFO_SECRET', encrypted: false } as IStorageOptions,
|
|
13
13
|
selected_organization: { name: 'selected_organization', secretName: 'SELECTED_ORG', encrypted: false } as IStorageOptions,
|
|
14
14
|
sales_terminal: { name: 'sales_terminal', secretName: 'SALES_TERMINAL', encrypted: false } as IStorageOptions,
|
|
15
|
-
active_project: { name: 'active_project', secretName: 'ACTIVE_PROJECT', encrypted: false } as IStorageOptions
|
|
15
|
+
active_project: { name: 'active_project', secretName: 'ACTIVE_PROJECT', encrypted: false } as IStorageOptions,
|
|
16
|
+
pos_fullscreen: { name: 'pos_fullscreen', secretName: 'POS_FULLSCREEN', encrypted: false } as IStorageOptions,
|
|
17
|
+
hide_pricing_note: { name: 'hide_pricing_note', secretName: 'HIDE_PRICING_NOTE', encrypted: false } as IStorageOptions,
|
|
18
|
+
hide_rule_note: { name: 'hide_rule_note', secretName: 'HIDE_RULE_NOTE', encrypted: false } as IStorageOptions
|
|
16
19
|
};
|
|
@@ -6,6 +6,7 @@ export interface IPricingRule {
|
|
|
6
6
|
markdown_percentage: number | null;
|
|
7
7
|
batch_id?: number | null;
|
|
8
8
|
final_rate?: number;
|
|
9
|
+
specificity_score?: number;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export class PriceCalculationService {
|
|
@@ -33,10 +34,17 @@ export class PriceCalculationService {
|
|
|
33
34
|
return { unitPrice: basePrice, discountPercent: 0, discountAmount: 0 };
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
// Sort by batch specificity first, then
|
|
37
|
+
// Sort by batch specificity first, then specificity score, then min_quantity descending
|
|
37
38
|
applicableRules.sort((a, b) => {
|
|
38
39
|
if (a.batch_id && !b.batch_id) return -1;
|
|
39
40
|
if (!a.batch_id && b.batch_id) return 1;
|
|
41
|
+
|
|
42
|
+
const scoreA = a.specificity_score || 0;
|
|
43
|
+
const scoreB = b.specificity_score || 0;
|
|
44
|
+
if (scoreA !== scoreB) {
|
|
45
|
+
return scoreB - scoreA;
|
|
46
|
+
}
|
|
47
|
+
|
|
40
48
|
return b.min_quantity - a.min_quantity;
|
|
41
49
|
});
|
|
42
50
|
|
package/src/utils/apiProxy.ts
CHANGED
|
@@ -117,6 +117,8 @@ export async function forwardApiProxyRequest(request: Request, pathSegments: str
|
|
|
117
117
|
const contentType = request.headers.get("content-type");
|
|
118
118
|
const organizationId = request.headers.get("x-organization-id") ?? selectedOrganizationId;
|
|
119
119
|
|
|
120
|
+
const tenantDomain = request.headers.get("x-tenant-domain");
|
|
121
|
+
|
|
120
122
|
if (accept) {
|
|
121
123
|
headers.set("accept", accept);
|
|
122
124
|
}
|
|
@@ -129,6 +131,10 @@ export async function forwardApiProxyRequest(request: Request, pathSegments: str
|
|
|
129
131
|
headers.set("x-organization-id", organizationId);
|
|
130
132
|
}
|
|
131
133
|
|
|
134
|
+
if (tenantDomain) {
|
|
135
|
+
headers.set("x-tenant-domain", tenantDomain);
|
|
136
|
+
}
|
|
137
|
+
|
|
132
138
|
if (token) {
|
|
133
139
|
headers.set("authorization", `Bearer ${token}`);
|
|
134
140
|
}
|
package/src/utils/httpClient.ts
CHANGED
|
@@ -113,6 +113,9 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
|
|
|
113
113
|
|
|
114
114
|
finalUrl = buildBrowserProxyUrl(finalUrl);
|
|
115
115
|
|
|
116
|
+
// Inject Tenant Domain dynamically for Database-per-Tenant isolation
|
|
117
|
+
defaultHeaders['X-Tenant-Domain'] = window.location.hostname;
|
|
118
|
+
|
|
116
119
|
// Automatically inject selected organization ID into every request
|
|
117
120
|
try {
|
|
118
121
|
const orgRaw = localStorage.getItem('selected_organization');
|
|
@@ -131,6 +134,22 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
|
|
|
131
134
|
defaultHeaders['Content-Type'] = 'application/json';
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
// Server-side Tenant Domain extraction
|
|
138
|
+
if (typeof window === 'undefined') {
|
|
139
|
+
try {
|
|
140
|
+
// Dynamically import next/headers to avoid client-side bundling issues
|
|
141
|
+
const nextHeaders = require('next/headers');
|
|
142
|
+
if (nextHeaders && typeof nextHeaders.headers === 'function') {
|
|
143
|
+
const host = nextHeaders.headers().get('host');
|
|
144
|
+
if (host) {
|
|
145
|
+
defaultHeaders['X-Tenant-Domain'] = host.split(':')[0];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
// Ignore if next/headers is unavailable
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
134
153
|
try {
|
|
135
154
|
const response = await fetch(finalUrl, {
|
|
136
155
|
method,
|