import { getDb } from './db'; const DEMO_URL = 'https://demo.econt.com/ee/services'; const PROD_URL = 'https://ee.econt.com/services'; interface EcontConfig { username: string; password: string; senderCity: string; senderPostCode: string; testMode: boolean; } function getEcontConfig(): EcontConfig & { senderStreet: string; senderStreetNum: string; senderQuarter: string } | null { const db = getDb(); const rows = db.query("SELECT key, value FROM content WHERE key LIKE 'econt_%'").all() as { key: string; value: string }[]; const cfg: Record = {}; for (const r of rows) cfg[r.key] = r.value; if (!cfg.econt_username || !cfg.econt_password) return null; return { username: cfg.econt_username, password: cfg.econt_password, senderCity: cfg.econt_sender_city || 'София', senderPostCode: cfg.econt_sender_postcode || '', testMode: cfg.econt_test_mode === '1', senderStreet: cfg.econt_sender_street || '', senderStreetNum: cfg.econt_sender_street_num || '', senderQuarter: cfg.econt_sender_quarter || '', }; } function authHeader(cfg: EcontConfig): string { return 'Basic ' + Buffer.from(`${cfg.username}:${cfg.password}`).toString('base64'); } function apiUrl(cfg: EcontConfig): string { return cfg.testMode ? DEMO_URL : PROD_URL; } function cityObj(name: string, postCode: string = '') { const c: any = { country: { code3: 'BGR' }, name }; if (postCode) c.postCode = postCode; return c; } function senderAddress(cfg: EcontConfig) { const addr: any = { city: cityObj(cfg.senderCity, cfg.senderPostCode) }; const street = (cfg as any).senderStreet; const num = (cfg as any).senderStreetNum; const quarter = (cfg as any).senderQuarter; if (street) addr.street = street; if (num) addr.num = num; if (quarter) addr.quarter = quarter; return addr; } export interface EcontCalculateResult { totalPrice: number; currency: string; priceBreakdown: { type: string; description: string; price: number; currency: string }[]; error?: string; } // Econt pricing via LabelService.createLabel with mode=calculate. // Uses city names directly (no ID resolution needed). // codAmountCents is the COD amount in euro cents (converted to EUR for the API). export async function econtCalculate( receiverCity: string, weightKg: number, codAmountCents: number = 0, officeDelivery: boolean = false, ): Promise { const cfg = getEcontConfig(); if (!cfg) return { totalPrice: 0, currency: 'EUR', priceBreakdown: [], error: 'econt not configured' }; const label: any = { senderAddress: { city: cityObj(cfg.senderCity) }, shipmentType: 'PACK', weight: Math.max(weightKg, 0.1), packCount: 1, }; if (officeDelivery) { label.receiverOfficeCode = receiverCity; } else { label.receiverAddress = { city: cityObj(receiverCity) }; } const cdEur = codAmountCents > 0 ? parseFloat((codAmountCents / 100).toFixed(2)) : 0; if (cdEur > 0) { label.services = { cdAmount: cdEur, cdType: 'CASH', cdCurrency: 'EUR' }; } try { const resp = await fetch(`${apiUrl(cfg)}/Shipments/LabelService.createLabel.json`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': authHeader(cfg), }, body: JSON.stringify({ mode: 'calculate', label }), }); if (!resp.ok) return { totalPrice: 0, currency: 'EUR', priceBreakdown: [], error: `econt API error: ${resp.status}` }; const data = await resp.json() as any; const result = data?.label; if (!result) return { totalPrice: 0, currency: 'EUR', priceBreakdown: [], error: 'unexpected econt response' }; if (result.error) return { totalPrice: 0, currency: 'EUR', priceBreakdown: [], error: result.error }; return { totalPrice: Number(result.totalPrice) || 0, currency: result.currency || 'EUR', priceBreakdown: (result.services || []).map((s: any) => ({ type: s.type, description: s.description, price: Number(s.price) || 0, currency: s.currency || 'EUR', })), }; } catch (e: any) { return { totalPrice: 0, currency: 'EUR', priceBreakdown: [], error: e.message || 'econt request failed' }; } } export interface EcontLabelResult { shipmentNumber?: string; pdfURL?: string; totalPrice?: number; currency?: string; error?: string; } export async function econtCreateLabel( receiverName: string, receiverPhone: string, receiverCity: string, receiverAddress: string, receiverPostCode: string, receiverQuarter: string, weightKg: number, officeDelivery: boolean, codAmountCents: number, ): Promise { const cfg = getEcontConfig(); if (!cfg) return { error: 'econt not configured' }; const label: any = { senderAddress: senderAddress(cfg), shipmentType: 'PACK', weight: Math.max(weightKg, 0.1), packCount: 1, shipmentDescription: 'Чай', }; if (officeDelivery) { label.receiverOfficeCode = receiverAddress; } else { label.receiverAddress = { city: cityObj(receiverCity, receiverPostCode), }; if (receiverAddress) label.receiverAddress.street = receiverAddress; if (receiverQuarter) label.receiverAddress.quarter = receiverQuarter; } label.receiverClient = { name: receiverName, phones: receiverPhone ? [receiverPhone] : [] }; const cdEur = codAmountCents > 0 ? parseFloat((codAmountCents / 100).toFixed(2)) : 0; if (cdEur > 0) { label.services = { cdAmount: cdEur, cdType: 'CASH', cdCurrency: 'EUR' }; } try { const resp = await fetch(`${apiUrl(cfg)}/Shipments/LabelService.createLabel.json`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': authHeader(cfg), }, body: JSON.stringify({ mode: 'create', label }), }); if (!resp.ok) { const err = await resp.json().catch(() => ({})); return { error: (err as any)?.message || `econt API error: ${resp.status}` }; } const data = await resp.json() as any; const result = data?.label; if (!result) return { error: 'unexpected econt response' }; if (result.error) return { error: result.error }; return { shipmentNumber: result.shipmentNumber, pdfURL: result.pdfURL, totalPrice: Number(result.totalPrice) || 0, currency: result.currency || 'EUR', }; } catch (e: any) { return { error: e.message || 'econt request failed' }; } }