- Introduced `FieldModule` to manage cycles and plans, including read and write controllers. - Created database migrations for `company_settings`, `cycles`, `cycle_weekdays`, `cycle_destinations`, `plans`, `plan_destinations`, `plan_invoices`, and `plan_packing_slips` tables, including constraints and unique indexes. - Developed service and repository layers for handling cycle and plan data operations. - Added unit tests for the cycles and plans services, repositories, and controllers to ensure functionality and correctness. - Updated application module to include the new `FieldModule` for better organization.
84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
import { sql } from 'drizzle-orm';
|
|
import {
|
|
index,
|
|
integer,
|
|
jsonb,
|
|
pgTable,
|
|
text,
|
|
uniqueIndex,
|
|
uuid,
|
|
} from 'drizzle-orm/pg-core';
|
|
import { branches } from './branches-table';
|
|
import { customers } from './customers-table';
|
|
import { employees } from './employees-table';
|
|
import { primaryEntityColumns } from './primary-entity-columns';
|
|
import { users } from './schema';
|
|
|
|
export type StoredRouteGeometry = {
|
|
readonly type: 'LineString';
|
|
readonly coordinates: readonly (readonly [number, number])[];
|
|
};
|
|
|
|
export const cycles = pgTable(
|
|
'cycles',
|
|
{
|
|
id: uuid('id').defaultRandom().notNull().primaryKey(),
|
|
employeeId: uuid('employee_id')
|
|
.notNull()
|
|
.references(() => employees.id, { onDelete: 'restrict' }),
|
|
purpose: text('purpose').notNull(),
|
|
cycleNumber: integer('cycle_number').notNull(),
|
|
...primaryEntityColumns(users),
|
|
},
|
|
(t) => [
|
|
uniqueIndex('cycles_employee_purpose_number_live_unique')
|
|
.on(t.employeeId, t.purpose, t.cycleNumber)
|
|
.where(sql`${t.status} <> 'archived'`),
|
|
index('cycles_employee_id_idx').on(t.employeeId),
|
|
],
|
|
);
|
|
|
|
export const cycleWeekdays = pgTable(
|
|
'cycle_weekdays',
|
|
{
|
|
id: uuid('id').defaultRandom().notNull().primaryKey(),
|
|
cycleId: uuid('cycle_id')
|
|
.notNull()
|
|
.references(() => cycles.id, { onDelete: 'cascade' }),
|
|
weekday: text('weekday').notNull(),
|
|
startBranchId: uuid('start_branch_id')
|
|
.notNull()
|
|
.references(() => branches.id, { onDelete: 'restrict' }),
|
|
endBranchId: uuid('end_branch_id')
|
|
.notNull()
|
|
.references(() => branches.id, { onDelete: 'restrict' }),
|
|
routeGeometry: jsonb('route_geometry')
|
|
.$type<StoredRouteGeometry>()
|
|
.notNull(),
|
|
},
|
|
(t) => [
|
|
uniqueIndex('cycle_weekdays_cycle_weekday_unique').on(t.cycleId, t.weekday),
|
|
index('cycle_weekdays_cycle_id_idx').on(t.cycleId),
|
|
],
|
|
);
|
|
|
|
export const cycleDestinations = pgTable(
|
|
'cycle_destinations',
|
|
{
|
|
id: uuid('id').defaultRandom().notNull().primaryKey(),
|
|
cycleWeekdayId: uuid('cycle_weekday_id')
|
|
.notNull()
|
|
.references(() => cycleWeekdays.id, { onDelete: 'cascade' }),
|
|
customerId: uuid('customer_id')
|
|
.notNull()
|
|
.references(() => customers.id, { onDelete: 'restrict' }),
|
|
sortOrder: integer('sort_order').notNull(),
|
|
},
|
|
(t) => [index('cycle_destinations_weekday_id_idx').on(t.cycleWeekdayId)],
|
|
);
|
|
|
|
export type CycleRow = typeof cycles.$inferSelect;
|
|
export type NewCycleRow = typeof cycles.$inferInsert;
|
|
export type CycleWeekdayRow = typeof cycleWeekdays.$inferSelect;
|
|
export type CycleDestinationRow = typeof cycleDestinations.$inferSelect;
|