couriers.ts raw

   1  import { getDb } from './db';
   2  
   3  export interface CourierOffice {
   4    id: string;
   5    name: string;
   6    city: string;
   7    address: string;
   8    courier: string;
   9  }
  10  
  11  export async function refreshEcontOffices(): Promise<number> {
  12    const resp = await fetch('https://ee.econt.com/services/Nomenclatures/NomenclaturesService.getOffices.json', {
  13      method: 'POST',
  14      headers: { 'Content-Type': 'application/json' },
  15      body: JSON.stringify({ countryCode: 'BGR' }),
  16    });
  17    if (!resp.ok) throw new Error(`econt api: ${resp.status}`);
  18    const data = await resp.json() as any;
  19    const offices = data.offices || [];
  20    if (offices.length === 0) throw new Error('econt returned no offices');
  21    const db = getDb();
  22    const upsert = db.prepare(`INSERT INTO offices (id, courier, name, city, address, updated_at)
  23      VALUES (?, 'econt', ?, ?, ?, datetime('now'))
  24      ON CONFLICT(id) DO UPDATE SET name = excluded.name, city = excluded.city, address = excluded.address, updated_at = excluded.updated_at`);
  25    const tx = db.transaction((items: any[]) => {
  26      for (const o of items) {
  27        upsert.run(String(o.id), o.name, o.address?.city?.name || '', o.address?.fullAddress || o.name);
  28      }
  29    });
  30    tx(offices);
  31    return offices.length;
  32  }
  33  
  34  export async function refreshSpeedyOffices(): Promise<number> {
  35    const user = process.env.SPEEDY_USERNAME;
  36    const pass = process.env.SPEEDY_PASSWORD;
  37    if (!user || !pass) return 0;
  38    const resp = await fetch('https://api.speedy.bg/v1/location/office', {
  39      method: 'POST',
  40      headers: { 'Content-Type': 'application/json' },
  41      body: JSON.stringify({ userName: user, password: pass, language: 'BG' }),
  42    });
  43    if (!resp.ok) throw new Error(`speedy api: ${resp.status}`);
  44    const data = await resp.json() as any;
  45    const offices = data.offices || [];
  46    if (offices.length === 0) throw new Error('speedy returned no offices');
  47    const db = getDb();
  48    const upsert = db.prepare(`INSERT INTO offices (id, courier, name, city, address, updated_at)
  49      VALUES (?, 'speedy', ?, ?, ?, datetime('now'))
  50      ON CONFLICT(id) DO UPDATE SET name = excluded.name, city = excluded.city, address = excluded.address, updated_at = excluded.updated_at`);
  51    const tx = db.transaction((items: any[]) => {
  52      for (const o of items) {
  53        upsert.run(String(o.id), o.name, o.address?.siteName || o.siteName || '', o.address?.fullAddress || o.address?.localAddress || o.name);
  54      }
  55    });
  56    tx(offices);
  57    return offices.length;
  58  }
  59  
  60  export async function refreshAllOffices(): Promise<{ econt: number; speedy: number }> {
  61    const db = getDb();
  62    db.run('DELETE FROM offices');
  63    const econt = await refreshEcontOffices().catch(() => 0);
  64    const speedy = await refreshSpeedyOffices().catch(() => 0);
  65    return { econt, speedy };
  66  }
  67  
  68  export function getOfficesByCourier(courier: string): CourierOffice[] {
  69    return getDb().query('SELECT id, courier, name, city, address FROM offices WHERE courier = ? ORDER BY city, name').all(courier) as CourierOffice[];
  70  }
  71  
  72  export function getCities(): string[] {
  73    const rows = getDb().query('SELECT DISTINCT city FROM offices ORDER BY city').all() as { city: string }[];
  74    if (rows.length > 0) return rows.map(r => r.city);
  75    return ['София', 'Пловдив', 'Варна', 'Бургас', 'Русе', 'Стара Загора', 'Плевен', 'Велико Търново', 'Благоевград', 'Добрич', 'Шумен', 'Перник'];
  76  }
  77  
  78  export function courierSupportsOffices(courier: string): boolean {
  79    return courier === 'econt';
  80  }
  81