Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(bulk-mileage): Hotfix - update bulk mileage #16665

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface UpdateResponseError {
type: string
title: string
status: number
Errors: Array<{
lookupNo: number
warnSever: string
errorMess: string
permno: string
warningSerialNumber: string
}>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ export class VehiclesListInputV3 {

@Field()
page!: number

@Field({ nullable: true })
query?: string
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Field, ObjectType, ID } from '@nestjs/graphql'
import { Field, ObjectType, ID, Int } from '@nestjs/graphql'

@ObjectType()
export class VehiclesBulkMileageReadingResponse {
@Field(() => ID, {
nullable: true,
description:
'The GUID of the mileage registration post request. Used to fetch job status',
})
requestId!: string
requestId?: string

@Field(() => Int, { nullable: true })
errorCode?: number

@Field({ nullable: true })
errorMessage?: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createUnionType } from '@nestjs/graphql'
import { VehicleMileageDetail } from '../getVehicleMileage.model'
import { VehiclesMileageUpdateError } from './vehicleMileageResponseError.model'

export const VehicleMileagePostResponse = createUnionType({
name: 'VehicleMileagePostResponse',
types: () => [VehicleMileageDetail, VehiclesMileageUpdateError] as const,
resolveType(value) {
if ('permno' in value && value.permno !== undefined) {
return VehicleMileageDetail
}

return VehiclesMileageUpdateError
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createUnionType } from '@nestjs/graphql'
import { VehicleMileagePutModel } from '../getVehicleMileage.model'
import { VehiclesMileageUpdateError } from './vehicleMileageResponseError.model'

export const VehicleMileagePutResponse = createUnionType({
name: 'VehicleMileagePutResponse',
types: () => [VehicleMileagePutModel, VehiclesMileageUpdateError] as const,
resolveType(value) {
if ('permno' in value && value.permno !== undefined) {
return VehicleMileagePutModel
}

return VehiclesMileageUpdateError
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import GraphQLJSON from 'graphql-type-json'

@ObjectType()
export class VehiclesMileageUpdateError {
@Field()
message!: string

@Field(() => Int, { nullable: true })
code?: number

@Field(() => GraphQLJSON, { nullable: true })
error?: string
}
45 changes: 45 additions & 0 deletions libs/api/domains/vehicles/src/lib/resolvers/mileage.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ import {
} from '@island.is/nest/feature-flags'
import { mileageDetailConstructor } from '../utils/helpers'
import { LOGGER_PROVIDER, type Logger } from '@island.is/logging'
import { VehicleMileagePostResponse } from '../models/v3/postVehicleMileageResponse.model'
import { VehiclesMileageUpdateError } from '../models/v3/vehicleMileageResponseError.model'
import { VehicleMileagePutResponse } from '../models/v3/putVehicleMileageResponse.model'

@UseGuards(IdsUserGuard, ScopesGuard, FeatureFlagGuard)
@FeatureFlag(Features.servicePortalVehicleMileagePageEnabled)
Expand Down Expand Up @@ -99,6 +102,48 @@ export class VehiclesMileageResolver {
return mileageDetailConstructor(res)
}

@Mutation(() => VehicleMileagePostResponse, {
name: 'vehicleMileagePostV2',
nullable: true,
})
@Audit()
async postVehicleMileageReadingV2(
@Args('input') input: PostVehicleMileageInput,
@CurrentUser() user: User,
) {
const res = await this.vehiclesService.postMileageReadingV2(user, {
...input,
mileage: Number(input.mileage ?? input.mileageNumber),
})

if (!res || res instanceof VehiclesMileageUpdateError) {
return res
}

return mileageDetailConstructor(res)
}

@Mutation(() => VehicleMileagePutResponse, {
name: 'vehicleMileagePutV2',
nullable: true,
})
@Audit()
async putVehicleMileageReadingV2(
@Args('input') input: PutVehicleMileageInput,
@CurrentUser() user: User,
) {
const res = await this.vehiclesService.putMileageReadingV2(user, {
...input,
mileage: Number(input.mileage ?? input.mileageNumber),
})

if (!res || res instanceof VehiclesMileageUpdateError) {
return res
}

return mileageDetailConstructor(res)
}

@ResolveField('canRegisterMileage', () => Boolean, {
nullable: true,
})
Expand Down
43 changes: 28 additions & 15 deletions libs/api/domains/vehicles/src/lib/services/bulkMileage.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Inject, Injectable } from '@nestjs/common'
import {
BulkMileageReadingRequestResultDto,
GetbulkmileagereadingrequeststatusGuidGetRequest,
MileageReadingApi,
} from '@island.is/clients/vehicles-mileage'
Expand All @@ -14,6 +13,7 @@ import { VehiclesBulkMileageReadingResponse } from '../models/v3/bulkMileage/bul
import { VehiclesBulkMileageRegistrationJobHistory } from '../models/v3/bulkMileage/bulkMileageRegistrationJobHistory.model'
import { VehiclesBulkMileageRegistrationRequestStatus } from '../models/v3/bulkMileage/bulkMileageRegistrationRequestStatus.model'
import { VehiclesBulkMileageRegistrationRequestOverview } from '../models/v3/bulkMileage/bulkMileageRegistrationRequestOverview.model'
import { FetchError } from '@island.is/clients/middlewares'

@Injectable()
export class BulkMileageService {
Expand All @@ -34,8 +34,10 @@ export class BulkMileageService {
return null
}

const res: BulkMileageReadingRequestResultDto =
await this.getMileageWithAuth(auth).requestbulkmileagereadingPost({
try {
const res = await this.getMileageWithAuth(
auth,
).requestbulkmileagereadingPost({
postBulkMileageReadingModel: {
originCode: input.originCode,
mileageData: input.mileageData.map((m) => ({
Expand All @@ -45,19 +47,30 @@ export class BulkMileageService {
},
})

if (!res.guid) {
this.logger.warn(
'Missing guid from bulk mileage reading registration response',
{
category: LOG_CATEGORY,
},
)
return null
}
if (!res.guid) {
this.logger.warn(
'Missing guid from bulk mileage reading registration response',
{
category: LOG_CATEGORY,
},
)
return null
}

return {
requestId: res.guid,
errorMessage: res.errorMessage ?? undefined,
return {
requestId: res.guid,
errorMessage: res.errorMessage ?? undefined,
}
} catch (e) {
const error: Error = e
if (error instanceof FetchError && error.status === 429) {
return {
requestId: undefined,
errorCode: 429,
errorMessage: error.statusText,
}
}
throw e
}
}

Expand Down
92 changes: 90 additions & 2 deletions libs/api/domains/vehicles/src/lib/services/vehicles.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import {
VehicleDtoListPagedResponse,
PersidnoLookupResultDto,
CurrentVehiclesWithMilageAndNextInspDtoListPagedResponse,
ApiResponse,
} from '@island.is/clients/vehicles'
import {
CanregistermileagePermnoGetRequest,
GetMileageReadingRequest,
MileageReadingApi,
MileageReadingDto,
PostMileageReadingModel,
PutMileageReadingModel,
RequiresmileageregistrationPermnoGetRequest,
RootPostRequest,
RootPutRequest,
Expand All @@ -33,17 +35,22 @@ import {
GetVehiclesForUserInput,
GetVehiclesListV2Input,
} from '../dto/getVehiclesForUserInput'
import { VehicleMileageOverview } from '../models/getVehicleMileage.model'
import {
VehicleMileageDetail,
VehicleMileageOverview,
} from '../models/getVehicleMileage.model'
import isSameDay from 'date-fns/isSameDay'
import { mileageDetailConstructor } from '../utils/helpers'
import { handle404 } from '@island.is/clients/middlewares'
import { FetchError, handle404 } from '@island.is/clients/middlewares'
import { VehicleSearchCustomDto } from '../vehicles.type'
import { operatorStatusMapper } from '../utils/operatorStatusMapper'
import { VehiclesListInputV3 } from '../dto/vehiclesListInputV3'
import { VehiclesCurrentListResponse } from '../models/v3/currentVehicleListResponse.model'
import { isDefined } from '@island.is/shared/utils'
import { GetVehicleMileageInput } from '../dto/getVehicleMileageInput'
import { MileageRegistrationHistory } from '../models/v3/mileageRegistrationHistory.model'
import { VehiclesMileageUpdateError } from '../models/v3/vehicleMileageResponseError.model'
import { UpdateResponseError } from '../dto/updateResponseError.dto'

const ORIGIN_CODE = 'ISLAND.IS'
const LOG_CATEGORY = 'vehicle-service'
Expand Down Expand Up @@ -111,6 +118,11 @@ export class VehiclesService {
showOwned: true,
page: input.page,
pageSize: input.pageSize,
permno: input.query
? input.query.length < 5
? `${input.query}*`
: `${input.query}`
: undefined,
})

if (
Expand Down Expand Up @@ -463,6 +475,82 @@ export class VehiclesService {
})
}

async postMileageReadingV2(
auth: User,
input: RootPostRequest['postMileageReadingModel'],
): Promise<PostMileageReadingModel | VehiclesMileageUpdateError | null> {
if (!input) return null

const isAllowed = await this.isAllowedMileageRegistration(
auth,
input.permno,
)
if (!isAllowed) {
this.logger.error(UNAUTHORIZED_OWNERSHIP_LOG, {
category: LOG_CATEGORY,
error: 'postMileageReading failed',
})
throw new ForbiddenException(UNAUTHORIZED_OWNERSHIP_LOG)
}

try {
const res = await this.getMileageWithAuth(auth).rootPostRaw({
postMileageReadingModel: input,
})

if (res.raw.status === 200) {
this.logger.info(
'Tried to post already existing mileage reading. Should use PUT',
)
return null
}

const value = await res.value()
return value
} catch (e) {
if (e instanceof FetchError && (e.status === 400 || e.status === 429)) {
const errorBody = e.body as UpdateResponseError
return {
code: e.status,
message: errorBody.Errors?.[0]?.errorMess || 'Unknown error',
}
} else throw e
}
}

async putMileageReadingV2(
auth: User,
input: RootPutRequest['putMileageReadingModel'],
): Promise<MileageReadingDto | VehiclesMileageUpdateError | null> {
if (!input) return null

const isAllowed = await this.isAllowedMileageRegistration(
auth,
input.permno,
)
if (!isAllowed) {
this.logger.error(UNAUTHORIZED_OWNERSHIP_LOG, {
category: LOG_CATEGORY,
error: 'putMileageReading failed',
})
throw new ForbiddenException(UNAUTHORIZED_OWNERSHIP_LOG)
}

try {
return this.getMileageWithAuth(auth).rootPut({
putMileageReadingModel: input,
})
} catch (e) {
if (e instanceof FetchError && (e.status === 400 || e.status === 429)) {
const errorBody = e.body as UpdateResponseError
return {
code: e.status,
message: errorBody.Errors?.[0]?.errorMess || 'Unknown error',
}
} else throw e
}
}

async canRegisterMileage(
auth: User,
input: CanregistermileagePermnoGetRequest,
Expand Down
17 changes: 15 additions & 2 deletions libs/service-portal/assets/src/lib/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -874,14 +874,23 @@ export const vehicleMessage = defineMessages({
id: 'sp.vehicles:mileage-errors-input-too-low',
defaultMessage: 'Verður að vera hærri en síðasta staðfesta skráning',
},
mileageInputPositive: {
id: 'sp.vehicles:mileage-errors-min-value',
defaultMessage: 'Skráning þarf að vera að minnsta kosti 1 km',
},
mileageInputMinLength: {
id: 'sp.vehicles:mileage-errors-min-length',
defaultMessage: 'Skrá verður inn kílómetrastöðu til að vista',
defaultMessage: 'Skrá þarf einhverja kílómetrastöðu',
},
mileageSuccessFormTitle: {
id: 'sp.vehicles:mileage-success-form-title',
defaultMessage: 'Kílómetrastaða skráð',
},
mileageUploadTooManyRequests: {
id: 'sp.vehicles:mileage-error-too-many-request',
defaultMessage:
'Of margar upphleðslur á stuttum tíma. Vinsamlegast hinkraðu um stund.',
},
mileageSuccessFormText: {
id: 'sp.vehicles:mileage-success-form-text',
defaultMessage:
Expand Down Expand Up @@ -972,6 +981,10 @@ export const vehicleMessage = defineMessages({
id: 'sp.vehicles:upload-failed',
defaultMessage: 'Upphleðsla mistókst',
},
wrongFileType: {
id: 'sp.vehicles:wrong-file-type',
defaultMessage: 'Vitlaus skráartýpa. Skrá verður að vera .csv eða .xslx',
},
errorWhileProcessing: {
id: 'sp.vehicles:error-while-processing',
defaultMessage: 'Villa við að meðhöndla skjal. Villur: ',
Expand Down Expand Up @@ -1026,7 +1039,7 @@ export const vehicleMessage = defineMessages({
},
fileUploadAcceptedTypes: {
id: 'sp.vehicles:file-upload-accepted-types',
defaultMessage: 'Tekið er við skjölum með endingu; .csv',
defaultMessage: 'Tekið er við skjölum með endingu; .csv, .xlsx',
},
dataAboutJob: {
id: 'sp.vehicles:data-about-job',
Expand Down
Loading
Loading