first
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import axios from "axios";
|
||||
import { inject, injectable } from "inversify";
|
||||
import { startSession } from "mongoose";
|
||||
|
||||
import { AddressRepo, CityRepo, ProvinceRepo } from "./address.repository";
|
||||
import { SaveSellerAddressDTO, SaveUserAddressDTO } from "./DTO/userAddress.dto";
|
||||
import { INominatimResponse } from "./interfaces/ILocation";
|
||||
import { AddressMessage, CommonMessage, ShopMessage, UserMessage } from "../../common/enums/message.enum";
|
||||
import { BadRequestError, InternalError } from "../../core/app/app.errors";
|
||||
import { IOCTYPES } from "../../IOC/ioc.types";
|
||||
import { UserRepository } from "../user/user.repository";
|
||||
import { ICity } from "./models/city.model";
|
||||
import { IProvince } from "./models/province.model";
|
||||
import { OwnerRef } from "../shop/models/Abstraction/IShop";
|
||||
import { ShopRepo } from "../shop/shop.repository";
|
||||
|
||||
@injectable()
|
||||
class AddressService {
|
||||
private NOMINATIM_URL = "https://nominatim.openstreetmap.org/reverse";
|
||||
// https://nominatim.openstreetmap.org/reverse?lat=34.198770&lon=49.663600&format=json&accept-language=fa
|
||||
// private MAP_IR_URL = "https://map.ir/reverse";
|
||||
// private MAP_IR_API_KEY = process.env.MAP_API_KEY;
|
||||
// private NEHSNAN_URL = "https://api.neshan.org/v5/reverse";
|
||||
// private NESHAN_API_KEY = process.env.NESHAN_API_KEY;
|
||||
@inject(IOCTYPES.UserRepository) private userRepository: UserRepository;
|
||||
@inject(IOCTYPES.AddressRepo) addressRepo: AddressRepo;
|
||||
@inject(IOCTYPES.CityRepo) private cityRepo: CityRepo;
|
||||
@inject(IOCTYPES.ProvinceRepo) private provinceRepo: ProvinceRepo;
|
||||
@inject(IOCTYPES.ShopRepo) shopRepo: ShopRepo;
|
||||
|
||||
//#############################################################
|
||||
//#############################################################
|
||||
async getLocationWithGeo(geo: { lat: string; lon: string }) {
|
||||
const location = await this.getAddressFromCoordinates(geo.lat, geo.lon);
|
||||
let province: IProvince | null;
|
||||
let city: ICity | null;
|
||||
|
||||
//TODO:fix this
|
||||
const provinceName =
|
||||
location?.address?.province?.replace(/^استان\s*/, "").trim() ?? location?.address?.state?.replace(/^استان\s*/, "").trim();
|
||||
const cityName = location.address?.town ? location.address?.town?.replace(/^شهر\s*/, "").trim() : location?.address?.city;
|
||||
|
||||
if (!provinceName || !cityName) throw new BadRequestError(AddressMessage.InvalidLocation);
|
||||
|
||||
province = await this.provinceRepo.model.findOne({ name: provinceName });
|
||||
if (!province) province = await this.provinceRepo.model.create({ name: provinceName });
|
||||
|
||||
city = await this.cityRepo.model.findOne({ name: cityName });
|
||||
if (!city) city = await this.cityRepo.model.create({ name: cityName, province: province._id });
|
||||
|
||||
const displayNameArray = location.display_name.split(",").map((item) => item.trim());
|
||||
|
||||
const filteredDisplayNameArray = location.address.postcode
|
||||
? displayNameArray.filter((item) => !item.includes(location.address.postcode as string))
|
||||
: displayNameArray;
|
||||
|
||||
const address = filteredDisplayNameArray.reverse().join(",").trim();
|
||||
|
||||
return {
|
||||
province: provinceName,
|
||||
provinceId: province._id,
|
||||
city: city.name,
|
||||
cityId: city._id,
|
||||
address,
|
||||
region: location.address.suburb,
|
||||
};
|
||||
}
|
||||
//#############################################################
|
||||
//#############################################################
|
||||
|
||||
async getUserAddress(addressId: string) {
|
||||
const userAddress = await this.addressRepo.findById(addressId);
|
||||
if (!userAddress) throw new BadRequestError([AddressMessage.UserShouldHaveAddress, AddressMessage.NotFound]);
|
||||
return userAddress;
|
||||
}
|
||||
|
||||
//#############################################################
|
||||
//#############################################################
|
||||
|
||||
async setUserAddress(userId: string, addressDto: SaveUserAddressDTO) {
|
||||
const session = await startSession();
|
||||
session.startTransaction();
|
||||
try {
|
||||
const address = await this.addressRepo.model.create(
|
||||
[
|
||||
{
|
||||
address: addressDto.address,
|
||||
city: addressDto.cityId,
|
||||
province: addressDto.provinceId,
|
||||
plaque: addressDto.plaque,
|
||||
postalCode: addressDto.postalCode,
|
||||
lat: addressDto.lat,
|
||||
lon: addressDto.lon,
|
||||
},
|
||||
],
|
||||
{ session },
|
||||
);
|
||||
|
||||
const updatedUser = await this.userRepository.model.findByIdAndUpdate(userId, { address: address[0]._id }, { session });
|
||||
if (!updatedUser) throw new BadRequestError(CommonMessage.NotValid);
|
||||
|
||||
await session.commitTransaction();
|
||||
|
||||
return {
|
||||
message: UserMessage.UserUpdated,
|
||||
address: address[0],
|
||||
};
|
||||
//
|
||||
} catch (error) {
|
||||
await session.abortTransaction();
|
||||
throw error;
|
||||
//
|
||||
} finally {
|
||||
await session.endSession();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
async setSellerShopAddress(sellerId: string, addressDto: SaveSellerAddressDTO) {
|
||||
const session = await startSession();
|
||||
session.startTransaction();
|
||||
try {
|
||||
const shop = await this.shopRepo.model.findOne({ owner: sellerId, ownerRef: OwnerRef.SELLER }).session(session);
|
||||
if (!shop) throw new BadRequestError(ShopMessage.ShopNotFound);
|
||||
const address = await this.addressRepo.model.create(
|
||||
[
|
||||
{
|
||||
address: addressDto.address,
|
||||
city: addressDto.cityId,
|
||||
province: addressDto.provinceId,
|
||||
plaque: addressDto.plaque,
|
||||
// postalCode: addressDto.postalCode,
|
||||
lat: addressDto.lat,
|
||||
lon: addressDto.lon,
|
||||
},
|
||||
],
|
||||
{ session },
|
||||
);
|
||||
shop.address = address[0]._id;
|
||||
await shop.save({ session });
|
||||
|
||||
await session.commitTransaction();
|
||||
|
||||
return {
|
||||
message: AddressMessage.Updated,
|
||||
address: address[0],
|
||||
};
|
||||
} catch (error) {
|
||||
await session.abortTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await session.endSession();
|
||||
}
|
||||
}
|
||||
|
||||
//helpers
|
||||
//##########################
|
||||
private async getAddressFromCoordinates(lat: string, lon: string) {
|
||||
try {
|
||||
const response = await axios.get(this.NOMINATIM_URL, {
|
||||
params: { lat, lon, format: "json", "accept-language": "fa" },
|
||||
headers: {
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
},
|
||||
});
|
||||
|
||||
const location = response.data as INominatimResponse;
|
||||
|
||||
if (!location) throw new BadRequestError("Address not found for the given coordinates.");
|
||||
|
||||
return location;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw new InternalError([`Failed to get address from coordinates: ${error}`]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { AddressService };
|
||||
Reference in New Issue
Block a user