done with timeSlots lookup

This commit is contained in:
Kfir Dayan 2023-04-26 13:35:39 +03:00
parent fee7f1a266
commit 53dd3ada4f
9 changed files with 193 additions and 56 deletions

View file

@ -17,6 +17,30 @@ install pg MacOS -
Start Postgres - Start Postgres -
brew services start postgresql brew services start postgresql
Postgres CLI -
psql postgres
init POSTGRES Database -
CREATE DATABASE drop_shopping;
create tables -
timeSlots -
CREATE TABLE time_slots (
id SERIAL PRIMARY KEY,
start_time TIME NOT NULL,
end_time TIME NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
holidays -
CREATE TABLE holidays (
id SERIAL PRIMARY KEY,
holiday_date DATE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
knex for migration files knex for migration files

View file

@ -1,7 +1,17 @@
{ [
"holidays": [ {
"2023-05-01", "name": "New Year's Day",
"2023-06-12", "date": "2023-01-17",
"2023-09-25" "country": "US"
},
{
"name": "Mother's Day",
"date": "2023-09-18",
"country": "US"
},
{
"name": "Independence Day",
"date": "2023-09-17",
"country": "GB"
}
] ]
}

View file

@ -1,10 +1,39 @@
{ {
"timeSlots": [ "courier_available_timeslots": [
"08:00 - 10:00", {
"10:00 - 12:00", "start_time": "2023-09-17 08:00:00",
"12:00 - 14:00", "end_time": "2023-09-17 09:00:00",
"14:00 - 16:00", "supported_postcodes": [
"16:00 - 18:00", "W1H 1LJ",
"18:00 - 20:00" "2222222"
]
},
{
"start_time": "2023-09-17 09:00:00",
"end_time": "2023-09-17 10:00:00",
"supported_postcodes": [
"1111111",
"2222222",
"3333333"
]
},
{
"start_time": "2023-09-17 09:00:00",
"end_time": "2023-09-17 10:00:00",
"supported_postcodes": [
"4444444",
"5555555",
"6666666"
]
},
{
"start_time": "2023-09-18 14:00:00",
"end_time": "2023-09-18 15:00:00",
"supported_postcodes": [
"W1H 1LJ",
"5555555",
"6666666"
]
}
] ]
} }

View file

@ -13,12 +13,14 @@ export const resolveAddress = async (searchTerm: string): Promise<Address> => {
const response = await axios.get(`https://api.geoapify.com/v1/geocode/search?text=${searchTerm}&format=json&apiKey=${GEOCODING_API_KEY}`); const response = await axios.get(`https://api.geoapify.com/v1/geocode/search?text=${searchTerm}&format=json&apiKey=${GEOCODING_API_KEY}`);
if (response.data.results.length > 0) { if (response.data.results.length > 0) {
const result = response.data.results[0]; const result = response.data.results[0];
console.log(result)
return { return {
country: result.country, country: result.country,
street: result.street, street: result.street,
line1: result.address_line1, line1: result.address_line1,
line2: result.address_line2, line2: result.address_line2,
postcode: result.postcode postcode: result.postcode,
code: result.country_code.toUpperCase()
} }
} else { } else {
throw new Error('No results found'); throw new Error('No results found');

View file

@ -1,25 +1,35 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { resolveAddress } from './geocoding'; import { resolveAddress } from './geocoding';
import { Address } from './types'; import { Address, AvailableTimeslots } from './types';
// DOME // DOME
import { getAvailableTimeSlots } from './services/timeslotsService'; import { getAvailableTimeSlots } from './services/timeslotsService';
import { getHolidays } from './services/holidaysService'; import { getHolidays } from './services/holidaysService';
export const resolveAddressHandler = (req: Request, res: Response) => { export const resolveAddressHandler = (req: Request, res: Response) => {
console.info("resolveAddressHandler called"); console.info("resolveAddressHandler called");
if (!req.body.searchTerm) {
res.status(400).json({ error: 'Missing searchTerm' });
return;
}
const address: Promise<Address> = resolveAddress(req.body.searchTerm); const address: Promise<Address> = resolveAddress(req.body.searchTerm);
address.then((result) => { address.then((result) => {
console.info("resolveAddressHandler result: ", result); console.info("resolveAddressHandler result: ", result);
res.status(200).json(result); res.status(200).json(result);
}) })
};
export const timeslotsHandler = (req: Request, res: Response) => {
// TODO: Implement timeslots functionality
}; };
export const timeslotsHandler = async (req: Request, res: Response) => {
// TODO: Implement timeslots functionality
if (!req.body.address) {
res.status(400).json({ error: 'Missing address' });
return;
}
const address: Address = req.body.address;
const timeSlots: AvailableTimeslots[] = await availableTimeSlots(address);
const availableTimeSlotsResult = await filterOutHolidaysByCountryCode(address, timeSlots);
res.status(200).json(availableTimeSlotsResult);
};
export const deliveriesHandler = (req: Request, res: Response) => { export const deliveriesHandler = (req: Request, res: Response) => {
// TODO: Implement deliveries functionality // TODO: Implement deliveries functionality
}; };
@ -35,3 +45,41 @@ export const dailyDeliveriesHandler = (req: Request, res: Response) => {
export const weeklyDeliveriesHandler = (req: Request, res: Response) => { export const weeklyDeliveriesHandler = (req: Request, res: Response) => {
// TODO: Implement weekly deliveries functionality // TODO: Implement weekly deliveries functionality
}; };
async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]) {
const countryCode = address.code;
const holidays = await getHolidays();
const filteredAvailableTimeSlot = [];
console.log(availableTimeSlot)
holidays.forEach((holiday) => {
if(holiday.country === countryCode) {
availableTimeSlot.forEach((timeSlot) => {
if(timeSlot.start_time.split(' ')[0] !== holiday.date) {
filteredAvailableTimeSlot.push(timeSlot)
}
})
}
});
return filteredAvailableTimeSlot;
}
async function availableTimeSlots(address: Address) {
const availableTimeSlot = [];
const timeslots = await getAvailableTimeSlots();
// check by postcode if any available timeslots
for (const timeslot of timeslots.courier_available_timeslots) {
if (timeslot.supported_postcodes.includes(address.postcode)) {
availableTimeSlot.push({
start_time: timeslot.start_time,
end_time: timeslot.end_time
});
}
}
return availableTimeSlot;
}

View file

@ -8,40 +8,52 @@ app.listen(PORT, () => {
console.log("STARTING ... ") console.log("STARTING ... ")
if (env === 'development') { if (env === 'development') {
console.log("Generating mock data files") console.log("Generating mock data files")
generateMockDataFiles(); // generateMockDataFiles();
} }
console.log(`Server is running on port ${PORT}`); console.log(`Server is running on port ${PORT}`);
}); });
const generateMockDataFiles = () => { // const generateMockDataFiles = () => {
if (!fs.existsSync('./data')) { // if (!fs.existsSync('./data')) {
fs.mkdirSync('./data'); // fs.mkdirSync('./data');
} // }
if (!fs.existsSync('./data/timeSlots.json')) { // if (!fs.existsSync('./data/timeSlots.json')) {
const timeSlots = { // const timeSlots = {
timeSlots: [ // timeSlots: [
"08:00 - 10:00", // "08:00 - 10:00",
"10:00 - 12:00", // "10:00 - 12:00",
"12:00 - 14:00", // "12:00 - 14:00",
"14:00 - 16:00", // "14:00 - 16:00",
"16:00 - 18:00", // "16:00 - 18:00",
"18:00 - 20:00" // "18:00 - 20:00"
] // ]
} // }
fs.writeFileSync('./data/timeSlots.json', JSON.stringify(timeSlots)); // fs.writeFileSync('./data/timeSlots.json', JSON.stringify(timeSlots));
} // }
if (!fs.existsSync('./data/holidays.json')) { // if (!fs.existsSync('./data/holidays.json')) {
const holidays = { // const holidays = {
holidays: [ // "holidays": [
"2023-05-01", // {
"2023-06-12", // "name": "New Year's Day",
"2023-09-25" // "date": "2023-01-17",
] // "country": "US"
} // },
fs.writeFileSync('./data/holidays.json', JSON.stringify(holidays)); // {
} // "name": "Mother's Day",
} // "date": "2023-09-18",
// "country": "US"
// },
// {
// "name": "Independence Day",
// "date": "2023-10-17",
// "country": "US"
// }
// ]
// }
// fs.writeFileSync('./data/holidays.json', JSON.stringify(holidays));
// }
// }

View file

@ -4,9 +4,9 @@ import { resolveAddressHandler, timeslotsHandler, deliveriesHandler, cancelDeliv
const router = express.Router(); const router = express.Router();
router.post('/resolve-address', resolveAddressHandler); router.post('/resolve-address', resolveAddressHandler);
router.post('/timeslots', timeslotsHandler);
router.get('/deliveries/daily', dailyDeliveriesHandler); router.get('/deliveries/daily', dailyDeliveriesHandler);
router.get('/deliveries/weekly', weeklyDeliveriesHandler); router.get('/deliveries/weekly', weeklyDeliveriesHandler);
router.post('/timeslots', timeslotsHandler);
router.post('/deliveries', deliveriesHandler); router.post('/deliveries', deliveriesHandler);
router.delete('/deliveries/:id', cancelDeliveryHandler); router.delete('/deliveries/:id', cancelDeliveryHandler);

View file

@ -12,9 +12,15 @@ exports.seed = async function(knex) {
const holidays = require('../data/holidays.json'); const holidays = require('../data/holidays.json');
const timeslots = require('../data/timeslots.json'); const timeslots = require('../data/timeslots.json');
console.log(holidays)
// Insert the holiday dates into the holidays table // Insert the holiday dates into the holidays table
for (const date of holidays) { for (const date of holidays) {
await knex('holidays').insert({ date }); console.log(date)
await knex('holidays').insert( {
name: "test",
date: "2020-12-25",
country: "US"
} );
} }
// Insert the time slots into the timeslots table // Insert the time slots into the timeslots table

View file

@ -4,4 +4,10 @@ export interface Address {
line2: string; line2: string;
country: string; country: string;
postcode: string; postcode: string;
} code: string;
}
export interface AvailableTimeslots {
start_time: string;
end_time: string;
}