Remove Odoo order fallback
All checks were successful
Build Docker Image / build (push) Successful in 5m6s
All checks were successful
Build Docker Image / build (push) Successful in 5m6s
This commit is contained in:
@@ -9,8 +9,6 @@ import {
|
||||
import { requireScopes, type AuthContext } from '../auth.js'
|
||||
import { prisma } from '../db.js'
|
||||
|
||||
const ODOO_INTERNAL_URL = process.env.ODOO_INTERNAL_URL || 'odoo:8069'
|
||||
|
||||
const quotationInclude = {
|
||||
selectedTariff: true,
|
||||
changes: {
|
||||
@@ -27,82 +25,6 @@ const orderInclude = {
|
||||
type QuotationWithRelations = Prisma.QuotationGetPayload<{ include: typeof quotationInclude }>
|
||||
type OrderWithRelations = Prisma.OrderGetPayload<{ include: typeof orderInclude }>
|
||||
|
||||
interface OdooCompany {
|
||||
uuid?: string
|
||||
name?: string
|
||||
tax_id?: string
|
||||
country?: string
|
||||
country_code?: string
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
interface OdooTrip {
|
||||
uuid?: string
|
||||
name?: string
|
||||
sequence?: number
|
||||
company?: OdooCompany
|
||||
planned_loading_date?: string
|
||||
actual_loading_date?: string
|
||||
real_loading_date?: string
|
||||
planned_unloading_date?: string
|
||||
actual_unloading_date?: string
|
||||
planned_weight?: number
|
||||
weight_at_loading?: number
|
||||
weight_at_unloading?: number
|
||||
}
|
||||
|
||||
interface OdooStage {
|
||||
uuid?: string
|
||||
name?: string
|
||||
sequence?: number
|
||||
stage_type?: string
|
||||
transport_type?: string
|
||||
source_location_name?: string
|
||||
source_latitude?: number
|
||||
source_longitude?: number
|
||||
destination_location_name?: string
|
||||
destination_latitude?: number
|
||||
destination_longitude?: number
|
||||
location_name?: string
|
||||
location_latitude?: number
|
||||
location_longitude?: number
|
||||
selected_company?: OdooCompany
|
||||
trips?: OdooTrip[]
|
||||
}
|
||||
|
||||
interface OdooOrderLine {
|
||||
uuid?: string
|
||||
product_uuid?: string
|
||||
product_name?: string
|
||||
quantity?: number
|
||||
unit?: string
|
||||
price_unit?: number
|
||||
subtotal?: number
|
||||
currency?: string
|
||||
notes?: string
|
||||
}
|
||||
|
||||
interface OdooOrder {
|
||||
uuid?: string
|
||||
name?: string
|
||||
team_uuid?: string
|
||||
user_id?: string
|
||||
status?: string
|
||||
total_amount?: number
|
||||
currency?: string
|
||||
source_location_uuid?: string
|
||||
source_location_name?: string
|
||||
source_latitude?: number
|
||||
source_longitude?: number
|
||||
destination_location_uuid?: string
|
||||
destination_location_name?: string
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
notes?: string
|
||||
order_lines?: OdooOrderLine[]
|
||||
stages?: OdooStage[]
|
||||
}
|
||||
|
||||
interface TariffMatchResult {
|
||||
tariff: PrismaTariffReference
|
||||
score: number
|
||||
@@ -491,95 +413,6 @@ function assertTeamAccess(ctx: AuthContext): { teamUuid: string; userId: string
|
||||
}
|
||||
}
|
||||
|
||||
function mapCompany(c?: OdooCompany | null) {
|
||||
if (!c) return null
|
||||
return {
|
||||
uuid: c.uuid ?? '',
|
||||
name: c.name ?? '',
|
||||
taxId: c.tax_id ?? '',
|
||||
country: c.country ?? '',
|
||||
countryCode: c.country_code ?? '',
|
||||
active: c.active ?? true,
|
||||
}
|
||||
}
|
||||
|
||||
function mapTrip(t: OdooTrip) {
|
||||
return {
|
||||
uuid: t.uuid,
|
||||
name: t.name,
|
||||
sequence: t.sequence,
|
||||
company: mapCompany(t.company),
|
||||
plannedLoadingDate: t.planned_loading_date,
|
||||
actualLoadingDate: t.actual_loading_date,
|
||||
realLoadingDate: t.real_loading_date,
|
||||
plannedUnloadingDate: t.planned_unloading_date,
|
||||
actualUnloadingDate: t.actual_unloading_date,
|
||||
plannedWeight: t.planned_weight,
|
||||
weightAtLoading: t.weight_at_loading,
|
||||
weightAtUnloading: t.weight_at_unloading,
|
||||
}
|
||||
}
|
||||
|
||||
function mapStage(s: OdooStage) {
|
||||
return {
|
||||
uuid: s.uuid,
|
||||
name: s.name,
|
||||
sequence: s.sequence,
|
||||
stageType: s.stage_type,
|
||||
transportType: s.transport_type,
|
||||
sourceLocationName: s.source_location_name,
|
||||
sourceLatitude: s.source_latitude,
|
||||
sourceLongitude: s.source_longitude,
|
||||
destinationLocationName: s.destination_location_name,
|
||||
destinationLatitude: s.destination_latitude,
|
||||
destinationLongitude: s.destination_longitude,
|
||||
locationName: s.location_name,
|
||||
locationLatitude: s.location_latitude,
|
||||
locationLongitude: s.location_longitude,
|
||||
selectedCompany: mapCompany(s.selected_company),
|
||||
trips: (s.trips ?? []).map(mapTrip),
|
||||
}
|
||||
}
|
||||
|
||||
function mapOdooOrder(o: OdooOrder) {
|
||||
const stages = o.stages ?? []
|
||||
const firstStage = stages[0]
|
||||
return {
|
||||
uuid: o.uuid,
|
||||
quotationUuid: null,
|
||||
name: o.name,
|
||||
teamUuid: o.team_uuid,
|
||||
userId: o.user_id,
|
||||
status: o.status ?? 'active',
|
||||
totalAmount: o.total_amount,
|
||||
currency: o.currency,
|
||||
sourceCountryCode: null,
|
||||
sourceLocationUuid: o.source_location_uuid,
|
||||
sourceLocationName: o.source_location_name,
|
||||
sourceLatitude: o.source_latitude || firstStage?.source_latitude,
|
||||
sourceLongitude: o.source_longitude || firstStage?.source_longitude,
|
||||
destinationCountryCode: null,
|
||||
destinationLocationUuid: o.destination_location_uuid,
|
||||
destinationLocationName: o.destination_location_name,
|
||||
etaDays: null,
|
||||
createdAt: o.created_at,
|
||||
updatedAt: o.updated_at,
|
||||
notes: o.notes ?? '',
|
||||
orderLines: (o.order_lines ?? []).map(l => ({
|
||||
uuid: l.uuid,
|
||||
productUuid: l.product_uuid,
|
||||
productName: l.product_name,
|
||||
quantity: l.quantity,
|
||||
unit: l.unit,
|
||||
priceUnit: l.price_unit,
|
||||
subtotal: l.subtotal,
|
||||
currency: l.currency,
|
||||
notes: l.notes ?? '',
|
||||
})),
|
||||
stages: stages.map(mapStage),
|
||||
}
|
||||
}
|
||||
|
||||
function mapTariffReference(item: PrismaTariffReference) {
|
||||
return {
|
||||
uuid: item.uuid,
|
||||
@@ -693,53 +526,6 @@ function mapLocalOrder(item: OrderWithRelations) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchOdoo(path: string): Promise<Response> {
|
||||
const controller = new AbortController()
|
||||
const timeout = setTimeout(() => controller.abort(), 10000)
|
||||
try {
|
||||
return await fetch(`http://${ODOO_INTERNAL_URL}${path}`, { signal: controller.signal })
|
||||
} finally {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchTeamOdooOrders(teamUuid: string) {
|
||||
try {
|
||||
const res = await fetchOdoo(`/fastapi/orders/orders/team/${teamUuid}`)
|
||||
if (!res.ok) return []
|
||||
const data = (await res.json()) as OdooOrder[]
|
||||
return data.map(mapOdooOrder)
|
||||
} catch (error) {
|
||||
console.error('Error calling Odoo:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchSingleOdooOrder(orderUuid: string, teamUuid: string) {
|
||||
try {
|
||||
const res = await fetchOdoo(`/fastapi/orders/orders/${orderUuid}`)
|
||||
if (!res.ok) return null
|
||||
const data = (await res.json()) as OdooOrder
|
||||
if (data.team_uuid !== teamUuid) {
|
||||
throw new GraphQLError('Access denied: order belongs to different team')
|
||||
}
|
||||
return mapOdooOrder(data)
|
||||
} catch (error) {
|
||||
if (error instanceof GraphQLError) throw error
|
||||
console.error('Error calling Odoo:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function compareByCreatedAtDesc(
|
||||
left: { createdAt: string | null | undefined },
|
||||
right: { createdAt: string | null | undefined },
|
||||
) {
|
||||
const leftTime = left.createdAt ? new Date(left.createdAt).getTime() : 0
|
||||
const rightTime = right.createdAt ? new Date(right.createdAt).getTime() : 0
|
||||
return rightTime - leftTime
|
||||
}
|
||||
|
||||
function requiredString(value: unknown, label: string): string {
|
||||
const next = normalizeString(value)
|
||||
if (!next) {
|
||||
@@ -1098,26 +884,23 @@ export const teamResolvers = {
|
||||
getTeamOrders: async (_: unknown, __: unknown, ctx: AuthContext) => {
|
||||
const { teamUuid } = assertTeamAccess(ctx)
|
||||
|
||||
const [localOrders, odooOrders] = await Promise.all([
|
||||
prisma.order.findMany({
|
||||
where: {
|
||||
teamUuid,
|
||||
},
|
||||
include: orderInclude,
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
}),
|
||||
fetchTeamOdooOrders(teamUuid),
|
||||
])
|
||||
const localOrders = await prisma.order.findMany({
|
||||
where: {
|
||||
teamUuid,
|
||||
},
|
||||
include: orderInclude,
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
})
|
||||
|
||||
return [...localOrders.map(mapLocalOrder), ...odooOrders].sort(compareByCreatedAtDesc)
|
||||
return localOrders.map(mapLocalOrder)
|
||||
},
|
||||
|
||||
getOrder: async (_: unknown, args: { orderUuid: string }, ctx: AuthContext) => {
|
||||
const { teamUuid } = assertTeamAccess(ctx)
|
||||
|
||||
const localOrder = await prisma.order.findFirst({
|
||||
const order = await prisma.order.findFirst({
|
||||
where: {
|
||||
uuid: args.orderUuid,
|
||||
teamUuid,
|
||||
@@ -1125,11 +908,7 @@ export const teamResolvers = {
|
||||
include: orderInclude,
|
||||
})
|
||||
|
||||
if (localOrder) {
|
||||
return mapLocalOrder(localOrder)
|
||||
}
|
||||
|
||||
return await fetchSingleOdooOrder(args.orderUuid, teamUuid)
|
||||
return order ? mapLocalOrder(order) : null
|
||||
},
|
||||
|
||||
quotations: async (_: unknown, args: { status?: string | null }, ctx: AuthContext) => {
|
||||
|
||||
Reference in New Issue
Block a user