Spaces:
Running
Running
| const bostaService = require('../utils/bostaService'); | |
| const ShippingPrice = require('../models/shippingPriceModel'); | |
| // Get all Cities (Governorates) merged with our local price data | |
| exports.getGovernorates = async (req, res) => { | |
| try { | |
| const bostaData = await bostaService.getBostaCities(); | |
| const governorates = bostaData.data || bostaData; | |
| // Fetch our local pricing data | |
| const localPrices = await ShippingPrice.find(); | |
| const priceMap = new Map(localPrices.map((p) => [p.bostaCityId, p])); | |
| // Merge price data into governorates list | |
| const mergedGovernorates = governorates.map((gov) => { | |
| const localData = priceMap.get(gov._id); | |
| return { | |
| ...gov, | |
| // Normalize names for frontend (Bosta uses name and nameAr strings) | |
| name: { | |
| ar: | |
| gov.nameAr || | |
| gov.name || | |
| (gov._id === 'Jrb6X6ucjiYgMP4T7' ? 'الإسكندرية' : ''), | |
| en: gov.name || (gov._id === 'Jrb6X6ucjiYgMP4T7' ? 'Alexandria' : ''), | |
| }, | |
| fees: localData ? localData.fees || 0 : 0, | |
| deliveryDays: localData ? localData.deliveryDays || 3 : 3, | |
| isActive: localData ? localData.isActive !== false : true, | |
| }; | |
| }); | |
| res.status(200).json({ | |
| status: 'success', | |
| results: mergedGovernorates.length, | |
| data: { | |
| governorates: mergedGovernorates, | |
| }, | |
| }); | |
| } catch (err) { | |
| res.status(500).json({ | |
| status: 'error', | |
| message: 'Failed to fetch governorates', | |
| error: err.message, | |
| }); | |
| } | |
| }; | |
| // Update or Create Shipping Fee for a City | |
| exports.updateShippingFee = async (req, res) => { | |
| try { | |
| const { | |
| bostaCityId, | |
| bostaZoneId, | |
| type = 'city', | |
| fees, | |
| deliveryDays, | |
| areaNameAr, | |
| areaNameEn, | |
| isActive, | |
| } = req.body; | |
| if (!bostaCityId) { | |
| return res.status(400).json({ | |
| status: 'fail', | |
| message: 'Bosta City ID is required', | |
| }); | |
| } | |
| // Search by both City and Zone ID to ensure uniqueness for zones | |
| // For better control, we'll explicitly pick which one to match if multiple exist | |
| // But usually there should be only one city document | |
| const shippingPrice = await ShippingPrice.findOneAndUpdate( | |
| { bostaCityId, bostaZoneId: bostaZoneId || null }, | |
| { | |
| fees, | |
| deliveryDays, | |
| areaNameAr, | |
| areaNameEn, | |
| type, | |
| isActive, | |
| }, | |
| { | |
| new: true, | |
| upsert: true, | |
| runValidators: true, | |
| setDefaultsOnInsert: true, | |
| }, | |
| ); | |
| res.status(200).json({ | |
| status: 'success', | |
| data: { | |
| shippingPrice, | |
| }, | |
| }); | |
| } catch (err) { | |
| res.status(500).json({ | |
| status: 'error', | |
| message: 'Failed to update shipping fee', | |
| error: err.message, | |
| }); | |
| } | |
| }; | |
| // Get Zones (Areas/Districts) for a City | |
| exports.getCities = async (req, res) => { | |
| try { | |
| const { id } = req.params; // governorate ID | |
| const data = await bostaService.getBostaZones(id); | |
| const zones = data.data || data; | |
| // Fetch local prices for these zones | |
| const localPrices = await ShippingPrice.find({ | |
| bostaCityId: id, | |
| type: 'zone', | |
| }); | |
| const priceMap = new Map(localPrices.map((p) => [p.bostaZoneId, p])); | |
| const mergedZones = zones.map((zone) => { | |
| const localData = priceMap.get(zone._id); | |
| return { | |
| ...zone, | |
| name: { | |
| ar: zone.nameAr || zone.name, | |
| en: zone.name, | |
| }, | |
| fees: localData ? localData.fees : 0, | |
| isActive: localData ? localData.isActive : true, | |
| }; | |
| }); | |
| res.status(200).json({ | |
| status: 'success', | |
| results: mergedZones.length, | |
| data: { | |
| cities: mergedZones, | |
| }, | |
| }); | |
| } catch (err) { | |
| res.status(500).json({ | |
| status: 'error', | |
| message: 'Failed to fetch cities', | |
| error: err.message, | |
| }); | |
| } | |
| }; | |
| // Get Districts for a City/Governorate | |
| exports.getDistricts = async (req, res) => { | |
| try { | |
| const { id } = req.params; // governorate ID | |
| const data = await bostaService.getBostaDistricts(id); | |
| const districts = data.data || data; | |
| const normalizedDistricts = districts.map((d) => ({ | |
| _id: d.districtId, | |
| zoneId: d.zoneId, | |
| name: { | |
| ar: d.districtOtherName || d.districtName, | |
| en: d.districtName, | |
| }, | |
| })); | |
| res.status(200).json({ | |
| status: 'success', | |
| results: normalizedDistricts.length, | |
| data: { | |
| districts: normalizedDistricts, | |
| }, | |
| }); | |
| } catch (err) { | |
| res.status(500).json({ | |
| status: 'error', | |
| message: 'Failed to fetch districts', | |
| error: err.message, | |
| }); | |
| } | |
| }; | |