diff --git a/gov_api/exampleInput.json b/gov_api/exampleInput.json
index 2352f58..59df600 100644
--- a/gov_api/exampleInput.json
+++ b/gov_api/exampleInput.json
@@ -1,56 +1,161 @@
{
"debug": true,
- "userData": {
- "firstName": "נעם",
- "lastName": "געש",
- "id": "123456789",
- "email": "noam.gaash@gmail.com",
- "phone": "0536218158",
- "complaintType": "no_stop",
- "description": "the bus didn't stop, despite I was in the station and waved really hard :("
- },
- "databusData": {
- "operator": 5,
- "loc": [32.090954, 34.822861],
- "color": 22,
- "bearing": 252,
- "recorded_at_time": 1721836808000,
- "point": {
- "id": 4234669318,
- "siri_snapshot_id": 1295402,
- "siri_ride_stop_id": 1949443533,
- "recorded_at_time": "2024-07-24T16:00:08+00:00",
- "lon": 34.822861,
- "lat": 32.090954,
- "bearing": 252,
- "velocity": 22,
- "distance_from_journey_start": 8130,
- "distance_from_siri_ride_stop_meters": 92,
- "siri_snapshot__id": 1295402,
- "siri_snapshot__snapshot_id": "2024/07/24/16/00",
- "siri_snapshot__etl_status": "loaded",
- "siri_snapshot__etl_start_time": "2024-07-24T16:00:50.381498+00:00",
- "siri_snapshot__etl_end_time": "2024-07-24T16:01:39.312956+00:00",
- "siri_snapshot__error": "",
- "siri_snapshot__num_successful_parse_vehicle_locations": 7203,
- "siri_snapshot__num_failed_parse_vehicle_locations": 2,
- "siri_snapshot__num_added_siri_rides": 323,
- "siri_snapshot__num_added_siri_ride_stops": 3002,
- "siri_snapshot__num_added_siri_routes": 0,
- "siri_snapshot__num_added_siri_stops": 0,
- "siri_snapshot__last_heartbeat": "2024-07-24T16:01:22.660122+00:00",
- "siri_snapshot__created_by": "siri-etl-6c5955846-dcdxx",
- "siri_ride__id": 76618275,
- "siri_ride__journey_ref": "2024-07-24-501877",
- "siri_ride__scheduled_start_time": "2024-07-24T15:25:00+00:00",
- "siri_ride__vehicle_ref": "53109603",
- "siri_ride__first_vehicle_location_id": 4234378290,
- "siri_ride__last_vehicle_location_id": 4234811079,
- "siri_ride__duration_minutes": 60,
- "siri_ride__gtfs_ride_id": 81853537,
- "siri_route__id": 185,
- "siri_route__line_ref": 2544,
- "siri_route__operator_ref": 5
+ "data": {
+ "contactType": {
+ "selectContactType": "1",
+ "isChosenType": true
+ },
+ "personalDetails": {
+ "firstName": "נעם",
+ "lastName": "געש",
+ "iDNum": "212121214",
+ "mobile": "0536218158",
+ "phone": "",
+ "contactOptions": "1",
+ "fax": "",
+ "email": "emainh@gmail.com",
+ "city": {
+ "dataCode": -1,
+ "dataText": ""
+ },
+ "street": "",
+ "houseNumber": "",
+ "appartment": "",
+ "postBox": "",
+ "zipCode": "",
+ "name": "personalDetails",
+ "state": "completed",
+ "next": "",
+ "prev": "",
+ "isClosed": true
+ },
+ "requestSubject": {
+ "applySubject": {
+ "dataCode": "0",
+ "dataText": "אוטובוס"
+ },
+ "applyType": {
+ "dataCode": "3",
+ "dataText": "אי עצירה בתחנה"
+ },
+ "name": "requestSubject",
+ "state": "completed",
+ "next": "",
+ "prev": "",
+ "isClosed": true
+ },
+ "requestDetails": {
+ "taxi": {
+ "taxiType": "2"
+ },
+ "busAndOther": {
+ "ravKav": true,
+ "ravKavNumber": "",
+ "reportdate": "",
+ "reportTime": "",
+ "addingFrequencyReason": [],
+ "operator": {
+ "dataCode": 5,
+ "dataText": "אגד"
+ },
+ "addOrRemoveStation": "2",
+ "driverName": "",
+ "licenseNum": "",
+ "eventDate": "",
+ "eventHour": "",
+ "fromHour": "",
+ "toHour": "",
+ "fillByMakatOrAddress": "2",
+ "makatStation": "",
+ "lineNumberText": "",
+ "lineNumberFromList": {
+ "dataText": ""
+ },
+ "direction": {
+ "dataText": ""
+ },
+ "raisingStation": {
+ "dataText": ""
+ },
+ "applyContent": "the bus didn't stop, despite I was in the station and waved really hard :(",
+ "busDirectionFrom": "",
+ "busDirectionTo": "",
+ "raisingStationCity": {
+ "dataText": ""
+ },
+ "destinationStationCity": {
+ "dataText": ""
+ },
+ "raisingStationAddress": "",
+ "cityId": "",
+ "cityName": "",
+ "originCityCode": "",
+ "originCityName": "",
+ "destinationCityCode": "",
+ "destinationCityText": "",
+ "directionCode": "",
+ "stationName": "",
+ "lineCode": ""
+ },
+ "train": {
+ "trainType": "1",
+ "eventDate": "",
+ "eventHour": "",
+ "startStation": {
+ "dataText": ""
+ },
+ "destinationStation": {
+ "dataText": ""
+ },
+ "number": "",
+ "applyContent": ""
+ },
+ "requestSubjectCode": "",
+ "requestTypeCode": "",
+ "title": "",
+ "name": "requestDetails",
+ "state": "notValidated",
+ "next": "",
+ "prev": "",
+ "isClosed": false
+ },
+ "documentAttachment": {
+ "documentsList": [
+ {
+ "attacmentName": ""
+ }
+ ],
+ "name": "documentAttachment",
+ "state": "notValidated",
+ "next": "",
+ "prev": "",
+ "isClosed": true
+ },
+ "followStatus": {
+ "contactIdList": [
+ {
+ "ticketNumber": ""
+ }
+ ],
+ "contactIdResultList": [],
+ "name": "followStatus",
+ "state": "notValidated",
+ "next": "",
+ "prev": "",
+ "isClosed": true
+ },
+ "containersViewModel": {
+ "showPrintButton": true,
+ "isTabsMode": false,
+ "validatedStatus": true
+ },
+ "formInformation": {
+ "referenceNumber": "",
+ "stageStatus": "",
+ "loadingDate": "",
+ "firstLoadingDate": "",
+ "isMobile": false,
+ "language": ""
}
}
}
diff --git a/src/controllers/complaints.controller.js b/src/controllers/complaints.controller.js
index fac51b4..50a516b 100644
--- a/src/controllers/complaints.controller.js
+++ b/src/controllers/complaints.controller.js
@@ -21,7 +21,7 @@ export async function sendComplaint(request, reply) {
if (isDebug) {
request.log.info('Complaint submitted in debug mode');
- return reply.status(200).send({ success: true, debug: true, xml });
+ return reply.status(200).send({ success: true, debug: true, xml, referenceNumber });
}
const response = await axios.post(URL, xml, { headers: { 'Content-Type': 'application/xml' }, timeout: 30000 });
diff --git a/src/schemas/complaints.schema.js b/src/schemas/complaints.schema.js
index bfa32ef..1be2426 100644
--- a/src/schemas/complaints.schema.js
+++ b/src/schemas/complaints.schema.js
@@ -1,5 +1,223 @@
import { S } from './index.js';
+// const complaintsUserDataSchema = S.object()
+// .id('ComplaintsUserDataSchema')
+// .prop('firstName', S.string().maxLength(25))
+// .prop('lastName', S.string().maxLength(25))
+// .prop('id', S.string().maxLength(9).pattern(/\d+/u))
+// .prop('email', S.string().format('email'))
+// .prop('phone', S.string().maxLength(11))
+// .prop('complaintType', S.string())
+// .prop('description', S.string().minLength(2).maxLength(1500))
+// .prop('from', S.string().maxLength(90))
+// .prop('to', S.string().maxLength(90))
+// .prop('timeEvent', S.string().pattern(/^[0-2][0-9]:[0-5][0-9]$/u))
+// .prop('startWait', S.string().pattern(/^[0-2][0-9]:[0-5][0-9]$/u))
+// .prop('endWait', S.string().pattern(/^[0-2][0-9]:[0-5][0-9]$/u))
+// .prop('ravkavId', S.string().maxLength(10))
+// .required(['firstName', 'lastName', 'id', 'email', 'phone', 'complaintType', 'description']);
+
+// const complaintsDataBusDataModel = S.object()
+// .id('ComplaintsDataBusDataModel')
+// .prop('id', S.number())
+// .prop('siriRouteId', S.number())
+// .prop('journeyRef', S.string())
+// .prop('scheduledStartTime', S.string().format('date-time'))
+// .prop('vehicleRef', S.string())
+// .prop('updatedFirstLastVehicleLocations', S.string().format('date-time'))
+// .prop('firstVehicleLocationId', S.number())
+// .prop('lastVehicleLocationId', S.number())
+// .prop('updatedDurationMinutes', S.string().format('date-time'))
+// .prop('durationMinutes', S.number())
+// .prop('journeyGtfsRideId', S.number())
+// .prop('routeGtfsRideId', S.number())
+// .prop('gtfsRideId', S.number())
+// .prop('siriRouteLineRef', S.number())
+// .prop('siriRouteOperatorRef', S.number())
+// .prop('gtfsRideGtfsRouteId', S.number())
+// .prop('gtfsRideJourneyRef', S.string())
+// .prop('gtfsRideStartTime', S.string().format('date-time'))
+// .prop('gtfsRideEndTime', S.string().format('date-time'))
+// .prop('gtfsRouteDate', S.string().format('date-time'))
+// .prop('gtfsRouteLineRef', S.number())
+// .prop('gtfsRouteOperatorRef', S.number())
+// .prop('gtfsRouteRouteShortName', S.string())
+// .prop('gtfsRouteRouteLongName', S.string())
+// .prop('gtfsRouteRouteMkt', S.string())
+// .prop('gtfsRouteRouteDirection', S.string())
+// .prop('gtfsRouteRouteAlternative', S.string())
+// .prop('gtfsRouteAgencyName', S.string())
+// .prop('gtfsRouteRouteType', S.string());
+
+export const dataCodeSchema = S.object()
+ .id('DataCodeSchema')
+ .prop('dataCode', S.anyOf([S.string(), S.number()]))
+ .prop('dataText', S.string());
+
+export const contactIdSchema = S.object().id('ContactIdSchema').prop('ticketNumber', S.string());
+
+export const contactIdResultSchema = S.object()
+ .id('ContactIdResultSchema')
+ .prop('dateReceived', S.string())
+ .prop('contactName', S.string())
+ .prop('incidentStatus', S.string())
+ .prop('ticketNumber', S.string());
+
+export const contactTypeSchema = S.object().id('ContactTypeSchema').prop('selectContactType', S.string()).prop('isChosenType', S.boolean());
+
+export const personalDetailsSchema = S.object()
+ .id('PersonalDetailsSchema')
+ .prop('name', S.string().enum(['personalDetails']))
+ .prop('state', S.string().enum(['completed', 'notValidated']))
+ .prop('next', S.string())
+ .prop('prev', S.string())
+ .prop('isClosed', S.boolean())
+ .prop('firstName', S.string())
+ .prop('lastName', S.string())
+ .prop('iDNum', S.string())
+ .prop('mobile', S.string())
+ .prop('phone', S.string())
+ .prop('contactOptions', S.string())
+ .prop('fax', S.string())
+ .prop('email', S.string())
+ .prop('city', S.ref('DataCodeSchema'))
+ .prop('street', S.string())
+ .prop('houseNumber', S.string())
+ .prop('appartment', S.string())
+ .prop('postBox', S.string())
+ .prop('zipCode', S.string());
+
+export const requestSubjectSchema = S.object()
+ .id('RequestSubjectSchema')
+ .prop('name', S.string().enum(['requestSubject']))
+ .prop('state', S.string().enum(['completed', 'notValidated']))
+ .prop('next', S.string())
+ .prop('prev', S.string())
+ .prop('isClosed', S.boolean())
+ .prop('applySubject', S.ref('DataCodeSchema'))
+ .prop('applyType', S.ref('DataCodeSchema'));
+
+export const taxiDetailsSchema = S.object()
+ .id('TaxiDetailsSchema')
+ .prop('eventDetails', S.string())
+ .prop('invoice', S.string())
+ .prop('evidence', S.string())
+ .prop('otherFactors', S.string())
+ .prop('taxiType', S.string())
+ .prop('licenseNum', S.string())
+ .prop('cap', S.string())
+ .prop('eventDate', S.string())
+ .prop('eventHour', S.string())
+ .prop('eventLocation', S.string())
+ .prop('firstDeclaration', S.boolean())
+ .prop('secondDeclaration', S.boolean());
+
+export const busAndOtherDetailsSchema = S.object()
+ .id('BusAndOtherDetailsSchema')
+ .prop('ravKav', S.boolean())
+ .prop('ravKavNumber', S.string())
+ .prop('reportdate', S.string())
+ .prop('reportTime', S.string())
+ .prop('addingFrequencyReason', S.array().items(S.enum(['LoadTopics', 'LongWaiting', 'ExtensionHours'])))
+ .prop('operator', S.ref('DataCodeSchema'))
+ .prop('addOrRemoveStation', S.string())
+ .prop('driverName', S.string())
+ .prop('licenseNum', S.string())
+ .prop('eventDate', S.string())
+ .prop('eventHour', S.string())
+ .prop('fromHour', S.string())
+ .prop('toHour', S.string())
+ .prop('fillByMakatOrAddress', S.string())
+ .prop('makatStation', S.string())
+ .prop('lineNumberText', S.string())
+ .prop('lineNumberFromList', S.ref('DataCodeSchema'))
+ .prop('direction', S.ref('DataCodeSchema'))
+ .prop('raisingStation', S.ref('DataCodeSchema'))
+ .prop('applyContent', S.string())
+ .prop('busDirectionFrom', S.string())
+ .prop('busDirectionTo', S.string())
+ .prop('raisingStationCity', S.ref('DataCodeSchema'))
+ .prop('destinationStationCity', S.ref('DataCodeSchema'))
+ .prop('raisingStationAddress', S.string())
+ .prop('cityId', S.string())
+ .prop('cityName', S.string())
+ .prop('raisingStationCityCode', S.string())
+ .prop('raisingStationCityName', S.string())
+ .prop('destinationStationCityCode', S.string())
+ .prop('destinationStationCityText', S.string())
+ .prop('directionCode', S.string())
+ .prop('stationName', S.string())
+ .prop('lineCode', S.string());
+
+export const trainDetailsSchema = S.object()
+ .id('TrainDetailsSchema')
+ .prop('trainType', S.string())
+ .prop('eventDate', S.string())
+ .prop('eventHour', S.string())
+ .prop('startStation', S.ref('DataCodeSchema'))
+ .prop('destinationStation', S.ref('DataCodeSchema'))
+ .prop('number', S.string())
+ .prop('applyContent', S.string());
+
+export const requestDetailsSchema = S.object()
+ .id('RequestDetailsSchema')
+ .prop('name', S.string().enum(['requestDetails']))
+ .prop('state', S.string().enum(['completed', 'notValidated']))
+ .prop('next', S.string())
+ .prop('prev', S.string())
+ .prop('isClosed', S.boolean())
+ .prop('taxi', S.ref('TaxiDetailsSchema'))
+ .prop('busAndOther', S.ref('BusAndOtherDetailsSchema'))
+ .prop('train', S.ref('TrainDetailsSchema'))
+ .prop('requestSubjectCode', S.string())
+ .prop('requestTypeCode', S.string())
+ .prop('title', S.string());
+
+export const documentAttachmentSchema = S.object()
+ .id('DocumentAttachmentSchema')
+ .prop('name', S.string().enum(['documentAttachment']))
+ .prop('state', S.string().enum(['completed', 'notValidated']))
+ .prop('next', S.string())
+ .prop('prev', S.string())
+ .prop('isClosed', S.boolean())
+ .prop('documentsList', S.array().items(S.object().prop('attacmentName', S.string())));
+
+export const followStatusSchema = S.object()
+ .id('FollowStatusSchema')
+ .prop('name', S.string().enum(['followStatus']))
+ .prop('state', S.string().enum(['completed', 'notValidated']))
+ .prop('next', S.string())
+ .prop('prev', S.string())
+ .prop('isClosed', S.boolean())
+ .prop('contactIdList', S.array().items(S.ref('ContactIdSchema')))
+ .prop('contactIdResultList', S.array().items(S.ref('ContactIdResultSchema')));
+
+export const containersViewModelSchema = S.object()
+ .id('ContainersViewModelSchema')
+ .prop('showPrintButton', S.boolean())
+ .prop('isTabsMode', S.boolean())
+ .prop('validatedStatus', S.boolean());
+
+export const formInformationSchema = S.object()
+ .id('FormInformationSchema')
+ .prop('referenceNumber', S.string())
+ .prop('stageStatus', S.string())
+ .prop('loadingDate', S.string())
+ .prop('firstLoadingDate', S.string())
+ .prop('isMobile', S.boolean())
+ .prop('language', S.string());
+
+export const formDataModelSchema = S.object()
+ .id('FormDataModelSchema')
+ .prop('contactType', S.ref('ContactTypeSchema'))
+ .prop('personalDetails', S.ref('PersonalDetailsSchema'))
+ .prop('requestSubject', S.ref('RequestSubjectSchema'))
+ .prop('requestDetails', S.ref('RequestDetailsSchema'))
+ .prop('documentAttachment', S.ref('DocumentAttachmentSchema'))
+ .prop('followStatus', S.ref('FollowStatusSchema'))
+ .prop('containersViewModel', S.ref('ContainersViewModelSchema'))
+ .prop('formInformation', S.ref('FormInformationSchema'));
+
/**
* Send complaint endpoint schema
* @type {import('fastify').FastifySchema}
@@ -10,42 +228,7 @@ export const sendComplaintSchema = {
description: 'Submits a complaint to the government forms system',
body: S.object()
.prop('debug', S.boolean().description('Enable debug mode to return XML without sending').default(true))
- .prop(
- 'userData',
- S.object()
- .prop('firstName', S.string().minLength(1).maxLength(100).description('First name of the complainant'))
- .prop('lastName', S.string().minLength(1).maxLength(100).description('Last name of the complainant'))
- .prop('id', S.string().pattern('^[0-9]{9}$').description('ID number of the complainant'))
- .prop('email', S.string().format('email').description('Email address of the complainant'))
- .prop('phone', S.string().default('1234567890').description('Phone number of the complainant'))
- .prop('complaintType', S.string().description('Type of complaint (e.g., no_stop)'))
- .prop('description', S.string().minLength(10).maxLength(1000).description('Detailed description of the complaint'))
- .required(['firstName', 'lastName', 'id', 'email', 'phone']),
- )
- .prop(
- 'databusData',
- S.object(),
- // .prop('operator', S.number().description('Bus operator ID'))
- // .prop('loc', S.array().items([S.number(), S.number()]).description('Location coordinates [longitude, latitude]'))
- // .prop('color', S.number().description('Bus color code'))
- // .prop('bearing', S.number().description('Direction bearing in degrees'))
- // .prop('recorded_at_time', S.number().description('Timestamp when the incident was recorded'))
- // .prop(
- // 'point',
- // S.object()
- // .prop('id', S.number())
- // .prop('siri_snapshot_id', S.number())
- // .prop('siri_ride_stop_id', S.number())
- // .prop('recorded_at_time', S.string().format('date-time'))
- // .prop('lon', S.number())
- // .prop('lat', S.number())
- // .prop('bearing', S.number())
- // .prop('velocity', S.number())
- // .prop('distance_from_journey_start', S.number())
- // .prop('distance_from_siri_ride_stop_meters', S.number()),
- // ),
- // .required(['operator']),
- ),
+ .prop('data', S.ref('FormDataModelSchema')),
response: {
200: S.object()
.prop('success', S.boolean())
diff --git a/src/schemas/loadModels.js b/src/schemas/loadModels.js
index e8a7904..4820a17 100644
--- a/src/schemas/loadModels.js
+++ b/src/schemas/loadModels.js
@@ -1,3 +1,20 @@
+import {
+ busAndOtherDetailsSchema,
+ contactIdResultSchema,
+ contactIdSchema,
+ contactTypeSchema,
+ containersViewModelSchema,
+ dataCodeSchema,
+ documentAttachmentSchema,
+ followStatusSchema,
+ formDataModelSchema,
+ formInformationSchema,
+ personalDetailsSchema,
+ requestDetailsSchema,
+ requestSubjectSchema,
+ taxiDetailsSchema,
+ trainDetailsSchema,
+} from './complaints.schema.js';
import { cityModel, lineModel, notRealNumberModel, operatorModel, pniyaModel, stationModel, subjectModel } from './gov.schema.js';
import { commonErrorResponse } from './index.js';
import { githubIssueModel, githubMilestoneModel, githubUserModel } from './issues.schema.js';
@@ -8,6 +25,24 @@ import { githubIssueModel, githubMilestoneModel, githubUserModel } from './issue
*/
export function loadModels(fastify) {
fastify.addSchema(commonErrorResponse);
+
+ fastify.addSchema(dataCodeSchema);
+ fastify.addSchema(contactIdSchema);
+ fastify.addSchema(contactTypeSchema);
+
+ fastify.addSchema(busAndOtherDetailsSchema);
+ fastify.addSchema(contactIdResultSchema);
+ fastify.addSchema(containersViewModelSchema);
+ fastify.addSchema(documentAttachmentSchema);
+ fastify.addSchema(followStatusSchema);
+ fastify.addSchema(formDataModelSchema);
+ fastify.addSchema(formInformationSchema);
+ fastify.addSchema(personalDetailsSchema);
+ fastify.addSchema(requestDetailsSchema);
+ fastify.addSchema(requestSubjectSchema);
+ fastify.addSchema(taxiDetailsSchema);
+ fastify.addSchema(trainDetailsSchema);
+
fastify.addSchema(cityModel);
fastify.addSchema(lineModel);
fastify.addSchema(notRealNumberModel);
@@ -15,6 +50,7 @@ export function loadModels(fastify) {
fastify.addSchema(pniyaModel);
fastify.addSchema(stationModel);
fastify.addSchema(subjectModel);
+
fastify.addSchema(githubUserModel);
fastify.addSchema(githubMilestoneModel);
fastify.addSchema(githubIssueModel);
diff --git a/src/utils/idValidator.js b/src/utils/idValidator.js
new file mode 100644
index 0000000..1a7e214
--- /dev/null
+++ b/src/utils/idValidator.js
@@ -0,0 +1,14 @@
+/**
+ * @param {string} id
+ * @returns
+ */
+export function idValidator(id) {
+ const n = Number(id);
+ if (!n || isNaN(n) || id.length !== 9 || n <= 0) return false;
+ let sum = 0;
+ for (let i = 0; i < id.length; i += 1) {
+ const num = Number(id[i]) * ((i % 2) + 1);
+ sum += Math.floor(num / 10) + (num % 10);
+ }
+ return sum % 10 === 0;
+}
diff --git a/src/utils/templateBuilder.js b/src/utils/templateBuilder.js
index 4a944d2..6fef9f2 100644
--- a/src/utils/templateBuilder.js
+++ b/src/utils/templateBuilder.js
@@ -1,3 +1,5 @@
+import { idValidator } from './idValidator.js';
+
const dataModelTemplate = {
contactType: {
isChosenType: false,
@@ -174,26 +176,19 @@ function fillTemplate(template, data = {}) {
}
export function templateBuilder(body) {
- // Only support new input structure: { userData, databusData }
- if (!(body.userData && body.databusData)) {
- throw new Error('Input must have userData and databusData');
+ // Support new input structure: { debug?, data: FormDataModelSchema }
+ if (!body.data) {
+ throw new Error('Input must have data property');
+ }
+
+ // Validate ID number from personal details
+ if (!idValidator(String(body.data.personalDetails?.iDNum))) {
+ throw new Error('Invalid Id Number');
}
- // Map userData and databusData to the expected structure
+
+ // Use the data directly as it already matches the expected structure
const input = {
- dataModelSaver: {
- personalDetails: {
- iDNum: body.userData.id,
- firstName: body.userData.firstName,
- lastName: body.userData.lastName,
- email: body.userData.email,
- phone: body.userData.phone,
- },
- requestDetails: {
- busAndOther: {
- operator: { dataText: String(body.databusData.operator) },
- },
- },
- },
+ dataModelSaver: body.data,
};
const dataModelSaver = JSON.stringify(fillTemplate(dataModelTemplate, input.dataModelSaver), null, 2);
diff --git a/tests/complaints.test.js b/tests/complaints.test.js
index 011ad2b..42ae574 100644
--- a/tests/complaints.test.js
+++ b/tests/complaints.test.js
@@ -38,6 +38,25 @@ describe('sendComplaint', () => {
expect(reply.sendCalledWith).to.have.property('error');
});
+ it('should handle invalid id field', async () => {
+ // Create a fresh request with invalid ID
+ const invalidRequest = createMockRequest({
+ debug: true,
+ data: {
+ ...jsonData.data,
+ personalDetails: {
+ ...jsonData.data.personalDetails,
+ iDNum: '123456789',
+ },
+ },
+ });
+
+ await sendComplaint(invalidRequest, reply);
+
+ expect(reply.statusCalledWith).to.equal(500);
+ expect(reply.sendCalledWith).to.have.property('error');
+ });
+
it('should log the complaint processing', async () => {
await sendComplaint(request, reply);
diff --git a/tests/templateBuilder.test.js b/tests/templateBuilder.test.js
index 6967304..288efca 100644
--- a/tests/templateBuilder.test.js
+++ b/tests/templateBuilder.test.js
@@ -4,31 +4,682 @@ import { describe, it } from 'mocha';
import { templateBuilder } from '../src/utils/templateBuilder.js';
describe('templateBuilder', () => {
- it('should throw if input does not have userData and databusData', () => {
- expect(() => templateBuilder({})).to.throw('Input must have userData and databusData');
- expect(() => templateBuilder({ userData: {} })).to.throw('Input must have userData and databusData');
- expect(() => templateBuilder({ databusData: {} })).to.throw('Input must have userData and databusData');
+ it('should throw if input does not have data property', () => {
+ expect(() => templateBuilder({})).to.throw('Input must have data property');
});
- it('should support input structured as { userData, databusData }', () => {
+ it('should throw if input id not valid', () => {
+ expect(() =>
+ templateBuilder({
+ data: {
+ personalDetails: {
+ iDNum: '123456789',
+ firstName: 'נעם',
+ lastName: 'געש',
+ email: 'noam.gaash@gmail.com',
+ phone: '0536218158',
+ },
+ requestDetails: {
+ busAndOther: {
+ operator: { dataText: '5' },
+ },
+ },
+ },
+ }),
+ ).to.throw('Invalid Id Number');
+ });
+
+ it('should support input structured as { data: FormDataModelSchema }', () => {
const xml = templateBuilder({
- databusData: { operator: 5 },
- userData: {
- complaintType: 'no_stop',
- description: "the bus didn't stop, despite I was in the station and waved really hard :(",
- email: 'noam.gaash@gmail.com',
- firstName: 'נעם',
- id: '123456789',
- lastName: 'געש',
- phone: '0536218158',
+ data: {
+ personalDetails: {
+ iDNum: '212121214',
+ firstName: 'נעם',
+ lastName: 'געש',
+ email: 'noam.gaash@gmail.com',
+ phone: '0536218158',
+ },
+ requestDetails: {
+ busAndOther: {
+ operator: { dataText: '5' },
+ },
+ },
},
});
expect(xml).to.include('