optimal-cli 1.0.0 → 1.0.1
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/bin/optimal.d.ts +2 -0
- package/dist/bin/optimal.js +1590 -0
- package/dist/lib/assets/index.d.ts +79 -0
- package/dist/lib/assets/index.js +153 -0
- package/dist/lib/assets.d.ts +20 -0
- package/dist/lib/assets.js +112 -0
- package/dist/lib/auth/index.d.ts +83 -0
- package/dist/lib/auth/index.js +146 -0
- package/dist/lib/board/index.d.ts +39 -0
- package/dist/lib/board/index.js +285 -0
- package/dist/lib/board/types.d.ts +111 -0
- package/dist/lib/board/types.js +1 -0
- package/dist/lib/bot/claim.d.ts +3 -0
- package/dist/lib/bot/claim.js +20 -0
- package/dist/lib/bot/coordinator.d.ts +27 -0
- package/dist/lib/bot/coordinator.js +178 -0
- package/dist/lib/bot/heartbeat.d.ts +6 -0
- package/dist/lib/bot/heartbeat.js +30 -0
- package/dist/lib/bot/index.d.ts +9 -0
- package/dist/lib/bot/index.js +6 -0
- package/dist/lib/bot/protocol.d.ts +12 -0
- package/dist/lib/bot/protocol.js +74 -0
- package/dist/lib/bot/reporter.d.ts +3 -0
- package/dist/lib/bot/reporter.js +27 -0
- package/dist/lib/bot/skills.d.ts +26 -0
- package/dist/lib/bot/skills.js +69 -0
- package/dist/lib/budget/projections.d.ts +115 -0
- package/dist/lib/budget/projections.js +384 -0
- package/dist/lib/budget/scenarios.d.ts +93 -0
- package/dist/lib/budget/scenarios.js +214 -0
- package/dist/lib/cms/publish-blog.d.ts +62 -0
- package/dist/lib/cms/publish-blog.js +74 -0
- package/dist/lib/cms/strapi-client.d.ts +123 -0
- package/dist/lib/cms/strapi-client.js +213 -0
- package/dist/lib/config/registry.d.ts +17 -0
- package/dist/lib/config/registry.js +182 -0
- package/dist/lib/config/schema.d.ts +31 -0
- package/dist/lib/config/schema.js +25 -0
- package/dist/lib/config.d.ts +55 -0
- package/dist/lib/config.js +206 -0
- package/dist/lib/errors.d.ts +25 -0
- package/dist/lib/errors.js +91 -0
- package/dist/lib/format.d.ts +28 -0
- package/dist/lib/format.js +98 -0
- package/dist/lib/infra/deploy.d.ts +29 -0
- package/dist/lib/infra/deploy.js +58 -0
- package/dist/lib/infra/migrate.d.ts +34 -0
- package/dist/lib/infra/migrate.js +103 -0
- package/dist/lib/newsletter/distribute.d.ts +52 -0
- package/dist/lib/newsletter/distribute.js +193 -0
- package/{lib/newsletter/generate-insurance.ts → dist/lib/newsletter/generate-insurance.d.ts} +7 -24
- package/dist/lib/newsletter/generate-insurance.js +36 -0
- package/dist/lib/newsletter/generate.d.ts +104 -0
- package/dist/lib/newsletter/generate.js +571 -0
- package/dist/lib/returnpro/anomalies.d.ts +64 -0
- package/dist/lib/returnpro/anomalies.js +166 -0
- package/dist/lib/returnpro/audit.d.ts +32 -0
- package/dist/lib/returnpro/audit.js +147 -0
- package/dist/lib/returnpro/diagnose.d.ts +52 -0
- package/dist/lib/returnpro/diagnose.js +281 -0
- package/dist/lib/returnpro/kpis.d.ts +32 -0
- package/dist/lib/returnpro/kpis.js +192 -0
- package/dist/lib/returnpro/templates.d.ts +48 -0
- package/dist/lib/returnpro/templates.js +229 -0
- package/dist/lib/returnpro/upload-income.d.ts +25 -0
- package/dist/lib/returnpro/upload-income.js +235 -0
- package/dist/lib/returnpro/upload-netsuite.d.ts +37 -0
- package/dist/lib/returnpro/upload-netsuite.js +566 -0
- package/dist/lib/returnpro/upload-r1.d.ts +48 -0
- package/dist/lib/returnpro/upload-r1.js +398 -0
- package/dist/lib/returnpro/validate.d.ts +37 -0
- package/dist/lib/returnpro/validate.js +124 -0
- package/dist/lib/social/meta.d.ts +90 -0
- package/dist/lib/social/meta.js +160 -0
- package/dist/lib/social/post-generator.d.ts +83 -0
- package/dist/lib/social/post-generator.js +333 -0
- package/dist/lib/social/publish.d.ts +66 -0
- package/dist/lib/social/publish.js +226 -0
- package/dist/lib/social/scraper.d.ts +67 -0
- package/dist/lib/social/scraper.js +361 -0
- package/dist/lib/supabase.d.ts +4 -0
- package/dist/lib/supabase.js +20 -0
- package/dist/lib/transactions/delete-batch.d.ts +60 -0
- package/dist/lib/transactions/delete-batch.js +203 -0
- package/dist/lib/transactions/ingest.d.ts +43 -0
- package/dist/lib/transactions/ingest.js +555 -0
- package/dist/lib/transactions/stamp.d.ts +51 -0
- package/dist/lib/transactions/stamp.js +524 -0
- package/package.json +3 -4
- package/bin/optimal.ts +0 -1731
- package/lib/assets/index.ts +0 -225
- package/lib/assets.ts +0 -124
- package/lib/auth/index.ts +0 -189
- package/lib/board/index.ts +0 -309
- package/lib/board/types.ts +0 -124
- package/lib/bot/claim.ts +0 -43
- package/lib/bot/coordinator.ts +0 -254
- package/lib/bot/heartbeat.ts +0 -37
- package/lib/bot/index.ts +0 -9
- package/lib/bot/protocol.ts +0 -99
- package/lib/bot/reporter.ts +0 -42
- package/lib/bot/skills.ts +0 -81
- package/lib/budget/projections.ts +0 -561
- package/lib/budget/scenarios.ts +0 -312
- package/lib/cms/publish-blog.ts +0 -129
- package/lib/cms/strapi-client.ts +0 -302
- package/lib/config/registry.ts +0 -228
- package/lib/config/schema.ts +0 -58
- package/lib/config.ts +0 -247
- package/lib/errors.ts +0 -129
- package/lib/format.ts +0 -120
- package/lib/infra/.gitkeep +0 -0
- package/lib/infra/deploy.ts +0 -70
- package/lib/infra/migrate.ts +0 -141
- package/lib/newsletter/.gitkeep +0 -0
- package/lib/newsletter/distribute.ts +0 -256
- package/lib/newsletter/generate.ts +0 -735
- package/lib/returnpro/.gitkeep +0 -0
- package/lib/returnpro/anomalies.ts +0 -258
- package/lib/returnpro/audit.ts +0 -194
- package/lib/returnpro/diagnose.ts +0 -400
- package/lib/returnpro/kpis.ts +0 -255
- package/lib/returnpro/templates.ts +0 -323
- package/lib/returnpro/upload-income.ts +0 -311
- package/lib/returnpro/upload-netsuite.ts +0 -696
- package/lib/returnpro/upload-r1.ts +0 -563
- package/lib/returnpro/validate.ts +0 -154
- package/lib/social/meta.ts +0 -228
- package/lib/social/post-generator.ts +0 -468
- package/lib/social/publish.ts +0 -301
- package/lib/social/scraper.ts +0 -503
- package/lib/supabase.ts +0 -25
- package/lib/transactions/delete-batch.ts +0 -258
- package/lib/transactions/ingest.ts +0 -659
- package/lib/transactions/stamp.ts +0 -654
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AgentMessage {
|
|
2
|
+
type: 'heartbeat' | 'claim' | 'progress' | 'complete' | 'blocked' | 'release';
|
|
3
|
+
agentId: string;
|
|
4
|
+
taskId?: string;
|
|
5
|
+
payload?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface AgentResponse {
|
|
8
|
+
success: boolean;
|
|
9
|
+
data?: unknown;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function processAgentMessage(msg: AgentMessage): Promise<AgentResponse>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { sendHeartbeat } from './heartbeat.js';
|
|
2
|
+
import { claimNextTask, releaseTask } from './claim.js';
|
|
3
|
+
import { reportProgress, reportCompletion, reportBlocked } from './reporter.js';
|
|
4
|
+
// --- Message processor ---
|
|
5
|
+
export async function processAgentMessage(msg) {
|
|
6
|
+
try {
|
|
7
|
+
switch (msg.type) {
|
|
8
|
+
case 'heartbeat':
|
|
9
|
+
return await handleHeartbeat(msg);
|
|
10
|
+
case 'claim':
|
|
11
|
+
return await handleClaim(msg);
|
|
12
|
+
case 'progress':
|
|
13
|
+
return await handleProgress(msg);
|
|
14
|
+
case 'complete':
|
|
15
|
+
return await handleComplete(msg);
|
|
16
|
+
case 'blocked':
|
|
17
|
+
return await handleBlocked(msg);
|
|
18
|
+
case 'release':
|
|
19
|
+
return await handleRelease(msg);
|
|
20
|
+
default:
|
|
21
|
+
return { success: false, error: `Unknown message type: ${msg.type}` };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
26
|
+
return { success: false, error: errorMsg };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// --- Handlers ---
|
|
30
|
+
async function handleHeartbeat(msg) {
|
|
31
|
+
const status = msg.payload?.status ?? 'idle';
|
|
32
|
+
await sendHeartbeat(msg.agentId, status);
|
|
33
|
+
return { success: true, data: { agentId: msg.agentId, status } };
|
|
34
|
+
}
|
|
35
|
+
async function handleClaim(msg) {
|
|
36
|
+
const skills = msg.payload?.skills;
|
|
37
|
+
const task = await claimNextTask(msg.agentId, skills);
|
|
38
|
+
if (!task) {
|
|
39
|
+
return { success: true, data: null };
|
|
40
|
+
}
|
|
41
|
+
return { success: true, data: { taskId: task.id, title: task.title } };
|
|
42
|
+
}
|
|
43
|
+
async function handleProgress(msg) {
|
|
44
|
+
if (!msg.taskId) {
|
|
45
|
+
return { success: false, error: 'taskId is required for progress messages' };
|
|
46
|
+
}
|
|
47
|
+
const message = msg.payload?.message ?? 'Progress update';
|
|
48
|
+
await reportProgress(msg.taskId, msg.agentId, message);
|
|
49
|
+
return { success: true, data: { taskId: msg.taskId } };
|
|
50
|
+
}
|
|
51
|
+
async function handleComplete(msg) {
|
|
52
|
+
if (!msg.taskId) {
|
|
53
|
+
return { success: false, error: 'taskId is required for complete messages' };
|
|
54
|
+
}
|
|
55
|
+
const summary = msg.payload?.summary ?? 'Task completed';
|
|
56
|
+
await reportCompletion(msg.taskId, msg.agentId, summary);
|
|
57
|
+
return { success: true, data: { taskId: msg.taskId, status: 'done' } };
|
|
58
|
+
}
|
|
59
|
+
async function handleBlocked(msg) {
|
|
60
|
+
if (!msg.taskId) {
|
|
61
|
+
return { success: false, error: 'taskId is required for blocked messages' };
|
|
62
|
+
}
|
|
63
|
+
const reason = msg.payload?.reason ?? 'No reason given';
|
|
64
|
+
await reportBlocked(msg.taskId, msg.agentId, reason);
|
|
65
|
+
return { success: true, data: { taskId: msg.taskId, status: 'blocked' } };
|
|
66
|
+
}
|
|
67
|
+
async function handleRelease(msg) {
|
|
68
|
+
if (!msg.taskId) {
|
|
69
|
+
return { success: false, error: 'taskId is required for release messages' };
|
|
70
|
+
}
|
|
71
|
+
const reason = msg.payload?.reason;
|
|
72
|
+
const task = await releaseTask(msg.taskId, msg.agentId, reason);
|
|
73
|
+
return { success: true, data: { taskId: task.id, status: 'ready' } };
|
|
74
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function reportProgress(taskId: string, agentId: string, message: string): Promise<void>;
|
|
2
|
+
export declare function reportCompletion(taskId: string, agentId: string, summary: string): Promise<void>;
|
|
3
|
+
export declare function reportBlocked(taskId: string, agentId: string, reason: string): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { addComment, updateTask, completeTask } from '../board/index.js';
|
|
2
|
+
export async function reportProgress(taskId, agentId, message) {
|
|
3
|
+
await addComment({
|
|
4
|
+
task_id: taskId,
|
|
5
|
+
author: agentId,
|
|
6
|
+
body: message,
|
|
7
|
+
comment_type: 'comment',
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export async function reportCompletion(taskId, agentId, summary) {
|
|
11
|
+
await completeTask(taskId, agentId);
|
|
12
|
+
await addComment({
|
|
13
|
+
task_id: taskId,
|
|
14
|
+
author: agentId,
|
|
15
|
+
body: summary,
|
|
16
|
+
comment_type: 'status_change',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export async function reportBlocked(taskId, agentId, reason) {
|
|
20
|
+
await updateTask(taskId, { status: 'blocked' }, agentId);
|
|
21
|
+
await addComment({
|
|
22
|
+
task_id: taskId,
|
|
23
|
+
author: agentId,
|
|
24
|
+
body: `Blocked: ${reason}`,
|
|
25
|
+
comment_type: 'status_change',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Task } from '../board/types.js';
|
|
2
|
+
export interface AgentProfile {
|
|
3
|
+
id: string;
|
|
4
|
+
skills: string[];
|
|
5
|
+
maxConcurrent: number;
|
|
6
|
+
status: 'idle' | 'working' | 'error';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Reads agent profiles from agents/profiles.json.
|
|
10
|
+
* Falls back to a single default wildcard profile if the file doesn't exist.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAgentProfiles(): AgentProfile[];
|
|
13
|
+
/**
|
|
14
|
+
* Filters and ranks tasks an agent can work on.
|
|
15
|
+
*
|
|
16
|
+
* - Includes tasks whose skill_required is in the agent's skills list,
|
|
17
|
+
* or tasks with no skill_required, or if agent has wildcard '*'.
|
|
18
|
+
* - Sorts by priority (P1 first), then sort_order.
|
|
19
|
+
* - Returns at most agent.maxConcurrent tasks.
|
|
20
|
+
*/
|
|
21
|
+
export declare function matchTasksToAgent(agent: AgentProfile, tasks: Task[]): Task[];
|
|
22
|
+
/**
|
|
23
|
+
* Finds the first idle agent whose skills match the task's skill_required.
|
|
24
|
+
* Returns null if no suitable idle agent exists.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findBestAgent(profiles: AgentProfile[], task: Task): AgentProfile | null;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const DEFAULT_PROFILE = {
|
|
5
|
+
id: 'default',
|
|
6
|
+
skills: ['*'],
|
|
7
|
+
maxConcurrent: 1,
|
|
8
|
+
status: 'idle',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Reads agent profiles from agents/profiles.json.
|
|
12
|
+
* Falls back to a single default wildcard profile if the file doesn't exist.
|
|
13
|
+
*/
|
|
14
|
+
export function getAgentProfiles() {
|
|
15
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
16
|
+
const profilesPath = resolve(root, 'agents', 'profiles.json');
|
|
17
|
+
if (!existsSync(profilesPath)) {
|
|
18
|
+
return [DEFAULT_PROFILE];
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const raw = readFileSync(profilesPath, 'utf-8');
|
|
22
|
+
const parsed = JSON.parse(raw);
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return [DEFAULT_PROFILE];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Filters and ranks tasks an agent can work on.
|
|
31
|
+
*
|
|
32
|
+
* - Includes tasks whose skill_required is in the agent's skills list,
|
|
33
|
+
* or tasks with no skill_required, or if agent has wildcard '*'.
|
|
34
|
+
* - Sorts by priority (P1 first), then sort_order.
|
|
35
|
+
* - Returns at most agent.maxConcurrent tasks.
|
|
36
|
+
*/
|
|
37
|
+
export function matchTasksToAgent(agent, tasks) {
|
|
38
|
+
const hasWildcard = agent.skills.includes('*');
|
|
39
|
+
const matched = tasks.filter((t) => {
|
|
40
|
+
if (hasWildcard)
|
|
41
|
+
return true;
|
|
42
|
+
if (!t.skill_required)
|
|
43
|
+
return true;
|
|
44
|
+
return agent.skills.includes(t.skill_required);
|
|
45
|
+
});
|
|
46
|
+
matched.sort((a, b) => {
|
|
47
|
+
if (a.priority !== b.priority)
|
|
48
|
+
return a.priority - b.priority;
|
|
49
|
+
return a.sort_order - b.sort_order;
|
|
50
|
+
});
|
|
51
|
+
return matched.slice(0, agent.maxConcurrent);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Finds the first idle agent whose skills match the task's skill_required.
|
|
55
|
+
* Returns null if no suitable idle agent exists.
|
|
56
|
+
*/
|
|
57
|
+
export function findBestAgent(profiles, task) {
|
|
58
|
+
for (const agent of profiles) {
|
|
59
|
+
if (agent.status !== 'idle')
|
|
60
|
+
continue;
|
|
61
|
+
if (agent.skills.includes('*'))
|
|
62
|
+
return agent;
|
|
63
|
+
if (!task.skill_required)
|
|
64
|
+
return agent;
|
|
65
|
+
if (agent.skills.includes(task.skill_required))
|
|
66
|
+
return agent;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget projection calculator for FY26 planning
|
|
3
|
+
*
|
|
4
|
+
* Ported from wes-dashboard/src/lib/projections/calculator.ts
|
|
5
|
+
* Pure TypeScript — no React, no framework deps.
|
|
6
|
+
*
|
|
7
|
+
* Supports two adjustment types:
|
|
8
|
+
* - Percentage: projected = actual * (1 + rate/100)
|
|
9
|
+
* - Flat: projected = actual + flatAmount
|
|
10
|
+
*
|
|
11
|
+
* Supports both unit AND average retail projections for revenue forecasting.
|
|
12
|
+
*
|
|
13
|
+
* Data sources:
|
|
14
|
+
* - Supabase `fpa_wes_imports` table (ReturnPro instance)
|
|
15
|
+
* - JSON file from stdin or --file flag
|
|
16
|
+
*/
|
|
17
|
+
export interface CheckedInUnitsSummary {
|
|
18
|
+
programCode: string;
|
|
19
|
+
masterProgram: string;
|
|
20
|
+
masterProgramId: number | null;
|
|
21
|
+
clientId: number | null;
|
|
22
|
+
clientName: string;
|
|
23
|
+
unitCount: number;
|
|
24
|
+
countMethod: 'Unit' | 'Pallet';
|
|
25
|
+
avgRetail?: number;
|
|
26
|
+
monthLabel?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ProjectionEntry {
|
|
29
|
+
programCode: string;
|
|
30
|
+
masterProgram: string;
|
|
31
|
+
masterProgramId: number | null;
|
|
32
|
+
clientId: number | null;
|
|
33
|
+
clientName: string;
|
|
34
|
+
actualUnits: number;
|
|
35
|
+
adjustmentType: 'percentage' | 'flat';
|
|
36
|
+
adjustmentValue: number;
|
|
37
|
+
projectedUnits: number;
|
|
38
|
+
avgRetail?: number;
|
|
39
|
+
avgRetailAdjustmentType: 'percentage' | 'flat';
|
|
40
|
+
avgRetailAdjustmentValue: number;
|
|
41
|
+
projectedAvgRetail?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ProjectionInput {
|
|
44
|
+
actualUnits: number;
|
|
45
|
+
adjustmentType: 'percentage' | 'flat';
|
|
46
|
+
adjustmentValue: number;
|
|
47
|
+
}
|
|
48
|
+
export interface ProjectionTotals {
|
|
49
|
+
totalActual: number;
|
|
50
|
+
totalProjected: number;
|
|
51
|
+
percentageChange: number;
|
|
52
|
+
absoluteChange: number;
|
|
53
|
+
actualRevenue: number;
|
|
54
|
+
projectedRevenue: number;
|
|
55
|
+
revenueChange: number;
|
|
56
|
+
revenuePercentChange: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculate projected units based on adjustment type and value.
|
|
60
|
+
*/
|
|
61
|
+
export declare function calculateProjection(input: ProjectionInput): number;
|
|
62
|
+
/**
|
|
63
|
+
* Calculate projected average retail price.
|
|
64
|
+
*/
|
|
65
|
+
export declare function calculateAvgRetailProjection(actualAvgRetail: number | undefined, adjustmentType: 'percentage' | 'flat', adjustmentValue: number): number | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Convert checked-in units summary to projection entries with default values (0% change).
|
|
68
|
+
*/
|
|
69
|
+
export declare function initializeProjections(summary: CheckedInUnitsSummary[]): ProjectionEntry[];
|
|
70
|
+
/**
|
|
71
|
+
* Update a single projection entry's units.
|
|
72
|
+
*/
|
|
73
|
+
export declare function updateProjection(entry: ProjectionEntry, adjustmentType: 'percentage' | 'flat', adjustmentValue: number): ProjectionEntry;
|
|
74
|
+
/**
|
|
75
|
+
* Update a single projection entry's average retail.
|
|
76
|
+
*/
|
|
77
|
+
export declare function updateAvgRetailProjection(entry: ProjectionEntry, adjustmentType: 'percentage' | 'flat', adjustmentValue: number): ProjectionEntry;
|
|
78
|
+
/**
|
|
79
|
+
* Apply a uniform unit adjustment to all projections.
|
|
80
|
+
*/
|
|
81
|
+
export declare function applyUniformAdjustment(projections: ProjectionEntry[], adjustmentType: 'percentage' | 'flat', adjustmentValue: number): ProjectionEntry[];
|
|
82
|
+
/**
|
|
83
|
+
* Apply a uniform avg retail adjustment to all projections.
|
|
84
|
+
*/
|
|
85
|
+
export declare function applyUniformAvgRetailAdjustment(projections: ProjectionEntry[], adjustmentType: 'percentage' | 'flat', adjustmentValue: number): ProjectionEntry[];
|
|
86
|
+
/**
|
|
87
|
+
* Calculate totals for projection summary including revenue.
|
|
88
|
+
*/
|
|
89
|
+
export declare function calculateTotals(projections: ProjectionEntry[]): ProjectionTotals;
|
|
90
|
+
/**
|
|
91
|
+
* Group projections by client name.
|
|
92
|
+
*/
|
|
93
|
+
export declare function groupProjectionsByClient(projections: ProjectionEntry[]): Map<string, ProjectionEntry[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Export projections to CSV format with unit + avgRetail + inventory value data.
|
|
96
|
+
*/
|
|
97
|
+
export declare function exportToCSV(projections: ProjectionEntry[]): string;
|
|
98
|
+
/**
|
|
99
|
+
* Fetch FY25 actuals from fpa_wes_imports on the ReturnPro Supabase instance.
|
|
100
|
+
* Aggregates across all months for a given fiscal year and user,
|
|
101
|
+
* returning one CheckedInUnitsSummary per master program.
|
|
102
|
+
*/
|
|
103
|
+
export declare function fetchWesImports(options?: {
|
|
104
|
+
fiscalYear?: number;
|
|
105
|
+
userId?: string;
|
|
106
|
+
}): Promise<CheckedInUnitsSummary[]>;
|
|
107
|
+
/**
|
|
108
|
+
* Parse a JSON file (array of CheckedInUnitsSummary) as an alternative data source.
|
|
109
|
+
* Accepts raw JSON string (e.g., from stdin or file read).
|
|
110
|
+
*/
|
|
111
|
+
export declare function parseSummaryFromJson(json: string): CheckedInUnitsSummary[];
|
|
112
|
+
/**
|
|
113
|
+
* Format projections as a Bloomberg-dense markdown table.
|
|
114
|
+
*/
|
|
115
|
+
export declare function formatProjectionTable(projections: ProjectionEntry[]): string;
|