Add CPM (Customer Portfolio Manager) attribute to accounts

- New CPM field on AccountRecord type, DB schema, and migration
- Seed "David Stefan" as CPM for 20 specified accounts
- CPM filter dropdown on Account Explorer (alongside AD and IMS BA)
- CPM shown on account cards, account detail view, and activity overlay
- CPM column added to admin data table
- upsertAccount includes CPM in insert/update

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 09:19:38 -04:00
parent 957376c770
commit 9d016a08cb
6 changed files with 62 additions and 9 deletions

View File

@@ -32,6 +32,7 @@ function getDb(): Database.Database {
initSchema(_db);
migrateSchema(_db);
seedDefaultPlaybooks();
seedCPMValues();
}
return _db;
}
@@ -48,6 +49,9 @@ function migrateSchema(db: Database.Database) {
if (!colNames.has('Campaign_Artifacts_URL')) {
db.exec("ALTER TABLE accounts ADD COLUMN Campaign_Artifacts_URL TEXT DEFAULT NULL");
}
if (!colNames.has('CPM')) {
db.exec("ALTER TABLE accounts ADD COLUMN CPM TEXT DEFAULT NULL");
}
}
function initSchema(db: Database.Database) {
@@ -67,6 +71,8 @@ function initSchema(db: Database.Database) {
Area_Sales_Leader TEXT,
DM TEXT,
AD TEXT,
IMS_BA TEXT,
CPM TEXT,
Logo_URL TEXT,
Next_Renewal_Date TEXT,
Next_Renewal_EAR REAL,
@@ -504,13 +510,13 @@ export function deleteTarget(accountName: string) {
export function upsertAccount(record: Record<string, unknown>) {
const db = getDb();
db.prepare(`INSERT INTO accounts (Account_Name, District_Name, Tier, Priority, AgentMinder_Status, Current_ARR_USD, MAP_In_Place_YN, Company_URL, Area_Sales_Leader, DM, AD)
VALUES (@Account_Name, @District_Name, @Tier, @Priority, @AgentMinder_Status, @Current_ARR_USD, @MAP_In_Place_YN, @Company_URL, @Area_Sales_Leader, @DM, @AD)
db.prepare(`INSERT INTO accounts (Account_Name, District_Name, Tier, Priority, AgentMinder_Status, Current_ARR_USD, MAP_In_Place_YN, Company_URL, Area_Sales_Leader, DM, AD, CPM)
VALUES (@Account_Name, @District_Name, @Tier, @Priority, @AgentMinder_Status, @Current_ARR_USD, @MAP_In_Place_YN, @Company_URL, @Area_Sales_Leader, @DM, @AD, @CPM)
ON CONFLICT(Account_Name) DO UPDATE SET
District_Name=excluded.District_Name, Tier=excluded.Tier, Priority=excluded.Priority,
AgentMinder_Status=excluded.AgentMinder_Status, Current_ARR_USD=excluded.Current_ARR_USD,
MAP_In_Place_YN=excluded.MAP_In_Place_YN, Company_URL=excluded.Company_URL,
Area_Sales_Leader=excluded.Area_Sales_Leader, DM=excluded.DM, AD=excluded.AD
Area_Sales_Leader=excluded.Area_Sales_Leader, DM=excluded.DM, AD=excluded.AD, CPM=excluded.CPM
`).run({
Account_Name: record.Account_Name || '',
District_Name: record.District_Name || '',
@@ -523,6 +529,7 @@ export function upsertAccount(record: Record<string, unknown>) {
Area_Sales_Leader: record.Area_Sales_Leader ?? null,
DM: record.DM ?? null,
AD: record.AD ?? null,
CPM: record.CPM ?? null,
});
}
@@ -802,3 +809,19 @@ export function upsertTarget(record: Record<string, unknown>) {
Risk_Notes: record.Risk_Notes || record.Notes || null,
});
}
function seedCPMValues() {
const db = getDb();
const cpmAccounts = [
'ADT', 'ADVENTHEALTH', 'ARBITRATION FORUMS', 'CARLYLE GROUP', 'CARNIVAL',
'ENTERGY', 'Geographic Solutions', 'GUIDEWELL BLUE CROSS BLUE SHIELD OF FLORIDA',
'JABIL CIRCUIT', 'KASEYA', 'LEE MEMORIAL HEALTH SYSTEM', 'LUMEN',
'NEXTERA ENERGY', 'NORWEGIAN CRUISE LINE', 'OCHSNER HEALTH SYSTEM',
'ORLANDO HEALTH', 'PAYSPAN', 'PUBLIX SUPERMARKETS', 'RAYMOND JAMES FINANCIAL',
'TECH DATA',
];
const stmt = db.prepare("UPDATE accounts SET CPM = 'David Stefan' WHERE Account_Name = ? AND (CPM IS NULL OR CPM = '')");
for (const name of cpmAccounts) {
stmt.run(name);
}
}