1074 lines
39 KiB
JavaScript
1074 lines
39 KiB
JavaScript
import { Pool } from 'pg';
|
|
import { resolveDatabasePoolConfig } from '../src/services/db.js';
|
|
import { V2DemoFixture as fixture } from './v2-demo-fixture.mjs';
|
|
|
|
const poolConfig = resolveDatabasePoolConfig();
|
|
|
|
if (!poolConfig) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Database connection settings are required');
|
|
process.exit(1);
|
|
}
|
|
|
|
const pool = new Pool(poolConfig);
|
|
|
|
function hoursFromNow(hours) {
|
|
return new Date(Date.now() + (hours * 60 * 60 * 1000)).toISOString();
|
|
}
|
|
|
|
async function upsertUser(client, user) {
|
|
await client.query(
|
|
`
|
|
INSERT INTO users (id, email, display_name, status, metadata)
|
|
VALUES ($1, $2, $3, 'ACTIVE', '{}'::jsonb)
|
|
ON CONFLICT (id) DO UPDATE
|
|
SET email = EXCLUDED.email,
|
|
display_name = EXCLUDED.display_name,
|
|
status = 'ACTIVE',
|
|
updated_at = NOW()
|
|
`,
|
|
[user.id, user.email || null, user.displayName || null]
|
|
);
|
|
}
|
|
|
|
async function main() {
|
|
const client = await pool.connect();
|
|
try {
|
|
await client.query('BEGIN');
|
|
|
|
await client.query('DELETE FROM tenants WHERE id = $1', [fixture.tenant.id]);
|
|
|
|
const openStartsAt = hoursFromNow(4);
|
|
const openEndsAt = hoursFromNow(12);
|
|
const completedStartsAt = hoursFromNow(-28);
|
|
const completedEndsAt = hoursFromNow(-20);
|
|
const checkedInAt = hoursFromNow(-27.5);
|
|
const checkedOutAt = hoursFromNow(-20.25);
|
|
const assignedStartsAt = hoursFromNow(0.1);
|
|
const assignedEndsAt = hoursFromNow(8.1);
|
|
const swapEligibleStartsAt = hoursFromNow(26);
|
|
const swapEligibleEndsAt = hoursFromNow(34);
|
|
const availableStartsAt = hoursFromNow(30);
|
|
const availableEndsAt = hoursFromNow(38);
|
|
const cancelledStartsAt = hoursFromNow(20);
|
|
const cancelledEndsAt = hoursFromNow(28);
|
|
const noShowStartsAt = hoursFromNow(-18);
|
|
const noShowEndsAt = hoursFromNow(-10);
|
|
const invoiceDueAt = hoursFromNow(72);
|
|
|
|
await upsertUser(client, fixture.users.businessOwner);
|
|
await upsertUser(client, fixture.users.operationsManager);
|
|
await upsertUser(client, fixture.users.vendorManager);
|
|
await upsertUser(client, fixture.users.staffAna);
|
|
await upsertUser(client, fixture.users.staffBen);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO tenants (id, slug, name, status, metadata)
|
|
VALUES ($1, $2, $3, 'ACTIVE', $4::jsonb)
|
|
`,
|
|
[fixture.tenant.id, fixture.tenant.slug, fixture.tenant.name, JSON.stringify({ seededBy: 'seed-v2-demo-data' })]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO tenant_memberships (tenant_id, user_id, membership_status, base_role, metadata)
|
|
VALUES
|
|
($1, $2, 'ACTIVE', 'admin', '{"persona":"business_owner"}'::jsonb),
|
|
($1, $3, 'ACTIVE', 'manager', '{"persona":"ops_manager"}'::jsonb),
|
|
($1, $4, 'ACTIVE', 'manager', '{"persona":"vendor_manager"}'::jsonb),
|
|
($1, $5, 'ACTIVE', 'member', '{"persona":"staff"}'::jsonb),
|
|
($1, $6, 'ACTIVE', 'member', '{"persona":"staff"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.tenant.id,
|
|
fixture.users.businessOwner.id,
|
|
fixture.users.operationsManager.id,
|
|
fixture.users.vendorManager.id,
|
|
fixture.users.staffAna.id,
|
|
fixture.users.staffBen.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO businesses (
|
|
id, tenant_id, slug, business_name, status, contact_name, contact_email, contact_phone, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, 'ACTIVE', $5, $6, $7, $8::jsonb)
|
|
`,
|
|
[
|
|
fixture.business.id,
|
|
fixture.tenant.id,
|
|
fixture.business.slug,
|
|
fixture.business.name,
|
|
'Legendary Client Manager',
|
|
fixture.users.businessOwner.email,
|
|
'+15550001001',
|
|
JSON.stringify({ segment: 'buyer', seeded: true }),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO business_memberships (
|
|
tenant_id, business_id, user_id, membership_status, business_role, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $3, 'ACTIVE', 'owner', '{"persona":"client_owner"}'::jsonb),
|
|
($1, $2, $4, 'ACTIVE', 'manager', '{"persona":"client_ops"}'::jsonb)
|
|
`,
|
|
[fixture.tenant.id, fixture.business.id, fixture.users.businessOwner.id, fixture.users.operationsManager.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO vendors (
|
|
id, tenant_id, slug, company_name, status, contact_name, contact_email, contact_phone, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, 'ACTIVE', $5, $6, $7, $8::jsonb)
|
|
`,
|
|
[
|
|
fixture.vendor.id,
|
|
fixture.tenant.id,
|
|
fixture.vendor.slug,
|
|
fixture.vendor.name,
|
|
'Vendor Manager',
|
|
fixture.users.vendorManager.email,
|
|
'+15550001002',
|
|
JSON.stringify({ kind: 'internal_pool', seeded: true }),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO vendor_memberships (
|
|
tenant_id, vendor_id, user_id, membership_status, vendor_role, metadata
|
|
)
|
|
VALUES ($1, $2, $3, 'ACTIVE', 'owner', '{"persona":"vendor_owner"}'::jsonb)
|
|
`,
|
|
[fixture.tenant.id, fixture.vendor.id, fixture.users.vendorManager.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO cost_centers (id, tenant_id, business_id, code, name, status, metadata)
|
|
VALUES ($1, $2, $3, 'CAFE_OPS', $4, 'ACTIVE', '{"seeded":true}'::jsonb)
|
|
`,
|
|
[fixture.costCenters.cafeOps.id, fixture.tenant.id, fixture.business.id, fixture.costCenters.cafeOps.name]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO roles_catalog (id, tenant_id, code, name, status, metadata)
|
|
VALUES
|
|
($1, $3, $4, $5, 'ACTIVE', '{}'::jsonb),
|
|
($2, $3, $6, $7, 'ACTIVE', '{}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.roles.barista.id,
|
|
fixture.roles.captain.id,
|
|
fixture.tenant.id,
|
|
fixture.roles.barista.code,
|
|
fixture.roles.barista.name,
|
|
fixture.roles.captain.code,
|
|
fixture.roles.captain.name,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staffs (
|
|
id, tenant_id, user_id, full_name, email, phone, status, primary_role, onboarding_status,
|
|
average_rating, rating_count, metadata
|
|
)
|
|
VALUES
|
|
($1, $3, $4, $5, $6, $7, 'ACTIVE', $8, 'COMPLETED', 4.50, 1, $9::jsonb),
|
|
($2, $3, $10, $11, $12, $13, 'ACTIVE', $14, 'COMPLETED', 4.90, 3, $15::jsonb)
|
|
`,
|
|
[
|
|
fixture.staff.ana.id,
|
|
fixture.staff.ben.id,
|
|
fixture.tenant.id,
|
|
fixture.users.staffAna.id,
|
|
fixture.staff.ana.fullName,
|
|
fixture.staff.ana.email,
|
|
fixture.staff.ana.phone,
|
|
fixture.staff.ana.primaryRole,
|
|
JSON.stringify({
|
|
favoriteCandidate: true,
|
|
seeded: true,
|
|
firstName: 'Ana',
|
|
lastName: 'Barista',
|
|
bio: 'Experienced barista and event staffing professional.',
|
|
preferredLocations: [
|
|
{
|
|
city: 'Mountain View',
|
|
latitude: fixture.clockPoint.latitude,
|
|
longitude: fixture.clockPoint.longitude,
|
|
},
|
|
],
|
|
maxDistanceMiles: 20,
|
|
industries: ['CATERING', 'CAFE'],
|
|
skills: ['BARISTA', 'CUSTOMER_SERVICE'],
|
|
emergencyContact: {
|
|
name: 'Maria Barista',
|
|
phone: '+15550007777',
|
|
},
|
|
}),
|
|
fixture.users.staffBen.id,
|
|
fixture.staff.ben.fullName,
|
|
fixture.staff.ben.email,
|
|
fixture.staff.ben.phone,
|
|
fixture.staff.ben.primaryRole,
|
|
JSON.stringify({
|
|
favoriteCandidate: false,
|
|
seeded: true,
|
|
firstName: 'Ben',
|
|
lastName: 'Barista',
|
|
bio: 'Reliable event barista used for swap coverage and dispatch team ranking.',
|
|
preferredLocations: [
|
|
{
|
|
city: 'Mountain View',
|
|
latitude: fixture.clockPoint.latitude,
|
|
longitude: fixture.clockPoint.longitude,
|
|
},
|
|
],
|
|
maxDistanceMiles: 15,
|
|
industries: ['CATERING', 'CAFE'],
|
|
skills: ['BARISTA', 'CUSTOMER_SERVICE'],
|
|
emergencyContact: {
|
|
name: 'Noah Barista',
|
|
phone: '+15550008888',
|
|
},
|
|
}),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_roles (staff_id, role_id, is_primary)
|
|
VALUES
|
|
($1, $3, TRUE),
|
|
($2, $3, TRUE)
|
|
`,
|
|
[fixture.staff.ana.id, fixture.staff.ben.id, fixture.roles.barista.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO workforce (id, tenant_id, vendor_id, staff_id, workforce_number, employment_type, status, metadata)
|
|
VALUES
|
|
($1, $3, $4, $5, $6, 'TEMP', 'ACTIVE', $7::jsonb),
|
|
($2, $3, $4, $8, $9, 'TEMP', 'ACTIVE', $10::jsonb)
|
|
`,
|
|
[
|
|
fixture.workforce.ana.id,
|
|
fixture.workforce.ben.id,
|
|
fixture.tenant.id,
|
|
fixture.vendor.id,
|
|
fixture.staff.ana.id,
|
|
fixture.workforce.ana.workforceNumber,
|
|
JSON.stringify({ source: 'seed-v2-demo' }),
|
|
fixture.staff.ben.id,
|
|
fixture.workforce.ben.workforceNumber,
|
|
JSON.stringify({ source: 'seed-v2-demo' }),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_availability (
|
|
id, tenant_id, staff_id, day_of_week, availability_status, time_slots, metadata
|
|
)
|
|
VALUES
|
|
($1, $3, $4, 1, 'PARTIAL', '[{"start":"08:00","end":"18:00"}]'::jsonb, '{"seeded":true}'::jsonb),
|
|
($2, $3, $4, 5, 'PARTIAL', '[{"start":"09:00","end":"17:00"}]'::jsonb, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[fixture.availability.monday.id, fixture.availability.friday.id, fixture.tenant.id, fixture.staff.ana.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_benefits (
|
|
id, tenant_id, staff_id, benefit_type, title, status, tracked_hours, target_hours, metadata
|
|
)
|
|
VALUES ($1, $2, $3, 'COMMUTER', $4, 'ACTIVE', 32, 40, '{"description":"Commuter stipend unlocked after 40 hours"}'::jsonb)
|
|
`,
|
|
[fixture.benefits.commuter.id, fixture.tenant.id, fixture.staff.ana.id, fixture.benefits.commuter.title]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_benefit_history (
|
|
id, tenant_id, staff_id, benefit_id, benefit_type, title, status,
|
|
effective_at, ended_at, tracked_hours, target_hours, notes, metadata
|
|
)
|
|
VALUES
|
|
(
|
|
$1, $3, $4, $5, 'COMMUTER', $6, 'PENDING',
|
|
NOW() - INTERVAL '45 days', NOW() - INTERVAL '10 days', 18, 40,
|
|
'Hours were below threshold for payout window.',
|
|
'{"source":"seed-v2-demo","period":"previous"}'::jsonb
|
|
),
|
|
(
|
|
$2, $3, $4, $5, 'COMMUTER', $6, 'ACTIVE',
|
|
NOW() - INTERVAL '9 days', NULL, 32, 40,
|
|
'Current active commuter stipend tracking.',
|
|
'{"source":"seed-v2-demo","period":"current"}'::jsonb
|
|
)
|
|
`,
|
|
[
|
|
fixture.benefitHistory.commuterPending.id,
|
|
fixture.benefitHistory.commuterActive.id,
|
|
fixture.tenant.id,
|
|
fixture.staff.ana.id,
|
|
fixture.benefits.commuter.id,
|
|
fixture.benefits.commuter.title,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO emergency_contacts (
|
|
id, tenant_id, staff_id, full_name, phone, relationship_type, is_primary, metadata
|
|
)
|
|
VALUES ($1, $2, $3, 'Maria Barista', '+15550007777', 'SIBLING', TRUE, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[fixture.emergencyContacts.primary.id, fixture.tenant.id, fixture.staff.ana.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO clock_points (
|
|
id, tenant_id, business_id, cost_center_id, label, address, latitude, longitude,
|
|
geofence_radius_meters, nfc_tag_uid, default_clock_in_mode, allow_clock_in_override, status, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, 'ACTIVE', $13::jsonb)
|
|
`,
|
|
[
|
|
fixture.clockPoint.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.costCenters.cafeOps.id,
|
|
fixture.clockPoint.label,
|
|
fixture.clockPoint.address,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
fixture.clockPoint.geofenceRadiusMeters,
|
|
fixture.clockPoint.nfcTagUid,
|
|
fixture.clockPoint.defaultClockInMode,
|
|
fixture.clockPoint.allowClockInOverride,
|
|
JSON.stringify({ city: 'Mountain View', state: 'CA', zipCode: '94043', seeded: true }),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO hub_managers (id, tenant_id, hub_id, business_membership_id)
|
|
SELECT $1, $2, $3, bm.id
|
|
FROM business_memberships bm
|
|
WHERE bm.business_id = $4
|
|
AND bm.user_id = $5
|
|
`,
|
|
[
|
|
fixture.hubManagers.opsLead.id,
|
|
fixture.tenant.id,
|
|
fixture.clockPoint.id,
|
|
fixture.business.id,
|
|
fixture.users.operationsManager.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO dispatch_team_memberships (
|
|
id, tenant_id, business_id, hub_id, staff_id, team_type, source, status, reason, effective_at, created_by_user_id, metadata
|
|
)
|
|
VALUES
|
|
($1, $4, $5, NULL, $6, 'CORE', 'MANUAL', 'ACTIVE', 'Seeded core team member', NOW() - INTERVAL '7 days', $7, '{"seeded":true}'::jsonb),
|
|
($2, $4, $5, $8, $9, 'CERTIFIED_LOCATION', 'MANUAL', 'ACTIVE', 'Seeded location-certified member', NOW() - INTERVAL '2 days', $7, '{"seeded":true}'::jsonb),
|
|
($3, $4, $5, NULL, $9, 'MARKETPLACE', 'SYSTEM', 'ACTIVE', 'Seeded marketplace fallback member', NOW() - INTERVAL '2 days', $7, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.dispatchTeamMemberships.anaCore.id,
|
|
fixture.dispatchTeamMemberships.benCertifiedLocation.id,
|
|
fixture.dispatchTeamMemberships.benMarketplace.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.staff.ana.id,
|
|
fixture.users.operationsManager.id,
|
|
fixture.clockPoint.id,
|
|
fixture.staff.ben.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO orders (
|
|
id, tenant_id, business_id, vendor_id, order_number, title, description, status, service_type,
|
|
starts_at, ends_at, location_name, location_address, latitude, longitude, notes, created_by_user_id, metadata
|
|
)
|
|
VALUES
|
|
($1, $3, $4, $5, $6, $7, 'Open order for live v2 commands', 'OPEN', 'EVENT', $8, $9, 'Google Cafe', $10, $11, $12, 'Use this order for live smoke and frontend reads', $13, '{"slice":"open","orderType":"ONE_TIME"}'::jsonb),
|
|
($2, $3, $4, $5, $14, $15, 'Completed order for favorites, reviews, invoices, and attendance history', 'COMPLETED', 'CATERING', $16, $17, 'Google Catering', $10, $11, $12, 'Completed historical example', $13, '{"slice":"completed","orderType":"ONE_TIME"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.orders.open.id,
|
|
fixture.orders.completed.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.orders.open.number,
|
|
fixture.orders.open.title,
|
|
openStartsAt,
|
|
openEndsAt,
|
|
fixture.clockPoint.address,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
fixture.users.businessOwner.id,
|
|
fixture.orders.completed.number,
|
|
fixture.orders.completed.title,
|
|
completedStartsAt,
|
|
completedEndsAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO orders (
|
|
id, tenant_id, business_id, vendor_id, order_number, title, description, status, service_type,
|
|
starts_at, ends_at, location_name, location_address, latitude, longitude, notes, created_by_user_id, metadata
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, $4, $5, $6, 'Active order used to populate assigned, available, cancelled, and no-show shift states',
|
|
'ACTIVE', 'RESTAURANT', $7, $8, 'Google Cafe', $9, $10, $11, 'Mixed state scenario order', $12,
|
|
'{"slice":"active","orderType":"ONE_TIME"}'::jsonb
|
|
)
|
|
`,
|
|
[
|
|
fixture.orders.active.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.orders.active.number,
|
|
fixture.orders.active.title,
|
|
assignedStartsAt,
|
|
availableEndsAt,
|
|
fixture.clockPoint.address,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
fixture.users.operationsManager.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO shifts (
|
|
id, tenant_id, order_id, business_id, vendor_id, clock_point_id, shift_code, title, status, starts_at, ends_at, timezone,
|
|
location_name, location_address, latitude, longitude, geofence_radius_meters, clock_in_mode, allow_clock_in_override,
|
|
required_workers, assigned_workers, notes, metadata
|
|
)
|
|
VALUES
|
|
($1, $3, $5, $7, $9, $11, $13, $15, 'OPEN', $17, $18, 'America/Los_Angeles', 'Google Cafe', $19, $21, $22, $23, NULL, NULL, 1, 0, 'Open staffing need', '{"slice":"open"}'::jsonb),
|
|
($2, $4, $6, $8, $10, $12, $14, $16, 'COMPLETED', $20, $24, 'America/Los_Angeles', 'Google Catering', $19, $21, $22, $23, NULL, NULL, 1, 1, 'Completed staffed shift', '{"slice":"completed"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.shifts.open.id,
|
|
fixture.shifts.completed.id,
|
|
fixture.tenant.id,
|
|
fixture.tenant.id,
|
|
fixture.orders.open.id,
|
|
fixture.orders.completed.id,
|
|
fixture.business.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.vendor.id,
|
|
fixture.clockPoint.id,
|
|
fixture.clockPoint.id,
|
|
fixture.shifts.open.code,
|
|
fixture.shifts.completed.code,
|
|
fixture.shifts.open.title,
|
|
fixture.shifts.completed.title,
|
|
openStartsAt,
|
|
openEndsAt,
|
|
fixture.clockPoint.address,
|
|
completedStartsAt,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
fixture.clockPoint.geofenceRadiusMeters,
|
|
completedEndsAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO shifts (
|
|
id, tenant_id, order_id, business_id, vendor_id, clock_point_id, shift_code, title, status, starts_at, ends_at, timezone,
|
|
location_name, location_address, latitude, longitude, geofence_radius_meters, clock_in_mode, allow_clock_in_override,
|
|
required_workers, assigned_workers, notes, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, $6, $7, $8, 'OPEN', $9, $10, 'America/Los_Angeles', 'Google Cafe', $11, $12, $13, $14, NULL, NULL, 1, 0, 'Available shift for staff marketplace', '{"slice":"available"}'::jsonb),
|
|
($15, $2, $3, $4, $5, $6, $16, $17, 'ASSIGNED', $18, $19, 'America/Los_Angeles', 'Google Cafe', $11, $12, $13, $14, $35, $36, 1, 1, 'Assigned shift waiting for staff confirmation', '{"slice":"assigned"}'::jsonb),
|
|
($20, $2, $3, $4, $5, $6, $21, $22, 'ASSIGNED', $23, $24, 'America/Los_Angeles', 'Google Cafe', $11, $12, $13, $14, $35, $36, 1, 1, 'Future swap-eligible shift for workflow smoke coverage', '{"slice":"swap_eligible"}'::jsonb),
|
|
($25, $2, $3, $4, $5, $6, $26, $27, 'CANCELLED', $28, $29, 'America/Los_Angeles', 'Google Cafe', $11, $12, $13, $14, NULL, NULL, 1, 0, 'Cancelled shift history sample', '{"slice":"cancelled"}'::jsonb),
|
|
($30, $2, $3, $4, $5, $6, $31, $32, 'COMPLETED', $33, $34, 'America/Los_Angeles', 'Google Cafe', $11, $12, $13, $14, $35, $36, 1, 0, 'No-show historical sample', '{"slice":"no_show"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.shifts.available.id,
|
|
fixture.tenant.id,
|
|
fixture.orders.active.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.clockPoint.id,
|
|
fixture.shifts.available.code,
|
|
fixture.shifts.available.title,
|
|
availableStartsAt,
|
|
availableEndsAt,
|
|
fixture.clockPoint.address,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
fixture.clockPoint.geofenceRadiusMeters,
|
|
fixture.shifts.assigned.id,
|
|
fixture.shifts.assigned.code,
|
|
fixture.shifts.assigned.title,
|
|
assignedStartsAt,
|
|
assignedEndsAt,
|
|
fixture.shifts.swapEligible.id,
|
|
fixture.shifts.swapEligible.code,
|
|
fixture.shifts.swapEligible.title,
|
|
swapEligibleStartsAt,
|
|
swapEligibleEndsAt,
|
|
fixture.shifts.cancelled.id,
|
|
fixture.shifts.cancelled.code,
|
|
fixture.shifts.cancelled.title,
|
|
cancelledStartsAt,
|
|
cancelledEndsAt,
|
|
fixture.shifts.noShow.id,
|
|
fixture.shifts.noShow.code,
|
|
fixture.shifts.noShow.title,
|
|
noShowStartsAt,
|
|
noShowEndsAt,
|
|
fixture.shifts.assigned.clockInMode,
|
|
fixture.shifts.assigned.allowClockInOverride,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO shift_roles (
|
|
id, shift_id, role_id, role_code, role_name, workers_needed, assigned_count, pay_rate_cents, bill_rate_cents, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, 1, 0, 2200, 3500, '{"slice":"open"}'::jsonb),
|
|
($6, $7, $3, $4, $5, 1, 1, 2200, 3500, '{"slice":"completed"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.shiftRoles.openBarista.id,
|
|
fixture.shifts.open.id,
|
|
fixture.roles.barista.id,
|
|
fixture.roles.barista.code,
|
|
fixture.roles.barista.name,
|
|
fixture.shiftRoles.completedBarista.id,
|
|
fixture.shifts.completed.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO shift_roles (
|
|
id, shift_id, role_id, role_code, role_name, workers_needed, assigned_count, pay_rate_cents, bill_rate_cents, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $7, $8, $9, 1, 0, 2200, 3500, '{"slice":"available"}'::jsonb),
|
|
($3, $4, $7, $8, $9, 1, 1, 2300, 3600, '{"slice":"assigned"}'::jsonb),
|
|
($5, $6, $7, $8, $9, 1, 1, 2400, 3700, '{"slice":"swap_eligible"}'::jsonb),
|
|
($10, $11, $7, $8, $9, 1, 0, 2200, 3500, '{"slice":"cancelled"}'::jsonb),
|
|
($12, $13, $7, $8, $9, 1, 0, 2200, 3500, '{"slice":"no_show"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.shiftRoles.availableBarista.id,
|
|
fixture.shifts.available.id,
|
|
fixture.shiftRoles.assignedBarista.id,
|
|
fixture.shifts.assigned.id,
|
|
fixture.shiftRoles.swapEligibleBarista.id,
|
|
fixture.shifts.swapEligible.id,
|
|
fixture.roles.barista.id,
|
|
fixture.roles.barista.code,
|
|
fixture.roles.barista.name,
|
|
fixture.shiftRoles.cancelledBarista.id,
|
|
fixture.shifts.cancelled.id,
|
|
fixture.shiftRoles.noShowBarista.id,
|
|
fixture.shifts.noShow.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO applications (
|
|
id, tenant_id, shift_id, shift_role_id, staff_id, status, origin, applied_at, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, 'PENDING', 'STAFF', NOW(), '{"slice":"open"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.applications.openAna.id,
|
|
fixture.tenant.id,
|
|
fixture.shifts.open.id,
|
|
fixture.shiftRoles.openBarista.id,
|
|
fixture.staff.ana.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO assignments (
|
|
id, tenant_id, business_id, vendor_id, shift_id, shift_role_id, workforce_id, staff_id, status,
|
|
assigned_at, accepted_at, checked_in_at, checked_out_at, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'COMPLETED', $9, $10, $11, $12, '{"slice":"completed"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.assignments.completedAna.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.shifts.completed.id,
|
|
fixture.shiftRoles.completedBarista.id,
|
|
fixture.workforce.ana.id,
|
|
fixture.staff.ana.id,
|
|
completedStartsAt,
|
|
completedStartsAt,
|
|
checkedInAt,
|
|
checkedOutAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO assignments (
|
|
id, tenant_id, business_id, vendor_id, shift_id, shift_role_id, workforce_id, staff_id, status,
|
|
assigned_at, accepted_at, checked_in_at, checked_out_at, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, $6, $7, $8, 'ASSIGNED', NOW(), NULL, NULL, NULL, '{"slice":"assigned"}'::jsonb),
|
|
($9, $2, $3, $4, $10, $11, $7, $8, 'ACCEPTED', NOW(), NOW(), NULL, NULL, '{"slice":"swap_eligible"}'::jsonb),
|
|
($12, $2, $3, $4, $13, $14, $7, $8, 'CANCELLED', NOW(), NULL, NULL, NULL, '{"slice":"cancelled","cancellationReason":"Client cancelled"}'::jsonb),
|
|
($15, $2, $3, $4, $16, $17, $7, $8, 'NO_SHOW', $18, NULL, NULL, NULL, '{"slice":"no_show"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.assignments.assignedAna.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.shifts.assigned.id,
|
|
fixture.shiftRoles.assignedBarista.id,
|
|
fixture.workforce.ana.id,
|
|
fixture.staff.ana.id,
|
|
fixture.assignments.swapEligibleAna.id,
|
|
fixture.shifts.swapEligible.id,
|
|
fixture.shiftRoles.swapEligibleBarista.id,
|
|
fixture.assignments.cancelledAna.id,
|
|
fixture.shifts.cancelled.id,
|
|
fixture.shiftRoles.cancelledBarista.id,
|
|
fixture.assignments.noShowAna.id,
|
|
fixture.shifts.noShow.id,
|
|
fixture.shiftRoles.noShowBarista.id,
|
|
noShowStartsAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO attendance_events (
|
|
tenant_id, assignment_id, shift_id, staff_id, clock_point_id, event_type, source_type, source_reference,
|
|
nfc_tag_uid, device_id, latitude, longitude, accuracy_meters, distance_to_clock_point_meters, within_geofence,
|
|
validation_status, validation_reason, captured_at, raw_payload
|
|
)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, 'CLOCK_IN', 'NFC', 'seed', $6, 'seed-device', $7, $8, 5, 0, TRUE, 'ACCEPTED', NULL, $9, '{"seeded":true}'::jsonb),
|
|
($1, $2, $3, $4, $5, 'CLOCK_OUT', 'NFC', 'seed', $6, 'seed-device', $7, $8, 5, 0, TRUE, 'ACCEPTED', NULL, $10, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.tenant.id,
|
|
fixture.assignments.completedAna.id,
|
|
fixture.shifts.completed.id,
|
|
fixture.staff.ana.id,
|
|
fixture.clockPoint.id,
|
|
fixture.clockPoint.nfcTagUid,
|
|
fixture.clockPoint.latitude,
|
|
fixture.clockPoint.longitude,
|
|
checkedInAt,
|
|
checkedOutAt,
|
|
]
|
|
);
|
|
|
|
const attendanceEvents = await client.query(
|
|
`
|
|
SELECT id, event_type
|
|
FROM attendance_events
|
|
WHERE assignment_id = $1
|
|
ORDER BY captured_at ASC
|
|
`,
|
|
[fixture.assignments.completedAna.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO attendance_sessions (
|
|
id, tenant_id, assignment_id, staff_id, clock_in_event_id, clock_out_event_id, status,
|
|
check_in_at, check_out_at, worked_minutes, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, 'CLOSED', $7, $8, 435, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
'95f6017c-256c-4eb5-8033-eb942f018001',
|
|
fixture.tenant.id,
|
|
fixture.assignments.completedAna.id,
|
|
fixture.staff.ana.id,
|
|
attendanceEvents.rows.find((row) => row.event_type === 'CLOCK_IN')?.id,
|
|
attendanceEvents.rows.find((row) => row.event_type === 'CLOCK_OUT')?.id,
|
|
checkedInAt,
|
|
checkedOutAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO timesheets (
|
|
id, tenant_id, assignment_id, staff_id, status, regular_minutes, overtime_minutes, break_minutes, gross_pay_cents, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, 'APPROVED', 420, 15, 30, 15950, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[fixture.timesheets.completedAna.id, fixture.tenant.id, fixture.assignments.completedAna.id, fixture.staff.ana.id]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO documents (id, tenant_id, document_type, name, required_for_role_code, metadata)
|
|
VALUES
|
|
($1, $2, 'GOVERNMENT_ID', $3, $10, '{"seeded":true,"description":"State ID or passport","required":true}'::jsonb),
|
|
($4, $2, 'CERTIFICATION', $5, $10, '{"seeded":true}'::jsonb),
|
|
($6, $2, 'ATTIRE', $7, $10, '{"seeded":true,"description":"Upload a photo of your black shirt","required":true}'::jsonb),
|
|
($8, $2, 'TAX_FORM', $9, $10, '{"seeded":true}'::jsonb),
|
|
($11, $2, 'TAX_FORM', $12, $10, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.documents.governmentId.id,
|
|
fixture.tenant.id,
|
|
fixture.documents.governmentId.name,
|
|
fixture.documents.foodSafety.id,
|
|
fixture.documents.foodSafety.name,
|
|
fixture.documents.attireBlackShirt.id,
|
|
fixture.documents.attireBlackShirt.name,
|
|
fixture.documents.taxFormI9.id,
|
|
fixture.documents.taxFormI9.name,
|
|
fixture.roles.barista.code,
|
|
fixture.documents.taxFormW4.id,
|
|
fixture.documents.taxFormW4.name,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_documents (
|
|
id, tenant_id, staff_id, document_id, file_uri, status, expires_at, metadata
|
|
)
|
|
VALUES
|
|
($1, $2, $3, $4, $5, 'PENDING', $6, '{"seeded":true,"verificationStatus":"PENDING_REVIEW"}'::jsonb),
|
|
($7, $2, $3, $8, $9, 'VERIFIED', $10, '{"seeded":true,"verificationStatus":"APPROVED"}'::jsonb),
|
|
($11, $2, $3, $12, $13, 'VERIFIED', NULL, '{"seeded":true,"verificationStatus":"APPROVED"}'::jsonb),
|
|
($14, $2, $3, $15, $16, 'VERIFIED', NULL, '{"seeded":true,"formStatus":"SUBMITTED","fields":{"ssnLast4":"1234","filingStatus":"single"}}'::jsonb),
|
|
($17, $2, $3, $18, $19, 'PENDING', NULL, '{"seeded":true,"formStatus":"DRAFT","fields":{"section1Complete":true}}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.staffDocuments.governmentId.id,
|
|
fixture.tenant.id,
|
|
fixture.staff.ana.id,
|
|
fixture.documents.governmentId.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/government-id-front.jpg`,
|
|
hoursFromNow(24 * 365),
|
|
fixture.staffDocuments.foodSafety.id,
|
|
fixture.documents.foodSafety.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/food-handler-card.pdf`,
|
|
hoursFromNow(24 * 180),
|
|
fixture.staffDocuments.attireBlackShirt.id,
|
|
fixture.documents.attireBlackShirt.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/black-shirt.jpg`,
|
|
fixture.staffDocuments.taxFormW4.id,
|
|
fixture.documents.taxFormW4.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/w4-form.pdf`,
|
|
fixture.staffDocuments.taxFormI9.id,
|
|
fixture.documents.taxFormI9.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/i9-form.pdf`,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO certificates (
|
|
id, tenant_id, staff_id, certificate_type, certificate_number, issued_at, expires_at, status, file_uri, metadata
|
|
)
|
|
VALUES ($1, $2, $3, 'FOOD_SAFETY', 'FH-ANA-2026', $4, $5, 'VERIFIED', $6, $7::jsonb)
|
|
`,
|
|
[
|
|
fixture.certificates.foodSafety.id,
|
|
fixture.tenant.id,
|
|
fixture.staff.ana.id,
|
|
hoursFromNow(-24 * 30),
|
|
hoursFromNow(24 * 180),
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/food-safety-certificate.pdf`,
|
|
JSON.stringify({
|
|
seeded: true,
|
|
name: 'Food Safety Certificate',
|
|
issuer: 'ServSafe',
|
|
verificationStatus: 'APPROVED',
|
|
}),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO verification_jobs (
|
|
tenant_id, staff_id, document_id, type, file_uri, status, idempotency_key,
|
|
provider_name, provider_reference, confidence, reasons, extracted, review, metadata
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, 'certification', $4, 'APPROVED', 'seed-certification-job',
|
|
'seed', 'seed-certification-provider', 0.980, '["Verified by seed"]'::jsonb,
|
|
'{"certificateType":"FOOD_SAFETY"}'::jsonb, '{"decision":"APPROVED"}'::jsonb, '{"seeded":true}'::jsonb
|
|
)
|
|
`,
|
|
[
|
|
fixture.tenant.id,
|
|
fixture.staff.ana.id,
|
|
fixture.documents.foodSafety.id,
|
|
`gs://krow-workforce-dev-v2-private/uploads/${fixture.staff.ana.id}/food-handler-card.pdf`,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO accounts (
|
|
id, tenant_id, owner_type, owner_business_id, owner_vendor_id, owner_staff_id,
|
|
provider_name, provider_reference, last4, is_primary, metadata
|
|
)
|
|
VALUES
|
|
($1, $3, 'BUSINESS', $4, NULL, NULL, 'stripe', 'ba_business_demo', '6789', TRUE, '{"seeded":true,"accountType":"CHECKING","routingNumberMasked":"*****0001"}'::jsonb),
|
|
($2, $3, 'STAFF', NULL, NULL, $5, 'stripe', 'ba_staff_demo', '4321', TRUE, '{"seeded":true,"accountType":"CHECKING","routingNumberMasked":"*****0002"}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.accounts.businessPrimary.id,
|
|
fixture.accounts.staffPrimary.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.staff.ana.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO invoices (
|
|
id, tenant_id, order_id, business_id, vendor_id, invoice_number, status, currency_code,
|
|
subtotal_cents, tax_cents, total_cents, due_at, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, 'PENDING_REVIEW', 'USD', 15250, 700, 15950, $7, '{"seeded":true,"savingsCents":1250}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.invoices.completed.id,
|
|
fixture.tenant.id,
|
|
fixture.orders.completed.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.invoices.completed.number,
|
|
invoiceDueAt,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO recent_payments (
|
|
id, tenant_id, invoice_id, assignment_id, staff_id, status, amount_cents, process_date, metadata
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, 'PENDING', 15950, NULL, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.recentPayments.completed.id,
|
|
fixture.tenant.id,
|
|
fixture.invoices.completed.id,
|
|
fixture.assignments.completedAna.id,
|
|
fixture.staff.ana.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_favorites (id, tenant_id, business_id, staff_id, created_by_user_id, created_at)
|
|
VALUES ($1, $2, $3, $4, $5, NOW())
|
|
`,
|
|
[
|
|
fixture.favorites.ana.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.staff.ana.id,
|
|
fixture.users.businessOwner.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO staff_reviews (
|
|
id, tenant_id, business_id, staff_id, assignment_id, reviewer_user_id, rating, review_text, tags, created_at, updated_at
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, 5, 'Reliable, on time, and client friendly.', '["reliable","favorite"]'::jsonb, NOW(), NOW())
|
|
`,
|
|
[
|
|
fixture.reviews.anaCompleted.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.staff.ana.id,
|
|
fixture.assignments.completedAna.id,
|
|
fixture.users.businessOwner.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO domain_events (tenant_id, aggregate_type, aggregate_id, sequence, event_type, actor_user_id, payload)
|
|
VALUES
|
|
($1, 'order', $2, 1, 'ORDER_CREATED', $3, '{"seeded":true}'::jsonb),
|
|
($1, 'assignment', $4, 1, 'STAFF_ASSIGNED', $3, '{"seeded":true}'::jsonb)
|
|
`,
|
|
[
|
|
fixture.tenant.id,
|
|
fixture.orders.completed.id,
|
|
fixture.users.businessOwner.id,
|
|
fixture.assignments.completedAna.id,
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO location_stream_batches (
|
|
id, tenant_id, business_id, vendor_id, shift_id, assignment_id, staff_id, actor_user_id,
|
|
source_type, device_id, object_uri, point_count, out_of_geofence_count, missing_coordinate_count,
|
|
max_distance_to_clock_point_meters, started_at, ended_at, metadata
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, $4, $5, $6, $7, $8, 'GEO', 'seed-device',
|
|
$9, 4, 2, 0, 910, $10, $11, '{"seeded":true,"source":"seed-v2-demo"}'::jsonb
|
|
)
|
|
`,
|
|
[
|
|
fixture.locationStreamBatches.noShowSample.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.shifts.noShow.id,
|
|
fixture.assignments.noShowAna.id,
|
|
fixture.staff.ana.id,
|
|
fixture.users.staffAna.id,
|
|
`gs://krow-workforce-dev-v2-private/location-streams/${fixture.tenant.id}/${fixture.staff.ana.id}/${fixture.assignments.noShowAna.id}/${fixture.locationStreamBatches.noShowSample.id}.json`,
|
|
hoursFromNow(-18.25),
|
|
hoursFromNow(-17.75),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO geofence_incidents (
|
|
id, tenant_id, business_id, vendor_id, shift_id, assignment_id, staff_id, actor_user_id, location_stream_batch_id,
|
|
incident_type, severity, status, effective_clock_in_mode, source_type, device_id,
|
|
latitude, longitude, accuracy_meters, distance_to_clock_point_meters, within_geofence,
|
|
override_reason, message, occurred_at, metadata
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, $4, $5, $6, $7, $8, $9,
|
|
'OUTSIDE_GEOFENCE', 'CRITICAL', 'OPEN', 'GEO_REQUIRED', 'GEO', 'seed-device',
|
|
$10, $11, 12, 910, FALSE, NULL, 'Worker drifted outside hub geofence during active monitoring',
|
|
$12, '{"seeded":true,"outOfGeofenceCount":2}'::jsonb
|
|
)
|
|
`,
|
|
[
|
|
fixture.geofenceIncidents.noShowOutsideGeofence.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.vendor.id,
|
|
fixture.shifts.noShow.id,
|
|
fixture.assignments.noShowAna.id,
|
|
fixture.staff.ana.id,
|
|
fixture.users.staffAna.id,
|
|
fixture.locationStreamBatches.noShowSample.id,
|
|
fixture.clockPoint.latitude + 0.0065,
|
|
fixture.clockPoint.longitude + 0.0065,
|
|
hoursFromNow(-17.9),
|
|
]
|
|
);
|
|
|
|
await client.query(
|
|
`
|
|
INSERT INTO notification_outbox (
|
|
id, tenant_id, business_id, shift_id, assignment_id, related_incident_id, audience_type,
|
|
recipient_user_id, recipient_business_membership_id, channel, notification_type, priority, dedupe_key,
|
|
subject, body, payload, status, scheduled_at, created_at, updated_at
|
|
)
|
|
SELECT
|
|
$1, $2, $3, $4, $5, $6, 'USER',
|
|
bm.user_id, bm.id, 'PUSH', 'GEOFENCE_BREACH_ALERT', 'CRITICAL', $7,
|
|
'Worker left the workplace geofence',
|
|
'Seeded alert for coverage incident review',
|
|
jsonb_build_object('seeded', TRUE, 'batchId', $8::text),
|
|
'PENDING', NOW(), NOW(), NOW()
|
|
FROM business_memberships bm
|
|
WHERE bm.tenant_id = $2
|
|
AND bm.business_id = $3
|
|
AND bm.user_id = $9
|
|
`,
|
|
[
|
|
fixture.notificationOutbox.noShowManagerAlert.id,
|
|
fixture.tenant.id,
|
|
fixture.business.id,
|
|
fixture.shifts.noShow.id,
|
|
fixture.assignments.noShowAna.id,
|
|
fixture.geofenceIncidents.noShowOutsideGeofence.id,
|
|
`seed-geofence-breach:${fixture.geofenceIncidents.noShowOutsideGeofence.id}:${fixture.users.operationsManager.id}`,
|
|
fixture.locationStreamBatches.noShowSample.id,
|
|
fixture.users.operationsManager.id,
|
|
]
|
|
);
|
|
|
|
await client.query('COMMIT');
|
|
|
|
// eslint-disable-next-line no-console
|
|
console.log(JSON.stringify({
|
|
tenantId: fixture.tenant.id,
|
|
businessId: fixture.business.id,
|
|
vendorId: fixture.vendor.id,
|
|
staffId: fixture.staff.ana.id,
|
|
staffUserId: fixture.users.staffAna.id,
|
|
workforceId: fixture.workforce.ana.id,
|
|
openOrderId: fixture.orders.open.id,
|
|
openShiftId: fixture.shifts.open.id,
|
|
openShiftRoleId: fixture.shiftRoles.openBarista.id,
|
|
openApplicationId: fixture.applications.openAna.id,
|
|
completedOrderId: fixture.orders.completed.id,
|
|
completedAssignmentId: fixture.assignments.completedAna.id,
|
|
clockPointId: fixture.clockPoint.id,
|
|
nfcTagUid: fixture.clockPoint.nfcTagUid,
|
|
businessOwnerUid: fixture.users.businessOwner.id,
|
|
}, null, 2));
|
|
} catch (error) {
|
|
await client.query('ROLLBACK');
|
|
throw error;
|
|
} finally {
|
|
client.release();
|
|
await pool.end();
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
// eslint-disable-next-line no-console
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|