Acert script on database

This commit is contained in:
Rayan Konecny 2026-05-05 12:53:41 -03:00
parent 92aa1cb2bb
commit d508e27bac
27 changed files with 1136 additions and 139 deletions

View file

@ -17,7 +17,19 @@
"Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); print\\('Scripts:', d.get\\('scripts',{}\\)\\); print\\('Deps:', list\\(d.get\\('dependencies',{}\\).keys\\(\\)\\)\\)\")",
"Bash(podman-compose down *)",
"Bash(podman-compose up *)",
"Bash(podman logs *)"
"Bash(podman logs *)",
"Bash(apt-cache show *)",
"Bash(dpkg -l)",
"Bash(REACT_NATIVE_DEVTOOLS=false npx expo start)",
"Bash(REACT_NATIVE_DEVTOOLS=false npx expo start --port 8082)",
"Read(//home/dev/.cache/dotslash/cb/2a59c5919ce27ef30b55119edf89e556e015ef/React Native DevTools-linux-x64/**)",
"Bash(perl -i -0pe 's/ try \\\\{/ try {\\\\n const db = await dbPromise;/g' /home/dev/projetos/toptran/toptran-app/src/services/db.ts)",
"Bash(python3 -c \"import reportlab\")",
"Bash(python3 -c \"import weasyprint\")",
"Read(//usr/bin/**)",
"Bash(chromium --headless --disable-gpu --no-sandbox --print-to-pdf=proposta-toptran.pdf --no-pdf-header-footer file:///home/dev/projetos/toptran/proposta-toptran.html)",
"Bash(npx tsc *)",
"Bash(echo \"exit=$?\")"
]
}
}

152
README.md
View file

@ -100,17 +100,20 @@ model companies {
}
model rides {
id String @id
user_id String
company String
km Decimal @db.Decimal(10, 2)
cost_per_km Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
ride_date String
synced Int? @default(0) @db.SmallInt
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade)
id String @id
user_id String
company String
km Decimal @db.Decimal(10, 2)
cost_per_km Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
ride_date String
departures Int? @default(0)
failed_service Int? @default(0)
idle_hours Decimal? @default(0) @db.Decimal(10, 2)
synced Int? @default(0) @db.SmallInt
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade)
}
enum TokenType {
@ -120,21 +123,32 @@ enum TokenType {
### Variáveis de ambiente
Crie o arquivo `backend/.env` com as variáveis abaixo:
O backend trabalha com **dois bancos** — um de homologação (`toptrandev`) e um de produção (`toptranprod`) — e dois arquivos `.env` separados:
| Arquivo | Banco | Porta |
|---|---|---|
| `backend/.env.development` | `toptrandev` | `4000` |
| `backend/.env.production` | `toptranprod` | `5000` |
Modelo do `.env.development`:
```env
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DATABASE_URL=postgresql://USER:PASS@HOST:5432/toptrandev
DB_USER=...
DB_PASSWORD=...
DB_HOST=...
DB_PORT=5432
DB_NAME=toptran
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/toptran"
DB_NAME=toptrandev
PORT=4000
JWT_SECRET=sua_chave_secreta_aqui
NODE_ENV=development
JWT_SECRET=...
JWT_REFRESH_SECRET=...
```
Modelo do `.env.production`: idêntico, trocando `DB_NAME=toptranprod`, `PORT=5000` e `NODE_ENV=production`.
> `JWT_SECRET` é obrigatório em produção. O access token expira em **15 minutos** e o refresh token em **7 dias**.
### Instalação e execução
@ -148,15 +162,28 @@ npm install
# Gerar cliente Prisma
npx prisma generate
# Rodar migrations
npx prisma migrate deploy
# Iniciar em modo desenvolvimento
# Rodar a API apontando pro banco de homologação (toptrandev)
npm run dev
# Build de produção
# Rodar a API apontando pro banco de produção (toptranprod)
npm run dev:prod
# Build + start em produção
npm run build
npm start
npm start # usa .env.production por padrão
npm run start:dev # caso queira o build rodando contra o banco de dev
```
**Migrations e Prisma CLI por ambiente** (via `dotenv-cli`):
```bash
# Homologação
npm run prisma:dev migrate dev
npm run prisma:dev studio
# Produção
npm run prisma:prod migrate deploy
npm run prisma:prod studio
```
### API Reference
@ -365,7 +392,19 @@ Retorna todas as corridas cadastradas no servidor.
{
"success": true,
"data": [
{ "id": "uuid", "user_id": "uuid", "company": "Empresa X", "km": "12.5", "total": "31.25", ... }
{
"id": "uuid",
"user_id": "uuid",
"company": "Empresa X",
"km": "12.5",
"cost_per_km": "2.50",
"total": "31.25",
"ride_date": "2026-05-01",
"departures": 3,
"failed_service": 1,
"idle_hours": "1.50",
"synced": 1
}
]
}
```
@ -374,13 +413,24 @@ Retorna todas as corridas cadastradas no servidor.
**POST `/sync/rides`**
Sincroniza (upsert) uma lista de corridas no servidor.
Sincroniza (upsert) uma lista de corridas no servidor. Os campos `departures`, `failed_service` e `idle_hours` são opcionais e assumem `0` por padrão.
```json
// Request body
{
"rides": [
{ "id": "uuid", "user_id": "uuid", "company": "Empresa X", "km": 12.5, "cost_per_km": 2.50, "total": 31.25, "ride_date": "2026-05-01" }
{
"id": "uuid",
"user_id": "uuid",
"company": "Empresa X",
"km": 12.5,
"cost_per_km": 2.50,
"total": 31.25,
"ride_date": "2026-05-01",
"departures": 3,
"failed_service": 1,
"idle_hours": 1.5
}
]
}
@ -392,6 +442,22 @@ Sincroniza (upsert) uma lista de corridas no servidor.
}
```
**Campos da corrida:**
| Campo | Tipo | Descrição |
|---|---|---|
| `id` | string | Identificador único da corrida |
| `user_id` | string | ID do usuário dono da corrida |
| `company` | string | Nome da empresa |
| `km` | number\|string | Quilômetros rodados |
| `cost_per_km` | number\|string | Custo por km no momento da corrida |
| `total` | number\|string | Valor total da corrida |
| `ride_date` | string | Data da corrida (formato `YYYY-MM-DD`) |
| `departures` | number? | Quantidade de partidas/saídas (default `0`) |
| `failed_service` | number? | Quantidade de serviços não realizados (default `0`) |
| `idle_hours` | number\|string? | Horas ociosas, com 2 casas decimais (default `0`) |
| `synced` | number? | Flag de sincronização (`0` ou `1`) |
---
#### Respostas de erro
@ -507,6 +573,34 @@ A tela `/sincronizar` executa três etapas em sequência com feedback visual em
2. **Download de empresas** — baixa empresas do servidor se o cadastro local estiver vazio
3. **Upload de corridas** — compara IDs locais com os do servidor e envia apenas as corridas ausentes via `POST /sync/rides`
### Ambientes (dev / prod)
O app não conversa direto com o PostgreSQL — ele consome a API do backend. Alternar de banco no app significa apontar pra um backend diferente via `EXPO_PUBLIC_API_URL`.
| Arquivo | API | Banco |
|---|---|---|
| `toptran-app/.env.development` | `http://175.15.15.93:4000/api` | `toptrandev` |
| `toptran-app/.env.production` | `https://toptran.olymp.com.br/api` | `toptranprod` |
O Expo carrega o arquivo certo automaticamente conforme o modo:
| Comando | Arquivo carregado |
|---|---|
| `npx expo start` (dev) | `.env.development` |
| `npx expo export` / EAS Build production | `.env.production` |
> Variáveis `EXPO_PUBLIC_*` são inlined no bundle em build time. Reinicie sempre com `npx expo start -c` após trocar o `.env`.
#### Perfis EAS
Configurados em [`toptran-app/eas.json`](toptran-app/eas.json):
| Perfil | Formato | API/Banco | Comando | Pra quê serve |
|---|---|---|---|---|
| `development` | APK + dev client | dev (`:4000``toptrandev`) | `eas build --profile development` | Rodar com `expo start` plugado, hot reload |
| `preview` | APK standalone | prod (`toptranprod`) | `eas build --profile preview` | APK pra testar/distribuir fora da Play |
| `production` | AAB | prod (`toptranprod`) | `eas build --profile production` | Bundle pra Google Play (`eas submit`) |
### Execução
```bash
@ -515,7 +609,7 @@ cd toptran-app
# Instalar dependências
npm install
# Iniciar o servidor Expo
# Iniciar o servidor Expo (carrega .env.development → backend dev)
npm start
# Build e abrir no Android

11
backend/[teste.env] Normal file
View file

@ -0,0 +1,11 @@
DB_USER=toptranadm
DB_PASSWORD=ft7zJdVNk8FivQUk
DB_HOST=175.15.15.90
DB_PORT=5432
DB_NAME=toptrandev
DATABASE_URL="postgresql://toptranadm:ft7zJdVNk8FivQUk@175.15.15.90:5432/toptrandev"
PORT=4000
JWT_SECRET=iDgji2sbBKqmPerRHnQXFK0iHwmfNTNb5zreuetUecD

View file

@ -26,6 +26,7 @@
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^25.6.0",
"dotenv": "^17.4.2",
"dotenv-cli": "^11.0.0",
"prisma": "^7.8.0",
"ts-node-dev": "^2.0.0",
"tsx": "^4.21.0"
@ -1627,6 +1628,51 @@
"url": "https://dotenvx.com"
}
},
"node_modules/dotenv-cli": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-11.0.0.tgz",
"integrity": "sha512-r5pA8idbk7GFWuHEU7trSTflWcdBpQEK+Aw17UrSHjS6CReuhrrPcyC3zcQBPQvhArRHnBo/h6eLH1fkCvNlww==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.6",
"dotenv": "^17.1.0",
"dotenv-expand": "^12.0.0",
"minimist": "^1.2.6"
},
"bin": {
"dotenv": "cli.js"
}
},
"node_modules/dotenv-expand": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz",
"integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"dotenv": "^16.4.5"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dotenv-expand/node_modules/dotenv": {
"version": "16.6.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",

View file

@ -4,10 +4,14 @@
"description": "",
"main": "index.js",
"scripts": {
"dev": "tsx watch src/server.ts",
"dev": "tsx watch --env-file=.env.development src/server.ts",
"dev:prod": "tsx watch --env-file=.env.production src/server.ts",
"build": "tsc",
"start": "node dist/server.js",
"typecheck": "tsc --noEmit"
"start": "node --env-file=.env.production dist/server.js",
"start:dev": "node --env-file=.env.development dist/server.js",
"typecheck": "tsc --noEmit",
"prisma:dev": "dotenv -e env.development -- prisma migrate dev",
"prisma:prod": "dotenv -e env.production -- prisma migrate deploy"
},
"keywords": [],
"author": "Rayan",
@ -20,6 +24,7 @@
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^25.6.0",
"dotenv": "^17.4.2",
"dotenv-cli": "^11.0.0",
"prisma": "^7.8.0",
"ts-node-dev": "^2.0.0",
"tsx": "^4.21.0"

View file

@ -33,28 +33,34 @@ model users {
}
model companies {
id String @id
name String
cost_per_km Decimal @db.Decimal(10, 2)
notes String? @default("")
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
id String @id
name String
cost_per_km Decimal @db.Decimal(10, 2)
departures Int? @default(0)
failed_service Int? @default(0)
idle_hours Decimal @default(0.0) @db.Decimal(10, 2)
notes String? @default("")
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
@@index([name], map: "idx_companies_name")
}
model rides {
id String @id
user_id String
company String
km Decimal @db.Decimal(10, 2)
cost_per_km Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
ride_date String
synced Int? @default(0) @db.SmallInt
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
id String @id
user_id String
company String
km Decimal @db.Decimal(10, 2)
cost_per_km Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2)
ride_date String
departures Int? @default(0)
failed_service Int? @default(0)
idle_hours Decimal? @default(0) @db.Decimal(10, 2)
synced Int? @default(0) @db.SmallInt
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @default(now()) @db.Timestamptz(6)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
@@index([synced], map: "idx_rides_synced")
@@index([user_id], map: "idx_rides_user_id")

View file

@ -138,6 +138,17 @@ export type DecimalFilter<$PrismaModel = never> = {
not?: Prisma.NestedDecimalFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type IntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type DateTimeNullableFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
@ -165,31 +176,6 @@ export type DecimalWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDecimalFilter<$PrismaModel>
}
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type IntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type IntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
@ -206,6 +192,47 @@ export type IntNullableWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedIntNullableFilter<$PrismaModel>
}
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type DecimalNullableFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
}
export type DecimalNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_min?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_max?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
}
export type NestedStringFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
@ -370,20 +397,6 @@ export type NestedDecimalWithAggregatesFilter<$PrismaModel = never> = {
_max?: Prisma.NestedDecimalFilter<$PrismaModel>
}
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type NestedIntNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
@ -411,4 +424,45 @@ export type NestedFloatNullableFilter<$PrismaModel = never> = {
not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null
}
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type NestedDecimalNullableFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
}
export type NestedDecimalNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null
in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null
lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel>
not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_min?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
_max?: Prisma.NestedDecimalNullableFilter<$PrismaModel>
}

File diff suppressed because one or more lines are too long

View file

@ -772,6 +772,9 @@ export const CompaniesScalarFieldEnum = {
id: 'id',
name: 'name',
cost_per_km: 'cost_per_km',
departures: 'departures',
failed_service: 'failed_service',
idle_hours: 'idle_hours',
notes: 'notes',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
@ -788,6 +791,9 @@ export const RidesScalarFieldEnum = {
cost_per_km: 'cost_per_km',
total: 'total',
ride_date: 'ride_date',
departures: 'departures',
failed_service: 'failed_service',
idle_hours: 'idle_hours',
synced: 'synced',
createdAt: 'createdAt',
updatedAt: 'updatedAt'

View file

@ -103,6 +103,9 @@ export const CompaniesScalarFieldEnum = {
id: 'id',
name: 'name',
cost_per_km: 'cost_per_km',
departures: 'departures',
failed_service: 'failed_service',
idle_hours: 'idle_hours',
notes: 'notes',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
@ -119,6 +122,9 @@ export const RidesScalarFieldEnum = {
cost_per_km: 'cost_per_km',
total: 'total',
ride_date: 'ride_date',
departures: 'departures',
failed_service: 'failed_service',
idle_hours: 'idle_hours',
synced: 'synced',
createdAt: 'createdAt',
updatedAt: 'updatedAt'

View file

@ -28,16 +28,25 @@ export type AggregateCompanies = {
export type CompaniesAvgAggregateOutputType = {
cost_per_km: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
}
export type CompaniesSumAggregateOutputType = {
cost_per_km: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
}
export type CompaniesMinAggregateOutputType = {
id: string | null
name: string | null
cost_per_km: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
notes: string | null
createdAt: Date | null
updatedAt: Date | null
@ -47,6 +56,9 @@ export type CompaniesMaxAggregateOutputType = {
id: string | null
name: string | null
cost_per_km: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
notes: string | null
createdAt: Date | null
updatedAt: Date | null
@ -56,6 +68,9 @@ export type CompaniesCountAggregateOutputType = {
id: number
name: number
cost_per_km: number
departures: number
failed_service: number
idle_hours: number
notes: number
createdAt: number
updatedAt: number
@ -65,16 +80,25 @@ export type CompaniesCountAggregateOutputType = {
export type CompaniesAvgAggregateInputType = {
cost_per_km?: true
departures?: true
failed_service?: true
idle_hours?: true
}
export type CompaniesSumAggregateInputType = {
cost_per_km?: true
departures?: true
failed_service?: true
idle_hours?: true
}
export type CompaniesMinAggregateInputType = {
id?: true
name?: true
cost_per_km?: true
departures?: true
failed_service?: true
idle_hours?: true
notes?: true
createdAt?: true
updatedAt?: true
@ -84,6 +108,9 @@ export type CompaniesMaxAggregateInputType = {
id?: true
name?: true
cost_per_km?: true
departures?: true
failed_service?: true
idle_hours?: true
notes?: true
createdAt?: true
updatedAt?: true
@ -93,6 +120,9 @@ export type CompaniesCountAggregateInputType = {
id?: true
name?: true
cost_per_km?: true
departures?: true
failed_service?: true
idle_hours?: true
notes?: true
createdAt?: true
updatedAt?: true
@ -189,6 +219,9 @@ export type CompaniesGroupByOutputType = {
id: string
name: string
cost_per_km: runtime.Decimal
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal
notes: string | null
createdAt: Date | null
updatedAt: Date | null
@ -221,6 +254,9 @@ export type companiesWhereInput = {
id?: Prisma.StringFilter<"companies"> | string
name?: Prisma.StringFilter<"companies"> | string
cost_per_km?: Prisma.DecimalFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.IntNullableFilter<"companies"> | number | null
failed_service?: Prisma.IntNullableFilter<"companies"> | number | null
idle_hours?: Prisma.DecimalFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.StringNullableFilter<"companies"> | string | null
createdAt?: Prisma.DateTimeNullableFilter<"companies"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableFilter<"companies"> | Date | string | null
@ -230,6 +266,9 @@ export type companiesOrderByWithRelationInput = {
id?: Prisma.SortOrder
name?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrderInput | Prisma.SortOrder
failed_service?: Prisma.SortOrderInput | Prisma.SortOrder
idle_hours?: Prisma.SortOrder
notes?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrderInput | Prisma.SortOrder
updatedAt?: Prisma.SortOrderInput | Prisma.SortOrder
@ -242,6 +281,9 @@ export type companiesWhereUniqueInput = Prisma.AtLeast<{
NOT?: Prisma.companiesWhereInput | Prisma.companiesWhereInput[]
name?: Prisma.StringFilter<"companies"> | string
cost_per_km?: Prisma.DecimalFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.IntNullableFilter<"companies"> | number | null
failed_service?: Prisma.IntNullableFilter<"companies"> | number | null
idle_hours?: Prisma.DecimalFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.StringNullableFilter<"companies"> | string | null
createdAt?: Prisma.DateTimeNullableFilter<"companies"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableFilter<"companies"> | Date | string | null
@ -251,6 +293,9 @@ export type companiesOrderByWithAggregationInput = {
id?: Prisma.SortOrder
name?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrderInput | Prisma.SortOrder
failed_service?: Prisma.SortOrderInput | Prisma.SortOrder
idle_hours?: Prisma.SortOrder
notes?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrderInput | Prisma.SortOrder
updatedAt?: Prisma.SortOrderInput | Prisma.SortOrder
@ -268,6 +313,9 @@ export type companiesScalarWhereWithAggregatesInput = {
id?: Prisma.StringWithAggregatesFilter<"companies"> | string
name?: Prisma.StringWithAggregatesFilter<"companies"> | string
cost_per_km?: Prisma.DecimalWithAggregatesFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.IntNullableWithAggregatesFilter<"companies"> | number | null
failed_service?: Prisma.IntNullableWithAggregatesFilter<"companies"> | number | null
idle_hours?: Prisma.DecimalWithAggregatesFilter<"companies"> | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.StringNullableWithAggregatesFilter<"companies"> | string | null
createdAt?: Prisma.DateTimeNullableWithAggregatesFilter<"companies"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"companies"> | Date | string | null
@ -277,6 +325,9 @@ export type companiesCreateInput = {
id: string
name: string
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: string | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -286,6 +337,9 @@ export type companiesUncheckedCreateInput = {
id: string
name: string
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: string | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -295,6 +349,9 @@ export type companiesUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -304,6 +361,9 @@ export type companiesUncheckedUpdateInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -313,6 +373,9 @@ export type companiesCreateManyInput = {
id: string
name: string
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: string | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -322,6 +385,9 @@ export type companiesUpdateManyMutationInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -331,6 +397,9 @@ export type companiesUncheckedUpdateManyInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
notes?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -340,6 +409,9 @@ export type companiesCountOrderByAggregateInput = {
id?: Prisma.SortOrder
name?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
notes?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -347,12 +419,18 @@ export type companiesCountOrderByAggregateInput = {
export type companiesAvgOrderByAggregateInput = {
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
}
export type companiesMaxOrderByAggregateInput = {
id?: Prisma.SortOrder
name?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
notes?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -362,6 +440,9 @@ export type companiesMinOrderByAggregateInput = {
id?: Prisma.SortOrder
name?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
notes?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -369,6 +450,9 @@ export type companiesMinOrderByAggregateInput = {
export type companiesSumOrderByAggregateInput = {
cost_per_km?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
}
export type DecimalFieldUpdateOperationsInput = {
@ -379,6 +463,14 @@ export type DecimalFieldUpdateOperationsInput = {
divide?: runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type NullableIntFieldUpdateOperationsInput = {
set?: number | null
increment?: number
decrement?: number
multiply?: number
divide?: number
}
export type NullableDateTimeFieldUpdateOperationsInput = {
set?: Date | string | null
}
@ -389,6 +481,9 @@ export type companiesSelect<ExtArgs extends runtime.Types.Extensions.InternalArg
id?: boolean
name?: boolean
cost_per_km?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
notes?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -398,6 +493,9 @@ export type companiesSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Ext
id?: boolean
name?: boolean
cost_per_km?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
notes?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -407,6 +505,9 @@ export type companiesSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Ext
id?: boolean
name?: boolean
cost_per_km?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
notes?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -416,12 +517,15 @@ export type companiesSelectScalar = {
id?: boolean
name?: boolean
cost_per_km?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
notes?: boolean
createdAt?: boolean
updatedAt?: boolean
}
export type companiesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "cost_per_km" | "notes" | "createdAt" | "updatedAt", ExtArgs["result"]["companies"]>
export type companiesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "name" | "cost_per_km" | "departures" | "failed_service" | "idle_hours" | "notes" | "createdAt" | "updatedAt", ExtArgs["result"]["companies"]>
export type $companiesPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
name: "companies"
@ -430,6 +534,9 @@ export type $companiesPayload<ExtArgs extends runtime.Types.Extensions.InternalA
id: string
name: string
cost_per_km: runtime.Decimal
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal
notes: string | null
createdAt: Date | null
updatedAt: Date | null
@ -859,6 +966,9 @@ export interface companiesFieldRefs {
readonly id: Prisma.FieldRef<"companies", 'String'>
readonly name: Prisma.FieldRef<"companies", 'String'>
readonly cost_per_km: Prisma.FieldRef<"companies", 'Decimal'>
readonly departures: Prisma.FieldRef<"companies", 'Int'>
readonly failed_service: Prisma.FieldRef<"companies", 'Int'>
readonly idle_hours: Prisma.FieldRef<"companies", 'Decimal'>
readonly notes: Prisma.FieldRef<"companies", 'String'>
readonly createdAt: Prisma.FieldRef<"companies", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"companies", 'DateTime'>

View file

@ -30,6 +30,9 @@ export type RidesAvgAggregateOutputType = {
km: runtime.Decimal | null
cost_per_km: runtime.Decimal | null
total: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
}
@ -37,6 +40,9 @@ export type RidesSumAggregateOutputType = {
km: runtime.Decimal | null
cost_per_km: runtime.Decimal | null
total: runtime.Decimal | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
}
@ -48,6 +54,9 @@ export type RidesMinAggregateOutputType = {
cost_per_km: runtime.Decimal | null
total: runtime.Decimal | null
ride_date: string | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
createdAt: Date | null
updatedAt: Date | null
@ -61,6 +70,9 @@ export type RidesMaxAggregateOutputType = {
cost_per_km: runtime.Decimal | null
total: runtime.Decimal | null
ride_date: string | null
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
createdAt: Date | null
updatedAt: Date | null
@ -74,6 +86,9 @@ export type RidesCountAggregateOutputType = {
cost_per_km: number
total: number
ride_date: number
departures: number
failed_service: number
idle_hours: number
synced: number
createdAt: number
updatedAt: number
@ -85,6 +100,9 @@ export type RidesAvgAggregateInputType = {
km?: true
cost_per_km?: true
total?: true
departures?: true
failed_service?: true
idle_hours?: true
synced?: true
}
@ -92,6 +110,9 @@ export type RidesSumAggregateInputType = {
km?: true
cost_per_km?: true
total?: true
departures?: true
failed_service?: true
idle_hours?: true
synced?: true
}
@ -103,6 +124,9 @@ export type RidesMinAggregateInputType = {
cost_per_km?: true
total?: true
ride_date?: true
departures?: true
failed_service?: true
idle_hours?: true
synced?: true
createdAt?: true
updatedAt?: true
@ -116,6 +140,9 @@ export type RidesMaxAggregateInputType = {
cost_per_km?: true
total?: true
ride_date?: true
departures?: true
failed_service?: true
idle_hours?: true
synced?: true
createdAt?: true
updatedAt?: true
@ -129,6 +156,9 @@ export type RidesCountAggregateInputType = {
cost_per_km?: true
total?: true
ride_date?: true
departures?: true
failed_service?: true
idle_hours?: true
synced?: true
createdAt?: true
updatedAt?: true
@ -229,6 +259,9 @@ export type RidesGroupByOutputType = {
cost_per_km: runtime.Decimal
total: runtime.Decimal
ride_date: string
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
createdAt: Date | null
updatedAt: Date | null
@ -265,6 +298,9 @@ export type ridesWhereInput = {
cost_per_km?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFilter<"rides"> | string
departures?: Prisma.IntNullableFilter<"rides"> | number | null
failed_service?: Prisma.IntNullableFilter<"rides"> | number | null
idle_hours?: Prisma.DecimalNullableFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.IntNullableFilter<"rides"> | number | null
createdAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
@ -279,6 +315,9 @@ export type ridesOrderByWithRelationInput = {
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
ride_date?: Prisma.SortOrder
departures?: Prisma.SortOrderInput | Prisma.SortOrder
failed_service?: Prisma.SortOrderInput | Prisma.SortOrder
idle_hours?: Prisma.SortOrderInput | Prisma.SortOrder
synced?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrderInput | Prisma.SortOrder
updatedAt?: Prisma.SortOrderInput | Prisma.SortOrder
@ -296,6 +335,9 @@ export type ridesWhereUniqueInput = Prisma.AtLeast<{
cost_per_km?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFilter<"rides"> | string
departures?: Prisma.IntNullableFilter<"rides"> | number | null
failed_service?: Prisma.IntNullableFilter<"rides"> | number | null
idle_hours?: Prisma.DecimalNullableFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.IntNullableFilter<"rides"> | number | null
createdAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
@ -310,6 +352,9 @@ export type ridesOrderByWithAggregationInput = {
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
ride_date?: Prisma.SortOrder
departures?: Prisma.SortOrderInput | Prisma.SortOrder
failed_service?: Prisma.SortOrderInput | Prisma.SortOrder
idle_hours?: Prisma.SortOrderInput | Prisma.SortOrder
synced?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrderInput | Prisma.SortOrder
updatedAt?: Prisma.SortOrderInput | Prisma.SortOrder
@ -331,6 +376,9 @@ export type ridesScalarWhereWithAggregatesInput = {
cost_per_km?: Prisma.DecimalWithAggregatesFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalWithAggregatesFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringWithAggregatesFilter<"rides"> | string
departures?: Prisma.IntNullableWithAggregatesFilter<"rides"> | number | null
failed_service?: Prisma.IntNullableWithAggregatesFilter<"rides"> | number | null
idle_hours?: Prisma.DecimalNullableWithAggregatesFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.IntNullableWithAggregatesFilter<"rides"> | number | null
createdAt?: Prisma.DateTimeNullableWithAggregatesFilter<"rides"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"rides"> | Date | string | null
@ -343,6 +391,9 @@ export type ridesCreateInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -357,6 +408,9 @@ export type ridesUncheckedCreateInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -369,6 +423,9 @@ export type ridesUpdateInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -383,6 +440,9 @@ export type ridesUncheckedUpdateInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -396,6 +456,9 @@ export type ridesCreateManyInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -408,6 +471,9 @@ export type ridesUpdateManyMutationInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -421,6 +487,9 @@ export type ridesUncheckedUpdateManyInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -444,6 +513,9 @@ export type ridesCountOrderByAggregateInput = {
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
ride_date?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
synced?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -453,6 +525,9 @@ export type ridesAvgOrderByAggregateInput = {
km?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
synced?: Prisma.SortOrder
}
@ -464,6 +539,9 @@ export type ridesMaxOrderByAggregateInput = {
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
ride_date?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
synced?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -477,6 +555,9 @@ export type ridesMinOrderByAggregateInput = {
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
ride_date?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
synced?: Prisma.SortOrder
createdAt?: Prisma.SortOrder
updatedAt?: Prisma.SortOrder
@ -486,6 +567,9 @@ export type ridesSumOrderByAggregateInput = {
km?: Prisma.SortOrder
cost_per_km?: Prisma.SortOrder
total?: Prisma.SortOrder
departures?: Prisma.SortOrder
failed_service?: Prisma.SortOrder
idle_hours?: Prisma.SortOrder
synced?: Prisma.SortOrder
}
@ -531,12 +615,12 @@ export type ridesUncheckedUpdateManyWithoutUsersNestedInput = {
deleteMany?: Prisma.ridesScalarWhereInput | Prisma.ridesScalarWhereInput[]
}
export type NullableIntFieldUpdateOperationsInput = {
set?: number | null
increment?: number
decrement?: number
multiply?: number
divide?: number
export type NullableDecimalFieldUpdateOperationsInput = {
set?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
increment?: runtime.Decimal | runtime.DecimalJsLike | number | string
decrement?: runtime.Decimal | runtime.DecimalJsLike | number | string
multiply?: runtime.Decimal | runtime.DecimalJsLike | number | string
divide?: runtime.Decimal | runtime.DecimalJsLike | number | string
}
export type ridesCreateWithoutUsersInput = {
@ -546,6 +630,9 @@ export type ridesCreateWithoutUsersInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -558,6 +645,9 @@ export type ridesUncheckedCreateWithoutUsersInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -600,6 +690,9 @@ export type ridesScalarWhereInput = {
cost_per_km?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFilter<"rides"> | string
departures?: Prisma.IntNullableFilter<"rides"> | number | null
failed_service?: Prisma.IntNullableFilter<"rides"> | number | null
idle_hours?: Prisma.DecimalNullableFilter<"rides"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.IntNullableFilter<"rides"> | number | null
createdAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
updatedAt?: Prisma.DateTimeNullableFilter<"rides"> | Date | string | null
@ -612,6 +705,9 @@ export type ridesCreateManyUsersInput = {
cost_per_km: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date: string
departures?: number | null
failed_service?: number | null
idle_hours?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: number | null
createdAt?: Date | string | null
updatedAt?: Date | string | null
@ -624,6 +720,9 @@ export type ridesUpdateWithoutUsersInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -636,6 +735,9 @@ export type ridesUncheckedUpdateWithoutUsersInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -648,6 +750,9 @@ export type ridesUncheckedUpdateManyWithoutUsersInput = {
cost_per_km?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
ride_date?: Prisma.StringFieldUpdateOperationsInput | string
departures?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
failed_service?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
idle_hours?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
synced?: Prisma.NullableIntFieldUpdateOperationsInput | number | null
createdAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
updatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
@ -663,6 +768,9 @@ export type ridesSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs =
cost_per_km?: boolean
total?: boolean
ride_date?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
synced?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -677,6 +785,9 @@ export type ridesSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extensi
cost_per_km?: boolean
total?: boolean
ride_date?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
synced?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -691,6 +802,9 @@ export type ridesSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extensi
cost_per_km?: boolean
total?: boolean
ride_date?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
synced?: boolean
createdAt?: boolean
updatedAt?: boolean
@ -705,12 +819,15 @@ export type ridesSelectScalar = {
cost_per_km?: boolean
total?: boolean
ride_date?: boolean
departures?: boolean
failed_service?: boolean
idle_hours?: boolean
synced?: boolean
createdAt?: boolean
updatedAt?: boolean
}
export type ridesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "user_id" | "company" | "km" | "cost_per_km" | "total" | "ride_date" | "synced" | "createdAt" | "updatedAt", ExtArgs["result"]["rides"]>
export type ridesOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "user_id" | "company" | "km" | "cost_per_km" | "total" | "ride_date" | "departures" | "failed_service" | "idle_hours" | "synced" | "createdAt" | "updatedAt", ExtArgs["result"]["rides"]>
export type ridesInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
users?: boolean | Prisma.usersDefaultArgs<ExtArgs>
}
@ -734,6 +851,9 @@ export type $ridesPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs
cost_per_km: runtime.Decimal
total: runtime.Decimal
ride_date: string
departures: number | null
failed_service: number | null
idle_hours: runtime.Decimal | null
synced: number | null
createdAt: Date | null
updatedAt: Date | null
@ -1168,6 +1288,9 @@ export interface ridesFieldRefs {
readonly cost_per_km: Prisma.FieldRef<"rides", 'Decimal'>
readonly total: Prisma.FieldRef<"rides", 'Decimal'>
readonly ride_date: Prisma.FieldRef<"rides", 'String'>
readonly departures: Prisma.FieldRef<"rides", 'Int'>
readonly failed_service: Prisma.FieldRef<"rides", 'Int'>
readonly idle_hours: Prisma.FieldRef<"rides", 'Decimal'>
readonly synced: Prisma.FieldRef<"rides", 'Int'>
readonly createdAt: Prisma.FieldRef<"rides", 'DateTime'>
readonly updatedAt: Prisma.FieldRef<"rides", 'DateTime'>

View file

@ -8,6 +8,9 @@ export async function createCompany(data: {
id: string;
name: string;
cost_per_km: any;
departures?: number;
failed_service?: number;
idle_hours?: any;
notes?: string;
}) {
return prisma.companies.create({ data });
@ -18,6 +21,9 @@ export async function updateCompany(
data: Partial<{
name: string;
cost_per_km: any;
departures: number;
failed_service: number;
idle_hours: any;
notes: string;
}>
) {
@ -36,6 +42,9 @@ export async function upsertCompany(data: {
id: string;
name: string;
cost_per_km: any;
departures?: number;
failed_service?: number;
idle_hours?: any;
notes?: string;
}) {
return prisma.companies.upsert({
@ -43,6 +52,9 @@ export async function upsertCompany(data: {
update: {
name: data.name,
cost_per_km: data.cost_per_km,
departures: data.departures,
failed_service: data.failed_service,
idle_hours: data.idle_hours,
notes: data.notes,
},
create: data,

View file

@ -12,6 +12,9 @@ export async function createRide(data: {
cost_per_km: any;
total: any;
ride_date: string;
departures?: number;
failed_service?: number;
idle_hours?: any;
synced?: number;
}) {
return prisma.rides.create({ data });
@ -26,6 +29,9 @@ export async function updateRide(
cost_per_km: any;
total: any;
ride_date: string;
departures: number;
failed_service: number;
idle_hours: any;
synced: number;
}>
) {
@ -68,6 +74,9 @@ export async function upsertRide(data: {
cost_per_km: any;
total: any;
ride_date: string;
departures?: number;
failed_service?: number;
idle_hours?: any;
synced?: number;
}) {
return prisma.rides.upsert({
@ -79,6 +88,9 @@ export async function upsertRide(data: {
cost_per_km: data.cost_per_km,
total: data.total,
ride_date: data.ride_date,
departures: data.departures,
failed_service: data.failed_service,
idle_hours: data.idle_hours,
synced: data.synced,
},
create: data,

View file

@ -9,6 +9,9 @@ export const syncCompaniesSchema = z.object({
id: z.string(),
name: z.string(),
cost_per_km: z.number().or(z.string()),
departures: z.number().optional(),
failed_service: z.number().optional(),
idle_hours: z.number().or(z.string()).optional(),
notes: z.string().optional(),
})
),
@ -24,6 +27,9 @@ export const syncRidesSchema = z.object({
cost_per_km: z.number().or(z.string()),
total: z.number().or(z.string()),
ride_date: z.string(),
departures: z.number().optional(),
failed_service: z.number().optional(),
idle_hours: z.number().or(z.string()).optional(),
synced: z.number().optional(),
})
),
@ -38,6 +44,9 @@ export async function syncCompanies(
id: company.id,
name: company.name,
cost_per_km: company.cost_per_km,
departures: company.departures,
failed_service: company.failed_service,
idle_hours: company.idle_hours,
notes: company.notes,
});
synced.push(result);
@ -58,6 +67,9 @@ export async function syncRides(
cost_per_km: ride.cost_per_km,
total: ride.total,
ride_date: ride.ride_date,
departures: ride.departures,
failed_service: ride.failed_service,
idle_hours: ride.idle_hours,
synced: ride.synced,
});
synced.push(result);

280
proposta-toptran.html Normal file
View file

@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Proposta — TopTran</title>
<style>
@page {
size: A4;
margin: 18mm 16mm;
}
* { box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
color: #1a1a1a;
line-height: 1.5;
font-size: 10.5pt;
margin: 0;
}
header {
border-bottom: 3px solid #0a0a0a;
padding-bottom: 12px;
margin-bottom: 22px;
}
header h1 {
margin: 0 0 4px 0;
font-size: 22pt;
color: #0a0a0a;
}
header .subtitle {
color: #555;
font-size: 11pt;
}
header .meta {
margin-top: 8px;
font-size: 9pt;
color: #777;
}
h2 {
font-size: 13.5pt;
color: #0a0a0a;
border-bottom: 1px solid #ddd;
padding-bottom: 4px;
margin-top: 22px;
margin-bottom: 10px;
}
h3 {
font-size: 11.5pt;
color: #222;
margin-top: 14px;
margin-bottom: 6px;
}
p { margin: 6px 0; }
ul { margin: 6px 0; padding-left: 22px; }
li { margin: 3px 0; }
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
font-size: 10pt;
}
th, td {
text-align: left;
padding: 7px 10px;
border-bottom: 1px solid #e3e3e3;
}
th {
background-color: #f4f4f4;
font-weight: 600;
}
td.num, th.num { text-align: right; }
.price-table td:last-child { font-weight: 600; }
.highlight-box {
background-color: #f8f8f8;
border-left: 4px solid #0a0a0a;
padding: 12px 16px;
margin: 14px 0;
border-radius: 2px;
}
.recommendation {
background-color: #fff8e6;
border: 1px solid #f0d480;
padding: 14px 18px;
margin-top: 14px;
border-radius: 4px;
}
.recommendation strong { color: #6b4f00; }
code {
font-family: "SF Mono", Consolas, monospace;
background-color: #f0f0f0;
padding: 1px 5px;
border-radius: 3px;
font-size: 9.5pt;
}
footer {
margin-top: 30px;
padding-top: 12px;
border-top: 1px solid #ddd;
font-size: 8.5pt;
color: #888;
text-align: center;
}
.badge {
display: inline-block;
background: #0a0a0a;
color: #fff;
font-size: 8pt;
padding: 2px 7px;
border-radius: 3px;
margin-right: 4px;
}
</style>
</head>
<body>
<header>
<h1>Proposta Comercial — TopTran</h1>
<div class="subtitle">Aplicativo mobile + backend para gestão de corridas de transporte</div>
<div class="meta">Análise técnica e estimativa de valor &middot; Maio de 2026</div>
</header>
<h2>1. Escopo entregue</h2>
<h3>Backend — API REST</h3>
<p><span class="badge">Node.js</span><span class="badge">Express 5</span><span class="badge">TypeScript</span><span class="badge">Prisma 7</span><span class="badge">PostgreSQL</span><span class="badge">Docker</span></p>
<ul>
<li>~1.100 linhas de código próprio, arquitetura em camadas (routes → middleware → controller → service → repository)</li>
<li>Autenticação JWT com access token (15 min) + refresh token (7 dias)</li>
<li>Validação de input com Zod, hash de senha com bcrypt</li>
<li>13 endpoints REST: <code>/auth</code> (register, login, logout), <code>/users</code> (me, profile, update, delete), <code>/sync</code> (companies, rides — upload e download)</li>
<li>Deploy completo com Docker + Compose (ambientes <em>development</em> e <em>production</em>) e script de deploy automatizado</li>
</ul>
<h3>Aplicativo Mobile</h3>
<p><span class="badge">React Native 0.83</span><span class="badge">Expo SDK 55</span><span class="badge">Expo Router</span><span class="badge">SQLite</span><span class="badge">TypeScript</span></p>
<ul>
<li>~4.460 linhas de código distribuídas em 21 arquivos</li>
<li><strong>11 telas:</strong> login, cadastro, dashboard, lançamento de corrida, histórico, empresas (CRUD), relatório mensal com PDF, perfil (foto + bio), sincronização com timeline visual, hub de cadastros, redirect de corrida</li>
<li><strong>Offline-first:</strong> SQLite local com 4 tabelas e sincronização inteligente (compara IDs locais com servidor)</li>
<li>Tema escuro customizado aplicado em todo o app</li>
<li>Geração e compartilhamento de relatório em PDF (<code>expo-print</code> + <code>expo-sharing</code>)</li>
<li>Upload de foto de perfil via <code>expo-image-picker</code></li>
<li>Build Android nativo com <em>keystore</em> de produção assinado (<code>.jks</code>)</li>
<li>Configuração EAS pronta para futuros builds</li>
</ul>
<h2>2. Estimativa de esforço técnico</h2>
<table>
<thead>
<tr><th>Frente de trabalho</th><th class="num">Horas estimadas</th></tr>
</thead>
<tbody>
<tr><td>Backend (API + autenticação + sync + deploy Docker)</td><td class="num">50 70 h</td></tr>
<tr><td>Mobile — telas e UI (11 telas com tema custom)</td><td class="num">70 90 h</td></tr>
<tr><td>Mobile — sincronização offline-first + SQLite + lógica de negócio</td><td class="num">30 40 h</td></tr>
<tr><td>Relatório PDF + perfil + upload de imagem</td><td class="num">15 20 h</td></tr>
<tr><td>Build / assinatura Android + ajustes de New Architecture</td><td class="num">15 20 h</td></tr>
<tr><td>Testes, debug em dispositivo, polimento</td><td class="num">20 30 h</td></tr>
<tr style="background-color: #f4f4f4;"><td><strong>Total estimado</strong></td><td class="num"><strong>200 270 h</strong></td></tr>
</tbody>
</table>
<h2>3. Faixa de preço sugerida</h2>
<p>Como o projeto é um <strong>aplicativo interno corporativo</strong> — sem publicação em loja pública, sem onboarding de usuário externo e sem complexidade de marketing — a precificação é mais direta:</p>
<table class="price-table">
<thead>
<tr><th>Cenário</th><th class="num">Valor/hora</th><th class="num">Preço total</th></tr>
</thead>
<tbody>
<tr><td><strong>Mínimo</strong> — freelancer pleno, projeto direto</td><td class="num">R$ 90/h</td><td class="num">R$ 18.000 24.000</td></tr>
<tr><td><strong>Justo</strong> — fullstack experiente, entrega completa</td><td class="num">R$ 130/h</td><td class="num">R$ 26.000 35.000</td></tr>
<tr><td><strong>Premium</strong> — sênior, com garantia e suporte inicial</td><td class="num">R$ 180/h</td><td class="num">R$ 36.000 48.000</td></tr>
</tbody>
</table>
<div class="highlight-box">
<strong>O que justifica o valor:</strong>
<ul style="margin-top: 6px;">
<li>Stack moderna e correta (Expo SDK 55, React Native 0.83, Prisma 7)</li>
<li>Arquitetura limpa no backend, com separação real de responsabilidades</li>
<li>Sincronização offline-first não trivial: bidirecional, com reconciliação de IDs e flag <code>synced</code></li>
<li>App em produção, com APK assinado e pronto para distribuição interna</li>
</ul>
</div>
<h3>Itens não inclusos no preço de desenvolvimento</h3>
<table>
<thead>
<tr><th>Item</th><th class="num">Custo recorrente</th></tr>
</thead>
<tbody>
<tr><td>Hospedagem do backend (VPS)</td><td class="num">R$ 60 150 / mês</td></tr>
<tr><td>Manutenção mensal e correções</td><td class="num">R$ 800 2.000 / mês</td></tr>
<tr><td>Novas features (push, dashboard web, multi-empresa real)</td><td class="num">sob orçamento</td></tr>
</tbody>
</table>
<h2>4. Modelo alternativo — Aluguel / SaaS</h2>
<p>Em vez de venda única do código-fonte, o aplicativo pode ser disponibilizado em modelo de assinatura (SaaS): o cliente não compra o app, paga uma mensalidade pelo uso. Setup baixo, receita recorrente, atualizações contínuas inclusas.</p>
<h3>Setup inicial (taxa única)</h3>
<table>
<thead>
<tr><th>Faixa</th><th class="num">Valor</th></tr>
</thead>
<tbody>
<tr><td>Setup enxuto — cliente fornece a VPS</td><td class="num">R$ 1.500</td></tr>
<tr><td>Setup completo — VPS, domínio e deploy gerenciados</td><td class="num">R$ 2.500 3.500</td></tr>
</tbody>
</table>
<p style="font-size: 9.5pt; color: #555;">Inclui deploy do backend, criação do banco, geração do APK assinado, cadastro inicial de empresas/usuários e treinamento de 1 2 h.</p>
<h3>Planos mensais</h3>
<table class="price-table">
<thead>
<tr><th>Plano</th><th>Limite</th><th class="num">Mensal</th><th class="num">Anual (10% off)</th></tr>
</thead>
<tbody>
<tr><td><strong>Básico</strong></td><td>até 5 motoristas, 1 empresa</td><td class="num">R$ 349</td><td class="num">R$ 3.770</td></tr>
<tr><td><strong>Profissional</strong></td><td>até 20 motoristas, até 5 empresas, suporte prioritário</td><td class="num">R$ 899</td><td class="num">R$ 9.710</td></tr>
<tr><td><strong>Empresarial</strong></td><td>usuários e empresas ilimitados, customizações leves, SLA</td><td class="num">R$ 1.890</td><td class="num">R$ 20.412</td></tr>
</tbody>
</table>
<h3>Alternativa por usuário ativo</h3>
<p>Se o cliente preferir escalar conforme o uso real:</p>
<ul>
<li><strong>R$ 29 por motorista / mês</strong>, mínimo de 5 usuários (R$ 145/mês)</li>
<li>Setup de R$ 2.500</li>
<li>Inclui hospedagem, atualizações e correções de bug</li>
</ul>
<h3>O que está incluso na mensalidade</h3>
<ul>
<li>Hospedagem do backend em VPS gerenciada</li>
<li>Banco PostgreSQL com backups diários</li>
<li>Atualizações de versão e correções de bugs</li>
<li>Suporte por WhatsApp/e-mail (tempo de resposta conforme o plano)</li>
<li>Geração de novas versões do APK quando houver atualização</li>
</ul>
<h3>Não incluso (cobrado à parte)</h3>
<table>
<thead>
<tr><th>Item</th><th class="num">Valor</th></tr>
</thead>
<tbody>
<tr><td>Novas funcionalidades sob demanda</td><td class="num">R$ 130 150 / h</td></tr>
<tr><td>Migração de dados de sistema legado</td><td class="num">sob orçamento</td></tr>
<tr><td>Integrações externas (ERP, gateways de pagamento, etc.)</td><td class="num">sob orçamento</td></tr>
<tr><td>Publicação na Play Store (taxa Google + serviço)</td><td class="num">USD 25 + R$ 600 1.000</td></tr>
</tbody>
</table>
<div class="highlight-box">
<strong>Ponto de equilíbrio e benefícios do modelo:</strong>
<ul style="margin-top: 6px;">
<li>Plano Profissional (R$ 899/mês) se equipara à venda de R$ 30.000 em aproximadamente 33 meses</li>
<li>Para o cliente: vira despesa operacional (OPEX) em vez de investimento (CAPEX) — geralmente mais fácil de aprovar</li>
<li>Para o fornecedor: receita previsível, atualizações contínuas e relação de longo prazo</li>
<li>Sem risco de o cliente ficar com versão desatualizada ou sem suporte</li>
</ul>
</div>
<h2>5. Recomendação final</h2>
<div class="recommendation">
<p style="margin-top: 0;"><strong>Modelo de venda única:</strong> R$ 25.000 R$ 30.000, com 30 dias de garantia para correção de bugs. Valor por hora alternativo: R$ 120 R$ 150/hora.</p>
<p style="margin-bottom: 0;"><strong>Modelo SaaS recomendado:</strong> Setup R$ 2.500 + Plano Profissional R$ 899/mês — equilíbrio entre acessibilidade para o cliente e sustentabilidade do serviço.</p>
</div>
<footer>
Proposta gerada com base em análise direta do código-fonte do projeto TopTran &middot; backend + toptran-app
</footer>
</body>
</html>

BIN
proposta-toptran.pdf Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
EXPO_PUBLIC_API_URL=http://175.15.15.93:4000/api

View file

@ -0,0 +1 @@
EXPO_PUBLIC_API_URL=https://toptran.olymp.com.br/api

View file

@ -39,30 +39,47 @@ CREATE TABLE IF NOT EXISTS tokens (
-- Companies
-- ============================================================
CREATE TABLE IF NOT EXISTS companies (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
cost_per_km NUMERIC(10,2) NOT NULL,
notes TEXT DEFAULT '',
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
cost_per_km NUMERIC(10,2) NOT NULL,
departures INTEGER DEFAULT 0,
failed_service INTEGER DEFAULT 0,
idle_hours NUMERIC(10,2) DEFAULT 0,
notes TEXT DEFAULT '',
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE companies ADD COLUMN IF NOT EXISTS departures INTEGER DEFAULT 0;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS failed_service INTEGER DEFAULT 0;
ALTER TABLE companies ADD COLUMN IF NOT EXISTS idle_hours NUMERIC(10,2) DEFAULT 0;
-- ============================================================
-- Rides
-- ============================================================
CREATE TABLE IF NOT EXISTS rides (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
company TEXT NOT NULL,
km NUMERIC(10,2) NOT NULL,
cost_per_km NUMERIC(10,2) NOT NULL,
total NUMERIC(10,2) NOT NULL,
ride_date TEXT NOT NULL,
synced SMALLINT DEFAULT 0,
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
company TEXT NOT NULL,
km NUMERIC(10,2) NOT NULL,
cost_per_km NUMERIC(10,2) NOT NULL,
total NUMERIC(10,2) NOT NULL,
ride_date TEXT NOT NULL,
departures INTEGER DEFAULT 0,
failed_service INTEGER DEFAULT 0,
idle_hours NUMERIC(10,2) DEFAULT 0,
synced SMALLINT DEFAULT 0,
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================
-- Migrations: add new columns if table already exists
-- ============================================================
ALTER TABLE rides ADD COLUMN IF NOT EXISTS departures INTEGER DEFAULT 0;
ALTER TABLE rides ADD COLUMN IF NOT EXISTS failed_service INTEGER DEFAULT 0;
ALTER TABLE rides ADD COLUMN IF NOT EXISTS idle_hours NUMERIC(10,2) DEFAULT 0;
-- ============================================================
-- Indexes
-- ============================================================

View file

@ -11,7 +11,7 @@
"buildType": "apk"
},
"env": {
"EXPO_PUBLIC_API_URL": "https://toptran.olymp.com.br/api"
"EXPO_PUBLIC_API_URL": "http://175.15.15.93:4000/api"
}
},
"preview": {

View file

@ -2,6 +2,7 @@ import { BORDER_RADIUS, COLORS, SPACING } from "@/constants/theme";
import { router } from "expo-router";
import React from "react";
import {
Alert,
ScrollView,
StyleSheet,
Text,
@ -31,19 +32,25 @@ export default function CadastrosPage() {
icon: "👤",
label: "Motoristas",
description: "Cadastro de motoristas",
onPress: () => {},
onPress: () => {
Alert.alert("Em desenvolvimento!");
},
},
{
icon: "🚛",
label: "Veículos",
description: "Cadastro de veículos",
onPress: () => {},
onPress: () => {
Alert.alert("Em desenvolvimento!");
},
},
{
icon: "📍",
label: "Rotas",
description: "Rotas e destinos frequentes",
onPress: () => {},
onPress: () => {
Alert.alert("Em desenvolvimento!");
},
},
];
@ -66,9 +73,7 @@ export default function CadastrosPage() {
>
<View style={styles.titleSection}>
<Text style={styles.title}>Cadastros</Text>
<Text style={styles.subtitle}>
Gerencie os dados base do sistema
</Text>
<Text style={styles.subtitle}>Gerencie os dados base do sistema</Text>
</View>
<Text style={styles.sectionTitle}>Categorias</Text>

View file

@ -26,10 +26,20 @@ import { SafeAreaView } from "react-native-safe-area-context";
type FormState = {
nome: string;
custoPorKm: string;
partidas: string;
servicoFalho: string;
horasOciosas: string;
observacoes: string;
};
const FORM_VAZIO: FormState = { nome: "", custoPorKm: "", observacoes: "" };
const FORM_VAZIO: FormState = {
nome: "",
custoPorKm: "",
partidas: "",
servicoFalho: "",
horasOciosas: "",
observacoes: "",
};
export default function EmpresasPage() {
const [empresas, setEmpresas] = useState<CompanyDB[]>([]);
@ -59,6 +69,9 @@ export default function EmpresasPage() {
setForm({
nome: empresa.name,
custoPorKm: empresa.cost_per_km.toString(),
partidas: (empresa.departures ?? 0).toString(),
servicoFalho: (empresa.failed_service ?? 0).toString(),
horasOciosas: (empresa.idle_hours ?? 0).toString(),
observacoes: empresa.notes ?? "",
});
setModalVisible(true);
@ -73,6 +86,9 @@ export default function EmpresasPage() {
const handleSalvar = async () => {
const nomeTrimmed = form.nome.trim();
const custo = parseFloat(form.custoPorKm.replace(",", "."));
const partidas = parseInt(form.partidas, 10) || 0;
const servicoFalho = parseInt(form.servicoFalho, 10) || 0;
const horasOciosas = parseFloat(form.horasOciosas.replace(",", ".")) || 0;
if (!nomeTrimmed) {
Alert.alert("Validação", "Informe o nome da empresa.");
@ -90,6 +106,9 @@ export default function EmpresasPage() {
id: editando.id,
name: nomeTrimmed,
cost_per_km: custo,
departures: partidas,
failed_service: servicoFalho,
idle_hours: horasOciosas,
notes: form.observacoes.trim(),
});
} else {
@ -97,6 +116,9 @@ export default function EmpresasPage() {
id: Date.now().toString(),
name: nomeTrimmed,
cost_per_km: custo,
departures: partidas,
failed_service: servicoFalho,
idle_hours: horasOciosas,
notes: form.observacoes.trim(),
});
}
@ -258,6 +280,36 @@ export default function EmpresasPage() {
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.formLabel}>Partidas</Text>
<Input
placeholder="0"
keyboardType="number-pad"
value={form.partidas}
onChangeText={(v) => setForm((f) => ({ ...f, partidas: v }))}
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.formLabel}>Serviço falho</Text>
<Input
placeholder="0"
keyboardType="number-pad"
value={form.servicoFalho}
onChangeText={(v) => setForm((f) => ({ ...f, servicoFalho: v }))}
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.formLabel}>Horas ociosas</Text>
<Input
placeholder="0,00"
keyboardType="decimal-pad"
value={form.horasOciosas}
onChangeText={(v) => setForm((f) => ({ ...f, horasOciosas: v }))}
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.formLabel}>Observações (opcional)</Text>
<Input

View file

@ -33,6 +33,9 @@ export default function LancamentoPage() {
const [empresasDB, setEmpresasDB] = useState<CompanyDB[]>([]);
const [empresaId, setEmpresaId] = useState("");
const [custoPorKm, setCustoPorKm] = useState(0);
const [partidas, setPartidas] = useState(0);
const [servicoFalho, setServicoFalho] = useState(0);
const [horasOciosas, setHorasOciosas] = useState(0);
const [distancia, setDistancia] = useState("");
const [loading, setLoading] = useState(false);
@ -56,6 +59,9 @@ export default function LancamentoPage() {
setEmpresaId(id);
const found = empresasDB.find((e) => e.id === id);
setCustoPorKm(found?.cost_per_km ?? 0);
setPartidas(found?.departures ?? 0);
setServicoFalho(found?.failed_service ?? 0);
setHorasOciosas(found?.idle_hours ?? 0);
};
const handleLancarCorrida = async () => {
@ -80,11 +86,17 @@ export default function LancamentoPage() {
cost_per_km: custoPorKm,
total: totalCorrida,
ride_date: new Date().toLocaleString("pt-BR"),
departures: partidas,
failed_service: servicoFalho,
idle_hours: horasOciosas,
synced: 0,
});
setEmpresaId("");
setCustoPorKm(0);
setDistancia("");
setPartidas(0);
setServicoFalho(0);
setHorasOciosas(0);
Alert.alert("Sucesso", "Corrida registrada com sucesso!", [
{ text: "OK", onPress: () => router.back() },
]);
@ -140,6 +152,27 @@ export default function LancamentoPage() {
</View>
</View>
<View style={styles.card}>
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>Partidas</Text>
<Text style={styles.infoValue}>{partidas}</Text>
</View>
</View>
<View style={styles.card}>
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>Serviço falho</Text>
<Text style={styles.infoValue}>{servicoFalho}</Text>
</View>
</View>
<View style={styles.card}>
<View style={styles.infoRow}>
<Text style={styles.infoLabel}>Horas ociosas</Text>
<Text style={styles.infoValue}>{horasOciosas.toFixed(2)}</Text>
</View>
</View>
<View style={[styles.card, styles.totalCard]}>
<Text style={styles.totalLabel}>Valor Total</Text>
<Text style={styles.totalAmount}>R$ {totalCorrida.toFixed(2)}</Text>

View file

@ -105,6 +105,9 @@ export default function SincronizarPage() {
id: c.id,
name: c.name,
cost_per_km: Number(c.cost_per_km),
departures: Number(c.departures ?? 0),
failed_service: Number(c.failed_service ?? 0),
idle_hours: Number(c.idle_hours ?? 0),
notes: c.notes ?? "",
});
}

View file

@ -1,6 +1,10 @@
import axios from "axios";
const BASE_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://175.15.15.93:3000";
const BASE_URL = process.env.EXPO_PUBLIC_API_URL;
if (!BASE_URL) {
throw new Error("EXPO_PUBLIC_API_URL não definida — verifique .env.development / .env.production");
}
export const api = axios.create({
baseURL: BASE_URL,

View file

@ -18,6 +18,9 @@ export type RideDB = {
cost_per_km: number;
total: number;
ride_date: string;
departures: number;
failed_service: number;
idle_hours: number;
synced: 0 | 1;
createdAt: string;
};
@ -26,6 +29,9 @@ export type CompanyDB = {
id: string;
name: string;
cost_per_km: number;
departures: number;
failed_service: number;
idle_hours: number;
notes: string;
createdAt: string;
};
@ -51,11 +57,34 @@ export const initDB = async () => {
cost_per_km REAL NOT NULL,
total REAL NOT NULL,
ride_date TEXT NOT NULL,
departures INTEGER DEFAULT 0,
failed_service INTEGER DEFAULT 0,
idle_hours REAL DEFAULT 0,
synced INTEGER DEFAULT 0,
createdAt TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);`,
);
const ridesCols = await db.getAllAsync<{ name: string }>(
`PRAGMA table_info(rides);`,
);
const colNames = new Set(ridesCols.map((c) => c.name));
if (!colNames.has("departures")) {
await db.execAsync(
`ALTER TABLE rides ADD COLUMN departures INTEGER DEFAULT 0;`,
);
}
if (!colNames.has("failed_service")) {
await db.execAsync(
`ALTER TABLE rides ADD COLUMN failed_service INTEGER DEFAULT 0;`,
);
}
if (!colNames.has("idle_hours")) {
await db.execAsync(
`ALTER TABLE rides ADD COLUMN idle_hours REAL DEFAULT 0;`,
);
}
await db.execAsync(
`CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
@ -67,10 +96,33 @@ export const initDB = async () => {
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
cost_per_km REAL NOT NULL,
departures INTEGER DEFAULT 0,
failed_service INTEGER DEFAULT 0,
idle_hours REAL DEFAULT 0,
notes TEXT DEFAULT '',
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
);`,
);
const companiesCols = await db.getAllAsync<{ name: string }>(
`PRAGMA table_info(companies);`,
);
const compColNames = new Set(companiesCols.map((c) => c.name));
if (!compColNames.has("departures")) {
await db.execAsync(
`ALTER TABLE companies ADD COLUMN departures INTEGER DEFAULT 0;`,
);
}
if (!compColNames.has("failed_service")) {
await db.execAsync(
`ALTER TABLE companies ADD COLUMN failed_service INTEGER DEFAULT 0;`,
);
}
if (!compColNames.has("idle_hours")) {
await db.execAsync(
`ALTER TABLE companies ADD COLUMN idle_hours REAL DEFAULT 0;`,
);
}
} catch (error) {
console.error("Failed to initialize database:", error);
throw error;
@ -178,8 +230,8 @@ export const salvarCorrida = async (corrida: Omit<RideDB, "createdAt">) => {
try {
const db = await dbPromise;
const result = await db.runAsync(
`INSERT INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, synced)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
`INSERT INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, departures, failed_service, idle_hours, synced)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
corrida.id,
corrida.user_id,
@ -188,6 +240,9 @@ export const salvarCorrida = async (corrida: Omit<RideDB, "createdAt">) => {
corrida.cost_per_km,
corrida.total,
corrida.ride_date,
corrida.departures,
corrida.failed_service,
corrida.idle_hours,
corrida.synced,
],
);
@ -282,8 +337,17 @@ export const salvarEmpresa = async (
try {
const db = await dbPromise;
await db.runAsync(
`INSERT INTO companies (id, name, cost_per_km, notes) VALUES (?, ?, ?, ?)`,
[empresa.id, empresa.name, empresa.cost_per_km, empresa.notes],
`INSERT INTO companies (id, name, cost_per_km, departures, failed_service, idle_hours, notes)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[
empresa.id,
empresa.name,
empresa.cost_per_km,
empresa.departures,
empresa.failed_service,
empresa.idle_hours,
empresa.notes,
],
);
} catch (error) {
console.error("Error saving company:", error);
@ -297,8 +361,17 @@ export const upsertEmpresaLocal = async (
try {
const db = await dbPromise;
await db.runAsync(
`INSERT OR REPLACE INTO companies (id, name, cost_per_km, notes) VALUES (?, ?, ?, ?)`,
[empresa.id, empresa.name, empresa.cost_per_km, empresa.notes],
`INSERT OR REPLACE INTO companies (id, name, cost_per_km, departures, failed_service, idle_hours, notes)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[
empresa.id,
empresa.name,
empresa.cost_per_km,
empresa.departures,
empresa.failed_service,
empresa.idle_hours,
empresa.notes,
],
);
} catch (error) {
console.error("Error upserting company:", error);
@ -312,9 +385,20 @@ export const upsertCorridaLocal = async (
try {
const db = await dbPromise;
await db.runAsync(
`INSERT OR REPLACE INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, synced)
VALUES (?, ?, ?, ?, ?, ?, ?, 1)`,
[corrida.id, corrida.user_id, corrida.company, corrida.km, corrida.cost_per_km, corrida.total, corrida.ride_date],
`INSERT OR REPLACE INTO rides (id, user_id, company, km, cost_per_km, total, ride_date, departures, failed_service, idle_hours, synced)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)`,
[
corrida.id,
corrida.user_id,
corrida.company,
corrida.km,
corrida.cost_per_km,
corrida.total,
corrida.ride_date,
corrida.departures,
corrida.failed_service,
corrida.idle_hours,
],
);
} catch (error) {
console.error("Error upserting ride:", error);
@ -328,8 +412,16 @@ export const atualizarEmpresa = async (
try {
const db = await dbPromise;
await db.runAsync(
`UPDATE companies SET name = ?, cost_per_km = ?, notes = ? WHERE id = ?`,
[empresa.name, empresa.cost_per_km, empresa.notes, empresa.id],
`UPDATE companies SET name = ?, cost_per_km = ?, departures = ?, failed_service = ?, idle_hours = ?, notes = ? WHERE id = ?`,
[
empresa.name,
empresa.cost_per_km,
empresa.departures,
empresa.failed_service,
empresa.idle_hours,
empresa.notes,
empresa.id,
],
);
} catch (error) {
console.error("Error updating company:", error);